Cred explorer: display commit short hash + summary (#879)

This modifies how commits are displayed in the cred explorer. Rather
than printing the full hash, we now print a short hash followed by the
summary.

Test plan:
Snapshot is updated, also I tested it by running SourceCred on a real
repository.
This commit is contained in:
Dandelion Mané 2018-09-21 13:24:28 -07:00 committed by GitHub
parent 09ed51ed6e
commit 1e5f728e29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 71 additions and 30 deletions

View File

@ -1,6 +1,7 @@
# Changelog
## [Unreleased]
- Display short hash + summary for commits (#879)
- Hyperlink to GitHub entities (#860)
- Add GitHub reactions to the graph (#846)
- Detect references to commits (#833)

View File

@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`plugins/git/render commit snapshots as expected 1`] = `"commit 3715ddfb8d4c4fd2a6f6af75488c82f84c92ec2f"`;
exports[`plugins/git/render commit snapshots as expected 1`] = `"3715ddf: This is an example commit"`;

View File

@ -9,6 +9,7 @@ import * as E from "./edges";
import {description} from "./render";
import type {Assets} from "../../app/assets";
import type {Repo} from "../../core/repo";
import type {Repository} from "./types";
export class StaticPluginAdapter implements IStaticPluginAdapter {
name() {
@ -42,23 +43,38 @@ export class StaticPluginAdapter implements IStaticPluginAdapter {
];
}
async load(assets: Assets, repo: Repo): Promise<IDynamicPluginAdapter> {
const url = assets.resolve(
`/api/v1/data/data/${repo.owner}/${repo.name}/git/graph.json`
);
const response = await fetch(url);
if (!response.ok) {
return Promise.reject(response);
const baseUrl = `/api/v1/data/data/${repo.owner}/${repo.name}/git/`;
async function loadGraph() {
const url = assets.resolve(baseUrl + "graph.json");
const response = await fetch(url);
if (!response.ok) {
return Promise.reject(response);
}
const json = await response.json();
return Graph.fromJSON(json);
}
const json = await response.json();
const graph = Graph.fromJSON(json);
return new DynamicPluginAdapter(graph);
async function loadRepository(): Promise<Repository> {
const url = assets.resolve(baseUrl + "repository.json");
const response = await fetch(url);
if (!response.ok) {
return Promise.reject(response);
}
return await response.json();
}
const [graph, repository] = await Promise.all([
loadGraph(),
loadRepository(),
]);
return new DynamicPluginAdapter(graph, repository);
}
}
class DynamicPluginAdapter implements IDynamicPluginAdapter {
+_graph: Graph;
constructor(graph: Graph) {
+_repository: Repository;
constructor(graph: Graph, repository: Repository) {
this._graph = graph;
this._repository = repository;
}
graph() {
return this._graph;
@ -67,7 +83,7 @@ class DynamicPluginAdapter implements IDynamicPluginAdapter {
// This cast is unsound, and might throw at runtime, but won't have
// silent failures or cause problems down the road.
const address = N.fromRaw((node: any));
return description(address);
return description(address, this._repository);
}
static() {
return new StaticPluginAdapter();

View File

@ -1,19 +1,23 @@
// @flow
import * as N from "./nodes";
import type {Repository} from "./types";
export function description(address: N.StructuredAddress) {
export function description(
address: N.StructuredAddress,
repository: Repository
) {
switch (address.type) {
case "COMMIT":
return `commit ${address.hash}`;
case "TREE":
return `tree ${address.hash}`;
case "BLOB":
return `blob ${address.hash}`;
case "TREE_ENTRY":
return `entry ${JSON.stringify(address.name)} in tree ${
address.treeHash
}`;
case "COMMIT": {
const hash = address.hash;
const commit = repository.commits[hash];
if (commit == null) {
console.error(`Unable to find data for commit ${hash}`);
return hash;
}
const {shortHash, summary} = commit;
return `${shortHash}: ${summary}`;
}
default:
throw new Error(`unknown type: ${(address.type: empty)}`);
}

View File

@ -2,15 +2,35 @@
import * as GN from "./nodes";
import {description} from "./render";
import type {Repository} from "./types";
describe("plugins/git/render", () => {
const examples = {
commit: (): GN.CommitAddress => ({
type: GN.COMMIT_TYPE,
hash: "3715ddfb8d4c4fd2a6f6af75488c82f84c92ec2f",
}),
};
const exampleHash = "3715ddfb8d4c4fd2a6f6af75488c82f84c92ec2f";
const exampleCommit: GN.CommitAddress = Object.freeze({
type: GN.COMMIT_TYPE,
hash: exampleHash,
});
const exampleRepository: Repository = Object.freeze({
commits: {
[exampleHash]: {
hash: exampleHash,
shortHash: exampleHash.slice(0, 7),
summary: "This is an example commit",
parentHashes: [],
},
},
});
it("commit snapshots as expected", () => {
expect(description(examples.commit())).toMatchSnapshot();
expect(description(exampleCommit, exampleRepository)).toMatchSnapshot();
});
it("logs an error for a commit not in the repository", () => {
const badCommit = {type: GN.COMMIT_TYPE, hash: "1234"};
// $ExpectFlowError
console.error = jest.fn();
expect(description(badCommit, exampleRepository)).toBe("1234");
expect(console.error).toHaveBeenCalledWith(
"Unable to find data for commit 1234"
);
});
});