Represent submodule commits as normal commits (#423)
Summary: Closes #417. Submodule commits are dead; long live commits. The ontology is now: - A tree includes tree entries. - A tree entry may have a blob as contents. - A tree entry may have a tree as contents. - A tree entry may have a commit as contents. Test Plan: Existing unit tests suffice, especially `#commits yields all commits`. wchargin-branch: git-remove-submodule-commits
This commit is contained in:
parent
38c364c916
commit
518d5b819c
|
@ -121,7 +121,7 @@ Array [
|
||||||
"3dfb84795e07341b05fad3a0d5a55f8304b2d7d8",
|
"3dfb84795e07341b05fad3a0d5a55f8304b2d7d8",
|
||||||
"pygravitydefier",
|
"pygravitydefier",
|
||||||
],
|
],
|
||||||
"dstIndex": 15,
|
"dstIndex": 10,
|
||||||
"srcIndex": 29,
|
"srcIndex": 29,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
|
@ -186,7 +186,7 @@ Array [
|
||||||
"569e1d383759903134df75230d63c0090196d4cb",
|
"569e1d383759903134df75230d63c0090196d4cb",
|
||||||
"pygravitydefier",
|
"pygravitydefier",
|
||||||
],
|
],
|
||||||
"dstIndex": 15,
|
"dstIndex": 10,
|
||||||
"srcIndex": 34,
|
"srcIndex": 34,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
|
@ -303,7 +303,7 @@ Array [
|
||||||
"7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
"7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||||
"pygravitydefier",
|
"pygravitydefier",
|
||||||
],
|
],
|
||||||
"dstIndex": 14,
|
"dstIndex": 7,
|
||||||
"srcIndex": 43,
|
"srcIndex": 43,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
|
@ -381,7 +381,7 @@ Array [
|
||||||
"819fc546cea489476ce8dc90785e9ba7753d0a8f",
|
"819fc546cea489476ce8dc90785e9ba7753d0a8f",
|
||||||
"pygravitydefier",
|
"pygravitydefier",
|
||||||
],
|
],
|
||||||
"dstIndex": 14,
|
"dstIndex": 7,
|
||||||
"srcIndex": 49,
|
"srcIndex": 49,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
|
@ -459,7 +459,7 @@ Array [
|
||||||
"bbf3b8b3d26a4f884b5c022d46851f593d329192",
|
"bbf3b8b3d26a4f884b5c022d46851f593d329192",
|
||||||
"pygravitydefier",
|
"pygravitydefier",
|
||||||
],
|
],
|
||||||
"dstIndex": 14,
|
"dstIndex": 7,
|
||||||
"srcIndex": 55,
|
"srcIndex": 55,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
|
@ -513,8 +513,8 @@ Array [
|
||||||
"COMMIT",
|
"COMMIT",
|
||||||
"69c5aad50eec8f2a0a07c988c3b283a6490eb45b",
|
"69c5aad50eec8f2a0a07c988c3b283a6490eb45b",
|
||||||
],
|
],
|
||||||
"dstIndex": 8,
|
"dstIndex": 9,
|
||||||
"srcIndex": 7,
|
"srcIndex": 8,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"address": Array [
|
"address": Array [
|
||||||
|
@ -528,8 +528,8 @@ Array [
|
||||||
"COMMIT",
|
"COMMIT",
|
||||||
"e8b7a8f19701cd5a25e4a097d513ead60e5f8bcc",
|
"e8b7a8f19701cd5a25e4a097d513ead60e5f8bcc",
|
||||||
],
|
],
|
||||||
"dstIndex": 13,
|
"dstIndex": 15,
|
||||||
"srcIndex": 8,
|
"srcIndex": 9,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"address": Array [
|
"address": Array [
|
||||||
|
@ -543,8 +543,8 @@ Array [
|
||||||
"COMMIT",
|
"COMMIT",
|
||||||
"c08ee3a4edea384d5291ffcbf06724a13ed72325",
|
"c08ee3a4edea384d5291ffcbf06724a13ed72325",
|
||||||
],
|
],
|
||||||
"dstIndex": 10,
|
"dstIndex": 12,
|
||||||
"srcIndex": 9,
|
"srcIndex": 11,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"address": Array [
|
"address": Array [
|
||||||
|
@ -558,8 +558,8 @@ Array [
|
||||||
"COMMIT",
|
"COMMIT",
|
||||||
"c2b51945e7457546912a8ce158ed9d294558d294",
|
"c2b51945e7457546912a8ce158ed9d294558d294",
|
||||||
],
|
],
|
||||||
"dstIndex": 11,
|
"dstIndex": 13,
|
||||||
"srcIndex": 10,
|
"srcIndex": 12,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"address": Array [
|
"address": Array [
|
||||||
|
@ -573,8 +573,8 @@ Array [
|
||||||
"COMMIT",
|
"COMMIT",
|
||||||
"8d287c3bfbf8455ef30187bf5153ffc1b6eef268",
|
"8d287c3bfbf8455ef30187bf5153ffc1b6eef268",
|
||||||
],
|
],
|
||||||
"dstIndex": 9,
|
"dstIndex": 11,
|
||||||
"srcIndex": 12,
|
"srcIndex": 14,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"address": Array [
|
"address": Array [
|
||||||
|
@ -588,8 +588,8 @@ Array [
|
||||||
"COMMIT",
|
"COMMIT",
|
||||||
"d160cca97611e9dfed642522ad44408d0292e8ea",
|
"d160cca97611e9dfed642522ad44408d0292e8ea",
|
||||||
],
|
],
|
||||||
"dstIndex": 12,
|
"dstIndex": 14,
|
||||||
"srcIndex": 13,
|
"srcIndex": 15,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"address": Array [
|
"address": Array [
|
||||||
|
@ -601,7 +601,7 @@ Array [
|
||||||
"3715ddfb8d4c4fd2a6f6af75488c82f84c92ec2f",
|
"3715ddfb8d4c4fd2a6f6af75488c82f84c92ec2f",
|
||||||
],
|
],
|
||||||
"dstIndex": 21,
|
"dstIndex": 21,
|
||||||
"srcIndex": 7,
|
"srcIndex": 8,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"address": Array [
|
"address": Array [
|
||||||
|
@ -613,7 +613,7 @@ Array [
|
||||||
"69c5aad50eec8f2a0a07c988c3b283a6490eb45b",
|
"69c5aad50eec8f2a0a07c988c3b283a6490eb45b",
|
||||||
],
|
],
|
||||||
"dstIndex": 23,
|
"dstIndex": 23,
|
||||||
"srcIndex": 8,
|
"srcIndex": 9,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"address": Array [
|
"address": Array [
|
||||||
|
@ -625,7 +625,7 @@ Array [
|
||||||
"8d287c3bfbf8455ef30187bf5153ffc1b6eef268",
|
"8d287c3bfbf8455ef30187bf5153ffc1b6eef268",
|
||||||
],
|
],
|
||||||
"dstIndex": 17,
|
"dstIndex": 17,
|
||||||
"srcIndex": 9,
|
"srcIndex": 11,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"address": Array [
|
"address": Array [
|
||||||
|
@ -637,7 +637,7 @@ Array [
|
||||||
"c08ee3a4edea384d5291ffcbf06724a13ed72325",
|
"c08ee3a4edea384d5291ffcbf06724a13ed72325",
|
||||||
],
|
],
|
||||||
"dstIndex": 16,
|
"dstIndex": 16,
|
||||||
"srcIndex": 10,
|
"srcIndex": 12,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"address": Array [
|
"address": Array [
|
||||||
|
@ -649,7 +649,7 @@ Array [
|
||||||
"c2b51945e7457546912a8ce158ed9d294558d294",
|
"c2b51945e7457546912a8ce158ed9d294558d294",
|
||||||
],
|
],
|
||||||
"dstIndex": 24,
|
"dstIndex": 24,
|
||||||
"srcIndex": 11,
|
"srcIndex": 13,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"address": Array [
|
"address": Array [
|
||||||
|
@ -661,7 +661,7 @@ Array [
|
||||||
"d160cca97611e9dfed642522ad44408d0292e8ea",
|
"d160cca97611e9dfed642522ad44408d0292e8ea",
|
||||||
],
|
],
|
||||||
"dstIndex": 18,
|
"dstIndex": 18,
|
||||||
"srcIndex": 12,
|
"srcIndex": 14,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"address": Array [
|
"address": Array [
|
||||||
|
@ -673,7 +673,7 @@ Array [
|
||||||
"e8b7a8f19701cd5a25e4a097d513ead60e5f8bcc",
|
"e8b7a8f19701cd5a25e4a097d513ead60e5f8bcc",
|
||||||
],
|
],
|
||||||
"dstIndex": 22,
|
"dstIndex": 22,
|
||||||
"srcIndex": 13,
|
"srcIndex": 15,
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
"address": Array [
|
"address": Array [
|
||||||
|
@ -1161,6 +1161,12 @@ Array [
|
||||||
"BLOB",
|
"BLOB",
|
||||||
"f1f2514ca6d7a6a1a0511957021b1995bf9ace1c",
|
"f1f2514ca6d7a6a1a0511957021b1995bf9ace1c",
|
||||||
],
|
],
|
||||||
|
Array [
|
||||||
|
"sourcecred",
|
||||||
|
"git",
|
||||||
|
"COMMIT",
|
||||||
|
"29ef158bc982733e2ba429fcf73e2f7562244188",
|
||||||
|
],
|
||||||
Array [
|
Array [
|
||||||
"sourcecred",
|
"sourcecred",
|
||||||
"git",
|
"git",
|
||||||
|
@ -1173,6 +1179,12 @@ Array [
|
||||||
"COMMIT",
|
"COMMIT",
|
||||||
"69c5aad50eec8f2a0a07c988c3b283a6490eb45b",
|
"69c5aad50eec8f2a0a07c988c3b283a6490eb45b",
|
||||||
],
|
],
|
||||||
|
Array [
|
||||||
|
"sourcecred",
|
||||||
|
"git",
|
||||||
|
"COMMIT",
|
||||||
|
"762c062fbdc7ec198cd693e95d55b374a08ff3e3",
|
||||||
|
],
|
||||||
Array [
|
Array [
|
||||||
"sourcecred",
|
"sourcecred",
|
||||||
"git",
|
"git",
|
||||||
|
@ -1203,20 +1215,6 @@ Array [
|
||||||
"COMMIT",
|
"COMMIT",
|
||||||
"e8b7a8f19701cd5a25e4a097d513ead60e5f8bcc",
|
"e8b7a8f19701cd5a25e4a097d513ead60e5f8bcc",
|
||||||
],
|
],
|
||||||
Array [
|
|
||||||
"sourcecred",
|
|
||||||
"git",
|
|
||||||
"SUBMODULE_COMMIT",
|
|
||||||
"https://github.com/sourcecred/example-git-submodule.git",
|
|
||||||
"29ef158bc982733e2ba429fcf73e2f7562244188",
|
|
||||||
],
|
|
||||||
Array [
|
|
||||||
"sourcecred",
|
|
||||||
"git",
|
|
||||||
"SUBMODULE_COMMIT",
|
|
||||||
"https://github.com/sourcecred/example-git-submodule.git",
|
|
||||||
"762c062fbdc7ec198cd693e95d55b374a08ff3e3",
|
|
||||||
],
|
|
||||||
Array [
|
Array [
|
||||||
"sourcecred",
|
"sourcecred",
|
||||||
"git",
|
"git",
|
||||||
|
|
|
@ -30,23 +30,6 @@ Object {
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`plugins/git/nodes snapshots as expected: submoduleCommit 1`] = `
|
|
||||||
Object {
|
|
||||||
"address": Array [
|
|
||||||
"sourcecred",
|
|
||||||
"git",
|
|
||||||
"SUBMODULE_COMMIT",
|
|
||||||
"https://github.com/sourcecred/example-git-submodule.git",
|
|
||||||
"29ef158bc982733e2ba429fcf73e2f7562244188",
|
|
||||||
],
|
|
||||||
"structured": Object {
|
|
||||||
"commitHash": "29ef158bc982733e2ba429fcf73e2f7562244188",
|
|
||||||
"submoduleUrl": "https://github.com/sourcecred/example-git-submodule.git",
|
|
||||||
"type": "SUBMODULE_COMMIT",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`plugins/git/nodes snapshots as expected: tree 1`] = `
|
exports[`plugins/git/nodes snapshots as expected: tree 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"address": Array [
|
"address": Array [
|
||||||
|
|
|
@ -24,11 +24,8 @@ class GraphCreator {
|
||||||
}
|
}
|
||||||
|
|
||||||
addRepository(repository: GT.Repository) {
|
addRepository(repository: GT.Repository) {
|
||||||
const treeAndNameToSubmoduleUrls = this.treeAndNameToSubmoduleUrls(
|
|
||||||
repository
|
|
||||||
);
|
|
||||||
for (const treeHash of Object.keys(repository.trees)) {
|
for (const treeHash of Object.keys(repository.trees)) {
|
||||||
this.addTree(repository.trees[treeHash], treeAndNameToSubmoduleUrls);
|
this.addTree(repository.trees[treeHash]);
|
||||||
}
|
}
|
||||||
for (const commitHash of Object.keys(repository.commits)) {
|
for (const commitHash of Object.keys(repository.commits)) {
|
||||||
this.addCommit(repository.commits[commitHash]);
|
this.addCommit(repository.commits[commitHash]);
|
||||||
|
@ -36,38 +33,6 @@ class GraphCreator {
|
||||||
this.addBecomesEdges(repository);
|
this.addBecomesEdges(repository);
|
||||||
}
|
}
|
||||||
|
|
||||||
treeAndNameToSubmoduleUrls(repository: GT.Repository) {
|
|
||||||
const result: {[tree: GT.Hash]: {[name: string]: string[]}} = {};
|
|
||||||
Object.keys(repository.commits).forEach((commitHash) => {
|
|
||||||
const {treeHash: rootTreeHash, submoduleUrls} = repository.commits[
|
|
||||||
commitHash
|
|
||||||
];
|
|
||||||
Object.keys(submoduleUrls).forEach((path) => {
|
|
||||||
const parts = path.split("/");
|
|
||||||
const [treePath, name] = [
|
|
||||||
parts.slice(0, parts.length - 1),
|
|
||||||
parts[parts.length - 1],
|
|
||||||
];
|
|
||||||
let tree = repository.trees[rootTreeHash];
|
|
||||||
for (const pathComponent of treePath) {
|
|
||||||
tree = repository.trees[tree.entries[pathComponent].hash];
|
|
||||||
if (tree == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result[tree.hash] == null) {
|
|
||||||
result[tree.hash] = {};
|
|
||||||
}
|
|
||||||
const url = submoduleUrls[path];
|
|
||||||
if (result[tree.hash][name] == null) {
|
|
||||||
result[tree.hash][name] = [];
|
|
||||||
}
|
|
||||||
result[tree.hash][name].push(url);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
addCommit(commit: GT.Commit) {
|
addCommit(commit: GT.Commit) {
|
||||||
const node: GN.CommitAddress = {type: GN.COMMIT_TYPE, hash: commit.hash};
|
const node: GN.CommitAddress = {type: GN.COMMIT_TYPE, hash: commit.hash};
|
||||||
const tree: GN.TreeAddress = {type: GN.TREE_TYPE, hash: commit.treeHash};
|
const tree: GN.TreeAddress = {type: GN.TREE_TYPE, hash: commit.treeHash};
|
||||||
|
@ -81,7 +46,7 @@ class GraphCreator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addTree(tree: GT.Tree, treeAndNameToSubmoduleUrls) {
|
addTree(tree: GT.Tree) {
|
||||||
const treeNode: GN.TreeAddress = {type: GN.TREE_TYPE, hash: tree.hash};
|
const treeNode: GN.TreeAddress = {type: GN.TREE_TYPE, hash: tree.hash};
|
||||||
this.graph.addNode(GN.toRaw(treeNode));
|
this.graph.addNode(GN.toRaw(treeNode));
|
||||||
for (const name of Object.keys(tree.entries)) {
|
for (const name of Object.keys(tree.entries)) {
|
||||||
|
@ -93,34 +58,25 @@ class GraphCreator {
|
||||||
};
|
};
|
||||||
this.graph.addNode(GN.toRaw(entryNode));
|
this.graph.addNode(GN.toRaw(entryNode));
|
||||||
this.graph.addEdge(GE.createEdge.includes(treeNode, entryNode));
|
this.graph.addEdge(GE.createEdge.includes(treeNode, entryNode));
|
||||||
let targets: GN.TreeEntryContentsAddress[] = [];
|
let target: ?GN.TreeEntryContentsAddress = null;
|
||||||
switch (entry.type) {
|
switch (entry.type) {
|
||||||
case "blob":
|
case "blob":
|
||||||
targets.push({type: GN.BLOB_TYPE, hash: entry.hash});
|
target = {type: GN.BLOB_TYPE, hash: entry.hash};
|
||||||
break;
|
break;
|
||||||
case "tree":
|
case "tree":
|
||||||
targets.push({type: GN.TREE_TYPE, hash: entry.hash});
|
target = {type: GN.TREE_TYPE, hash: entry.hash};
|
||||||
break;
|
break;
|
||||||
case "commit":
|
case "commit":
|
||||||
// One entry for each possible URL.
|
// Submodule commit.
|
||||||
const urls = treeAndNameToSubmoduleUrls[tree.hash][name];
|
target = {type: GN.COMMIT_TYPE, hash: entry.hash};
|
||||||
for (const url of urls) {
|
|
||||||
targets.push({
|
|
||||||
type: GN.SUBMODULE_COMMIT_TYPE,
|
|
||||||
submoduleUrl: url,
|
|
||||||
commitHash: entry.hash,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// eslint-disable-next-line no-unused-expressions
|
// eslint-disable-next-line no-unused-expressions
|
||||||
(entry.type: empty);
|
(entry.type: empty);
|
||||||
throw new Error(String(entry.type));
|
throw new Error(String(entry.type));
|
||||||
}
|
}
|
||||||
for (const target of targets) {
|
this.graph.addNode(GN.toRaw(target));
|
||||||
this.graph.addNode(GN.toRaw(target));
|
this.graph.addEdge(GE.createEdge.hasContents(entryNode, target));
|
||||||
this.graph.addEdge(GE.createEdge.hasContents(entryNode, target));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,13 +37,11 @@ describe("plugins/git/createGraph", () => {
|
||||||
hash: "commit1",
|
hash: "commit1",
|
||||||
parentHashes: [],
|
parentHashes: [],
|
||||||
treeHash: beforeTree,
|
treeHash: beforeTree,
|
||||||
submoduleUrls: {},
|
|
||||||
},
|
},
|
||||||
commit2: {
|
commit2: {
|
||||||
hash: "commit2",
|
hash: "commit2",
|
||||||
parentHashes: ["commit1"],
|
parentHashes: ["commit1"],
|
||||||
treeHash: afterTree,
|
treeHash: afterTree,
|
||||||
submoduleUrls: {},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
trees,
|
trees,
|
||||||
|
|
|
@ -5,9 +5,6 @@
|
||||||
"parentHashes": [
|
"parentHashes": [
|
||||||
"69c5aad50eec8f2a0a07c988c3b283a6490eb45b"
|
"69c5aad50eec8f2a0a07c988c3b283a6490eb45b"
|
||||||
],
|
],
|
||||||
"submoduleUrls": {
|
|
||||||
"pygravitydefier": "https://github.com/sourcecred/example-git-submodule.git"
|
|
||||||
},
|
|
||||||
"treeHash": "7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed"
|
"treeHash": "7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed"
|
||||||
},
|
},
|
||||||
"69c5aad50eec8f2a0a07c988c3b283a6490eb45b": {
|
"69c5aad50eec8f2a0a07c988c3b283a6490eb45b": {
|
||||||
|
@ -15,9 +12,6 @@
|
||||||
"parentHashes": [
|
"parentHashes": [
|
||||||
"e8b7a8f19701cd5a25e4a097d513ead60e5f8bcc"
|
"e8b7a8f19701cd5a25e4a097d513ead60e5f8bcc"
|
||||||
],
|
],
|
||||||
"submoduleUrls": {
|
|
||||||
"pygravitydefier": "https://github.com/sourcecred/example-git-submodule.git"
|
|
||||||
},
|
|
||||||
"treeHash": "bbf3b8b3d26a4f884b5c022d46851f593d329192"
|
"treeHash": "bbf3b8b3d26a4f884b5c022d46851f593d329192"
|
||||||
},
|
},
|
||||||
"8d287c3bfbf8455ef30187bf5153ffc1b6eef268": {
|
"8d287c3bfbf8455ef30187bf5153ffc1b6eef268": {
|
||||||
|
@ -25,9 +19,6 @@
|
||||||
"parentHashes": [
|
"parentHashes": [
|
||||||
"c08ee3a4edea384d5291ffcbf06724a13ed72325"
|
"c08ee3a4edea384d5291ffcbf06724a13ed72325"
|
||||||
],
|
],
|
||||||
"submoduleUrls": {
|
|
||||||
"pygravitydefier": "https://github.com/sourcecred/example-git-submodule.git"
|
|
||||||
},
|
|
||||||
"treeHash": "3dfb84795e07341b05fad3a0d5a55f8304b2d7d8"
|
"treeHash": "3dfb84795e07341b05fad3a0d5a55f8304b2d7d8"
|
||||||
},
|
},
|
||||||
"c08ee3a4edea384d5291ffcbf06724a13ed72325": {
|
"c08ee3a4edea384d5291ffcbf06724a13ed72325": {
|
||||||
|
@ -35,16 +26,12 @@
|
||||||
"parentHashes": [
|
"parentHashes": [
|
||||||
"c2b51945e7457546912a8ce158ed9d294558d294"
|
"c2b51945e7457546912a8ce158ed9d294558d294"
|
||||||
],
|
],
|
||||||
"submoduleUrls": {
|
|
||||||
},
|
|
||||||
"treeHash": "2f7155e359fd0ecb96ffdca66fa45b6ed5792809"
|
"treeHash": "2f7155e359fd0ecb96ffdca66fa45b6ed5792809"
|
||||||
},
|
},
|
||||||
"c2b51945e7457546912a8ce158ed9d294558d294": {
|
"c2b51945e7457546912a8ce158ed9d294558d294": {
|
||||||
"hash": "c2b51945e7457546912a8ce158ed9d294558d294",
|
"hash": "c2b51945e7457546912a8ce158ed9d294558d294",
|
||||||
"parentHashes": [
|
"parentHashes": [
|
||||||
],
|
],
|
||||||
"submoduleUrls": {
|
|
||||||
},
|
|
||||||
"treeHash": "bdff5d94193170015d6cbb549b7b630649428b1f"
|
"treeHash": "bdff5d94193170015d6cbb549b7b630649428b1f"
|
||||||
},
|
},
|
||||||
"d160cca97611e9dfed642522ad44408d0292e8ea": {
|
"d160cca97611e9dfed642522ad44408d0292e8ea": {
|
||||||
|
@ -52,9 +39,6 @@
|
||||||
"parentHashes": [
|
"parentHashes": [
|
||||||
"8d287c3bfbf8455ef30187bf5153ffc1b6eef268"
|
"8d287c3bfbf8455ef30187bf5153ffc1b6eef268"
|
||||||
],
|
],
|
||||||
"submoduleUrls": {
|
|
||||||
"pygravitydefier": "https://github.com/sourcecred/example-git-submodule.git"
|
|
||||||
},
|
|
||||||
"treeHash": "569e1d383759903134df75230d63c0090196d4cb"
|
"treeHash": "569e1d383759903134df75230d63c0090196d4cb"
|
||||||
},
|
},
|
||||||
"e8b7a8f19701cd5a25e4a097d513ead60e5f8bcc": {
|
"e8b7a8f19701cd5a25e4a097d513ead60e5f8bcc": {
|
||||||
|
@ -62,9 +46,6 @@
|
||||||
"parentHashes": [
|
"parentHashes": [
|
||||||
"d160cca97611e9dfed642522ad44408d0292e8ea"
|
"d160cca97611e9dfed642522ad44408d0292e8ea"
|
||||||
],
|
],
|
||||||
"submoduleUrls": {
|
|
||||||
"pygravitydefier": "https://github.com/sourcecred/example-git-submodule.git"
|
|
||||||
},
|
|
||||||
"treeHash": "819fc546cea489476ce8dc90785e9ba7753d0a8f"
|
"treeHash": "819fc546cea489476ce8dc90785e9ba7753d0a8f"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -19,11 +19,6 @@ describe("plugins/git/edges", () => {
|
||||||
type: GN.COMMIT_TYPE,
|
type: GN.COMMIT_TYPE,
|
||||||
hash: "69c5aad50eec8f2a0a07c988c3b283a6490eb45b",
|
hash: "69c5aad50eec8f2a0a07c988c3b283a6490eb45b",
|
||||||
}),
|
}),
|
||||||
submoduleCommit: (): GN.SubmoduleCommitAddress => ({
|
|
||||||
type: GN.SUBMODULE_COMMIT_TYPE,
|
|
||||||
submoduleUrl: "https://github.com/sourcecred/example-git-submodule.git",
|
|
||||||
commitHash: "29ef158bc982733e2ba429fcf73e2f7562244188",
|
|
||||||
}),
|
|
||||||
tree: (): GN.TreeAddress => ({
|
tree: (): GN.TreeAddress => ({
|
||||||
type: GN.TREE_TYPE,
|
type: GN.TREE_TYPE,
|
||||||
hash: "7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
hash: "7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||||
|
|
|
@ -172,10 +172,7 @@ export class GraphView {
|
||||||
homs: [
|
homs: [
|
||||||
{srcPrefix: GN._Prefix.treeEntry, dstPrefix: GN._Prefix.blob},
|
{srcPrefix: GN._Prefix.treeEntry, dstPrefix: GN._Prefix.blob},
|
||||||
{srcPrefix: GN._Prefix.treeEntry, dstPrefix: GN._Prefix.tree},
|
{srcPrefix: GN._Prefix.treeEntry, dstPrefix: GN._Prefix.tree},
|
||||||
{
|
{srcPrefix: GN._Prefix.treeEntry, dstPrefix: GN._Prefix.commit},
|
||||||
srcPrefix: GN._Prefix.treeEntry,
|
|
||||||
dstPrefix: GN._Prefix.submoduleCommit,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,7 @@ import cloneDeep from "lodash.clonedeep";
|
||||||
|
|
||||||
import {EdgeAddress, Graph, NodeAddress, edgeToString} from "../../core/graph";
|
import {EdgeAddress, Graph, NodeAddress, edgeToString} from "../../core/graph";
|
||||||
import {createGraph} from "./createGraph";
|
import {createGraph} from "./createGraph";
|
||||||
|
import * as exampleRepo from "./demoData/exampleRepo";
|
||||||
import {GraphView} from "./graphView";
|
import {GraphView} from "./graphView";
|
||||||
import type {Repository} from "./types";
|
import type {Repository} from "./types";
|
||||||
|
|
||||||
|
@ -32,7 +33,13 @@ describe("plugins/git/graphView", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("#commits yields all commits", () => {
|
it("#commits yields all commits", () => {
|
||||||
const expectedHashes = Object.keys(makeData().commits);
|
const extraSubmoduleCommits = [
|
||||||
|
exampleRepo.SUBMODULE_COMMIT_1,
|
||||||
|
exampleRepo.SUBMODULE_COMMIT_2,
|
||||||
|
];
|
||||||
|
const expectedHashes = Object.keys(makeData().commits).concat(
|
||||||
|
extraSubmoduleCommits
|
||||||
|
);
|
||||||
const actualHashes = Array.from(view.commits()).map((a) => a.hash);
|
const actualHashes = Array.from(view.commits()).map((a) => a.hash);
|
||||||
expectEqualMultisets(actualHashes, expectedHashes);
|
expectEqualMultisets(actualHashes, expectedHashes);
|
||||||
});
|
});
|
||||||
|
@ -104,12 +111,10 @@ describe("plugins/git/graphView", () => {
|
||||||
const actual = Array.from(
|
const actual = Array.from(
|
||||||
view.contents(entryByName("pygravitydefier"))
|
view.contents(entryByName("pygravitydefier"))
|
||||||
);
|
);
|
||||||
const expected: $ReadOnlyArray<GN.SubmoduleCommitAddress> = [
|
const expected: $ReadOnlyArray<GN.CommitAddress> = [
|
||||||
{
|
{
|
||||||
type: GN.SUBMODULE_COMMIT_TYPE,
|
type: GN.COMMIT_TYPE,
|
||||||
submoduleUrl:
|
hash: "29ef158bc982733e2ba429fcf73e2f7562244188",
|
||||||
"https://github.com/sourcecred/example-git-submodule.git",
|
|
||||||
commitHash: "29ef158bc982733e2ba429fcf73e2f7562244188",
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
expect(actual).toEqual(expected);
|
expect(actual).toEqual(expected);
|
||||||
|
|
|
@ -43,85 +43,10 @@ function findCommits(git: GitDriver, rootRef: string): Commit[] {
|
||||||
.filter((line) => line.length > 0)
|
.filter((line) => line.length > 0)
|
||||||
.map((line) => {
|
.map((line) => {
|
||||||
const [hash, treeHash, ...parentHashes] = line.trim().split(" ");
|
const [hash, treeHash, ...parentHashes] = line.trim().split(" ");
|
||||||
const submoduleUrls = loadSubmoduleUrls(git, hash);
|
return {hash, parentHashes, treeHash};
|
||||||
return {hash, parentHashes, treeHash, submoduleUrls};
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const GITMODULES_SUBMODULES_KEY_RE = /^submodule\.(.*)\.(path|url)$/;
|
|
||||||
|
|
||||||
function loadSubmoduleUrls(
|
|
||||||
git: GitDriver,
|
|
||||||
commitHash: Hash
|
|
||||||
): {[path: string]: string} {
|
|
||||||
const gitmodulesRef = `${commitHash}:.gitmodules`;
|
|
||||||
const gitmodulesBlob: string | null = (() => {
|
|
||||||
try {
|
|
||||||
return git(["rev-parse", "--quiet", "--verify", gitmodulesRef]).trim();
|
|
||||||
} catch (e) {
|
|
||||||
if (e.status === 1) {
|
|
||||||
// No .gitmodules file here.
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
if (gitmodulesBlob == null) {
|
|
||||||
// No problem; there just weren't any submodules at this commit.
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// The output format of the following is `${key}\n${value}\0...`, as
|
|
||||||
// specified in `git help config`'s section about the `-z` option.
|
|
||||||
// The format is safe because keys are strictly validated; see the
|
|
||||||
// function `git_config_parse_key` in `git/git:config.c`.
|
|
||||||
const rawConfig = git(["config", "--blob", gitmodulesBlob, "--list", "-z"]);
|
|
||||||
const configKeyValuePairs = rawConfig
|
|
||||||
.split("\0")
|
|
||||||
.filter((line) => line.length > 0)
|
|
||||||
.map((line) => {
|
|
||||||
const separator = line.indexOf("\n");
|
|
||||||
if (separator < 0) {
|
|
||||||
// Shouldn't happen, according to Git docs. Guard anyway.
|
|
||||||
throw new Error(`Bad .gitmodules line at ${commitHash}: ${line}`);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
key: line.substring(0, separator),
|
|
||||||
value: line.substring(separator + 1),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const submoduleInfoByKey: {
|
|
||||||
[submoduleKey: string]: {path: string | null, url: string | null},
|
|
||||||
} = {};
|
|
||||||
configKeyValuePairs.forEach(({key, value}) => {
|
|
||||||
const match = key.match(GITMODULES_SUBMODULES_KEY_RE);
|
|
||||||
if (!match) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const [_, submoduleKey, kind] = match;
|
|
||||||
if (submoduleInfoByKey[submoduleKey] == null) {
|
|
||||||
submoduleInfoByKey[submoduleKey] = {path: null, url: null};
|
|
||||||
}
|
|
||||||
if (kind !== "path" && kind !== "url") {
|
|
||||||
throw new Error(`Invariant violation: bad kind: ${kind}`);
|
|
||||||
}
|
|
||||||
submoduleInfoByKey[submoduleKey][kind] = value;
|
|
||||||
});
|
|
||||||
|
|
||||||
const result = {};
|
|
||||||
Object.keys(submoduleInfoByKey).forEach((submoduleKey) => {
|
|
||||||
const {path, url} = submoduleInfoByKey[submoduleKey];
|
|
||||||
if (path != null && url != null) {
|
|
||||||
result[path] = url;
|
|
||||||
} else {
|
|
||||||
console.warn(`Partial submodule at ${commitHash}: ${submoduleKey}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function findTrees(git: GitDriver, rootTrees: Set<Hash>): Tree[] {
|
function findTrees(git: GitDriver, rootTrees: Set<Hash>): Tree[] {
|
||||||
const result: Tree[] = [];
|
const result: Tree[] = [];
|
||||||
const visited: Set<Hash> = new Set();
|
const visited: Set<Hash> = new Set();
|
||||||
|
|
|
@ -12,7 +12,6 @@ export function _gitAddress(...parts: string[]): RawAddress {
|
||||||
|
|
||||||
export const BLOB_TYPE: "BLOB" = "BLOB";
|
export const BLOB_TYPE: "BLOB" = "BLOB";
|
||||||
export const COMMIT_TYPE: "COMMIT" = "COMMIT";
|
export const COMMIT_TYPE: "COMMIT" = "COMMIT";
|
||||||
export const SUBMODULE_COMMIT_TYPE: "SUBMODULE_COMMIT" = "SUBMODULE_COMMIT";
|
|
||||||
export const TREE_TYPE: "TREE" = "TREE";
|
export const TREE_TYPE: "TREE" = "TREE";
|
||||||
export const TREE_ENTRY_TYPE: "TREE_ENTRY" = "TREE_ENTRY";
|
export const TREE_ENTRY_TYPE: "TREE_ENTRY" = "TREE_ENTRY";
|
||||||
|
|
||||||
|
@ -20,7 +19,6 @@ export const _Prefix = Object.freeze({
|
||||||
base: GIT_PREFIX,
|
base: GIT_PREFIX,
|
||||||
blob: _gitAddress(BLOB_TYPE),
|
blob: _gitAddress(BLOB_TYPE),
|
||||||
commit: _gitAddress(COMMIT_TYPE),
|
commit: _gitAddress(COMMIT_TYPE),
|
||||||
submoduleCommit: _gitAddress(SUBMODULE_COMMIT_TYPE),
|
|
||||||
tree: _gitAddress(TREE_TYPE),
|
tree: _gitAddress(TREE_TYPE),
|
||||||
treeEntry: _gitAddress(TREE_ENTRY_TYPE),
|
treeEntry: _gitAddress(TREE_ENTRY_TYPE),
|
||||||
});
|
});
|
||||||
|
@ -33,11 +31,6 @@ export type CommitAddress = {|
|
||||||
+type: typeof COMMIT_TYPE,
|
+type: typeof COMMIT_TYPE,
|
||||||
+hash: Hash,
|
+hash: Hash,
|
||||||
|};
|
|};
|
||||||
export type SubmoduleCommitAddress = {|
|
|
||||||
+type: typeof SUBMODULE_COMMIT_TYPE,
|
|
||||||
+submoduleUrl: string,
|
|
||||||
+commitHash: Hash,
|
|
||||||
|};
|
|
||||||
export type TreeAddress = {|
|
export type TreeAddress = {|
|
||||||
+type: typeof TREE_TYPE,
|
+type: typeof TREE_TYPE,
|
||||||
+hash: Hash,
|
+hash: Hash,
|
||||||
|
@ -52,13 +45,12 @@ export type TreeEntryAddress = {|
|
||||||
// addresses.
|
// addresses.
|
||||||
export type TreeEntryContentsAddress =
|
export type TreeEntryContentsAddress =
|
||||||
| BlobAddress
|
| BlobAddress
|
||||||
| TreeAddress
|
| CommitAddress
|
||||||
| SubmoduleCommitAddress;
|
| TreeAddress;
|
||||||
|
|
||||||
export type StructuredAddress =
|
export type StructuredAddress =
|
||||||
| BlobAddress
|
| BlobAddress
|
||||||
| CommitAddress
|
| CommitAddress
|
||||||
| SubmoduleCommitAddress
|
|
||||||
| TreeAddress
|
| TreeAddress
|
||||||
| TreeEntryAddress;
|
| TreeEntryAddress;
|
||||||
|
|
||||||
|
@ -82,11 +74,6 @@ export function fromRaw(x: RawAddress): StructuredAddress {
|
||||||
const [hash] = rest;
|
const [hash] = rest;
|
||||||
return {type: COMMIT_TYPE, hash};
|
return {type: COMMIT_TYPE, hash};
|
||||||
}
|
}
|
||||||
case "SUBMODULE_COMMIT": {
|
|
||||||
if (rest.length !== 2) throw fail();
|
|
||||||
const [submoduleUrl, commitHash] = rest;
|
|
||||||
return {type: SUBMODULE_COMMIT_TYPE, submoduleUrl, commitHash};
|
|
||||||
}
|
|
||||||
case "TREE": {
|
case "TREE": {
|
||||||
if (rest.length !== 1) throw fail();
|
if (rest.length !== 1) throw fail();
|
||||||
const [hash] = rest;
|
const [hash] = rest;
|
||||||
|
@ -110,12 +97,6 @@ export function toRaw(x: StructuredAddress): RawAddress {
|
||||||
return NodeAddress.append(_Prefix.blob, x.hash);
|
return NodeAddress.append(_Prefix.blob, x.hash);
|
||||||
case COMMIT_TYPE:
|
case COMMIT_TYPE:
|
||||||
return NodeAddress.append(_Prefix.commit, x.hash);
|
return NodeAddress.append(_Prefix.commit, x.hash);
|
||||||
case SUBMODULE_COMMIT_TYPE:
|
|
||||||
return NodeAddress.append(
|
|
||||||
_Prefix.submoduleCommit,
|
|
||||||
x.submoduleUrl,
|
|
||||||
x.commitHash
|
|
||||||
);
|
|
||||||
case TREE_TYPE:
|
case TREE_TYPE:
|
||||||
return NodeAddress.append(_Prefix.tree, x.hash);
|
return NodeAddress.append(_Prefix.tree, x.hash);
|
||||||
case TREE_ENTRY_TYPE:
|
case TREE_ENTRY_TYPE:
|
||||||
|
|
|
@ -14,11 +14,6 @@ describe("plugins/git/nodes", () => {
|
||||||
type: GN.COMMIT_TYPE,
|
type: GN.COMMIT_TYPE,
|
||||||
hash: "3715ddfb8d4c4fd2a6f6af75488c82f84c92ec2f",
|
hash: "3715ddfb8d4c4fd2a6f6af75488c82f84c92ec2f",
|
||||||
}),
|
}),
|
||||||
submoduleCommit: (): GN.SubmoduleCommitAddress => ({
|
|
||||||
type: GN.SUBMODULE_COMMIT_TYPE,
|
|
||||||
submoduleUrl: "https://github.com/sourcecred/example-git-submodule.git",
|
|
||||||
commitHash: "29ef158bc982733e2ba429fcf73e2f7562244188",
|
|
||||||
}),
|
|
||||||
tree: (): GN.TreeAddress => ({
|
tree: (): GN.TreeAddress => ({
|
||||||
type: GN.TREE_TYPE,
|
type: GN.TREE_TYPE,
|
||||||
hash: "7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
hash: "7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||||
|
@ -129,20 +124,6 @@ describe("plugins/git/nodes", () => {
|
||||||
examples.treeEntry().name,
|
examples.treeEntry().name,
|
||||||
"wat",
|
"wat",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expectBadAddress("submodule commit with no fields", [
|
|
||||||
GN.SUBMODULE_COMMIT_TYPE,
|
|
||||||
]);
|
|
||||||
expectBadAddress("submodule commit with only URL", [
|
|
||||||
GN.SUBMODULE_COMMIT_TYPE,
|
|
||||||
examples.submoduleCommit().submoduleUrl,
|
|
||||||
]);
|
|
||||||
expectBadAddress("submodule commit with extra field", [
|
|
||||||
GN.SUBMODULE_COMMIT_TYPE,
|
|
||||||
examples.submoduleCommit().submoduleUrl,
|
|
||||||
examples.submoduleCommit().commitHash,
|
|
||||||
"wat",
|
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("toRaw(...) with", () => {
|
describe("toRaw(...) with", () => {
|
||||||
|
|
|
@ -9,7 +9,6 @@ export type Commit = {|
|
||||||
+hash: Hash,
|
+hash: Hash,
|
||||||
+parentHashes: $ReadOnlyArray<Hash>,
|
+parentHashes: $ReadOnlyArray<Hash>,
|
||||||
+treeHash: Hash,
|
+treeHash: Hash,
|
||||||
+submoduleUrls: {[path: string]: string},
|
|
||||||
|};
|
|};
|
||||||
export type Tree = {|
|
export type Tree = {|
|
||||||
+hash: Hash,
|
+hash: Hash,
|
||||||
|
|
Loading…
Reference in New Issue