mirror of
https://github.com/status-im/sourcecred.git
synced 2025-02-17 06:56:36 +00:00
Connect PRs and commits via MERGED_AS edges (#200)
This adds MERGED_AS edges which link from a PullRequest to a Commit. It adds a corresponding `mergedCommitHash` method on the porcelain PR that returns the hash of the merged commit (if available). I would have preferred to return a porcelain wrapper over the commit, but since we don't have a porcelain Git api, it seemed preferrable to return the hash as a string. Returning a Node would both break consistency in the porcelain api, and be problematic as the node does not necessarily exist in the api. To ensure that the hash is available without parsing Addresses, I used the edge payload. :) Test plan: Inspect the snapshot changes in the graph (they are fairly readable) and the api testing in api.test.js.
This commit is contained in:
parent
723efeb05f
commit
a76d01ab75
@ -49,7 +49,7 @@ Object {
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`GitHub porcelain API has wrappers for PullRequests 1`] = `
|
||||
exports[`GitHub porcelain API has wrappers for PullRequests Merged 1`] = `
|
||||
Object {
|
||||
"address": Object {
|
||||
"id": "https://github.com/sourcecred/example-github/pull/3",
|
||||
|
@ -199,6 +199,21 @@ Object {
|
||||
"type": "PULL_REQUEST_REVIEW",
|
||||
},
|
||||
},
|
||||
"{\\"id\\":\\"[{\\\\\\"id\\\\\\":\\\\\\"https://github.com/sourcecred/example-github/pull/5\\\\\\",\\\\\\"pluginName\\\\\\":\\\\\\"sourcecred/github-beta\\\\\\",\\\\\\"type\\\\\\":\\\\\\"PULL_REQUEST\\\\\\"},{\\\\\\"id\\\\\\":\\\\\\"6d5b3aa31ebb68a06ceb46bbd6cf49b6ccd6f5e6\\\\\\",\\\\\\"pluginName\\\\\\":\\\\\\"sourcecred/git-beta\\\\\\",\\\\\\"type\\\\\\":\\\\\\"COMMIT\\\\\\"}]\\",\\"pluginName\\":\\"sourcecred/github-beta\\",\\"type\\":\\"MERGED_AS\\"}": Object {
|
||||
"dst": Object {
|
||||
"id": "6d5b3aa31ebb68a06ceb46bbd6cf49b6ccd6f5e6",
|
||||
"pluginName": "sourcecred/git-beta",
|
||||
"type": "COMMIT",
|
||||
},
|
||||
"payload": Object {
|
||||
"hash": "6d5b3aa31ebb68a06ceb46bbd6cf49b6ccd6f5e6",
|
||||
},
|
||||
"src": Object {
|
||||
"id": "https://github.com/sourcecred/example-github/pull/5",
|
||||
"pluginName": "sourcecred/github-beta",
|
||||
"type": "PULL_REQUEST",
|
||||
},
|
||||
},
|
||||
"{\\"id\\":\\"[{\\\\\\"id\\\\\\":\\\\\\"https://github.com/sourcecred/example-github/pull/5\\\\\\",\\\\\\"pluginName\\\\\\":\\\\\\"sourcecred/github-beta\\\\\\",\\\\\\"type\\\\\\":\\\\\\"PULL_REQUEST\\\\\\"},{\\\\\\"id\\\\\\":\\\\\\"https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100313899\\\\\\",\\\\\\"pluginName\\\\\\":\\\\\\"sourcecred/github-beta\\\\\\",\\\\\\"type\\\\\\":\\\\\\"PULL_REQUEST_REVIEW\\\\\\"}]\\",\\"pluginName\\":\\"sourcecred/github-beta\\",\\"type\\":\\"CONTAINS\\"}": Object {
|
||||
"dst": Object {
|
||||
"id": "https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100313899",
|
||||
@ -358,6 +373,21 @@ Object {
|
||||
"type": "PULL_REQUEST",
|
||||
},
|
||||
},
|
||||
"{\\"id\\":\\"[{\\\\\\"id\\\\\\":\\\\\\"https://github.com/sourcecred/example-github/pull/3\\\\\\",\\\\\\"pluginName\\\\\\":\\\\\\"sourcecred/github-beta\\\\\\",\\\\\\"type\\\\\\":\\\\\\"PULL_REQUEST\\\\\\"},{\\\\\\"id\\\\\\":\\\\\\"0a223346b4e6dec0127b1e6aa892c4ee0424b66a\\\\\\",\\\\\\"pluginName\\\\\\":\\\\\\"sourcecred/git-beta\\\\\\",\\\\\\"type\\\\\\":\\\\\\"COMMIT\\\\\\"}]\\",\\"pluginName\\":\\"sourcecred/github-beta\\",\\"type\\":\\"MERGED_AS\\"}": Object {
|
||||
"dst": Object {
|
||||
"id": "0a223346b4e6dec0127b1e6aa892c4ee0424b66a",
|
||||
"pluginName": "sourcecred/git-beta",
|
||||
"type": "COMMIT",
|
||||
},
|
||||
"payload": Object {
|
||||
"hash": "0a223346b4e6dec0127b1e6aa892c4ee0424b66a",
|
||||
},
|
||||
"src": Object {
|
||||
"id": "https://github.com/sourcecred/example-github/pull/3",
|
||||
"pluginName": "sourcecred/github-beta",
|
||||
"type": "PULL_REQUEST",
|
||||
},
|
||||
},
|
||||
"{\\"id\\":\\"[{\\\\\\"id\\\\\\":\\\\\\"https://github.com/sourcecred/example-github/pull/3\\\\\\",\\\\\\"pluginName\\\\\\":\\\\\\"sourcecred/github-beta\\\\\\",\\\\\\"type\\\\\\":\\\\\\"PULL_REQUEST\\\\\\"},{\\\\\\"id\\\\\\":\\\\\\"https://github.com/sourcecred/example-github/pull/3#issuecomment-369162222\\\\\\",\\\\\\"pluginName\\\\\\":\\\\\\"sourcecred/github-beta\\\\\\",\\\\\\"type\\\\\\":\\\\\\"COMMENT\\\\\\"}]\\",\\"pluginName\\":\\"sourcecred/github-beta\\",\\"type\\":\\"CONTAINS\\"}": Object {
|
||||
"dst": Object {
|
||||
"id": "https://github.com/sourcecred/example-github/pull/3#issuecomment-369162222",
|
||||
@ -1830,6 +1860,21 @@ Object {
|
||||
"type": "COMMENT",
|
||||
},
|
||||
},
|
||||
"{\\"id\\":\\"[{\\\\\\"id\\\\\\":\\\\\\"https://github.com/sourcecred/example-github/pull/3\\\\\\",\\\\\\"pluginName\\\\\\":\\\\\\"sourcecred/github-beta\\\\\\",\\\\\\"type\\\\\\":\\\\\\"PULL_REQUEST\\\\\\"},{\\\\\\"id\\\\\\":\\\\\\"0a223346b4e6dec0127b1e6aa892c4ee0424b66a\\\\\\",\\\\\\"pluginName\\\\\\":\\\\\\"sourcecred/git-beta\\\\\\",\\\\\\"type\\\\\\":\\\\\\"COMMIT\\\\\\"}]\\",\\"pluginName\\":\\"sourcecred/github-beta\\",\\"type\\":\\"MERGED_AS\\"}": Object {
|
||||
"dst": Object {
|
||||
"id": "0a223346b4e6dec0127b1e6aa892c4ee0424b66a",
|
||||
"pluginName": "sourcecred/git-beta",
|
||||
"type": "COMMIT",
|
||||
},
|
||||
"payload": Object {
|
||||
"hash": "0a223346b4e6dec0127b1e6aa892c4ee0424b66a",
|
||||
},
|
||||
"src": Object {
|
||||
"id": "https://github.com/sourcecred/example-github/pull/3",
|
||||
"pluginName": "sourcecred/github-beta",
|
||||
"type": "PULL_REQUEST",
|
||||
},
|
||||
},
|
||||
"{\\"id\\":\\"[{\\\\\\"id\\\\\\":\\\\\\"https://github.com/sourcecred/example-github/pull/3\\\\\\",\\\\\\"pluginName\\\\\\":\\\\\\"sourcecred/github-beta\\\\\\",\\\\\\"type\\\\\\":\\\\\\"PULL_REQUEST\\\\\\"},{\\\\\\"id\\\\\\":\\\\\\"https://github.com/sourcecred/example-github/pull/3#issuecomment-369162222\\\\\\",\\\\\\"pluginName\\\\\\":\\\\\\"sourcecred/github-beta\\\\\\",\\\\\\"type\\\\\\":\\\\\\"COMMENT\\\\\\"}]\\",\\"pluginName\\":\\"sourcecred/github-beta\\",\\"type\\":\\"CONTAINS\\"}": Object {
|
||||
"dst": Object {
|
||||
"id": "https://github.com/sourcecred/example-github/pull/3#issuecomment-369162222",
|
||||
@ -1856,6 +1901,21 @@ Object {
|
||||
"type": "PULL_REQUEST_REVIEW",
|
||||
},
|
||||
},
|
||||
"{\\"id\\":\\"[{\\\\\\"id\\\\\\":\\\\\\"https://github.com/sourcecred/example-github/pull/5\\\\\\",\\\\\\"pluginName\\\\\\":\\\\\\"sourcecred/github-beta\\\\\\",\\\\\\"type\\\\\\":\\\\\\"PULL_REQUEST\\\\\\"},{\\\\\\"id\\\\\\":\\\\\\"6d5b3aa31ebb68a06ceb46bbd6cf49b6ccd6f5e6\\\\\\",\\\\\\"pluginName\\\\\\":\\\\\\"sourcecred/git-beta\\\\\\",\\\\\\"type\\\\\\":\\\\\\"COMMIT\\\\\\"}]\\",\\"pluginName\\":\\"sourcecred/github-beta\\",\\"type\\":\\"MERGED_AS\\"}": Object {
|
||||
"dst": Object {
|
||||
"id": "6d5b3aa31ebb68a06ceb46bbd6cf49b6ccd6f5e6",
|
||||
"pluginName": "sourcecred/git-beta",
|
||||
"type": "COMMIT",
|
||||
},
|
||||
"payload": Object {
|
||||
"hash": "6d5b3aa31ebb68a06ceb46bbd6cf49b6ccd6f5e6",
|
||||
},
|
||||
"src": Object {
|
||||
"id": "https://github.com/sourcecred/example-github/pull/5",
|
||||
"pluginName": "sourcecred/github-beta",
|
||||
"type": "PULL_REQUEST",
|
||||
},
|
||||
},
|
||||
"{\\"id\\":\\"[{\\\\\\"id\\\\\\":\\\\\\"https://github.com/sourcecred/example-github/pull/5\\\\\\",\\\\\\"pluginName\\\\\\":\\\\\\"sourcecred/github-beta\\\\\\",\\\\\\"type\\\\\\":\\\\\\"PULL_REQUEST\\\\\\"},{\\\\\\"id\\\\\\":\\\\\\"https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100313899\\\\\\",\\\\\\"pluginName\\\\\\":\\\\\\"sourcecred/github-beta\\\\\\",\\\\\\"type\\\\\\":\\\\\\"PULL_REQUEST_REVIEW\\\\\\"}]\\",\\"pluginName\\":\\"sourcecred/github-beta\\",\\"type\\":\\"CONTAINS\\"}": Object {
|
||||
"dst": Object {
|
||||
"id": "https://github.com/sourcecred/example-github/pull/5#pullrequestreview-100313899",
|
||||
|
@ -6,31 +6,35 @@ import {Graph} from "../../core/graph";
|
||||
import type {Node} from "../../core/graph";
|
||||
import type {Address} from "../../core/address";
|
||||
import type {
|
||||
NodePayload,
|
||||
EdgePayload,
|
||||
NodeType,
|
||||
IssueNodePayload,
|
||||
PullRequestNodePayload,
|
||||
PullRequestReviewNodePayload,
|
||||
PullRequestReviewCommentNodePayload,
|
||||
PullRequestReviewState,
|
||||
CommentNodePayload,
|
||||
AuthorNodePayload,
|
||||
AuthorSubtype,
|
||||
CommentNodePayload,
|
||||
EdgePayload,
|
||||
IssueNodePayload,
|
||||
MergedAsEdgePayload,
|
||||
NodePayload,
|
||||
NodeType,
|
||||
PullRequestNodePayload,
|
||||
PullRequestReviewCommentNodePayload,
|
||||
PullRequestReviewNodePayload,
|
||||
PullRequestReviewState,
|
||||
} from "./types";
|
||||
|
||||
import {
|
||||
CONTAINS_EDGE_TYPE,
|
||||
COMMENT_NODE_TYPE,
|
||||
AUTHORS_EDGE_TYPE,
|
||||
AUTHOR_NODE_TYPE,
|
||||
COMMENT_NODE_TYPE,
|
||||
CONTAINS_EDGE_TYPE,
|
||||
ISSUE_NODE_TYPE,
|
||||
MERGED_AS_EDGE_TYPE,
|
||||
PULL_REQUEST_NODE_TYPE,
|
||||
PULL_REQUEST_REVIEW_NODE_TYPE,
|
||||
PULL_REQUEST_REVIEW_COMMENT_NODE_TYPE,
|
||||
PULL_REQUEST_REVIEW_NODE_TYPE,
|
||||
REFERENCES_EDGE_TYPE,
|
||||
} from "./types";
|
||||
|
||||
import {COMMIT_NODE_TYPE} from "../git/types";
|
||||
|
||||
export type Entity =
|
||||
| Issue
|
||||
| PullRequest
|
||||
@ -221,6 +225,25 @@ export class PullRequest extends Commentable<PullRequestNodePayload> {
|
||||
})
|
||||
.map(({neighbor}) => new PullRequestReview(this.graph, neighbor));
|
||||
}
|
||||
mergeCommitHash(): ?string {
|
||||
const mergeEdge = this.graph
|
||||
.neighborhood(this.nodeAddress, {
|
||||
edgeType: MERGED_AS_EDGE_TYPE,
|
||||
nodeType: COMMIT_NODE_TYPE,
|
||||
direction: "OUT",
|
||||
})
|
||||
.map(({edge}) => edge);
|
||||
if (mergeEdge.length > 1) {
|
||||
throw new Error(
|
||||
`Node at ${this.nodeAddress.id} has too many MERGED_AS edges`
|
||||
);
|
||||
}
|
||||
if (mergeEdge.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const payload: MergedAsEdgePayload = (mergeEdge[0].payload: any);
|
||||
return payload.hash;
|
||||
}
|
||||
}
|
||||
|
||||
export class Issue extends Commentable<IssueNodePayload> {
|
||||
|
@ -35,18 +35,26 @@ describe("GitHub porcelain API", () => {
|
||||
expect(issue.address()).toEqual(issue.node().address);
|
||||
expect(issue.authors().map((x) => x.login())).toEqual(["decentralion"]);
|
||||
});
|
||||
|
||||
it("PullRequests", () => {
|
||||
const pullRequest = issueOrPRByNumber(3);
|
||||
expect(pullRequest.body()).toBe("Oh look, it's a pull request.");
|
||||
expect(pullRequest.title()).toBe("Add README, merge via PR.");
|
||||
expect(pullRequest.url()).toBe(
|
||||
"https://github.com/sourcecred/example-github/pull/3"
|
||||
);
|
||||
expect(pullRequest.number()).toBe(3);
|
||||
expect(pullRequest.type()).toBe(PULL_REQUEST_NODE_TYPE);
|
||||
expect(pullRequest.node()).toMatchSnapshot();
|
||||
expect(pullRequest.address()).toEqual(pullRequest.node().address);
|
||||
describe("PullRequests", () => {
|
||||
it("Merged", () => {
|
||||
const pullRequest = PullRequest.from(issueOrPRByNumber(3));
|
||||
expect(pullRequest.body()).toBe("Oh look, it's a pull request.");
|
||||
expect(pullRequest.title()).toBe("Add README, merge via PR.");
|
||||
expect(pullRequest.url()).toBe(
|
||||
"https://github.com/sourcecred/example-github/pull/3"
|
||||
);
|
||||
expect(pullRequest.number()).toBe(3);
|
||||
expect(pullRequest.type()).toBe(PULL_REQUEST_NODE_TYPE);
|
||||
expect(pullRequest.node()).toMatchSnapshot();
|
||||
expect(pullRequest.address()).toEqual(pullRequest.node().address);
|
||||
expect(pullRequest.mergeCommitHash()).toEqual(
|
||||
"0a223346b4e6dec0127b1e6aa892c4ee0424b66a"
|
||||
);
|
||||
});
|
||||
it("Unmerged", () => {
|
||||
const pullRequest = PullRequest.from(issueOrPRByNumber(9));
|
||||
expect(pullRequest.mergeCommitHash()).toEqual(null);
|
||||
});
|
||||
});
|
||||
|
||||
it("Pull Request Reviews", () => {
|
||||
|
@ -19,6 +19,7 @@ import type {
|
||||
AuthorSubtype,
|
||||
} from "./types";
|
||||
|
||||
import {MERGED_AS_EDGE_TYPE} from "./types";
|
||||
import type {
|
||||
RepositoryJSON,
|
||||
PullRequestReviewJSON,
|
||||
@ -32,6 +33,7 @@ import type {Address} from "../../core/address";
|
||||
import {PLUGIN_NAME} from "./pluginName";
|
||||
import {Graph, edgeID} from "../../core/graph";
|
||||
import {findReferences} from "./findReferences";
|
||||
import {commitAddress} from "../git/address";
|
||||
|
||||
export function parse(
|
||||
repositoryJSON: RepositoryJSON
|
||||
@ -217,6 +219,22 @@ class GithubParser {
|
||||
prJson.reviews.nodes.forEach((r) =>
|
||||
this.addPullRequestReview(pullRequestNode, r)
|
||||
);
|
||||
|
||||
if (prJson.mergeCommit != null) {
|
||||
const hash = prJson.mergeCommit.oid;
|
||||
const dstAddr = commitAddress(hash);
|
||||
const mergedAsEdge = {
|
||||
address: this.makeEdgeAddress(
|
||||
MERGED_AS_EDGE_TYPE,
|
||||
pullRequestNode.address,
|
||||
dstAddr
|
||||
),
|
||||
payload: {hash},
|
||||
src: pullRequestNode.address,
|
||||
dst: dstAddr,
|
||||
};
|
||||
this.graph.addEdge(mergedAsEdge);
|
||||
}
|
||||
}
|
||||
|
||||
addPullRequestReview(
|
||||
|
@ -98,6 +98,8 @@ export type AuthorsEdgePayload = {};
|
||||
export const AUTHORS_EDGE_TYPE: "AUTHORS" = "AUTHORS";
|
||||
export type ContainsEdgePayload = {};
|
||||
export const CONTAINS_EDGE_TYPE: "CONTAINS" = "CONTAINS";
|
||||
export type MergedAsEdgePayload = {|+hash: string|};
|
||||
export const MERGED_AS_EDGE_TYPE: "MERGED_AS" = "MERGED_AS";
|
||||
export type ReferencesEdgePayload = {};
|
||||
export const REFERENCES_EDGE_TYPE: "REFERENCES" = "REFERENCES";
|
||||
|
||||
@ -110,6 +112,10 @@ export type EdgeTypes = {|
|
||||
payload: ContainsEdgePayload,
|
||||
type: typeof CONTAINS_EDGE_TYPE,
|
||||
},
|
||||
MERGED_AS: {
|
||||
payload: MergedAsEdgePayload,
|
||||
type: typeof MERGED_AS_EDGE_TYPE,
|
||||
},
|
||||
REFERENCES: {
|
||||
payload: ReferencesEdgePayload,
|
||||
type: typeof REFERENCES_EDGE_TYPE,
|
||||
@ -119,6 +125,7 @@ export type EdgeTypes = {|
|
||||
export type EdgeType =
|
||||
| typeof AUTHORS_EDGE_TYPE
|
||||
| typeof CONTAINS_EDGE_TYPE
|
||||
| typeof MERGED_AS_EDGE_TYPE
|
||||
| typeof REFERENCES_EDGE_TYPE;
|
||||
|
||||
export type EdgePayload =
|
||||
|
Loading…
x
Reference in New Issue
Block a user