Merge pull request #13 from actions/lsep/fix-version-selection
Correctly identify dependency versions chosen by Go
This commit is contained in:
Vendored
+83
-22
@@ -72,8 +72,28 @@ function main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const packageCache = yield (0, process_1.processGoGraph)(goModDir);
|
const directDeps = yield (0, process_1.processGoDirectDependencies)(goModDir, goBuildTarget);
|
||||||
const manifest = yield (0, process_1.processGoBuildTarget)(goModDir, goBuildTarget, packageCache);
|
const indirectDeps = yield (0, process_1.processGoIndirectDependencies)(goModDir, goBuildTarget);
|
||||||
|
const packageCache = yield (0, process_1.processGoGraph)(goModDir, directDeps, indirectDeps);
|
||||||
|
// no file path if using the pseudotargets "all" or "./..."
|
||||||
|
const filepath = goBuildTarget === 'all' || goBuildTarget === './...'
|
||||||
|
? undefined
|
||||||
|
: path_1.default.join(goModDir, goBuildTarget);
|
||||||
|
const manifest = new dependency_submission_toolkit_1.Manifest(goBuildTarget, filepath);
|
||||||
|
directDeps.forEach((pkgUrl) => {
|
||||||
|
const dep = packageCache.lookupPackage(pkgUrl);
|
||||||
|
if (!dep) {
|
||||||
|
throw new Error('assertion failed: expected all direct dependencies to have entries in PackageCache');
|
||||||
|
}
|
||||||
|
manifest.addDirectDependency(dep);
|
||||||
|
});
|
||||||
|
indirectDeps.forEach((pkgUrl) => {
|
||||||
|
const dep = packageCache.lookupPackage(pkgUrl);
|
||||||
|
if (!dep) {
|
||||||
|
throw new Error('assertion failed: expected all indirect dependencies to have entries in PackageCache');
|
||||||
|
}
|
||||||
|
manifest.addIndirectDependency(dep);
|
||||||
|
});
|
||||||
const snapshot = new dependency_submission_toolkit_1.Snapshot({
|
const snapshot = new dependency_submission_toolkit_1.Snapshot({
|
||||||
name: 'actions/go-dependency-submission',
|
name: 'actions/go-dependency-submission',
|
||||||
url: 'https://github.com/actions/go-dependency-submission',
|
url: 'https://github.com/actions/go-dependency-submission',
|
||||||
@@ -194,17 +214,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.processGoBuildTarget = exports.processGoGraph = void 0;
|
exports.processGoIndirectDependencies = exports.processGoDirectDependencies = exports.processGoGraph = void 0;
|
||||||
const path_1 = __importDefault(__nccwpck_require__(1017));
|
|
||||||
const exec = __importStar(__nccwpck_require__(1514));
|
const exec = __importStar(__nccwpck_require__(1514));
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const dependency_submission_toolkit_1 = __nccwpck_require__(9810);
|
const dependency_submission_toolkit_1 = __nccwpck_require__(9810);
|
||||||
const parse_1 = __nccwpck_require__(5933);
|
const parse_1 = __nccwpck_require__(5933);
|
||||||
function processGoGraph(goModDir) {
|
function processGoGraph(goModDir, directDependencies, indirectDependencies) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
console.log(`Running 'go mod graph' in ${goModDir}`);
|
console.log(`Running 'go mod graph' in ${goModDir}`);
|
||||||
const goModGraph = yield exec.getExecOutput('go', ['mod', 'graph'], {
|
const goModGraph = yield exec.getExecOutput('go', ['mod', 'graph'], {
|
||||||
@@ -215,39 +231,84 @@ function processGoGraph(goModDir) {
|
|||||||
core.setFailed("'go mod graph' failed!");
|
core.setFailed("'go mod graph' failed!");
|
||||||
throw new Error("Failed to execute 'go mod graph'");
|
throw new Error("Failed to execute 'go mod graph'");
|
||||||
}
|
}
|
||||||
|
/* add all direct and indirect packages to a new PackageCache */
|
||||||
const cache = new dependency_submission_toolkit_1.PackageCache();
|
const cache = new dependency_submission_toolkit_1.PackageCache();
|
||||||
|
directDependencies.forEach((pkg) => {
|
||||||
|
cache.package(pkg);
|
||||||
|
});
|
||||||
|
indirectDependencies.forEach((pkg) => {
|
||||||
|
cache.package(pkg);
|
||||||
|
});
|
||||||
const packageAssocList = (0, parse_1.parseGoModGraph)(goModGraph.stdout);
|
const packageAssocList = (0, parse_1.parseGoModGraph)(goModGraph.stdout);
|
||||||
packageAssocList.forEach(([parentPkg, childPkg]) => {
|
packageAssocList.forEach(([parentPkg, childPkg]) => {
|
||||||
cache.package(parentPkg).dependsOn(cache.package(childPkg));
|
/* Look up the parent package in the cache. go mod graph will return
|
||||||
|
* multiple versions of packages with the same namespace and name. We
|
||||||
|
* select only package versions used in the Go build target. */
|
||||||
|
const targetPackage = cache.lookupPackage(parentPkg);
|
||||||
|
if (!targetPackage)
|
||||||
|
return;
|
||||||
|
/* Build a matcher to select on the namespace+name of the child package in
|
||||||
|
* the cache. The child package version specified by go mod graph is not
|
||||||
|
* the one guaranteed to be selected when building Go build targets. */
|
||||||
|
const matcher = {
|
||||||
|
name: childPkg.name
|
||||||
|
};
|
||||||
|
if (childPkg.namespace)
|
||||||
|
matcher.namespace = childPkg.namespace;
|
||||||
|
/* There should only ever be a single package with a namespace+name in the
|
||||||
|
* build target list. Go does not support multiple versions of the same
|
||||||
|
* package */
|
||||||
|
const matches = cache.packagesMatching(matcher);
|
||||||
|
if (matches.length === 0)
|
||||||
|
return;
|
||||||
|
if (matches.length !== 1) {
|
||||||
|
throw new Error('assertion failed: expected no more than one package in cache with namespace+name. ' +
|
||||||
|
'Found: ' +
|
||||||
|
JSON.stringify(matches) +
|
||||||
|
'for ' +
|
||||||
|
JSON.stringify(matcher));
|
||||||
|
}
|
||||||
|
// create the dependency relationship
|
||||||
|
targetPackage.dependsOn(matches[0]);
|
||||||
});
|
});
|
||||||
return cache;
|
return cache;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.processGoGraph = processGoGraph;
|
exports.processGoGraph = processGoGraph;
|
||||||
// For a specific Go _build target_, this template lists all dependencies used
|
// For a specific Go _build target_, these templates list dependencies used to
|
||||||
// to build the build target It does not provide association between the
|
// in the build target. It does not provide association between the
|
||||||
// dependencies (i.e. which dependencies depend on which)
|
// dependencies (i.e. which dependencies depend on which)
|
||||||
// eslint-disable-next-line quotes
|
// eslint-disable-next-line quotes
|
||||||
// eslint-disable-next-line no-useless-escape
|
// eslint-disable-next-line no-useless-escape
|
||||||
const GO_LIST_DEP_TEMPLATE = '{{define "M"}}{{.Path}}@{{.Version}}{{end}}{{with .Module}}{{if not .Main}}{{if .Replace}}{{template "M" .Replace}}{{else}}{{template "M" .}}{{end}}{{end}}{{end}}';
|
const GO_DIRECT_DEPS_TEMPLATE = '{{define "M"}}{{if not .Indirect}}{{.Path}}@{{.Version}}{{end}}{{end}}{{with .Module}}{{if not .Main}}{{if .Replace}}{{template "M" .Replace}}{{else}}{{template "M" .}}{{end}}{{end}}{{end}}';
|
||||||
function processGoBuildTarget(goModDir, goBuildTarget, cache) {
|
// eslint-disable-next-line quotes
|
||||||
|
// eslint-disable-next-line no-useless-escape
|
||||||
|
const GO_INDIRECT_DEPS_TEMPLATE = '{{define "M"}}{{if .Indirect}}{{.Path}}@{{.Version}}{{end}}{{end}}{{with .Module}}{{if not .Main}}{{if .Replace}}{{template "M" .Replace}}{{else}}{{template "M" .}}{{end}}{{end}}{{end}}';
|
||||||
|
function processGoDirectDependencies(goModDir, goBuildTarget) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
console.log(`Running go package detection in ${goModDir} on build target ${goBuildTarget}`);
|
console.log(`go direct package detection in ${goModDir} on build target ${goBuildTarget}`);
|
||||||
const goList = yield exec.getExecOutput('go', ['list', '-deps', '-f', GO_LIST_DEP_TEMPLATE, goBuildTarget], { cwd: goModDir });
|
return processGoList(goModDir, goBuildTarget, GO_DIRECT_DEPS_TEMPLATE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.processGoDirectDependencies = processGoDirectDependencies;
|
||||||
|
function processGoIndirectDependencies(goModDir, goBuildTarget) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
console.log(`go indirect package detection in ${goModDir} on build target ${goBuildTarget}`);
|
||||||
|
return processGoList(goModDir, goBuildTarget, GO_INDIRECT_DEPS_TEMPLATE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.processGoIndirectDependencies = processGoIndirectDependencies;
|
||||||
|
function processGoList(goModDir, goBuildTarget, goListTemplate) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const goList = yield exec.getExecOutput('go', ['list', '-deps', '-f', goListTemplate, goBuildTarget], { cwd: goModDir });
|
||||||
if (goList.exitCode !== 0) {
|
if (goList.exitCode !== 0) {
|
||||||
core.error(goList.stderr);
|
core.error(goList.stderr);
|
||||||
core.setFailed("'go list' failed!");
|
core.setFailed("'go list' failed!");
|
||||||
throw new Error("Failed to execute 'go list'");
|
throw new Error("Failed to execute 'go list'");
|
||||||
}
|
}
|
||||||
const dependencies = (0, parse_1.parseGoList)(goList.stdout);
|
return (0, parse_1.parseGoList)(goList.stdout);
|
||||||
const manifest = new dependency_submission_toolkit_1.BuildTarget(goBuildTarget, path_1.default.join(goModDir, goBuildTarget));
|
|
||||||
dependencies.forEach((dep) => {
|
|
||||||
manifest.addBuildDependency(cache.package(dep));
|
|
||||||
});
|
|
||||||
return manifest;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.processGoBuildTarget = processGoBuildTarget;
|
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+61
-20
@@ -31,17 +31,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.processGoBuildTarget = exports.processGoGraph = void 0;
|
exports.processGoIndirectDependencies = exports.processGoDirectDependencies = exports.processGoGraph = void 0;
|
||||||
const path_1 = __importDefault(require("path"));
|
|
||||||
const exec = __importStar(require("@actions/exec"));
|
const exec = __importStar(require("@actions/exec"));
|
||||||
const core = __importStar(require("@actions/core"));
|
const core = __importStar(require("@actions/core"));
|
||||||
const dependency_submission_toolkit_1 = require("@github/dependency-submission-toolkit");
|
const dependency_submission_toolkit_1 = require("@github/dependency-submission-toolkit");
|
||||||
const parse_1 = require("./parse");
|
const parse_1 = require("./parse");
|
||||||
function processGoGraph(goModDir) {
|
function processGoGraph(goModDir, directDependencies, indirectDependencies) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
console.log(`Running 'go mod graph' in ${goModDir}`);
|
console.log(`Running 'go mod graph' in ${goModDir}`);
|
||||||
const goModGraph = yield exec.getExecOutput('go', ['mod', 'graph'], {
|
const goModGraph = yield exec.getExecOutput('go', ['mod', 'graph'], {
|
||||||
@@ -52,36 +48,81 @@ function processGoGraph(goModDir) {
|
|||||||
core.setFailed("'go mod graph' failed!");
|
core.setFailed("'go mod graph' failed!");
|
||||||
throw new Error("Failed to execute 'go mod graph'");
|
throw new Error("Failed to execute 'go mod graph'");
|
||||||
}
|
}
|
||||||
|
/* add all direct and indirect packages to a new PackageCache */
|
||||||
const cache = new dependency_submission_toolkit_1.PackageCache();
|
const cache = new dependency_submission_toolkit_1.PackageCache();
|
||||||
|
directDependencies.forEach((pkg) => {
|
||||||
|
cache.package(pkg);
|
||||||
|
});
|
||||||
|
indirectDependencies.forEach((pkg) => {
|
||||||
|
cache.package(pkg);
|
||||||
|
});
|
||||||
const packageAssocList = (0, parse_1.parseGoModGraph)(goModGraph.stdout);
|
const packageAssocList = (0, parse_1.parseGoModGraph)(goModGraph.stdout);
|
||||||
packageAssocList.forEach(([parentPkg, childPkg]) => {
|
packageAssocList.forEach(([parentPkg, childPkg]) => {
|
||||||
cache.package(parentPkg).dependsOn(cache.package(childPkg));
|
/* Look up the parent package in the cache. go mod graph will return
|
||||||
|
* multiple versions of packages with the same namespace and name. We
|
||||||
|
* select only package versions used in the Go build target. */
|
||||||
|
const targetPackage = cache.lookupPackage(parentPkg);
|
||||||
|
if (!targetPackage)
|
||||||
|
return;
|
||||||
|
/* Build a matcher to select on the namespace+name of the child package in
|
||||||
|
* the cache. The child package version specified by go mod graph is not
|
||||||
|
* the one guaranteed to be selected when building Go build targets. */
|
||||||
|
const matcher = {
|
||||||
|
name: childPkg.name
|
||||||
|
};
|
||||||
|
if (childPkg.namespace)
|
||||||
|
matcher.namespace = childPkg.namespace;
|
||||||
|
/* There should only ever be a single package with a namespace+name in the
|
||||||
|
* build target list. Go does not support multiple versions of the same
|
||||||
|
* package */
|
||||||
|
const matches = cache.packagesMatching(matcher);
|
||||||
|
if (matches.length === 0)
|
||||||
|
return;
|
||||||
|
if (matches.length !== 1) {
|
||||||
|
throw new Error('assertion failed: expected no more than one package in cache with namespace+name. ' +
|
||||||
|
'Found: ' +
|
||||||
|
JSON.stringify(matches) +
|
||||||
|
'for ' +
|
||||||
|
JSON.stringify(matcher));
|
||||||
|
}
|
||||||
|
// create the dependency relationship
|
||||||
|
targetPackage.dependsOn(matches[0]);
|
||||||
});
|
});
|
||||||
return cache;
|
return cache;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.processGoGraph = processGoGraph;
|
exports.processGoGraph = processGoGraph;
|
||||||
// For a specific Go _build target_, this template lists all dependencies used
|
// For a specific Go _build target_, these templates list dependencies used to
|
||||||
// to build the build target It does not provide association between the
|
// in the build target. It does not provide association between the
|
||||||
// dependencies (i.e. which dependencies depend on which)
|
// dependencies (i.e. which dependencies depend on which)
|
||||||
// eslint-disable-next-line quotes
|
// eslint-disable-next-line quotes
|
||||||
// eslint-disable-next-line no-useless-escape
|
// eslint-disable-next-line no-useless-escape
|
||||||
const GO_LIST_DEP_TEMPLATE = '{{define "M"}}{{.Path}}@{{.Version}}{{end}}{{with .Module}}{{if not .Main}}{{if .Replace}}{{template "M" .Replace}}{{else}}{{template "M" .}}{{end}}{{end}}{{end}}';
|
const GO_DIRECT_DEPS_TEMPLATE = '{{define "M"}}{{if not .Indirect}}{{.Path}}@{{.Version}}{{end}}{{end}}{{with .Module}}{{if not .Main}}{{if .Replace}}{{template "M" .Replace}}{{else}}{{template "M" .}}{{end}}{{end}}{{end}}';
|
||||||
function processGoBuildTarget(goModDir, goBuildTarget, cache) {
|
// eslint-disable-next-line quotes
|
||||||
|
// eslint-disable-next-line no-useless-escape
|
||||||
|
const GO_INDIRECT_DEPS_TEMPLATE = '{{define "M"}}{{if .Indirect}}{{.Path}}@{{.Version}}{{end}}{{end}}{{with .Module}}{{if not .Main}}{{if .Replace}}{{template "M" .Replace}}{{else}}{{template "M" .}}{{end}}{{end}}{{end}}';
|
||||||
|
function processGoDirectDependencies(goModDir, goBuildTarget) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
console.log(`Running go package detection in ${goModDir} on build target ${goBuildTarget}`);
|
console.log(`go direct package detection in ${goModDir} on build target ${goBuildTarget}`);
|
||||||
const goList = yield exec.getExecOutput('go', ['list', '-deps', '-f', GO_LIST_DEP_TEMPLATE, goBuildTarget], { cwd: goModDir });
|
return processGoList(goModDir, goBuildTarget, GO_DIRECT_DEPS_TEMPLATE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.processGoDirectDependencies = processGoDirectDependencies;
|
||||||
|
function processGoIndirectDependencies(goModDir, goBuildTarget) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
console.log(`go indirect package detection in ${goModDir} on build target ${goBuildTarget}`);
|
||||||
|
return processGoList(goModDir, goBuildTarget, GO_INDIRECT_DEPS_TEMPLATE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.processGoIndirectDependencies = processGoIndirectDependencies;
|
||||||
|
function processGoList(goModDir, goBuildTarget, goListTemplate) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const goList = yield exec.getExecOutput('go', ['list', '-deps', '-f', goListTemplate, goBuildTarget], { cwd: goModDir });
|
||||||
if (goList.exitCode !== 0) {
|
if (goList.exitCode !== 0) {
|
||||||
core.error(goList.stderr);
|
core.error(goList.stderr);
|
||||||
core.setFailed("'go list' failed!");
|
core.setFailed("'go list' failed!");
|
||||||
throw new Error("Failed to execute 'go list'");
|
throw new Error("Failed to execute 'go list'");
|
||||||
}
|
}
|
||||||
const dependencies = (0, parse_1.parseGoList)(goList.stdout);
|
return (0, parse_1.parseGoList)(goList.stdout);
|
||||||
const manifest = new dependency_submission_toolkit_1.BuildTarget(goBuildTarget, path_1.default.join(goModDir, goBuildTarget));
|
|
||||||
dependencies.forEach((dep) => {
|
|
||||||
manifest.addBuildDependency(cache.package(dep));
|
|
||||||
});
|
|
||||||
return manifest;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.processGoBuildTarget = processGoBuildTarget;
|
|
||||||
|
|||||||
Generated
+7
-7
@@ -12,7 +12,7 @@
|
|||||||
"@actions/core": "^1.6.0",
|
"@actions/core": "^1.6.0",
|
||||||
"@actions/exec": "^1.1.1",
|
"@actions/exec": "^1.1.1",
|
||||||
"@actions/github": "^5.0.3",
|
"@actions/github": "^5.0.3",
|
||||||
"@github/dependency-submission-toolkit": "^1.1.2",
|
"@github/dependency-submission-toolkit": "^1.2.0",
|
||||||
"packageurl-js": "^0.0.6"
|
"packageurl-js": "^0.0.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -673,9 +673,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@github/dependency-submission-toolkit": {
|
"node_modules/@github/dependency-submission-toolkit": {
|
||||||
"version": "1.1.2",
|
"version": "1.2.0",
|
||||||
"resolved": "https://npm.pkg.github.com/download/@github/dependency-submission-toolkit/1.1.2/742faf4570a1f30532adc02edde4b27b7bd6b9439ce9bb39c2322eaca07239e1",
|
"resolved": "https://npm.pkg.github.com/download/@github/dependency-submission-toolkit/1.2.0/cd4d278f4bad1f7056d73bc205b8c7484980f7ffcb9c52c1df36dbc366a6221c",
|
||||||
"integrity": "sha512-uJyVJN9fUJf2djNLT9mNwBSbkQ+AdYuOBmUffHnHFhF+3kCN6zqy3m+3Iw//Ixln7kpe8qN7W0ZVGFOesXYZXA==",
|
"integrity": "sha512-b51hiCwNDO9Eim2MPvyeTDD1XxN7gpptRLGtUsnTpf8kcCILnVSbmbwjLfj4HNDbzg05yqfqW5jnI6ET2aFIqA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.6.0",
|
"@actions/core": "^1.6.0",
|
||||||
@@ -6383,9 +6383,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@github/dependency-submission-toolkit": {
|
"@github/dependency-submission-toolkit": {
|
||||||
"version": "1.1.2",
|
"version": "1.2.0",
|
||||||
"resolved": "https://npm.pkg.github.com/download/@github/dependency-submission-toolkit/1.1.2/742faf4570a1f30532adc02edde4b27b7bd6b9439ce9bb39c2322eaca07239e1",
|
"resolved": "https://npm.pkg.github.com/download/@github/dependency-submission-toolkit/1.2.0/cd4d278f4bad1f7056d73bc205b8c7484980f7ffcb9c52c1df36dbc366a6221c",
|
||||||
"integrity": "sha512-uJyVJN9fUJf2djNLT9mNwBSbkQ+AdYuOBmUffHnHFhF+3kCN6zqy3m+3Iw//Ixln7kpe8qN7W0ZVGFOesXYZXA==",
|
"integrity": "sha512-b51hiCwNDO9Eim2MPvyeTDD1XxN7gpptRLGtUsnTpf8kcCILnVSbmbwjLfj4HNDbzg05yqfqW5jnI6ET2aFIqA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@actions/core": "^1.6.0",
|
"@actions/core": "^1.6.0",
|
||||||
"@actions/exec": "^1.1.1",
|
"@actions/exec": "^1.1.1",
|
||||||
|
|||||||
+1
-1
@@ -43,7 +43,7 @@
|
|||||||
"@actions/core": "^1.6.0",
|
"@actions/core": "^1.6.0",
|
||||||
"@actions/exec": "^1.1.1",
|
"@actions/exec": "^1.1.1",
|
||||||
"@actions/github": "^5.0.3",
|
"@actions/github": "^5.0.3",
|
||||||
"@github/dependency-submission-toolkit": "^1.1.2",
|
"@github/dependency-submission-toolkit": "^1.2.0",
|
||||||
"packageurl-js": "^0.0.6"
|
"packageurl-js": "^0.0.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-6
@@ -3,9 +3,17 @@ import fs from 'fs'
|
|||||||
|
|
||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import * as github from '@actions/github'
|
import * as github from '@actions/github'
|
||||||
import { Snapshot, submitSnapshot } from '@github/dependency-submission-toolkit'
|
import {
|
||||||
|
Snapshot,
|
||||||
|
Manifest,
|
||||||
|
submitSnapshot
|
||||||
|
} from '@github/dependency-submission-toolkit'
|
||||||
|
|
||||||
import { processGoGraph, processGoBuildTarget } from './process'
|
import {
|
||||||
|
processGoGraph,
|
||||||
|
processGoDirectDependencies,
|
||||||
|
processGoIndirectDependencies
|
||||||
|
} from './process'
|
||||||
|
|
||||||
async function main () {
|
async function main () {
|
||||||
const goModPath = path.normalize(core.getInput('go-mod-path'))
|
const goModPath = path.normalize(core.getInput('go-mod-path'))
|
||||||
@@ -35,12 +43,39 @@ async function main () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const packageCache = await processGoGraph(goModDir)
|
const directDeps = await processGoDirectDependencies(goModDir, goBuildTarget)
|
||||||
const manifest = await processGoBuildTarget(
|
const indirectDeps = await processGoIndirectDependencies(
|
||||||
goModDir,
|
goModDir,
|
||||||
goBuildTarget,
|
goBuildTarget
|
||||||
packageCache
|
|
||||||
)
|
)
|
||||||
|
const packageCache = await processGoGraph(goModDir, directDeps, indirectDeps)
|
||||||
|
// no file path if using the pseudotargets "all" or "./..."
|
||||||
|
const filepath =
|
||||||
|
goBuildTarget === 'all' || goBuildTarget === './...'
|
||||||
|
? undefined
|
||||||
|
: path.join(goModDir, goBuildTarget)
|
||||||
|
const manifest = new Manifest(goBuildTarget, filepath)
|
||||||
|
|
||||||
|
directDeps.forEach((pkgUrl) => {
|
||||||
|
const dep = packageCache.lookupPackage(pkgUrl)
|
||||||
|
if (!dep) {
|
||||||
|
throw new Error(
|
||||||
|
'assertion failed: expected all direct dependencies to have entries in PackageCache'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
manifest.addDirectDependency(dep)
|
||||||
|
})
|
||||||
|
|
||||||
|
indirectDeps.forEach((pkgUrl) => {
|
||||||
|
const dep = packageCache.lookupPackage(pkgUrl)
|
||||||
|
if (!dep) {
|
||||||
|
throw new Error(
|
||||||
|
'assertion failed: expected all indirect dependencies to have entries in PackageCache'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
manifest.addIndirectDependency(dep)
|
||||||
|
})
|
||||||
|
|
||||||
const snapshot = new Snapshot(
|
const snapshot = new Snapshot(
|
||||||
{
|
{
|
||||||
name: 'actions/go-dependency-submission',
|
name: 'actions/go-dependency-submission',
|
||||||
|
|||||||
+78
-9
@@ -1,17 +1,86 @@
|
|||||||
import { processGoGraph, processGoBuildTarget } from './process'
|
import {
|
||||||
|
processGoGraph,
|
||||||
|
processGoDirectDependencies,
|
||||||
|
processGoIndirectDependencies
|
||||||
|
} from './process'
|
||||||
|
|
||||||
// NOTE: these tests all require "go" to be installed and available on the PATH!
|
// NOTE: these tests all require "go" to be installed and available on the PATH!
|
||||||
//
|
//
|
||||||
describe('processGoGraph', () => {
|
describe('processGoDirectDependencies', () => {
|
||||||
test('run in go-example', async () => {
|
test('run in go-example', async () => {
|
||||||
const cache = await processGoGraph('go-example')
|
const purls = await processGoDirectDependencies(
|
||||||
expect(cache.countPackages()).toEqual(8)
|
|
||||||
const manifest = await processGoBuildTarget(
|
|
||||||
'go-example',
|
'go-example',
|
||||||
'cmd/octocat.go',
|
'cmd/octocat.go'
|
||||||
cache
|
|
||||||
)
|
)
|
||||||
expect(manifest.directDependencies()).toHaveLength(4)
|
expect(purls).toHaveLength(1)
|
||||||
expect(manifest.indirectDependencies()).toHaveLength(2)
|
expect(purls).toEqual([
|
||||||
|
{
|
||||||
|
type: 'golang',
|
||||||
|
name: 'color',
|
||||||
|
namespace: 'github.com/fatih',
|
||||||
|
version: 'v1.13.0',
|
||||||
|
qualifiers: null,
|
||||||
|
subpath: null
|
||||||
|
}
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('processGoIndirectDependencies', () => {
|
||||||
|
test('run in go-example', async () => {
|
||||||
|
const purls = await processGoIndirectDependencies(
|
||||||
|
'go-example',
|
||||||
|
'cmd/octocat.go'
|
||||||
|
)
|
||||||
|
expect(purls).toHaveLength(3)
|
||||||
|
expect(purls).toEqual([
|
||||||
|
{
|
||||||
|
type: 'golang',
|
||||||
|
name: 'sys',
|
||||||
|
namespace: 'golang.org/x',
|
||||||
|
version: 'v0.0.0-20210630005230-0f9fa26af87c',
|
||||||
|
qualifiers: null,
|
||||||
|
subpath: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'golang',
|
||||||
|
name: 'go-isatty',
|
||||||
|
namespace: 'github.com/mattn',
|
||||||
|
version: 'v0.0.14',
|
||||||
|
qualifiers: null,
|
||||||
|
subpath: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'golang',
|
||||||
|
name: 'go-colorable',
|
||||||
|
namespace: 'github.com/mattn',
|
||||||
|
version: 'v0.1.9',
|
||||||
|
qualifiers: null,
|
||||||
|
subpath: null
|
||||||
|
}
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('processGoGraph', () => {
|
||||||
|
test.only('run in go-example', async () => {
|
||||||
|
const directDeps = await processGoDirectDependencies(
|
||||||
|
'go-example',
|
||||||
|
'cmd/octocat.go'
|
||||||
|
)
|
||||||
|
const indirectDeps = await processGoIndirectDependencies(
|
||||||
|
'go-example',
|
||||||
|
'cmd/octocat.go'
|
||||||
|
)
|
||||||
|
const cache = await processGoGraph('go-example', directDeps, indirectDeps)
|
||||||
|
|
||||||
|
// we expect the number of direct dependencies + indirect
|
||||||
|
expect(cache.countPackages()).toEqual(4)
|
||||||
|
|
||||||
|
const colorDep = cache.lookupPackage(
|
||||||
|
'pkg:golang/github.com/fatih/[email protected]'
|
||||||
|
)
|
||||||
|
expect(colorDep).not.toBeUndefined()
|
||||||
|
if (colorDep) expect(colorDep.dependencies).toHaveLength(2)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+80
-30
@@ -1,16 +1,16 @@
|
|||||||
import path from 'path'
|
import { PackageURL } from 'packageurl-js'
|
||||||
|
|
||||||
import * as exec from '@actions/exec'
|
import * as exec from '@actions/exec'
|
||||||
import * as core from '@actions/core'
|
import * as core from '@actions/core'
|
||||||
import {
|
import { PackageCache } from '@github/dependency-submission-toolkit'
|
||||||
Manifest,
|
|
||||||
BuildTarget,
|
|
||||||
PackageCache
|
|
||||||
} from '@github/dependency-submission-toolkit'
|
|
||||||
|
|
||||||
import { parseGoModGraph, parseGoList } from './parse'
|
import { parseGoModGraph, parseGoList } from './parse'
|
||||||
|
|
||||||
export async function processGoGraph (goModDir: string): Promise<PackageCache> {
|
export async function processGoGraph (
|
||||||
|
goModDir: string,
|
||||||
|
directDependencies: Array<PackageURL>,
|
||||||
|
indirectDependencies: Array<PackageURL>
|
||||||
|
): Promise<PackageCache> {
|
||||||
console.log(`Running 'go mod graph' in ${goModDir}`)
|
console.log(`Running 'go mod graph' in ${goModDir}`)
|
||||||
const goModGraph = await exec.getExecOutput('go', ['mod', 'graph'], {
|
const goModGraph = await exec.getExecOutput('go', ['mod', 'graph'], {
|
||||||
cwd: goModDir
|
cwd: goModDir
|
||||||
@@ -21,35 +21,94 @@ export async function processGoGraph (goModDir: string): Promise<PackageCache> {
|
|||||||
throw new Error("Failed to execute 'go mod graph'")
|
throw new Error("Failed to execute 'go mod graph'")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* add all direct and indirect packages to a new PackageCache */
|
||||||
const cache = new PackageCache()
|
const cache = new PackageCache()
|
||||||
|
directDependencies.forEach((pkg) => {
|
||||||
|
cache.package(pkg)
|
||||||
|
})
|
||||||
|
indirectDependencies.forEach((pkg) => {
|
||||||
|
cache.package(pkg)
|
||||||
|
})
|
||||||
|
|
||||||
const packageAssocList = parseGoModGraph(goModGraph.stdout)
|
const packageAssocList = parseGoModGraph(goModGraph.stdout)
|
||||||
packageAssocList.forEach(([parentPkg, childPkg]) => {
|
packageAssocList.forEach(([parentPkg, childPkg]) => {
|
||||||
cache.package(parentPkg).dependsOn(cache.package(childPkg))
|
/* Look up the parent package in the cache. go mod graph will return
|
||||||
|
* multiple versions of packages with the same namespace and name. We
|
||||||
|
* select only package versions used in the Go build target. */
|
||||||
|
const targetPackage = cache.lookupPackage(parentPkg)
|
||||||
|
if (!targetPackage) return
|
||||||
|
|
||||||
|
/* Build a matcher to select on the namespace+name of the child package in
|
||||||
|
* the cache. The child package version specified by go mod graph is not
|
||||||
|
* the one guaranteed to be selected when building Go build targets. */
|
||||||
|
const matcher: { name: string; namespace?: string } = {
|
||||||
|
name: childPkg.name
|
||||||
|
}
|
||||||
|
if (childPkg.namespace) matcher.namespace = childPkg.namespace
|
||||||
|
|
||||||
|
/* There should only ever be a single package with a namespace+name in the
|
||||||
|
* build target list. Go does not support multiple versions of the same
|
||||||
|
* package */
|
||||||
|
const matches = cache.packagesMatching(matcher)
|
||||||
|
|
||||||
|
if (matches.length === 0) return
|
||||||
|
|
||||||
|
if (matches.length !== 1) {
|
||||||
|
throw new Error(
|
||||||
|
'assertion failed: expected no more than one package in cache with namespace+name. ' +
|
||||||
|
'Found: ' +
|
||||||
|
JSON.stringify(matches) +
|
||||||
|
'for ' +
|
||||||
|
JSON.stringify(matcher)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// create the dependency relationship
|
||||||
|
targetPackage.dependsOn(matches[0])
|
||||||
})
|
})
|
||||||
|
|
||||||
return cache
|
return cache
|
||||||
}
|
}
|
||||||
|
|
||||||
// For a specific Go _build target_, this template lists all dependencies used
|
// For a specific Go _build target_, these templates list dependencies used to
|
||||||
// to build the build target It does not provide association between the
|
// in the build target. It does not provide association between the
|
||||||
// dependencies (i.e. which dependencies depend on which)
|
// dependencies (i.e. which dependencies depend on which)
|
||||||
// eslint-disable-next-line quotes
|
// eslint-disable-next-line quotes
|
||||||
// eslint-disable-next-line no-useless-escape
|
// eslint-disable-next-line no-useless-escape
|
||||||
const GO_LIST_DEP_TEMPLATE =
|
const GO_DIRECT_DEPS_TEMPLATE =
|
||||||
'{{define "M"}}{{.Path}}@{{.Version}}{{end}}{{with .Module}}{{if not .Main}}{{if .Replace}}{{template "M" .Replace}}{{else}}{{template "M" .}}{{end}}{{end}}{{end}}'
|
'{{define "M"}}{{if not .Indirect}}{{.Path}}@{{.Version}}{{end}}{{end}}{{with .Module}}{{if not .Main}}{{if .Replace}}{{template "M" .Replace}}{{else}}{{template "M" .}}{{end}}{{end}}{{end}}'
|
||||||
|
// eslint-disable-next-line quotes
|
||||||
|
// eslint-disable-next-line no-useless-escape
|
||||||
|
const GO_INDIRECT_DEPS_TEMPLATE =
|
||||||
|
'{{define "M"}}{{if .Indirect}}{{.Path}}@{{.Version}}{{end}}{{end}}{{with .Module}}{{if not .Main}}{{if .Replace}}{{template "M" .Replace}}{{else}}{{template "M" .}}{{end}}{{end}}{{end}}'
|
||||||
|
|
||||||
export async function processGoBuildTarget (
|
export async function processGoDirectDependencies (
|
||||||
|
goModDir: string,
|
||||||
|
goBuildTarget: string
|
||||||
|
): Promise<Array<PackageURL>> {
|
||||||
|
console.log(
|
||||||
|
`go direct package detection in ${goModDir} on build target ${goBuildTarget}`
|
||||||
|
)
|
||||||
|
return processGoList(goModDir, goBuildTarget, GO_DIRECT_DEPS_TEMPLATE)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function processGoIndirectDependencies (
|
||||||
|
goModDir: string,
|
||||||
|
goBuildTarget: string
|
||||||
|
): Promise<Array<PackageURL>> {
|
||||||
|
console.log(
|
||||||
|
`go indirect package detection in ${goModDir} on build target ${goBuildTarget}`
|
||||||
|
)
|
||||||
|
return processGoList(goModDir, goBuildTarget, GO_INDIRECT_DEPS_TEMPLATE)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function processGoList (
|
||||||
goModDir: string,
|
goModDir: string,
|
||||||
goBuildTarget: string,
|
goBuildTarget: string,
|
||||||
cache: PackageCache
|
goListTemplate: string
|
||||||
): Promise<Manifest> {
|
): Promise<Array<PackageURL>> {
|
||||||
console.log(
|
|
||||||
`Running go package detection in ${goModDir} on build target ${goBuildTarget}`
|
|
||||||
)
|
|
||||||
|
|
||||||
const goList = await exec.getExecOutput(
|
const goList = await exec.getExecOutput(
|
||||||
'go',
|
'go',
|
||||||
['list', '-deps', '-f', GO_LIST_DEP_TEMPLATE, goBuildTarget],
|
['list', '-deps', '-f', goListTemplate, goBuildTarget],
|
||||||
{ cwd: goModDir }
|
{ cwd: goModDir }
|
||||||
)
|
)
|
||||||
if (goList.exitCode !== 0) {
|
if (goList.exitCode !== 0) {
|
||||||
@@ -58,14 +117,5 @@ export async function processGoBuildTarget (
|
|||||||
throw new Error("Failed to execute 'go list'")
|
throw new Error("Failed to execute 'go list'")
|
||||||
}
|
}
|
||||||
|
|
||||||
const dependencies = parseGoList(goList.stdout)
|
return parseGoList(goList.stdout)
|
||||||
const manifest = new BuildTarget(
|
|
||||||
goBuildTarget,
|
|
||||||
path.join(goModDir, goBuildTarget)
|
|
||||||
)
|
|
||||||
dependencies.forEach((dep) => {
|
|
||||||
manifest.addBuildDependency(cache.package(dep))
|
|
||||||
})
|
|
||||||
|
|
||||||
return manifest
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user