Compare commits

..

2 Commits

Author SHA1 Message Date
Courtney Claessens 0dfaaf68a6 Merge branch 'main' into fix-missing-colon 2022-06-16 16:58:49 -04:00
Patrick Carlisle ecfa79a36c Fix typo 2022-06-16 10:31:12 -07:00
25 changed files with 16904 additions and 36821 deletions
-1
View File
@@ -1 +0,0 @@
dist/* linguist-generated=true
-48
View File
@@ -1,48 +0,0 @@
name: "CodeQL"
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
schedule:
- cron: '21 0 * * 4'
jobs:
analyze:
name: Analyze
runs-on: 'ubuntu-latest'
timeout-minutes: 360
permissions:
# required for all workflows
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript-typescript', 'actions', 'go' ]
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
config: |
paths-ignore:
- dist/index.js
- dist/sourcemap-register.js
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
@@ -13,9 +13,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v4
uses: actions/checkout@v3
- uses: actions/setup-go@v5
- uses: actions/setup-go@v3
with:
go-version: ">=1.18.0"
@@ -1,26 +0,0 @@
name: Release new action version
on:
release:
types: [released]
workflow_dispatch:
inputs:
TAG_NAME:
description: 'Tag name that the major tag will point to'
required: true
env:
TAG_NAME: ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }}
permissions:
contents: write
jobs:
update_tag:
name: Update the major tag to include the ${{ github.event.inputs.TAG_NAME || github.event.release.tag_name }} changes
environment:
name: releaseNewActionVersion
runs-on: ubuntu-latest
steps:
- name: Update the ${{ env.TAG_NAME }} tag
uses: actions/publish-action@v0.2.1
with:
source-tag: ${{ env.TAG_NAME }}
+9 -18
View File
@@ -8,10 +8,7 @@ on: # rebuild any PRs and main branch changes
branches:
- main
- 'releases/*'
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
@@ -22,19 +19,13 @@ jobs:
- name: Install Node
uses: actions/setup-node@v3
with:
node-version: 20
node-version: 16
registry-url: 'https://npm.pkg.github.com'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
- name: Install NPM dependencies
run: npm ci --ignore-scripts
- run: npm ci --ignore-scripts
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
- name: Build and run tests
run: npm rebuild && npm run all
- name: Verify no uncommitted files
run: |
if [ -n "$(git status --porcelain=v1 2>/dev/null)" ]; then
echo "There are uncommitted changes!"
git status --porcelain=v1
exit 1
fi
shell: bash
- run: npm rebuild && npm run all
-40
View File
@@ -28,46 +28,6 @@ Here are a few things you can do that will increase the likelihood of your pull
- Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests.
- Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
## Cutting a new release
<details>
_Note: these instructions are for maintainers_
1. Update the version number in [package.json](https://github.com/actions/go-dependency-submission/blob/main/package.json) and run `npm i` to update the lockfile.
1. Go to [Draft a new
release](https://github.com/actions/go-dependency-submission/releases/new)
in the Releases page.
1. Make sure that the `Publish this Action to the GitHub Marketplace`
checkbox is enabled
<img width="481" alt="Screenshot 2022-06-15 at 12 08 19" src="https://user-images.githubusercontent.com/2161/173822484-4b60d8b4-c674-4bff-b5ff-b0c4a3650ab7.png">
3. Click "Choose a tag" and then "Create new tag", where the tag name
will be your version prefixed by a `v` (e.g. `v1.2.3`).
4. Use a version number for the release title (e.g. "1.2.3").
<img width="700" alt="Screenshot 2022-06-15 at 12 08 36" src="https://user-images.githubusercontent.com/2161/173822548-33ab3432-d679-4dc1-adf8-b50fdaf47de3.png">
5. Add your release notes. If this is a major version make sure to
include a small description of the biggest changes in the new version.
6. Click "Publish Release".
You now have a tag and release using the semver version you used
above. The last remaining thing to do is to move the dynamic version
identifier to match the current SHA. This allows users to adopt a
major version number (e.g. `v1`) in their workflows while
automatically getting all the
minor/patch updates.
To do this just checkout `main`, force-create a new annotated tag, and push it:
```
git tag -fa v2 -m "Updating v2 to 2.0.1"
git push origin v2 --force
```
</details>
## Resources
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
+2 -89
View File
@@ -1,16 +1,7 @@
# Go Dependency Submission
This GitHub Action calculates dependencies for a Go build-target (a Go file with a
`main` function) and submits the list to the [Dependency submission API](https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/using-the-dependency-submission-api). Dependencies then appear in your repository's dependency graph, and you'll receive Dependabot alerts and updates for vulnerable or out-of-date dependencies.
### Running locally
Because we are checking in the Typescript output, you may see check failures if you don't generate the contents of `dist/` in a similar manner to our CI check. You can easily rectify this by regenerating in a codespace and using what we use in our workflow YAML:
```
npm ci --ignore-scripts
npm rebuild && npm run all
```
`main` function) and submits the list to the [Dependency submission API](https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/using-the-dependency-submission-api). Dependencies then appear in your repository's dependency graph, and you'll receive Dependabot alerts and updates for vulnerable or out-of-date dependencies.
### Example
```yaml
@@ -41,85 +32,7 @@ jobs:
go-version: ">=1.18.0"
- name: Run snapshot action
uses: actions/go-dependency-submission@v2
with:
# Required: Define the repo path to the go.mod file used by the
# build target
go-mod-path: go-example/go.mod
#
# Optional: Define the path of a build target (a file with a
# `main()` function) If not defined, this Action will collect all
# dependencies used by all build targets for the module, which may
# include Go dependencies used by tests and tooling.
go-build-target: go-example/cmd/octocat.go
```
### Accessing Private Go Modules
This action will fail if your `go.mod` contains private Go modules.
To access private Go modules the action requires an extra step to access your
private module registry.
See official Go documentation for more information at https://go.dev/doc/faq#git_https
#### Accessing Private Go Modules Hosted on GitHub
If your private Go modules are hosted on GitHub, there are various ways for the action to
access them. You can use either HTTPS authentication with a Personal Access Token (PAT) or SSH authentication with deploy keys or SSH keys.
#### Authentication Methods
**HTTPS with Personal Access Token**: Uses a GitHub Personal Access Token to authenticate with private repositories. This method requires storing the token as a repository secret. See [Creating a personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-personal-access-token-classic) for setup instructions.
**SSH Authentication**: Uses SSH keys or deploy keys for authentication. This method doesn't require storing tokens and can be more secure for some use cases. See the [GitHub documentation on SSH authentication](https://docs.github.com/en/authentication/connecting-to-github-with-ssh) for setup instructions.
#### Additional Environment Variables
- **`GONOPROXY`**: Set this to bypass the module proxy entirely for specific modules
- **`GOSUMDB`**: Set to `off` or configure to skip checksum verification for private modules
- **`GOPROXY`**: Can be set to `direct` to bypass proxies completely
#### Example: HTTPS Authentication with Personal Access Token
This example adds a step to the workflow which uses a GitHub
[Personal Access Token (PAT)](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)
which has repo permissions. The PAT is saved as a repo [actions secret](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions) `GH_ACCESS_TOKEN`.
The env variable `GOPRIVATE` has also been set so that the GitHub org `foo` is considered private.
```yaml
name: Go Dependency Submission
on:
push:
branches:
- main
# The API requires write permission on the repository to submit dependencies
permissions:
contents: write
# Environment variables to configure Go and Go modules. Customize as necessary
env:
GOPROXY: 'https://proxy.golang.org,direct' # To add a private proxy, place it between the public golang proxy and direct
GOPRIVATE: 'github.com/foo/*' # repositories in organization foo are considered private
jobs:
go-action-detection:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: ">=1.18.0"
# Authentication step
- name: Authenticate with GitHub
run: git config --global url.https://${{ secrets.GH_ACCESS_TOKEN }}@github.com/.insteadOf https://github.com/
- name: Run snapshot action
uses: actions/go-dependency-submission@v2
uses: actions/go-dependency-submission@v1
with:
# Required: Define the repo path to the go.mod file used by the
# build target
+1 -1
View File
@@ -28,4 +28,4 @@ This information will help us triage your report more quickly.
## Policy
See [GitHub's Safe Harbor Policy](https://docs.github.com/en/site-policy/security-policies/github-bug-bounty-program-legal-safe-harbor#1-safe-harbor-terms)
See [GitHub's Safe Harbor Policy](https://docs.github.com/en/github/site-policy/github-bug-bounty-program-legal-safe-harbor#1-safe-harbor-terms)
+2 -31
View File
@@ -11,40 +11,11 @@ inputs:
description: 'User provided map of max key/value pairs of metadata to include with the snapshot e.g. {"lastModified": "12-31-2022"}'
go-mod-path:
required: true
description: 'Repo path to the go.mod file used to detect dependencies for the Go build target. Defaults to go.mod in the root of the repository.'
default: 'go.mod'
description: 'Repo path to the go.mod file used to detect dependencies for the Go build target'
go-build-target:
required: true
description: 'Build target to detect build dependencies. If unspecified, will use "all", with will detect all dependencies used in all build targets (including tests and tools).'
default: 'all'
snapshot-sha:
description: The SHA that the results will be linked to in the dependency snapshot
type: string
required: false
default: ''
snapshot-ref:
description: The ref that the results will be linked to in the dependency snapshot
type: string
required: false
default: ''
# If any of detector-name, detector-version, or detector-url are provided, they all have to be provided.
# Defaults will be used if none are not provided. If only one or two are provided, the action will fail.
detector-name:
description: The name of the detector that generated the dependency snapshot
type: string
required: false
default: ''
detector-version:
description: The version of the detector that generated the dependency snapshot
type: string
required: false
default: ''
detector-url:
description: The URL to the detector that generated the dependency snapshot
type: string
required: false
default: ''
runs:
using: 'node24'
using: 'node16'
main: 'dist/index.js'
-6
View File
@@ -1,6 +0,0 @@
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: '20' } }],
'@babel/preset-typescript',
],
};
+14570 -31235
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+104 -43
View File
@@ -268,6 +268,16 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@vercel/ncc
MIT
Copyright 2018 ZEIT, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
before-after-hook
Apache-2.0
Apache License
@@ -492,6 +502,57 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
is-plain-object
MIT
The MIT License (MIT)
Copyright (c) 2014-2017, Jon Schlinkert.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
node-fetch
MIT
The MIT License (MIT)
Copyright (c) 2016 David Frank
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
once
ISC
The ISC License
@@ -513,25 +574,9 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
packageurl-js
MIT
Copyright (c) the purl authors
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
tr46
MIT
tunnel
MIT
@@ -558,31 +603,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
undici
MIT
MIT License
Copyright (c) Matteo Collina and Undici contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
universal-user-agent
ISC
# [ISC License](https://spdx.org/licenses/ISC)
@@ -594,6 +614,47 @@ Permission to use, copy, modify, and/or distribute this software for any purpose
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
webidl-conversions
BSD-2-Clause
# The BSD 2-Clause License
Copyright (c) 2014, Domenic Denicola
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
whatwg-url
MIT
The MIT License (MIT)
Copyright (c) 20152016 Sebastian Mayr
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
wrappy
ISC
The ISC License
-58
View File
@@ -1,58 +0,0 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseGoModGraph = exports.parseGoList = exports.parseGoPackage = void 0;
const path_1 = __importDefault(require("path"));
const packageurl_js_1 = require("packageurl-js");
function parseGoPackage(pkg) {
const [qualifiedPackage, version] = pkg.split('@');
let namespace = null;
let name;
if (qualifiedPackage.indexOf('/') !== -1) {
namespace = path_1.default.dirname(qualifiedPackage);
name = path_1.default.basename(qualifiedPackage);
}
else {
name = qualifiedPackage;
}
return new packageurl_js_1.PackageURL('golang', namespace, name, version !== null && version !== void 0 ? version : null, null, null);
}
exports.parseGoPackage = parseGoPackage;
/**
* parseGoList parses a list of Go packages (one per line) matching the format
* "${GO_PACKAGE}@v{VERSION}" into Package URLs. This expects the output of 'go
* list -deps' as input.
*
* @param {string} contents
* @returns {Array<PackageURL>}
*/
function parseGoList(contents) {
// split the input by newlines, sort, and dedup
const packages = Array.from(new Set(contents.split('\n').map((p) => p.trim())));
const purls = [];
packages.forEach((pkg) => {
if (!pkg.trim())
return;
purls.push(parseGoPackage(pkg));
});
return purls;
}
exports.parseGoList = parseGoList;
/**
* parseGoModGraph parses an *associative list* of Go packages into tuples into
* an associative list of PackageURLs. This expects the output of 'go mod
* graph' as input
*/
function parseGoModGraph(contents) {
const pkgAssocList = [];
contents.split('\n').forEach((line) => {
if (!line.trim())
return;
const [parentPkg, childPkg] = line.split(' ');
pkgAssocList.push([parseGoPackage(parentPkg), parseGoPackage(childPkg)]);
});
return pkgAssocList;
}
exports.parseGoModGraph = parseGoModGraph;
-128
View File
@@ -1,128 +0,0 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.processGoIndirectDependencies = exports.processGoDirectDependencies = exports.processGoGraph = void 0;
const exec = __importStar(require("@actions/exec"));
const core = __importStar(require("@actions/core"));
const dependency_submission_toolkit_1 = require("@github/dependency-submission-toolkit");
const parse_1 = require("./parse");
function processGoGraph(goModDir, directDependencies, indirectDependencies) {
return __awaiter(this, void 0, void 0, function* () {
console.log(`Running 'go mod graph' in ${goModDir}`);
const goModGraph = yield exec.getExecOutput('go', ['mod', 'graph'], {
cwd: goModDir
});
if (goModGraph.exitCode !== 0) {
core.error(goModGraph.stderr);
core.setFailed("'go mod graph' failed!");
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();
directDependencies.forEach((pkg) => {
cache.package(pkg);
});
indirectDependencies.forEach((pkg) => {
cache.package(pkg);
});
const packageAssocList = (0, parse_1.parseGoModGraph)(goModGraph.stdout);
packageAssocList.forEach(([parentPkg, 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;
});
}
exports.processGoGraph = processGoGraph;
// For a specific Go _build target_, these templates list dependencies used to
// in the build target. It does not provide association between the
// dependencies (i.e. which dependencies depend on which)
// eslint-disable-next-line quotes
// eslint-disable-next-line no-useless-escape
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}}';
// 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* () {
console.log(`go direct package detection in ${goModDir} on build target ${goBuildTarget}`);
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) {
core.error(goList.stderr);
core.setFailed("'go list' failed!");
throw new Error("Failed to execute 'go list'");
}
return (0, parse_1.parseGoList)(goList.stdout);
});
}
+1 -1
View File
@@ -7,5 +7,5 @@ require github.com/fatih/color v1.13.0
require (
github.com/mattn/go-colorable v0.1.9 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
golang.org/x/sys v0.1.0 // indirect
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
)
+1 -2
View File
@@ -7,6 +7,5 @@ github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+3 -9
View File
@@ -1,11 +1,5 @@
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
transform: {
'^.+\\.jsx?$': 'babel-jest',
'^.+\\.tsx?$': 'babel-jest',
},
preset: 'ts-jest',
testEnvironment: 'node',
moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx'],
transformIgnorePatterns: [
'/node_modules/(?!@octokit|@github)',
],
};
};
+2125 -4767
View File
File diff suppressed because it is too large Load Diff
+12 -22
View File
@@ -1,59 +1,49 @@
{
"name": "go-dependency-submission",
"version": "2.0.3",
"version": "1.0.0",
"description": "Go Dependency Submission",
"main": "dist/index.js",
"engines": {
"node": ">=24"
},
"scripts": {
"build": "tsc",
"format": "npx prettier --write '**/*.ts'",
"format-check": "npx prettier --check '**/*.ts'",
"format": "prettier --write '**/*.ts'",
"format-check": "prettier --check '**/*.ts'",
"lint": "eslint --fix src/**/*.ts",
"package": "ncc build --source-map --license licenses.txt",
"test": "jest --testTimeout=10000",
"test": "jest",
"test:watch": "jest --watch src",
"all": "npm run build && npm run format && npm run lint && npm run package && npm test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/actions/go-dependency-submission.git"
"url": "git+https://github.com/dsp-testing/go-dependency-submission.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/actions/go-dependency-submission/issues"
"url": "https://github.com/dsp-testing/go-dependency-submission/issues"
},
"homepage": "https://github.com/actions/go-dependency-submission#readme",
"homepage": "https://github.com/dsp-testing/go-dependency-submission#readme",
"devDependencies": {
"@babel/core": "^7.26.10",
"@babel/preset-env": "^7.26.9",
"@babel/preset-typescript": "^7.27.0",
"@types/jest": "^27.5.2",
"@typescript-eslint/eslint-plugin": "^5.20.0",
"@typescript-eslint/parser": "^5.20.0",
"@vercel/ncc": "^0.33.4",
"babel-jest": "^29.7.0",
"eslint": "^8.13.0",
"eslint-config-standard": "^17.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jest": "^26.5.3",
"eslint-plugin-n": "^15.1.0",
"eslint-plugin-promise": "^6.0.0",
"prettier": "^3.5.3",
"ts-jest": "^29.0.0",
"jest": "^28.0.0",
"ts-jest": "^28.0.4",
"typescript": "^4.6.4"
},
"dependencies": {
"@actions/core": "^1.11.1",
"@actions/core": "^1.6.0",
"@actions/exec": "^1.1.1",
"@actions/github": "^6.0.1",
"@github/dependency-submission-toolkit": "^2.0.5",
"@actions/github": "^5.0.3",
"@github/dependency-submission-toolkit": "^1.1.2",
"packageurl-js": "^0.0.6"
},
"overrides": {
"undici": "^6.24.0"
}
}
+19 -98
View File
@@ -1,25 +1,16 @@
import path from 'path'
import fs from 'fs'
import * as core from '@actions/core'
import * as github from '@actions/github'
import {
Snapshot,
Manifest,
submitSnapshot
} from '@github/dependency-submission-toolkit'
import { Snapshot, submitSnapshot } from '@github/dependency-submission-toolkit'
import {
processGoGraph,
processGoDirectDependencies,
processGoIndirectDependencies
} from './process'
import { processGoGraph, processGoBuildTarget } from './process'
async function main () {
const goModPath = path.normalize(
core.getInput('go-mod-path', { required: true })
)
const goModPath = path.normalize(core.getInput('go-mod-path'))
if (path.basename(goModPath) !== 'go.mod' || !fs.existsSync(goModPath)) {
if (path.basename(goModPath) !== 'go.mod' && fs.existsSync(goModPath)) {
throw new Error(`${goModPath} is not a go.mod file or does not exist!`)
}
const goModDir = path.dirname(goModPath)
@@ -44,95 +35,25 @@ async function main () {
}
}
const directDeps = await processGoDirectDependencies(goModDir, goBuildTarget)
const indirectDeps = await processGoIndirectDependencies(
const packageCache = await processGoGraph(goModDir)
const manifest = await processGoBuildTarget(
goModDir,
goBuildTarget
goBuildTarget,
packageCache
)
const packageCache = await processGoGraph(goModDir, directDeps, indirectDeps)
// if using the pseudotargets "all" or "./...", use the path to go.mod as filepath
const filepath =
goBuildTarget === 'all' || goBuildTarget === './...'
? goModPath
: 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)
})
type SnapshotDetector = {
name: string
url: string
version: string
}
let snapshotDetector: SnapshotDetector
const detectorName = core.getInput('detector-name')
const detectorUrl = core.getInput('detector-url')
const detectorVersion = core.getInput('detector-version')
if (detectorName === '' && detectorUrl === '' && detectorVersion === '') {
// use defaults if none are specified
snapshotDetector = {
name: 'actions/go-dependency-submission',
url: 'https://github.com/actions/go-dependency-submission',
const snapshot = new Snapshot(
{
name: 'github-go-dependency-detector',
url: 'https://github.com/github/github-go-dependency-detector',
version: '0.0.1'
},
github.context,
{
correlator: `${github.context.job}-${goBuildTarget}`,
id: github.context.runId.toString()
}
} else if (
detectorName === '' ||
detectorUrl === '' ||
detectorVersion === ''
) {
// if any of detectorName, detectorUrl, or detectorVersion have value, then they are all required
throw new Error(
"Invalid input: if any of 'detector-name', 'detector-url', or 'detector-version' have value, then thay are all required."
)
} else {
// use inputs since all are specified
snapshotDetector = {
name: detectorName,
url: core.getInput('detector-url', { required: true }),
version: core.getInput('detector-version', { required: true })
}
}
const snapshot = new Snapshot(snapshotDetector, github.context, {
correlator: `${github.context.job}-${goBuildTarget}`,
id: github.context.runId.toString()
})
)
snapshot.addManifest(manifest)
// only override the sha if the input has a value
// otherwise, continue to use the sha set from the context in the Snapshot constructor
const inputSHA = core.getInput('sha')
if (inputSHA !== '') {
snapshot.sha = inputSHA
}
// only override the ref if the input has a value
// otherwise, continue to use the ref set from the context in the Snapshot constructor
const inputRef = core.getInput('ref')
if (inputRef !== '') {
snapshot.ref = inputRef
}
submitSnapshot(snapshot)
}
+10 -28
View File
@@ -1,4 +1,4 @@
import { parseGoPackage, parseGoList, parseGoModGraph } from './parse'
import { parseGoList, parseGoModGraph } from './parse'
const GO_DEPENDENCIES = `go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp@v1.7.0
golang.org/x/sys@v0.0.0-20220317061510-51cd9980dadf
@@ -6,25 +6,7 @@ golang.org/x/text@v0.3.7
golang.org/x/text@v0.3.7
golang.org/x/text@v0.3.7`
describe('parseGoPackage', () => {
it('parses a package with a namespace', () => {
expect(parseGoPackage('foo/bar@0.1.2').toString()).toEqual(
'pkg:golang/foo/bar@0.1.2'
)
})
it('parses a package with a namespace with slashes', () => {
expect(parseGoPackage('github.com/foo/bar@0.1.2').toString()).toEqual(
'pkg:golang/github.com/foo/bar@0.1.2'
)
})
it('parses a package without a namespace', () => {
expect(parseGoPackage('foo.io@0.1.2').toString()).toEqual(
'pkg:golang/foo.io@0.1.2'
)
})
})
describe('parseGoList', () => {
describe('test dependenciesProcessorFunc', () => {
test('parses output of go list command into dependencies', () => {
const dependencies = parseGoList(GO_DEPENDENCIES)
@@ -33,7 +15,7 @@ describe('parseGoList', () => {
{
type: 'golang',
name: 'otlptracehttp',
namespace: 'go.opentelemetry.io/otel/exporters/otlp/otlptrace',
namespace: 'go.opentelemetry.io%2Fotel%2Fexporters%2Fotlp%2Fotlptrace',
version: 'v1.7.0',
qualifiers: null,
subpath: null
@@ -41,7 +23,7 @@ describe('parseGoList', () => {
{
type: 'golang',
name: 'sys',
namespace: 'golang.org/x',
namespace: 'golang.org%2Fx',
version: 'v0.0.0-20220317061510-51cd9980dadf',
qualifiers: null,
subpath: null
@@ -49,7 +31,7 @@ describe('parseGoList', () => {
{
type: 'golang',
name: 'text',
namespace: 'golang.org/x',
namespace: 'golang.org%2Fx',
version: 'v0.3.7',
qualifiers: null,
subpath: null
@@ -67,7 +49,7 @@ describe('parseGoModGraph', () => {
expect(assocList[0][0]).toEqual({
type: 'golang',
name: 'go-example',
namespace: null,
namespace: '.', // we expect the namespace for the root package to process to dot
version: null,
qualifiers: null,
subpath: null
@@ -85,7 +67,7 @@ github.com/mattn/go-colorable@v1.1.9 github.com/mattn/go-isatty@v0.0.12`)
{
type: 'golang',
name: 'color',
namespace: 'github.com/fatih',
namespace: 'github.com%2Ffatih',
version: 'v1.13.0',
qualifiers: null,
subpath: null
@@ -93,7 +75,7 @@ github.com/mattn/go-colorable@v1.1.9 github.com/mattn/go-isatty@v0.0.12`)
{
type: 'golang',
name: 'go-isatty',
namespace: 'github.com/mattn',
namespace: 'github.com%2Fmattn',
version: 'v0.0.14',
qualifiers: null,
subpath: null
@@ -103,7 +85,7 @@ github.com/mattn/go-colorable@v1.1.9 github.com/mattn/go-isatty@v0.0.12`)
{
type: 'golang',
name: 'go-colorable',
namespace: 'github.com/mattn',
namespace: 'github.com%2Fmattn',
version: 'v1.1.9',
qualifiers: null,
subpath: null
@@ -111,7 +93,7 @@ github.com/mattn/go-colorable@v1.1.9 github.com/mattn/go-isatty@v0.0.12`)
{
type: 'golang',
name: 'go-isatty',
namespace: 'github.com/mattn',
namespace: 'github.com%2Fmattn',
version: 'v0.0.12',
qualifiers: null,
subpath: null
+3 -9
View File
@@ -1,16 +1,10 @@
import path from 'path'
import { PackageURL } from 'packageurl-js'
export function parseGoPackage (pkg: string): PackageURL {
function parseGoPackage (pkg: string): PackageURL {
const [qualifiedPackage, version] = pkg.split('@')
let namespace: string | null = null
let name: string
if (qualifiedPackage.indexOf('/') !== -1) {
namespace = path.dirname(qualifiedPackage)
name = path.basename(qualifiedPackage)
} else {
name = qualifiedPackage
}
const namespace = encodeURIComponent(path.dirname(qualifiedPackage))
const name = path.basename(qualifiedPackage)
return new PackageURL('golang', namespace, name, version ?? null, null, null)
}
+9 -78
View File
@@ -1,86 +1,17 @@
import {
processGoGraph,
processGoDirectDependencies,
processGoIndirectDependencies
} from './process'
import { processGoGraph, processGoBuildTarget } from './process'
// NOTE: these tests all require "go" to be installed and available on the PATH!
//
describe('processGoDirectDependencies', () => {
test('run in go-example', async () => {
const purls = await processGoDirectDependencies(
'go-example',
'cmd/octocat.go'
)
expect(purls).toHaveLength(1)
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(
test('run in go-example', async () => {
const cache = await processGoGraph('go-example')
expect(cache.countPackages()).toEqual(8)
const manifest = await processGoBuildTarget(
'go-example',
'cmd/octocat.go'
'cmd/octocat.go',
cache
)
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/color@v1.13.0'
)
expect(colorDep).not.toBeUndefined()
if (colorDep) expect(colorDep.dependencies).toHaveLength(2)
expect(manifest.directDependencies()).toHaveLength(4)
expect(manifest.indirectDependencies()).toHaveLength(2)
})
})
+30 -80
View File
@@ -1,16 +1,16 @@
import { PackageURL } from 'packageurl-js'
import path from 'path'
import * as exec from '@actions/exec'
import * as core from '@actions/core'
import { PackageCache } from '@github/dependency-submission-toolkit'
import {
Manifest,
BuildTarget,
PackageCache
} from '@github/dependency-submission-toolkit'
import { parseGoModGraph, parseGoList } from './parse'
export async function processGoGraph (
goModDir: string,
directDependencies: Array<PackageURL>,
indirectDependencies: Array<PackageURL>
): Promise<PackageCache> {
export async function processGoGraph (goModDir: string): Promise<PackageCache> {
console.log(`Running 'go mod graph' in ${goModDir}`)
const goModGraph = await exec.getExecOutput('go', ['mod', 'graph'], {
cwd: goModDir
@@ -21,94 +21,35 @@ export async function processGoGraph (
throw new Error("Failed to execute 'go mod graph'")
}
/* add all direct and indirect packages to a new PackageCache */
const cache = new PackageCache()
directDependencies.forEach((pkg) => {
cache.package(pkg)
})
indirectDependencies.forEach((pkg) => {
cache.package(pkg)
})
const packageAssocList = parseGoModGraph(goModGraph.stdout)
packageAssocList.forEach(([parentPkg, 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])
cache.package(parentPkg).dependsOn(cache.package(childPkg))
})
return cache
}
// For a specific Go _build target_, these templates list dependencies used to
// in the build target. It does not provide association between the
// For a specific Go _build target_, this template lists all dependencies used
// to build the build target It does not provide association between the
// dependencies (i.e. which dependencies depend on which)
// eslint-disable-next-line quotes
// eslint-disable-next-line no-useless-escape
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}}'
// 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}}'
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}}'
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 (
export async function processGoBuildTarget (
goModDir: string,
goBuildTarget: string,
goListTemplate: string
): Promise<Array<PackageURL>> {
cache: PackageCache
): Promise<Manifest> {
console.log(
`Running go package detection in ${goModDir} on build target ${goBuildTarget}`
)
const goList = await exec.getExecOutput(
'go',
['list', '-deps', '-f', goListTemplate, goBuildTarget],
['list', '-deps', '-f', GO_LIST_DEP_TEMPLATE, goBuildTarget],
{ cwd: goModDir }
)
if (goList.exitCode !== 0) {
@@ -117,5 +58,14 @@ async function processGoList (
throw new Error("Failed to execute 'go list'")
}
return parseGoList(goList.stdout)
const dependencies = parseGoList(goList.stdout)
const manifest = new BuildTarget(
goBuildTarget,
path.join(goModDir, goBuildTarget)
)
dependencies.forEach((dep) => {
manifest.addBuildDependency(cache.package(dep))
})
return manifest
}