mirror of
https://github.com/github/codeql-action.git
synced 2026-08-05 13:02:04 -05:00
Compare commits
119 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1e83c72db7 | |||
| e8896a906a | |||
| f5ccce0c86 | |||
| 74268130c6 | |||
| ae2d7afe3b | |||
| 12a37237d2 | |||
| 5587e128ff | |||
| 74b4d8a6db | |||
| 175d681835 | |||
| f4e72f4a09 | |||
| 5f057318b6 | |||
| 0f88c0111f | |||
| bfaa0cf943 | |||
| 337dbe5618 | |||
| 6f42543a85 | |||
| 93dd64d351 | |||
| 87758a1402 | |||
| 813cb0479f | |||
| 9769e4a6df | |||
| 315a9f4b3c | |||
| 0446cb0aff | |||
| 29cf06569d | |||
| ee63f4ee4b | |||
| 5b4f4e40af | |||
| 58a0034549 | |||
| c7c1aa8045 | |||
| b673c57b89 | |||
| d138b00811 | |||
| b86c3701ed | |||
| 7bb6ac6c60 | |||
| d1d80761ef | |||
| 7a78ec0a54 | |||
| da3d6d25eb | |||
| c3dcf26eaf | |||
| 189b6ef4bf | |||
| 1a4c658bbf | |||
| ec154779ac | |||
| ca775cfb2e | |||
| fb9f2af49f | |||
| 60126bfb39 | |||
| 24367a89b5 | |||
| 70980b9f32 | |||
| bf5b437adb | |||
| b6efd2e6de | |||
| 8a6b404471 | |||
| d781c667b1 | |||
| 56417be251 | |||
| abf6f239fa | |||
| 9fb69dda17 | |||
| dcebdd6441 | |||
| 56e74b9096 | |||
| 13ee335beb | |||
| 07caa0f5cf | |||
| f77ab09bf4 | |||
| 8d908eeab3 | |||
| cfcff89771 | |||
| fe3dbb7e64 | |||
| 1aeb7665e7 | |||
| 0086c2ecdb | |||
| 9da537eb33 | |||
| 5ab09ae291 | |||
| c41d287cae | |||
| 8947510a57 | |||
| 5d84e87b3d | |||
| 9bc459c5f1 | |||
| 77e9a735f6 | |||
| 57a57713c3 | |||
| a0bf50cb7b | |||
| 72803c4251 | |||
| eaf6649611 | |||
| 55a6f9e0a8 | |||
| dfed1f7eea | |||
| 580e603e94 | |||
| de7ff148e5 | |||
| 480467971e | |||
| e2a8f32427 | |||
| 260a93fe06 | |||
| dc2678801a | |||
| c953f77bb6 | |||
| aa6c2c5bda | |||
| a52f1a55ed | |||
| 1bb294af6b | |||
| 25a0a6baed | |||
| 4b37db72e4 | |||
| 04b2540e30 | |||
| e0299c3c04 | |||
| 0e3f8311ed | |||
| ca76a2ca94 | |||
| aad14bf2cb | |||
| a08742f199 | |||
| 6afe41036b | |||
| ee4cc86b19 | |||
| 0607771cc2 | |||
| 151d531bd0 | |||
| 51becd2cf8 | |||
| a66f2b0b11 | |||
| 504c8cfc6f | |||
| a0d4330434 | |||
| 7c00663f08 | |||
| f8c87948ab | |||
| 9566d8c220 | |||
| 366d8a32d1 | |||
| bb9ed79f3d | |||
| 17548064f9 | |||
| ef507971e7 | |||
| 96d02d50f7 | |||
| 0fdc2c71e4 | |||
| 28944b580b | |||
| 388403b46e | |||
| 32c9898fa4 | |||
| 56292b1fa3 | |||
| 50a2815790 | |||
| a19d19e0a3 | |||
| 153a598a97 | |||
| f4cf65ca2d | |||
| b0af5695e6 | |||
| 43c1bea680 | |||
| 464ce1b43a | |||
| 74c48f71fa |
@@ -11,3 +11,4 @@ queries:
|
|||||||
- uses: security-and-quality
|
- uses: security-and-quality
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- tests
|
- tests
|
||||||
|
- lib
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
### Merge / deployment checklist
|
### Merge / deployment checklist
|
||||||
|
|
||||||
- Run test builds as necessary. Can be on this repository or elsewhere as needed in order to test the change - please include links to tests in other repos!
|
|
||||||
- [ ] CodeQL using init/analyze actions
|
|
||||||
- [ ] 3rd party tool using upload action
|
|
||||||
- [ ] Confirm this change is backwards compatible with existing workflows.
|
- [ ] Confirm this change is backwards compatible with existing workflows.
|
||||||
- [ ] Confirm the [readme](https://github.com/github/codeql-action/blob/master/README.md) has been updated if necessary.
|
- [ ] Confirm the [readme](https://github.com/github/codeql-action/blob/master/README.md) has been updated if necessary.
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
# Must fetch at least the immediate parents so that if this is
|
# Must fetch at least the immediate parents so that if this is
|
||||||
# a pull request then we can checkout the head of the pull request.
|
# a pull request then we can checkout the head of the pull request.
|
||||||
@@ -21,8 +21,7 @@ jobs:
|
|||||||
- run: git checkout HEAD^2
|
- run: git checkout HEAD^2
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
|
||||||
- uses: ./init
|
- uses: github/codeql-action/full@pre-hook
|
||||||
with:
|
with:
|
||||||
languages: javascript
|
languages: javascript
|
||||||
config-file: ./.github/codeql/codeql-config.yml
|
config-file: ./.github/codeql/codeql-config.yml
|
||||||
- uses: ./analyze
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
multi-language-repo_test-custom-queries:
|
multi-language-repo_test-custom-queries-and-remote-config:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -54,7 +54,7 @@ jobs:
|
|||||||
- uses: ./../action/init
|
- uses: ./../action/init
|
||||||
with:
|
with:
|
||||||
languages: cpp,csharp,java,javascript,python
|
languages: cpp,csharp,java,javascript,python
|
||||||
config-file: ./.github/codeql/custom-queries.yml
|
config-file: github/codeql-action/tests/multi-language-repo/.github/codeql/custom-queries.yml@${{ github.sha }}
|
||||||
- name: Build code
|
- name: Build code
|
||||||
shell: bash
|
shell: bash
|
||||||
run: ./build.sh
|
run: ./build.sh
|
||||||
@@ -93,7 +93,6 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
TEST_MODE: true
|
TEST_MODE: true
|
||||||
|
|
||||||
|
|
||||||
multi-language-repo_rubocop:
|
multi-language-repo_rubocop:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
@@ -124,3 +123,30 @@ jobs:
|
|||||||
sarif_file: rubocop.sarif
|
sarif_file: rubocop.sarif
|
||||||
env:
|
env:
|
||||||
TEST_MODE: true
|
TEST_MODE: true
|
||||||
|
|
||||||
|
test-proxy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ubuntu:18.04
|
||||||
|
options: --dns 127.0.0.1
|
||||||
|
services:
|
||||||
|
squid-proxy:
|
||||||
|
image: datadog/squid:latest
|
||||||
|
ports:
|
||||||
|
- 3128:3128
|
||||||
|
env:
|
||||||
|
https_proxy: http://squid-proxy:3128
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Move codeql-action
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir ../action
|
||||||
|
mv * .github ../action/
|
||||||
|
mv ../action/tests/multi-language-repo/{*,.github} .
|
||||||
|
- uses: ./../action/init
|
||||||
|
with:
|
||||||
|
languages: javascript
|
||||||
|
- uses: ./../action/analyze
|
||||||
|
env:
|
||||||
|
TEST_MODE: true
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ on:
|
|||||||
# curl -H "Authorization: Bearer <token>" -X POST https://api.github.com/repos/github/codeql-action/dispatches -d '{"event_type":"update-release-branch"}'
|
# curl -H "Authorization: Bearer <token>" -X POST https://api.github.com/repos/github/codeql-action/dispatches -d '{"event_type":"update-release-branch"}'
|
||||||
# Replace <token> with a personal access token from this page: https://github.com/settings/tokens
|
# Replace <token> with a personal access token from this page: https://github.com/settings/tokens
|
||||||
types: [update-release-branch]
|
types: [update-release-branch]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update:
|
update:
|
||||||
|
|||||||
Vendored
+25
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug AVA test file",
|
||||||
|
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/ava",
|
||||||
|
"runtimeArgs": [
|
||||||
|
"${file}",
|
||||||
|
"--break",
|
||||||
|
"--serial",
|
||||||
|
"--timeout=20m"
|
||||||
|
],
|
||||||
|
"port": 9229,
|
||||||
|
"outputCapture": "std",
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**/*.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
+24
-2
@@ -1,4 +1,4 @@
|
|||||||
## Contributing
|
# Contributing
|
||||||
|
|
||||||
[fork]: https://github.com/github/codeql-action/fork
|
[fork]: https://github.com/github/codeql-action/fork
|
||||||
[pr]: https://github.com/github/codeql-action/compare
|
[pr]: https://github.com/github/codeql-action/compare
|
||||||
@@ -10,13 +10,35 @@ Contributions to this project are [released](https://help.github.com/articles/gi
|
|||||||
|
|
||||||
Please note that this project is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms.
|
Please note that this project is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms.
|
||||||
|
|
||||||
|
## Development and Testing
|
||||||
|
|
||||||
|
Before you start, ensure that you have a recent version of node installed. You can see which version of node is used by the action in `init/action.yml`.
|
||||||
|
|
||||||
|
### Common tasks
|
||||||
|
|
||||||
|
* Transpile the TypeScript to JavaScript: `npm run build`. Note that the JavaScript files are committed to git.
|
||||||
|
* Run tests: `npm run test`. You’ll need to ensure that the JavaScript files are up-to-date first by running the command above.
|
||||||
|
* Run the linter: `npm run lint`.
|
||||||
|
|
||||||
|
This project also includes configuration to run tests from VSCode (with support for breakpoints) - open the test file you wish to run and choose "Debug AVA test file" from the Run menu in the Run panel.
|
||||||
|
|
||||||
|
### Running the action
|
||||||
|
|
||||||
|
To see the effect of your changes and to test them, push your changes in a branch and then look at the [Actions output](https://github.com/github/codeql-action/actions) for that branch. You can also exercise the code locally by running the automated tests.
|
||||||
|
|
||||||
|
### Integration tests
|
||||||
|
|
||||||
|
As well as the unit tests (see _Common tasks_ above), there are integration tests, defined in `.github/workflows/integration-testing.yml`. These are run by a CI check. Depending on the change you’re making, you may want to add a test to this file or extend an existing one.
|
||||||
|
|
||||||
## Submitting a pull request
|
## Submitting a pull request
|
||||||
|
|
||||||
1. [Fork][fork] and clone the repository
|
1. [Fork][fork] and clone the repository
|
||||||
2. Create a new branch: `git checkout -b my-branch-name`
|
2. Create a new branch: `git checkout -b my-branch-name`
|
||||||
3. Make your change, add tests, and make sure the tests still pass
|
3. Make your change, add tests, and make sure the tests still pass
|
||||||
4. Push to your fork and [submit a pull request][pr]
|
4. Push to your fork and [submit a pull request][pr]
|
||||||
5. Pat your self on the back and wait for your pull request to be reviewed and merged.
|
5. Pat yourself on the back and wait for your pull request to be reviewed and merged.
|
||||||
|
|
||||||
|
If you're a GitHub staff member, you can merge your own PR once it's approved; for external contributors, GitHub staff will merge your PR once it's approved.
|
||||||
|
|
||||||
Here are a few things you can do that will increase the likelihood of your pull request being accepted:
|
Here are a few things you can do that will increase the likelihood of your pull request being accepted:
|
||||||
|
|
||||||
|
|||||||
@@ -26,10 +26,6 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
CodeQL-Build:
|
CodeQL-Build:
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
|
|
||||||
# CodeQL runs on ubuntu-latest, windows-latest, and macos-latest
|
# CodeQL runs on ubuntu-latest, windows-latest, and macos-latest
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ inputs:
|
|||||||
description: The number of threads to be used by CodeQL.
|
description: The number of threads to be used by CodeQL.
|
||||||
required: false
|
required: false
|
||||||
default: "1"
|
default: "1"
|
||||||
|
checkout_path:
|
||||||
|
description: "The path at which the analyzed repository was checked out. Used to relativeize any absolute paths in the uploaded SARIF file."
|
||||||
|
required: false
|
||||||
|
default: ${{ github.workspace }}
|
||||||
token:
|
token:
|
||||||
default: ${{ github.token }}
|
default: ${{ github.token }}
|
||||||
matrix:
|
matrix:
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
name: 'CodeQL'
|
||||||
|
description: 'Setup the CodeQL tracer'
|
||||||
|
author: 'GitHub'
|
||||||
|
inputs:
|
||||||
|
tools:
|
||||||
|
description: URL of CodeQL tools
|
||||||
|
required: false
|
||||||
|
# If not specified the Action will check in several places until it finds the CodeQL tools.
|
||||||
|
languages:
|
||||||
|
description: The languages to be analysed
|
||||||
|
required: false
|
||||||
|
token:
|
||||||
|
default: ${{ github.token }}
|
||||||
|
matrix:
|
||||||
|
default: ${{ toJson(matrix) }}
|
||||||
|
config-file:
|
||||||
|
description: Path of the config file to use
|
||||||
|
required: false
|
||||||
|
|
||||||
|
check_name:
|
||||||
|
description: The name of the check run to add text to.
|
||||||
|
required: false
|
||||||
|
output:
|
||||||
|
description: The path of the directory in which to save the SARIF results
|
||||||
|
required: false
|
||||||
|
default: '../results'
|
||||||
|
upload:
|
||||||
|
description: Upload the SARIF file
|
||||||
|
required: false
|
||||||
|
default: "true"
|
||||||
|
ram:
|
||||||
|
description: Override the amount of memory in MB to be used by CodeQL. By default, almost all the memory of the machine is used.
|
||||||
|
required: false
|
||||||
|
threads:
|
||||||
|
description: The number of threads to be used by CodeQL.
|
||||||
|
required: false
|
||||||
|
default: "1"
|
||||||
|
checkout_path:
|
||||||
|
description: "The path at which the analyzed repository was checked out. Used to relativeize any absolute paths in the uploaded SARIF file."
|
||||||
|
required: false
|
||||||
|
default: ${{ github.workspace }}
|
||||||
|
runs:
|
||||||
|
using: 'node12'
|
||||||
|
pre: '../lib/setup-tracer.js'
|
||||||
|
main: '../lib/finalize-db.js'
|
||||||
+1
-1
@@ -5,7 +5,7 @@ inputs:
|
|||||||
tools:
|
tools:
|
||||||
description: URL of CodeQL tools
|
description: URL of CodeQL tools
|
||||||
required: false
|
required: false
|
||||||
default: https://github.com/github/codeql-action/releases/download/codeql-bundle-20200601/codeql-bundle.tar.gz
|
# If not specified the Action will check in several places until it finds the CodeQL tools.
|
||||||
languages:
|
languages:
|
||||||
description: The languages to be analysed
|
description: The languages to be analysed
|
||||||
required: false
|
required: false
|
||||||
|
|||||||
Generated
+39
-8
@@ -8,19 +8,50 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const core = __importStar(require("@actions/core"));
|
const core = __importStar(require("@actions/core"));
|
||||||
function includeAndExcludeAnalysisPaths(config, languages) {
|
function isInterpretedLanguage(language) {
|
||||||
|
return language === 'javascript' || language === 'python';
|
||||||
|
}
|
||||||
|
// Matches a string containing only characters that are legal to include in paths on windows.
|
||||||
|
exports.legalWindowsPathCharactersRegex = /^[^<>:"\|?]*$/;
|
||||||
|
// Builds an environment variable suitable for LGTM_INDEX_INCLUDE or LGTM_INDEX_EXCLUDE
|
||||||
|
function buildIncludeExcludeEnvVar(paths) {
|
||||||
|
// Ignore anything containing a *
|
||||||
|
paths = paths.filter(p => p.indexOf('*') === -1);
|
||||||
|
// Some characters are illegal in path names in windows
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
paths = paths.filter(p => p.match(exports.legalWindowsPathCharactersRegex));
|
||||||
|
}
|
||||||
|
return paths.join('\n');
|
||||||
|
}
|
||||||
|
function includeAndExcludeAnalysisPaths(config) {
|
||||||
|
// The 'LGTM_INDEX_INCLUDE' and 'LGTM_INDEX_EXCLUDE' environment variables
|
||||||
|
// control which files/directories are traversed when scanning.
|
||||||
|
// This allows including files that otherwise would not be scanned, or
|
||||||
|
// excluding and not traversing entire file subtrees.
|
||||||
|
// It does not understand globs or double-globs because that would require it to
|
||||||
|
// traverse the entire file tree to determine which files are matched.
|
||||||
|
// Any paths containing "*" are not included in these.
|
||||||
if (config.paths.length !== 0) {
|
if (config.paths.length !== 0) {
|
||||||
core.exportVariable('LGTM_INDEX_INCLUDE', config.paths.join('\n'));
|
core.exportVariable('LGTM_INDEX_INCLUDE', buildIncludeExcludeEnvVar(config.paths));
|
||||||
}
|
}
|
||||||
if (config.pathsIgnore.length !== 0) {
|
if (config.pathsIgnore.length !== 0) {
|
||||||
core.exportVariable('LGTM_INDEX_EXCLUDE', config.pathsIgnore.join('\n'));
|
core.exportVariable('LGTM_INDEX_EXCLUDE', buildIncludeExcludeEnvVar(config.pathsIgnore));
|
||||||
}
|
}
|
||||||
function isInterpretedLanguage(language) {
|
// The 'LGTM_INDEX_FILTERS' environment variable controls which files are
|
||||||
return language === 'javascript' || language === 'python';
|
// extracted or ignored. It does not control which directories are traversed.
|
||||||
|
// This does understand the glob and double-glob syntax.
|
||||||
|
const filters = [];
|
||||||
|
filters.push(...config.paths.map(p => 'include:' + p));
|
||||||
|
filters.push(...config.pathsIgnore.map(p => 'exclude:' + p));
|
||||||
|
if (filters.length !== 0) {
|
||||||
|
core.exportVariable('LGTM_INDEX_FILTERS', filters.join('\n'));
|
||||||
}
|
}
|
||||||
// Index include/exclude only work in javascript and python
|
// Index include/exclude/filters only work in javascript and python.
|
||||||
// If some other language is detected/configured show a warning
|
// If any other languages are detected/configured then show a warning.
|
||||||
if ((config.paths.length !== 0 || config.pathsIgnore.length !== 0) && !languages.every(isInterpretedLanguage)) {
|
if ((config.paths.length !== 0 ||
|
||||||
|
config.pathsIgnore.length !== 0 ||
|
||||||
|
filters.length !== 0) &&
|
||||||
|
!config.languages.every(isInterpretedLanguage)) {
|
||||||
core.warning('The "paths"/"paths-ignore" fields of the config only have effect for Javascript and Python');
|
core.warning('The "paths"/"paths-ignore" fields of the config only have effect for Javascript and Python');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"analysis-paths.js","sourceRoot":"","sources":["../src/analysis-paths.ts"],"names":[],"mappings":";;;;;;;;;AAAA,oDAAsC;AAItC,SAAgB,8BAA8B,CAAC,MAA0B,EAAE,SAAmB;IAC5F,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;QAC7B,IAAI,CAAC,cAAc,CAAC,oBAAoB,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;KACpE;IAED,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE;QACnC,IAAI,CAAC,cAAc,CAAC,oBAAoB,EAAE,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;KAC1E;IAED,SAAS,qBAAqB,CAAC,QAAQ;QACrC,OAAO,QAAQ,KAAK,YAAY,IAAI,QAAQ,KAAK,QAAQ,CAAC;IAC5D,CAAC;IAED,2DAA2D;IAC3D,+DAA+D;IAC/D,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,qBAAqB,CAAC,EAAE;QAC7G,IAAI,CAAC,OAAO,CAAC,4FAA4F,CAAC,CAAC;KAC5G;AACH,CAAC;AAlBD,wEAkBC"}
|
{"version":3,"file":"analysis-paths.js","sourceRoot":"","sources":["../src/analysis-paths.ts"],"names":[],"mappings":";;;;;;;;;AAAA,oDAAsC;AAItC,SAAS,qBAAqB,CAAC,QAAQ;IACrC,OAAO,QAAQ,KAAK,YAAY,IAAI,QAAQ,KAAK,QAAQ,CAAC;AAC5D,CAAC;AAED,6FAA6F;AAChF,QAAA,+BAA+B,GAAG,eAAe,CAAC;AAE/D,uFAAuF;AACvF,SAAS,yBAAyB,CAAC,KAAe;IAChD,iCAAiC;IACjC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEjD,uDAAuD;IACvD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE;QAChC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,uCAA+B,CAAC,CAAC,CAAC;KACrE;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAgB,8BAA8B,CAAC,MAA0B;IACvE,0EAA0E;IAC1E,+DAA+D;IAC/D,sEAAsE;IACtE,qDAAqD;IACrD,gFAAgF;IAChF,sEAAsE;IACtE,sDAAsD;IACtD,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;QAC7B,IAAI,CAAC,cAAc,CAAC,oBAAoB,EAAE,yBAAyB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;KACpF;IACD,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE;QACnC,IAAI,CAAC,cAAc,CAAC,oBAAoB,EAAE,yBAAyB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;KAC1F;IAED,yEAAyE;IACzE,6EAA6E;IAC7E,wDAAwD;IACxD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC;IACvD,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC;IAC7D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;QACxB,IAAI,CAAC,cAAc,CAAC,oBAAoB,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;KAC/D;IAED,oEAAoE;IACpE,sEAAsE;IACtE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;QACxB,MAAM,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC;QAC/B,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC;QACvB,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,qBAAqB,CAAC,EAAE;QAClD,IAAI,CAAC,OAAO,CAAC,4FAA4F,CAAC,CAAC;KAC5G;AACH,CAAC;AAjCD,wEAiCC"}
|
||||||
Generated
+20
-9
@@ -12,21 +12,32 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const ava_1 = __importDefault(require("ava"));
|
const ava_1 = __importDefault(require("ava"));
|
||||||
const analysisPaths = __importStar(require("./analysis-paths"));
|
const analysisPaths = __importStar(require("./analysis-paths"));
|
||||||
const configUtils = __importStar(require("./config-utils"));
|
|
||||||
const testing_utils_1 = require("./testing-utils");
|
const testing_utils_1 = require("./testing-utils");
|
||||||
testing_utils_1.silenceDebugOutput(ava_1.default);
|
testing_utils_1.setupTests(ava_1.default);
|
||||||
ava_1.default("emptyPaths", async (t) => {
|
ava_1.default("emptyPaths", async (t) => {
|
||||||
let config = new configUtils.Config();
|
const config = {
|
||||||
analysisPaths.includeAndExcludeAnalysisPaths(config, []);
|
languages: [],
|
||||||
|
queries: {},
|
||||||
|
pathsIgnore: [],
|
||||||
|
paths: [],
|
||||||
|
originalUserInput: {},
|
||||||
|
};
|
||||||
|
analysisPaths.includeAndExcludeAnalysisPaths(config);
|
||||||
t.is(process.env['LGTM_INDEX_INCLUDE'], undefined);
|
t.is(process.env['LGTM_INDEX_INCLUDE'], undefined);
|
||||||
t.is(process.env['LGTM_INDEX_EXCLUDE'], undefined);
|
t.is(process.env['LGTM_INDEX_EXCLUDE'], undefined);
|
||||||
|
t.is(process.env['LGTM_INDEX_FILTERS'], undefined);
|
||||||
});
|
});
|
||||||
ava_1.default("nonEmptyPaths", async (t) => {
|
ava_1.default("nonEmptyPaths", async (t) => {
|
||||||
let config = new configUtils.Config();
|
const config = {
|
||||||
config.paths.push('path1', 'path2');
|
languages: [],
|
||||||
config.pathsIgnore.push('path3', 'path4');
|
queries: {},
|
||||||
analysisPaths.includeAndExcludeAnalysisPaths(config, []);
|
paths: ['path1', 'path2', '**/path3'],
|
||||||
|
pathsIgnore: ['path4', 'path5', 'path6/**'],
|
||||||
|
originalUserInput: {},
|
||||||
|
};
|
||||||
|
analysisPaths.includeAndExcludeAnalysisPaths(config);
|
||||||
t.is(process.env['LGTM_INDEX_INCLUDE'], 'path1\npath2');
|
t.is(process.env['LGTM_INDEX_INCLUDE'], 'path1\npath2');
|
||||||
t.is(process.env['LGTM_INDEX_EXCLUDE'], 'path3\npath4');
|
t.is(process.env['LGTM_INDEX_EXCLUDE'], 'path4\npath5');
|
||||||
|
t.is(process.env['LGTM_INDEX_FILTERS'], 'include:path1\ninclude:path2\ninclude:**/path3\nexclude:path4\nexclude:path5\nexclude:path6/**');
|
||||||
});
|
});
|
||||||
//# sourceMappingURL=analysis-paths.test.js.map
|
//# sourceMappingURL=analysis-paths.test.js.map
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"analysis-paths.test.js","sourceRoot":"","sources":["../src/analysis-paths.test.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,8CAAuB;AAEvB,gEAAkD;AAClD,4DAA8C;AAC9C,mDAAmD;AAEnD,kCAAkB,CAAC,aAAI,CAAC,CAAC;AAEzB,aAAI,CAAC,YAAY,EAAE,KAAK,EAAC,CAAC,EAAC,EAAE;IAC3B,IAAI,MAAM,GAAG,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;IACtC,aAAa,CAAC,8BAA8B,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACzD,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE,SAAS,CAAC,CAAC;IACnD,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE,SAAS,CAAC,CAAC;AACrD,CAAC,CAAC,CAAC;AAEH,aAAI,CAAC,eAAe,EAAE,KAAK,EAAC,CAAC,EAAC,EAAE;IAC9B,IAAI,MAAM,GAAG,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;IACtC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACpC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC1C,aAAa,CAAC,8BAA8B,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACzD,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE,cAAc,CAAC,CAAC;IACxD,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE,cAAc,CAAC,CAAC;AAC1D,CAAC,CAAC,CAAC"}
|
{"version":3,"file":"analysis-paths.test.js","sourceRoot":"","sources":["../src/analysis-paths.test.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,8CAAuB;AAEvB,gEAAkD;AAClD,mDAA2C;AAE3C,0BAAU,CAAC,aAAI,CAAC,CAAC;AAEjB,aAAI,CAAC,YAAY,EAAE,KAAK,EAAC,CAAC,EAAC,EAAE;IAC3B,MAAM,MAAM,GAAG;QACb,SAAS,EAAE,EAAE;QACb,OAAO,EAAE,EAAE;QACX,WAAW,EAAE,EAAE;QACf,KAAK,EAAE,EAAE;QACT,iBAAiB,EAAE,EAAE;KACtB,CAAC;IACF,aAAa,CAAC,8BAA8B,CAAC,MAAM,CAAC,CAAC;IACrD,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE,SAAS,CAAC,CAAC;IACnD,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE,SAAS,CAAC,CAAC;IACnD,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE,SAAS,CAAC,CAAC;AACrD,CAAC,CAAC,CAAC;AAEH,aAAI,CAAC,eAAe,EAAE,KAAK,EAAC,CAAC,EAAC,EAAE;IAC9B,MAAM,MAAM,GAAG;QACb,SAAS,EAAE,EAAE;QACb,OAAO,EAAE,EAAE;QACX,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC;QACrC,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC;QAC3C,iBAAiB,EAAE,EAAE;KACtB,CAAC;IACF,aAAa,CAAC,8BAA8B,CAAC,MAAM,CAAC,CAAC;IACrD,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE,cAAc,CAAC,CAAC;IACxD,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE,cAAc,CAAC,CAAC;IACxD,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,EAAE,gGAAgG,CAAC,CAAC;AAC5I,CAAC,CAAC,CAAC"}
|
||||||
Generated
+22
@@ -0,0 +1,22 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||||
|
result["default"] = mod;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const core = __importStar(require("@actions/core"));
|
||||||
|
const github = __importStar(require("@actions/github"));
|
||||||
|
const console_log_level_1 = __importDefault(require("console-log-level"));
|
||||||
|
exports.getApiClient = function () {
|
||||||
|
return new github.GitHub(core.getInput('token'), {
|
||||||
|
userAgent: "CodeQL Action",
|
||||||
|
log: console_log_level_1.default({ level: "debug" })
|
||||||
|
});
|
||||||
|
};
|
||||||
|
//# sourceMappingURL=api-client.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,oDAAsC;AACtC,wDAA0C;AAC1C,0EAAgD;AAEnC,QAAA,YAAY,GAAG;IAC1B,OAAO,IAAI,MAAM,CAAC,MAAM,CACtB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EACtB;QACE,SAAS,EAAE,eAAe;QAC1B,GAAG,EAAE,2BAAe,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;KACzC,CAAC,CAAC;AACP,CAAC,CAAC"}
|
||||||
Generated
+21
-18
@@ -8,14 +8,27 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const core = __importStar(require("@actions/core"));
|
const core = __importStar(require("@actions/core"));
|
||||||
const exec = __importStar(require("@actions/exec"));
|
const codeql_1 = require("./codeql");
|
||||||
const path = __importStar(require("path"));
|
|
||||||
const sharedEnv = __importStar(require("./shared-environment"));
|
const sharedEnv = __importStar(require("./shared-environment"));
|
||||||
const util = __importStar(require("./util"));
|
const util = __importStar(require("./util"));
|
||||||
|
async function sendCompletedStatusReport(startedAt, allLanguages, failingLanguage, cause) {
|
||||||
|
var _a, _b;
|
||||||
|
const status = failingLanguage !== undefined || cause !== undefined ? 'failure' : 'success';
|
||||||
|
const statusReportBase = await util.createStatusReportBase('autobuild', status, startedAt, (_a = cause) === null || _a === void 0 ? void 0 : _a.message, (_b = cause) === null || _b === void 0 ? void 0 : _b.stack);
|
||||||
|
const statusReport = {
|
||||||
|
...statusReportBase,
|
||||||
|
autobuild_languages: allLanguages.join(','),
|
||||||
|
autobuild_failure: failingLanguage,
|
||||||
|
};
|
||||||
|
await util.sendStatusReport(statusReport);
|
||||||
|
}
|
||||||
async function run() {
|
async function run() {
|
||||||
var _a;
|
var _a;
|
||||||
|
const startedAt = new Date();
|
||||||
|
let language;
|
||||||
try {
|
try {
|
||||||
if (util.should_abort('autobuild', true) || !await util.reportActionStarting('autobuild')) {
|
if (util.should_abort('autobuild', true) ||
|
||||||
|
!await util.sendStatusReport(await util.createStatusReportBase('autobuild', 'starting', startedAt), true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Attempt to find a language to autobuild
|
// Attempt to find a language to autobuild
|
||||||
@@ -23,7 +36,7 @@ async function run() {
|
|||||||
// The languages are sorted in order specified by user or by lines of code if we got
|
// The languages are sorted in order specified by user or by lines of code if we got
|
||||||
// them from the GitHub API, so try to build the first language on the list.
|
// them from the GitHub API, so try to build the first language on the list.
|
||||||
const autobuildLanguages = ((_a = process.env[sharedEnv.CODEQL_ACTION_TRACED_LANGUAGES]) === null || _a === void 0 ? void 0 : _a.split(',')) || [];
|
const autobuildLanguages = ((_a = process.env[sharedEnv.CODEQL_ACTION_TRACED_LANGUAGES]) === null || _a === void 0 ? void 0 : _a.split(',')) || [];
|
||||||
const language = autobuildLanguages[0];
|
language = autobuildLanguages[0];
|
||||||
if (!language) {
|
if (!language) {
|
||||||
core.info("None of the languages in this project require extra build steps");
|
core.info("None of the languages in this project require extra build steps");
|
||||||
return;
|
return;
|
||||||
@@ -33,26 +46,16 @@ async function run() {
|
|||||||
core.warning(`We will only automatically build ${language} code. If you wish to scan ${autobuildLanguages.slice(1).join(' and ')}, you must replace this block with custom build steps.`);
|
core.warning(`We will only automatically build ${language} code. If you wish to scan ${autobuildLanguages.slice(1).join(' and ')}, you must replace this block with custom build steps.`);
|
||||||
}
|
}
|
||||||
core.startGroup(`Attempting to automatically build ${language} code`);
|
core.startGroup(`Attempting to automatically build ${language} code`);
|
||||||
// TODO: share config accross actions better via env variables
|
const codeQL = codeql_1.getCodeQL();
|
||||||
const codeqlCmd = util.getRequiredEnvParam(sharedEnv.CODEQL_ACTION_CMD);
|
await codeQL.runAutobuild(language);
|
||||||
const cmdName = process.platform === 'win32' ? 'autobuild.cmd' : 'autobuild.sh';
|
|
||||||
const autobuildCmd = path.join(path.dirname(codeqlCmd), language, 'tools', cmdName);
|
|
||||||
// Update JAVA_TOOL_OPTIONS to contain '-Dhttp.keepAlive=false'
|
|
||||||
// This is because of an issue with Azure pipelines timing out connections after 4 minutes
|
|
||||||
// and Maven not properly handling closed connections
|
|
||||||
// Otherwise long build processes will timeout when pulling down Java packages
|
|
||||||
// https://developercommunity.visualstudio.com/content/problem/292284/maven-hosted-agent-connection-timeout.html
|
|
||||||
let javaToolOptions = process.env['JAVA_TOOL_OPTIONS'] || "";
|
|
||||||
process.env['JAVA_TOOL_OPTIONS'] = [...javaToolOptions.split(/\s+/), '-Dhttp.keepAlive=false', '-Dmaven.wagon.http.pool=false'].join(' ');
|
|
||||||
await exec.exec(autobuildCmd);
|
|
||||||
core.endGroup();
|
core.endGroup();
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
core.setFailed("We were unable to automatically build your code. Please replace the call to the autobuild action with your custom build steps. " + error.message);
|
core.setFailed("We were unable to automatically build your code. Please replace the call to the autobuild action with your custom build steps. " + error.message);
|
||||||
await util.reportActionFailed('autobuild', error.message, error.stack);
|
await sendCompletedStatusReport(startedAt, [language], language, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await util.reportActionSucceeded('autobuild');
|
await sendCompletedStatusReport(startedAt, [language]);
|
||||||
}
|
}
|
||||||
run().catch(e => {
|
run().catch(e => {
|
||||||
core.setFailed("autobuild action failed. " + e);
|
core.setFailed("autobuild action failed. " + e);
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"autobuild.js","sourceRoot":"","sources":["../src/autobuild.ts"],"names":[],"mappings":";;;;;;;;;AAAA,oDAAsC;AACtC,oDAAsC;AACtC,2CAA6B;AAE7B,gEAAkD;AAClD,6CAA+B;AAE/B,KAAK,UAAU,GAAG;;IAChB,IAAI;QACF,IAAI,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,oBAAoB,CAAC,WAAW,CAAC,EAAE;YACzF,OAAO;SACR;QAED,0CAA0C;QAC1C,mFAAmF;QACnF,oFAAoF;QACpF,4EAA4E;QAC5E,MAAM,kBAAkB,GAAG,OAAA,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,8BAA8B,CAAC,0CAAE,KAAK,CAAC,GAAG,MAAK,EAAE,CAAC;QACnG,MAAM,QAAQ,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;QAEvC,IAAI,CAAC,QAAQ,EAAE;YACb,IAAI,CAAC,IAAI,CAAC,iEAAiE,CAAC,CAAC;YAC7E,OAAO;SACR;QAED,IAAI,CAAC,KAAK,CAAC,sCAAsC,QAAQ,EAAE,CAAC,CAAC;QAE7D,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE;YACjC,IAAI,CAAC,OAAO,CAAC,oCAAoC,QAAQ,8BAA8B,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,wDAAwD,CAAC,CAAC;SAC3L;QAED,IAAI,CAAC,UAAU,CAAC,qCAAqC,QAAQ,OAAO,CAAC,CAAC;QACtE,8DAA8D;QAC9D,MAAM,SAAS,GAAG,IAAI,CAAC,mBAAmB,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAExE,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,cAAc,CAAC;QAChF,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAGpF,+DAA+D;QAC/D,0FAA0F;QAC1F,qDAAqD;QACrD,8EAA8E;QAC9E,gHAAgH;QAChH,IAAI,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,EAAE,CAAC;QAC7D,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,GAAG,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,wBAAwB,EAAE,+BAA+B,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAE1I,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC9B,IAAI,CAAC,QAAQ,EAAE,CAAC;KAEjB;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,CAAC,SAAS,CAAC,kIAAkI,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;QACnK,MAAM,IAAI,CAAC,kBAAkB,CAAC,WAAW,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QACvE,OAAO;KACR;IAED,MAAM,IAAI,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC;AAChD,CAAC;AAED,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IACd,IAAI,CAAC,SAAS,CAAC,4BAA4B,GAAG,CAAC,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC"}
|
{"version":3,"file":"autobuild.js","sourceRoot":"","sources":["../src/autobuild.ts"],"names":[],"mappings":";;;;;;;;;AAAA,oDAAsC;AAEtC,qCAAqC;AACrC,gEAAkD;AAClD,6CAA+B;AAS/B,KAAK,UAAU,yBAAyB,CACtC,SAAe,EACf,YAAsB,EACtB,eAAwB,EACxB,KAAa;;IAEb,MAAM,MAAM,GAAG,eAAe,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5F,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,sBAAsB,CACxD,WAAW,EACX,MAAM,EACN,SAAS,QACT,KAAK,0CAAE,OAAO,QACd,KAAK,0CAAE,KAAK,CAAC,CAAC;IAChB,MAAM,YAAY,GAA0B;QAC1C,GAAG,gBAAgB;QACnB,mBAAmB,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC;QAC3C,iBAAiB,EAAE,eAAe;KACnC,CAAC;IACF,MAAM,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;AAC5C,CAAC;AAED,KAAK,UAAU,GAAG;;IAChB,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;IAC7B,IAAI,QAAQ,CAAC;IACb,IAAI;QACF,IAAI,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,IAAI,CAAC;YACpC,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,IAAI,CAAC,sBAAsB,CAAC,WAAW,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,EAAE;YAC7G,OAAO;SACR;QAED,0CAA0C;QAC1C,mFAAmF;QACnF,oFAAoF;QACpF,4EAA4E;QAC5E,MAAM,kBAAkB,GAAG,OAAA,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,8BAA8B,CAAC,0CAAE,KAAK,CAAC,GAAG,MAAK,EAAE,CAAC;QACnG,QAAQ,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;QAEjC,IAAI,CAAC,QAAQ,EAAE;YACb,IAAI,CAAC,IAAI,CAAC,iEAAiE,CAAC,CAAC;YAC7E,OAAO;SACR;QAED,IAAI,CAAC,KAAK,CAAC,sCAAsC,QAAQ,EAAE,CAAC,CAAC;QAE7D,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE;YACjC,IAAI,CAAC,OAAO,CAAC,oCAAoC,QAAQ,8BAA8B,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,wDAAwD,CAAC,CAAC;SAC3L;QAED,IAAI,CAAC,UAAU,CAAC,qCAAqC,QAAQ,OAAO,CAAC,CAAC;QACtE,MAAM,MAAM,GAAG,kBAAS,EAAE,CAAC;QAC3B,MAAM,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAEpC,IAAI,CAAC,QAAQ,EAAE,CAAC;KAEjB;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,CAAC,SAAS,CAAC,kIAAkI,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;QACnK,MAAM,yBAAyB,CAAC,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QACxE,OAAO;KACR;IAED,MAAM,yBAAyB,CAAC,SAAS,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IACd,IAAI,CAAC,SAAS,CAAC,4BAA4B,GAAG,CAAC,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC"}
|
||||||
Generated
+328
@@ -0,0 +1,328 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||||
|
result["default"] = mod;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const core = __importStar(require("@actions/core"));
|
||||||
|
const exec = __importStar(require("@actions/exec"));
|
||||||
|
const http = __importStar(require("@actions/http-client"));
|
||||||
|
const io = __importStar(require("@actions/io"));
|
||||||
|
const toolcache = __importStar(require("@actions/tool-cache"));
|
||||||
|
const fs = __importStar(require("fs"));
|
||||||
|
const path = __importStar(require("path"));
|
||||||
|
const semver = __importStar(require("semver"));
|
||||||
|
const stream = __importStar(require("stream"));
|
||||||
|
const globalutil = __importStar(require("util"));
|
||||||
|
const v4_1 = __importDefault(require("uuid/v4"));
|
||||||
|
const api = __importStar(require("./api-client"));
|
||||||
|
const util = __importStar(require("./util"));
|
||||||
|
/**
|
||||||
|
* Stores the CodeQL object, and is populated by `setupCodeQL` or `getCodeQL`.
|
||||||
|
* Can be overridden in tests using `setCodeQL`.
|
||||||
|
*/
|
||||||
|
let cachedCodeQL = undefined;
|
||||||
|
/**
|
||||||
|
* Environment variable used to store the location of the CodeQL CLI executable.
|
||||||
|
* Value is set by setupCodeQL and read by getCodeQL.
|
||||||
|
*/
|
||||||
|
const CODEQL_ACTION_CMD = "CODEQL_ACTION_CMD";
|
||||||
|
const CODEQL_BUNDLE_VERSION = "codeql-bundle-20200630";
|
||||||
|
const CODEQL_BUNDLE_NAME = "codeql-bundle.tar.gz";
|
||||||
|
const GITHUB_DOTCOM_API_URL = "https://api.github.com";
|
||||||
|
const CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action";
|
||||||
|
function getInstanceAPIURL() {
|
||||||
|
return process.env["GITHUB_API_URL"] || GITHUB_DOTCOM_API_URL;
|
||||||
|
}
|
||||||
|
function getCodeQLActionRepository() {
|
||||||
|
// Actions do not know their own repository name,
|
||||||
|
// so we currently use this hack to find the name based on where our files are.
|
||||||
|
// This can be removed once the change to the runner in https://github.com/actions/runner/pull/585 is deployed.
|
||||||
|
const runnerTemp = util.getRequiredEnvParam("RUNNER_TEMP");
|
||||||
|
const actionsDirectory = path.join(path.dirname(runnerTemp), "_actions");
|
||||||
|
const relativeScriptPath = path.relative(actionsDirectory, __filename);
|
||||||
|
// This handles the case where the Action does not come from an Action repository,
|
||||||
|
// e.g. our integration tests which use the Action code from the current checkout.
|
||||||
|
if (relativeScriptPath.startsWith("..") || path.isAbsolute(relativeScriptPath)) {
|
||||||
|
return CODEQL_DEFAULT_ACTION_REPOSITORY;
|
||||||
|
}
|
||||||
|
const relativeScriptPathParts = relativeScriptPath.split(path.sep);
|
||||||
|
return relativeScriptPathParts[0] + "/" + relativeScriptPathParts[1];
|
||||||
|
}
|
||||||
|
async function getCodeQLBundleDownloadURL() {
|
||||||
|
const codeQLActionRepository = getCodeQLActionRepository();
|
||||||
|
const potentialDownloadSources = [
|
||||||
|
// This GitHub instance, and this Action.
|
||||||
|
[getInstanceAPIURL(), codeQLActionRepository],
|
||||||
|
// This GitHub instance, and the canonical Action.
|
||||||
|
[getInstanceAPIURL(), CODEQL_DEFAULT_ACTION_REPOSITORY],
|
||||||
|
// GitHub.com, and the canonical Action.
|
||||||
|
[GITHUB_DOTCOM_API_URL, CODEQL_DEFAULT_ACTION_REPOSITORY],
|
||||||
|
];
|
||||||
|
// We now filter out any duplicates.
|
||||||
|
// Duplicates will happen either because the GitHub instance is GitHub.com, or because the Action is not a fork.
|
||||||
|
const uniqueDownloadSources = potentialDownloadSources.filter((url, index, self) => index === self.indexOf(url));
|
||||||
|
for (let downloadSource of uniqueDownloadSources) {
|
||||||
|
let [apiURL, repository] = downloadSource;
|
||||||
|
// If we've reached the final case, short-circuit the API check since we know the bundle exists and is public.
|
||||||
|
if (apiURL === GITHUB_DOTCOM_API_URL && repository === CODEQL_DEFAULT_ACTION_REPOSITORY) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let [repositoryOwner, repositoryName] = repository.split("/");
|
||||||
|
try {
|
||||||
|
const release = await api.getApiClient().repos.getReleaseByTag({
|
||||||
|
owner: repositoryOwner,
|
||||||
|
repo: repositoryName,
|
||||||
|
tag: CODEQL_BUNDLE_VERSION
|
||||||
|
});
|
||||||
|
for (let asset of release.data.assets) {
|
||||||
|
if (asset.name === CODEQL_BUNDLE_NAME) {
|
||||||
|
core.info(`Found CodeQL bundle in ${downloadSource[1]} on ${downloadSource[0]} with URL ${asset.url}.`);
|
||||||
|
return asset.url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
core.info(`Looked for CodeQL bundle in ${downloadSource[1]} on ${downloadSource[0]} but got error ${e}.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return `https://github.com/${CODEQL_DEFAULT_ACTION_REPOSITORY}/releases/download/${CODEQL_BUNDLE_VERSION}/${CODEQL_BUNDLE_NAME}`;
|
||||||
|
}
|
||||||
|
// We have to download CodeQL manually because the toolcache doesn't support Accept headers.
|
||||||
|
// This can be removed once https://github.com/actions/toolkit/pull/530 is merged and released.
|
||||||
|
async function toolcacheDownloadTool(url, headers) {
|
||||||
|
const client = new http.HttpClient('CodeQL Action');
|
||||||
|
const dest = path.join(util.getRequiredEnvParam('RUNNER_TEMP'), v4_1.default());
|
||||||
|
const response = await client.get(url, headers);
|
||||||
|
if (response.message.statusCode !== 200) {
|
||||||
|
const err = new toolcache.HTTPError(response.message.statusCode);
|
||||||
|
core.info(`Failed to download from "${url}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
const pipeline = globalutil.promisify(stream.pipeline);
|
||||||
|
await io.mkdirP(path.dirname(dest));
|
||||||
|
await pipeline(response.message, fs.createWriteStream(dest));
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
async function setupCodeQL() {
|
||||||
|
try {
|
||||||
|
let codeqlURL = core.getInput('tools');
|
||||||
|
const codeqlURLVersion = getCodeQLURLVersion(codeqlURL || `/${CODEQL_BUNDLE_VERSION}/`);
|
||||||
|
let codeqlFolder = toolcache.find('CodeQL', codeqlURLVersion);
|
||||||
|
if (codeqlFolder) {
|
||||||
|
core.debug(`CodeQL found in cache ${codeqlFolder}`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!codeqlURL) {
|
||||||
|
codeqlURL = await getCodeQLBundleDownloadURL();
|
||||||
|
}
|
||||||
|
const headers = { accept: 'application/octet-stream' };
|
||||||
|
// We only want to provide an authorization header if we are downloading
|
||||||
|
// from the same GitHub instance the Action is running on.
|
||||||
|
// This avoids leaking Enterprise tokens to dotcom.
|
||||||
|
if (codeqlURL.startsWith(getInstanceAPIURL() + "/")) {
|
||||||
|
core.debug('Downloading CodeQL bundle with token.');
|
||||||
|
let token = core.getInput('token', { required: true });
|
||||||
|
headers.authorization = `token ${token}`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
core.debug('Downloading CodeQL bundle without token.');
|
||||||
|
}
|
||||||
|
let codeqlPath = await toolcacheDownloadTool(codeqlURL, headers);
|
||||||
|
core.debug(`CodeQL bundle download to ${codeqlPath} complete.`);
|
||||||
|
const codeqlExtracted = await toolcache.extractTar(codeqlPath);
|
||||||
|
codeqlFolder = await toolcache.cacheDir(codeqlExtracted, 'CodeQL', codeqlURLVersion);
|
||||||
|
}
|
||||||
|
let codeqlCmd = path.join(codeqlFolder, 'codeql', 'codeql');
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
codeqlCmd += ".exe";
|
||||||
|
}
|
||||||
|
else if (process.platform !== 'linux' && process.platform !== 'darwin') {
|
||||||
|
throw new Error("Unsupported platform: " + process.platform);
|
||||||
|
}
|
||||||
|
cachedCodeQL = getCodeQLForCmd(codeqlCmd);
|
||||||
|
core.exportVariable(CODEQL_ACTION_CMD, codeqlCmd);
|
||||||
|
return cachedCodeQL;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
core.error(e);
|
||||||
|
throw new Error("Unable to download and extract CodeQL CLI");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.setupCodeQL = setupCodeQL;
|
||||||
|
function getCodeQLURLVersion(url) {
|
||||||
|
const match = url.match(/\/codeql-bundle-(.*)\//);
|
||||||
|
if (match === null || match.length < 2) {
|
||||||
|
throw new Error(`Malformed tools url: ${url}. Version could not be inferred`);
|
||||||
|
}
|
||||||
|
let version = match[1];
|
||||||
|
if (!semver.valid(version)) {
|
||||||
|
core.debug(`Bundle version ${version} is not in SemVer format. Will treat it as pre-release 0.0.0-${version}.`);
|
||||||
|
version = '0.0.0-' + version;
|
||||||
|
}
|
||||||
|
const s = semver.clean(version);
|
||||||
|
if (!s) {
|
||||||
|
throw new Error(`Malformed tools url ${url}. Version should be in SemVer format but have ${version} instead`);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
exports.getCodeQLURLVersion = getCodeQLURLVersion;
|
||||||
|
function getCodeQL() {
|
||||||
|
if (cachedCodeQL === undefined) {
|
||||||
|
const codeqlCmd = util.getRequiredEnvParam(CODEQL_ACTION_CMD);
|
||||||
|
cachedCodeQL = getCodeQLForCmd(codeqlCmd);
|
||||||
|
}
|
||||||
|
return cachedCodeQL;
|
||||||
|
}
|
||||||
|
exports.getCodeQL = getCodeQL;
|
||||||
|
function resolveFunction(partialCodeql, methodName) {
|
||||||
|
if (typeof partialCodeql[methodName] !== 'function') {
|
||||||
|
const dummyMethod = () => {
|
||||||
|
throw new Error('CodeQL ' + methodName + ' method not correctly defined');
|
||||||
|
};
|
||||||
|
return dummyMethod;
|
||||||
|
}
|
||||||
|
return partialCodeql[methodName];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set the functionality for CodeQL methods. Only for use in tests.
|
||||||
|
*
|
||||||
|
* Accepts a partial object and any undefined methods will be implemented
|
||||||
|
* to immediately throw an exception indicating which method is missing.
|
||||||
|
*/
|
||||||
|
function setCodeQL(partialCodeql) {
|
||||||
|
cachedCodeQL = {
|
||||||
|
getDir: resolveFunction(partialCodeql, 'getDir'),
|
||||||
|
printVersion: resolveFunction(partialCodeql, 'printVersion'),
|
||||||
|
getTracerEnv: resolveFunction(partialCodeql, 'getTracerEnv'),
|
||||||
|
databaseInit: resolveFunction(partialCodeql, 'databaseInit'),
|
||||||
|
runAutobuild: resolveFunction(partialCodeql, 'runAutobuild'),
|
||||||
|
extractScannedLanguage: resolveFunction(partialCodeql, 'extractScannedLanguage'),
|
||||||
|
finalizeDatabase: resolveFunction(partialCodeql, 'finalizeDatabase'),
|
||||||
|
resolveQueries: resolveFunction(partialCodeql, 'resolveQueries'),
|
||||||
|
databaseAnalyze: resolveFunction(partialCodeql, 'databaseAnalyze')
|
||||||
|
};
|
||||||
|
}
|
||||||
|
exports.setCodeQL = setCodeQL;
|
||||||
|
function getCodeQLForCmd(cmd) {
|
||||||
|
return {
|
||||||
|
getDir: function () {
|
||||||
|
return path.dirname(cmd);
|
||||||
|
},
|
||||||
|
printVersion: async function () {
|
||||||
|
await exec.exec(cmd, [
|
||||||
|
'version',
|
||||||
|
'--format=json'
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
getTracerEnv: async function (databasePath, compilerSpec) {
|
||||||
|
let envFile = path.resolve(databasePath, 'working', 'env.tmp');
|
||||||
|
const compilerSpecArg = compilerSpec ? ["--compiler-spec=" + compilerSpec] : [];
|
||||||
|
await exec.exec(cmd, [
|
||||||
|
'database',
|
||||||
|
'trace-command',
|
||||||
|
databasePath,
|
||||||
|
...compilerSpecArg,
|
||||||
|
process.execPath,
|
||||||
|
path.resolve(__dirname, 'tracer-env.js'),
|
||||||
|
envFile
|
||||||
|
]);
|
||||||
|
return JSON.parse(fs.readFileSync(envFile, 'utf-8'));
|
||||||
|
},
|
||||||
|
databaseInit: async function (databasePath, language, sourceRoot) {
|
||||||
|
await exec.exec(cmd, [
|
||||||
|
'database',
|
||||||
|
'init',
|
||||||
|
databasePath,
|
||||||
|
'--language=' + language,
|
||||||
|
'--source-root=' + sourceRoot,
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
runAutobuild: async function (language) {
|
||||||
|
const cmdName = process.platform === 'win32' ? 'autobuild.cmd' : 'autobuild.sh';
|
||||||
|
const autobuildCmd = path.join(path.dirname(cmd), language, 'tools', cmdName);
|
||||||
|
// Update JAVA_TOOL_OPTIONS to contain '-Dhttp.keepAlive=false'
|
||||||
|
// This is because of an issue with Azure pipelines timing out connections after 4 minutes
|
||||||
|
// and Maven not properly handling closed connections
|
||||||
|
// Otherwise long build processes will timeout when pulling down Java packages
|
||||||
|
// https://developercommunity.visualstudio.com/content/problem/292284/maven-hosted-agent-connection-timeout.html
|
||||||
|
let javaToolOptions = process.env['JAVA_TOOL_OPTIONS'] || "";
|
||||||
|
process.env['JAVA_TOOL_OPTIONS'] = [...javaToolOptions.split(/\s+/), '-Dhttp.keepAlive=false', '-Dmaven.wagon.http.pool=false'].join(' ');
|
||||||
|
await exec.exec(autobuildCmd);
|
||||||
|
},
|
||||||
|
extractScannedLanguage: async function (databasePath, language) {
|
||||||
|
// Get extractor location
|
||||||
|
let extractorPath = '';
|
||||||
|
await exec.exec(cmd, [
|
||||||
|
'resolve',
|
||||||
|
'extractor',
|
||||||
|
'--format=json',
|
||||||
|
'--language=' + language
|
||||||
|
], {
|
||||||
|
silent: true,
|
||||||
|
listeners: {
|
||||||
|
stdout: (data) => { extractorPath += data.toString(); },
|
||||||
|
stderr: (data) => { process.stderr.write(data); }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Set trace command
|
||||||
|
const ext = process.platform === 'win32' ? '.cmd' : '.sh';
|
||||||
|
const traceCommand = path.resolve(JSON.parse(extractorPath), 'tools', 'autobuild' + ext);
|
||||||
|
// Run trace command
|
||||||
|
await exec.exec(cmd, [
|
||||||
|
'database',
|
||||||
|
'trace-command',
|
||||||
|
databasePath,
|
||||||
|
'--',
|
||||||
|
traceCommand
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
finalizeDatabase: async function (databasePath) {
|
||||||
|
await exec.exec(cmd, [
|
||||||
|
'database',
|
||||||
|
'finalize',
|
||||||
|
databasePath
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
resolveQueries: async function (queries, extraSearchPath) {
|
||||||
|
const codeqlArgs = [
|
||||||
|
'resolve',
|
||||||
|
'queries',
|
||||||
|
...queries,
|
||||||
|
'--format=bylanguage'
|
||||||
|
];
|
||||||
|
if (extraSearchPath !== undefined) {
|
||||||
|
codeqlArgs.push('--search-path', extraSearchPath);
|
||||||
|
}
|
||||||
|
let output = '';
|
||||||
|
await exec.exec(cmd, codeqlArgs, {
|
||||||
|
listeners: {
|
||||||
|
stdout: (data) => {
|
||||||
|
output += data.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return JSON.parse(output);
|
||||||
|
},
|
||||||
|
databaseAnalyze: async function (databasePath, sarifFile, querySuite) {
|
||||||
|
await exec.exec(cmd, [
|
||||||
|
'database',
|
||||||
|
'analyze',
|
||||||
|
util.getMemoryFlag(),
|
||||||
|
util.getThreadsFlag(),
|
||||||
|
databasePath,
|
||||||
|
'--format=sarif-latest',
|
||||||
|
'--output=' + sarifFile,
|
||||||
|
'--no-sarif-add-snippets',
|
||||||
|
querySuite
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=codeql.js.map
|
||||||
File diff suppressed because one or more lines are too long
Generated
+60
@@ -0,0 +1,60 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||||
|
result["default"] = mod;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const toolcache = __importStar(require("@actions/tool-cache"));
|
||||||
|
const ava_1 = __importDefault(require("ava"));
|
||||||
|
const nock_1 = __importDefault(require("nock"));
|
||||||
|
const path = __importStar(require("path"));
|
||||||
|
const codeql = __importStar(require("./codeql"));
|
||||||
|
const testing_utils_1 = require("./testing-utils");
|
||||||
|
const util = __importStar(require("./util"));
|
||||||
|
testing_utils_1.setupTests(ava_1.default);
|
||||||
|
ava_1.default('download codeql bundle cache', async (t) => {
|
||||||
|
await util.withTmpDir(async (tmpDir) => {
|
||||||
|
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||||
|
process.env['RUNNER_TEMP'] = path.join(tmpDir, 'temp');
|
||||||
|
process.env['RUNNER_TOOL_CACHE'] = path.join(tmpDir, 'cache');
|
||||||
|
const versions = ['20200601', '20200610'];
|
||||||
|
for (let i = 0; i < versions.length; i++) {
|
||||||
|
const version = versions[i];
|
||||||
|
nock_1.default('https://example.com')
|
||||||
|
.get(`/download/codeql-bundle-${version}/codeql-bundle.tar.gz`)
|
||||||
|
.replyWithFile(200, path.join(__dirname, `/../src/testdata/codeql-bundle.tar.gz`));
|
||||||
|
process.env['INPUT_TOOLS'] = `https://example.com/download/codeql-bundle-${version}/codeql-bundle.tar.gz`;
|
||||||
|
await codeql.setupCodeQL();
|
||||||
|
t.assert(toolcache.find('CodeQL', `0.0.0-${version}`));
|
||||||
|
}
|
||||||
|
const cachedVersions = toolcache.findAllVersions('CodeQL');
|
||||||
|
t.is(cachedVersions.length, 2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
ava_1.default('parse codeql bundle url version', t => {
|
||||||
|
const tests = {
|
||||||
|
'20200601': '0.0.0-20200601',
|
||||||
|
'20200601.0': '0.0.0-20200601.0',
|
||||||
|
'20200601.0.0': '20200601.0.0',
|
||||||
|
'1.2.3': '1.2.3',
|
||||||
|
'1.2.3-alpha': '1.2.3-alpha',
|
||||||
|
'1.2.3-beta.1': '1.2.3-beta.1',
|
||||||
|
};
|
||||||
|
for (const [version, expectedVersion] of Object.entries(tests)) {
|
||||||
|
const url = `https://github.com/.../codeql-bundle-${version}/...`;
|
||||||
|
try {
|
||||||
|
const parsedVersion = codeql.getCodeQLURLVersion(url);
|
||||||
|
t.deepEqual(parsedVersion, expectedVersion);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
t.fail(e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=codeql.test.js.map
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"codeql.test.js","sourceRoot":"","sources":["../src/codeql.test.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,+DAAiD;AACjD,8CAAuB;AACvB,gDAAwB;AACxB,2CAA6B;AAE7B,iDAAmC;AACnC,mDAA2C;AAC3C,6CAA+B;AAE/B,0BAAU,CAAC,aAAI,CAAC,CAAC;AAEjB,aAAI,CAAC,8BAA8B,EAAE,KAAK,EAAC,CAAC,EAAC,EAAE;IAE7C,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,EAAC,MAAM,EAAC,EAAE;QAEnC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,GAAG,MAAM,CAAC;QAEzC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACvD,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAE9D,MAAM,QAAQ,GAAG,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAE1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACxC,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;YAE5B,cAAI,CAAC,qBAAqB,CAAC;iBACxB,GAAG,CAAC,2BAA2B,OAAO,uBAAuB,CAAC;iBAC9D,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,uCAAuC,CAAC,CAAC,CAAC;YAGrF,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,8CAA8C,OAAO,uBAAuB,CAAC;YAE1G,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;YAE3B,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC,CAAC,CAAC;SACxD;QAED,MAAM,cAAc,GAAG,SAAS,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;QAE3D,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,aAAI,CAAC,iCAAiC,EAAE,CAAC,CAAC,EAAE;IAE1C,MAAM,KAAK,GAAG;QACZ,UAAU,EAAE,gBAAgB;QAC5B,YAAY,EAAE,kBAAkB;QAChC,cAAc,EAAE,cAAc;QAC9B,OAAO,EAAE,OAAO;QAChB,aAAa,EAAE,aAAa;QAC5B,cAAc,EAAE,cAAc;KAC/B,CAAC;IAEF,KAAK,MAAM,CAAC,OAAO,EAAE,eAAe,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;QAC9D,MAAM,GAAG,GAAG,wCAAwC,OAAO,MAAM,CAAC;QAElE,IAAI;YACF,MAAM,aAAa,GAAG,MAAM,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC;YACtD,CAAC,CAAC,SAAS,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;SAC7C;QAAC,OAAO,CAAC,EAAE;YACV,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;SACnB;KACF;AACH,CAAC,CAAC,CAAC"}
|
||||||
Generated
+429
-128
@@ -12,104 +12,221 @@ const io = __importStar(require("@actions/io"));
|
|||||||
const fs = __importStar(require("fs"));
|
const fs = __importStar(require("fs"));
|
||||||
const yaml = __importStar(require("js-yaml"));
|
const yaml = __importStar(require("js-yaml"));
|
||||||
const path = __importStar(require("path"));
|
const path = __importStar(require("path"));
|
||||||
|
const api = __importStar(require("./api-client"));
|
||||||
|
const codeql_1 = require("./codeql");
|
||||||
|
const externalQueries = __importStar(require("./external-queries"));
|
||||||
const util = __importStar(require("./util"));
|
const util = __importStar(require("./util"));
|
||||||
|
// Property names from the user-supplied config file.
|
||||||
const NAME_PROPERTY = 'name';
|
const NAME_PROPERTY = 'name';
|
||||||
const DISPLAY_DEFAULT_QUERIES_PROPERTY = 'disable-default-queries';
|
const DISABLE_DEFAULT_QUERIES_PROPERTY = 'disable-default-queries';
|
||||||
const QUERIES_PROPERTY = 'queries';
|
const QUERIES_PROPERTY = 'queries';
|
||||||
const QUERIES_USES_PROPERTY = 'uses';
|
const QUERIES_USES_PROPERTY = 'uses';
|
||||||
const PATHS_IGNORE_PROPERTY = 'paths-ignore';
|
const PATHS_IGNORE_PROPERTY = 'paths-ignore';
|
||||||
const PATHS_PROPERTY = 'paths';
|
const PATHS_PROPERTY = 'paths';
|
||||||
class ExternalQuery {
|
/**
|
||||||
constructor(repository, ref) {
|
* A list of queries from https://github.com/github/codeql that
|
||||||
this.path = '';
|
* we don't want to run. Disabling them here is a quicker alternative to
|
||||||
this.repository = repository;
|
* disabling them in the code scanning query suites. Queries should also
|
||||||
this.ref = ref;
|
* be disabled in the suites, and removed from this list here once the
|
||||||
|
* bundle is updated to make those suite changes live.
|
||||||
|
*
|
||||||
|
* Format is a map from language to an array of path suffixes of .ql files.
|
||||||
|
*/
|
||||||
|
const DISABLED_BUILTIN_QUERIES = {
|
||||||
|
'csharp': [
|
||||||
|
'ql/src/Security Features/CWE-937/VulnerablePackage.ql',
|
||||||
|
'ql/src/Security Features/CWE-451/MissingXFrameOptions.ql',
|
||||||
|
]
|
||||||
|
};
|
||||||
|
function queryIsDisabled(language, query) {
|
||||||
|
return (DISABLED_BUILTIN_QUERIES[language] || [])
|
||||||
|
.some(disabledQuery => query.endsWith(disabledQuery));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Asserts that the noDeclaredLanguage and multipleDeclaredLanguages fields are
|
||||||
|
* both empty and errors if they are not.
|
||||||
|
*/
|
||||||
|
function validateQueries(resolvedQueries) {
|
||||||
|
const noDeclaredLanguage = resolvedQueries.noDeclaredLanguage;
|
||||||
|
const noDeclaredLanguageQueries = Object.keys(noDeclaredLanguage);
|
||||||
|
if (noDeclaredLanguageQueries.length !== 0) {
|
||||||
|
throw new Error('The following queries do not declare a language. ' +
|
||||||
|
'Their qlpack.yml files are either missing or is invalid.\n' +
|
||||||
|
noDeclaredLanguageQueries.join('\n'));
|
||||||
|
}
|
||||||
|
const multipleDeclaredLanguages = resolvedQueries.multipleDeclaredLanguages;
|
||||||
|
const multipleDeclaredLanguagesQueries = Object.keys(multipleDeclaredLanguages);
|
||||||
|
if (multipleDeclaredLanguagesQueries.length !== 0) {
|
||||||
|
throw new Error('The following queries declare multiple languages. ' +
|
||||||
|
'Their qlpack.yml files are either missing or is invalid.\n' +
|
||||||
|
multipleDeclaredLanguagesQueries.join('\n'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.ExternalQuery = ExternalQuery;
|
/**
|
||||||
|
* Run 'codeql resolve queries' and add the results to resultMap
|
||||||
|
*/
|
||||||
|
async function runResolveQueries(resultMap, toResolve, extraSearchPath, errorOnInvalidQueries) {
|
||||||
|
const codeQl = codeql_1.getCodeQL();
|
||||||
|
const resolvedQueries = await codeQl.resolveQueries(toResolve, extraSearchPath);
|
||||||
|
for (const [language, queries] of Object.entries(resolvedQueries.byLanguage)) {
|
||||||
|
if (resultMap[language] === undefined) {
|
||||||
|
resultMap[language] = [];
|
||||||
|
}
|
||||||
|
resultMap[language].push(...Object.keys(queries).filter(q => !queryIsDisabled(language, q)));
|
||||||
|
}
|
||||||
|
if (errorOnInvalidQueries) {
|
||||||
|
validateQueries(resolvedQueries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get the set of queries included by default.
|
||||||
|
*/
|
||||||
|
async function addDefaultQueries(languages, resultMap) {
|
||||||
|
const suites = languages.map(l => l + '-code-scanning.qls');
|
||||||
|
await runResolveQueries(resultMap, suites, undefined, false);
|
||||||
|
}
|
||||||
// The set of acceptable values for built-in suites from the codeql bundle
|
// The set of acceptable values for built-in suites from the codeql bundle
|
||||||
const builtinSuites = ['security-extended', 'security-and-quality'];
|
const builtinSuites = ['security-extended', 'security-and-quality'];
|
||||||
class Config {
|
/**
|
||||||
constructor() {
|
* Determine the set of queries associated with suiteName's suites and add them to resultMap.
|
||||||
this.name = "";
|
* Throws an error if suiteName is not a valid builtin suite.
|
||||||
this.disableDefaultQueries = false;
|
*/
|
||||||
this.additionalQueries = [];
|
async function addBuiltinSuiteQueries(configFile, languages, resultMap, suiteName) {
|
||||||
this.externalQueries = [];
|
const suite = builtinSuites.find((suite) => suite === suiteName);
|
||||||
this.additionalSuites = [];
|
if (!suite) {
|
||||||
this.pathsIgnore = [];
|
throw new Error(getQueryUsesInvalid(configFile, suiteName));
|
||||||
this.paths = [];
|
|
||||||
}
|
|
||||||
addQuery(configFile, queryUses) {
|
|
||||||
// The logic for parsing the string is based on what actions does for
|
|
||||||
// parsing the 'uses' actions in the workflow file
|
|
||||||
queryUses = queryUses.trim();
|
|
||||||
if (queryUses === "") {
|
|
||||||
throw new Error(getQueryUsesInvalid(configFile));
|
|
||||||
}
|
|
||||||
// Check for the local path case before we start trying to parse the repository name
|
|
||||||
if (queryUses.startsWith("./")) {
|
|
||||||
const localQueryPath = queryUses.slice(2);
|
|
||||||
// Resolve the local path against the workspace so that when this is
|
|
||||||
// passed to codeql it resolves to exactly the path we expect it to resolve to.
|
|
||||||
const workspacePath = fs.realpathSync(util.getRequiredEnvParam('GITHUB_WORKSPACE'));
|
|
||||||
let absoluteQueryPath = path.join(workspacePath, localQueryPath);
|
|
||||||
// Check the file exists
|
|
||||||
if (!fs.existsSync(absoluteQueryPath)) {
|
|
||||||
throw new Error(getLocalPathDoesNotExist(configFile, localQueryPath));
|
|
||||||
}
|
|
||||||
// Call this after checking file exists, because it'll fail if file doesn't exist
|
|
||||||
absoluteQueryPath = fs.realpathSync(absoluteQueryPath);
|
|
||||||
// Check the local path doesn't jump outside the repo using '..' or symlinks
|
|
||||||
if (!(absoluteQueryPath + path.sep).startsWith(workspacePath + path.sep)) {
|
|
||||||
throw new Error(getLocalPathOutsideOfRepository(configFile, localQueryPath));
|
|
||||||
}
|
|
||||||
this.additionalQueries.push(absoluteQueryPath);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Check for one of the builtin suites
|
|
||||||
if (queryUses.indexOf('/') === -1 && queryUses.indexOf('@') === -1) {
|
|
||||||
const suite = builtinSuites.find((suite) => suite === queryUses);
|
|
||||||
if (suite) {
|
|
||||||
this.additionalSuites.push(suite);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new Error(getQueryUsesInvalid(configFile, queryUses));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let tok = queryUses.split('@');
|
|
||||||
if (tok.length !== 2) {
|
|
||||||
throw new Error(getQueryUsesInvalid(configFile, queryUses));
|
|
||||||
}
|
|
||||||
const ref = tok[1];
|
|
||||||
tok = tok[0].split('/');
|
|
||||||
// The first token is the owner
|
|
||||||
// The second token is the repo
|
|
||||||
// The rest is a path, if there is more than one token combine them to form the full path
|
|
||||||
if (tok.length < 2) {
|
|
||||||
throw new Error(getQueryUsesInvalid(configFile, queryUses));
|
|
||||||
}
|
|
||||||
if (tok.length > 3) {
|
|
||||||
tok = [tok[0], tok[1], tok.slice(2).join('/')];
|
|
||||||
}
|
|
||||||
// Check none of the parts of the repository name are empty
|
|
||||||
if (tok[0].trim() === '' || tok[1].trim() === '') {
|
|
||||||
throw new Error(getQueryUsesInvalid(configFile, queryUses));
|
|
||||||
}
|
|
||||||
let external = new ExternalQuery(tok[0] + '/' + tok[1], ref);
|
|
||||||
if (tok.length === 3) {
|
|
||||||
external.path = tok[2];
|
|
||||||
}
|
|
||||||
this.externalQueries.push(external);
|
|
||||||
}
|
}
|
||||||
|
const suites = languages.map(l => l + '-' + suiteName + '.qls');
|
||||||
|
await runResolveQueries(resultMap, suites, undefined, false);
|
||||||
}
|
}
|
||||||
exports.Config = Config;
|
/**
|
||||||
|
* Retrieve the set of queries at localQueryPath and add them to resultMap.
|
||||||
|
*/
|
||||||
|
async function addLocalQueries(configFile, resultMap, localQueryPath) {
|
||||||
|
// Resolve the local path against the workspace so that when this is
|
||||||
|
// passed to codeql it resolves to exactly the path we expect it to resolve to.
|
||||||
|
const workspacePath = fs.realpathSync(util.getRequiredEnvParam('GITHUB_WORKSPACE'));
|
||||||
|
let absoluteQueryPath = path.join(workspacePath, localQueryPath);
|
||||||
|
// Check the file exists
|
||||||
|
if (!fs.existsSync(absoluteQueryPath)) {
|
||||||
|
throw new Error(getLocalPathDoesNotExist(configFile, localQueryPath));
|
||||||
|
}
|
||||||
|
// Call this after checking file exists, because it'll fail if file doesn't exist
|
||||||
|
absoluteQueryPath = fs.realpathSync(absoluteQueryPath);
|
||||||
|
// Check the local path doesn't jump outside the repo using '..' or symlinks
|
||||||
|
if (!(absoluteQueryPath + path.sep).startsWith(workspacePath + path.sep)) {
|
||||||
|
throw new Error(getLocalPathOutsideOfRepository(configFile, localQueryPath));
|
||||||
|
}
|
||||||
|
// Get the root of the current repo to use when resolving query dependencies
|
||||||
|
const rootOfRepo = util.getRequiredEnvParam('GITHUB_WORKSPACE');
|
||||||
|
await runResolveQueries(resultMap, [absoluteQueryPath], rootOfRepo, true);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Retrieve the set of queries at the referenced remote repo and add them to resultMap.
|
||||||
|
*/
|
||||||
|
async function addRemoteQueries(configFile, resultMap, queryUses) {
|
||||||
|
let tok = queryUses.split('@');
|
||||||
|
if (tok.length !== 2) {
|
||||||
|
throw new Error(getQueryUsesInvalid(configFile, queryUses));
|
||||||
|
}
|
||||||
|
const ref = tok[1];
|
||||||
|
tok = tok[0].split('/');
|
||||||
|
// The first token is the owner
|
||||||
|
// The second token is the repo
|
||||||
|
// The rest is a path, if there is more than one token combine them to form the full path
|
||||||
|
if (tok.length < 2) {
|
||||||
|
throw new Error(getQueryUsesInvalid(configFile, queryUses));
|
||||||
|
}
|
||||||
|
// Check none of the parts of the repository name are empty
|
||||||
|
if (tok[0].trim() === '' || tok[1].trim() === '') {
|
||||||
|
throw new Error(getQueryUsesInvalid(configFile, queryUses));
|
||||||
|
}
|
||||||
|
const nwo = tok[0] + '/' + tok[1];
|
||||||
|
// Checkout the external repository
|
||||||
|
const rootOfRepo = await externalQueries.checkoutExternalRepository(nwo, ref);
|
||||||
|
const queryPath = tok.length > 2
|
||||||
|
? path.join(rootOfRepo, tok.slice(2).join('/'))
|
||||||
|
: rootOfRepo;
|
||||||
|
await runResolveQueries(resultMap, [queryPath], rootOfRepo, true);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Parse a query 'uses' field to a discrete set of query files and update resultMap.
|
||||||
|
*
|
||||||
|
* The logic for parsing the string is based on what actions does for
|
||||||
|
* parsing the 'uses' actions in the workflow file. So it can handle
|
||||||
|
* local paths starting with './', or references to remote repos, or
|
||||||
|
* a finite set of hardcoded terms for builtin suites.
|
||||||
|
*/
|
||||||
|
async function parseQueryUses(configFile, languages, resultMap, queryUses) {
|
||||||
|
queryUses = queryUses.trim();
|
||||||
|
if (queryUses === "") {
|
||||||
|
throw new Error(getQueryUsesInvalid(configFile));
|
||||||
|
}
|
||||||
|
// Check for the local path case before we start trying to parse the repository name
|
||||||
|
if (queryUses.startsWith("./")) {
|
||||||
|
await addLocalQueries(configFile, resultMap, queryUses.slice(2));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Check for one of the builtin suites
|
||||||
|
if (queryUses.indexOf('/') === -1 && queryUses.indexOf('@') === -1) {
|
||||||
|
await addBuiltinSuiteQueries(configFile, languages, resultMap, queryUses);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Otherwise, must be a reference to another repo
|
||||||
|
await addRemoteQueries(configFile, resultMap, queryUses);
|
||||||
|
}
|
||||||
|
// Regex validating stars in paths or paths-ignore entries.
|
||||||
|
// The intention is to only allow ** to appear when immediately
|
||||||
|
// preceded and followed by a slash.
|
||||||
|
const pathStarsRegex = /.*(?:\*\*[^/].*|\*\*$|[^/]\*\*.*)/;
|
||||||
|
// Characters that are supported by filters in workflows, but not by us.
|
||||||
|
// See https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet
|
||||||
|
const filterPatternCharactersRegex = /.*[\?\+\[\]!].*/;
|
||||||
|
// Checks that a paths of paths-ignore entry is valid, possibly modifying it
|
||||||
|
// to make it valid, or if not possible then throws an error.
|
||||||
|
function validateAndSanitisePath(originalPath, propertyName, configFile) {
|
||||||
|
// Take a copy so we don't modify the original path, so we can still construct error messages
|
||||||
|
let path = originalPath;
|
||||||
|
// All paths are relative to the src root, so strip off leading slashes.
|
||||||
|
while (path.charAt(0) === '/') {
|
||||||
|
path = path.substring(1);
|
||||||
|
}
|
||||||
|
// Trailing ** are redundant, so strip them off
|
||||||
|
if (path.endsWith('/**')) {
|
||||||
|
path = path.substring(0, path.length - 2);
|
||||||
|
}
|
||||||
|
// An empty path is not allowed as it's meaningless
|
||||||
|
if (path === '') {
|
||||||
|
throw new Error(getConfigFilePropertyError(configFile, propertyName, '"' + originalPath + '" is not an invalid path. ' +
|
||||||
|
'It is not necessary to include it, and it is not allowed to exclude it.'));
|
||||||
|
}
|
||||||
|
// Check for illegal uses of **
|
||||||
|
if (path.match(pathStarsRegex)) {
|
||||||
|
throw new Error(getConfigFilePropertyError(configFile, propertyName, '"' + originalPath + '" contains an invalid "**" wildcard. ' +
|
||||||
|
'They must be immediately preceeded and followed by a slash as in "/**/", or come at the start or end.'));
|
||||||
|
}
|
||||||
|
// Check for other regex characters that we don't support.
|
||||||
|
// Output a warning so the user knows, but otherwise continue normally.
|
||||||
|
if (path.match(filterPatternCharactersRegex)) {
|
||||||
|
core.warning(getConfigFilePropertyError(configFile, propertyName, '"' + originalPath + '" contains an unsupported character. ' +
|
||||||
|
'The filter pattern characters ?, +, [, ], ! are not supported and will be matched literally.'));
|
||||||
|
}
|
||||||
|
// Ban any uses of backslash for now.
|
||||||
|
// This may not play nicely with project layouts.
|
||||||
|
// This restriction can be lifted later if we determine they are ok.
|
||||||
|
if (path.indexOf('\\') !== -1) {
|
||||||
|
throw new Error(getConfigFilePropertyError(configFile, propertyName, '"' + originalPath + '" contains an "\\" character. These are not allowed in filters. ' +
|
||||||
|
'If running on windows we recommend using "/" instead for path filters.'));
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
exports.validateAndSanitisePath = validateAndSanitisePath;
|
||||||
function getNameInvalid(configFile) {
|
function getNameInvalid(configFile) {
|
||||||
return getConfigFilePropertyError(configFile, NAME_PROPERTY, 'must be a non-empty string');
|
return getConfigFilePropertyError(configFile, NAME_PROPERTY, 'must be a non-empty string');
|
||||||
}
|
}
|
||||||
exports.getNameInvalid = getNameInvalid;
|
exports.getNameInvalid = getNameInvalid;
|
||||||
function getDisableDefaultQueriesInvalid(configFile) {
|
function getDisableDefaultQueriesInvalid(configFile) {
|
||||||
return getConfigFilePropertyError(configFile, DISPLAY_DEFAULT_QUERIES_PROPERTY, 'must be a boolean');
|
return getConfigFilePropertyError(configFile, DISABLE_DEFAULT_QUERIES_PROPERTY, 'must be a boolean');
|
||||||
}
|
}
|
||||||
exports.getDisableDefaultQueriesInvalid = getDisableDefaultQueriesInvalid;
|
exports.getDisableDefaultQueriesInvalid = getDisableDefaultQueriesInvalid;
|
||||||
function getQueriesInvalid(configFile) {
|
function getQueriesInvalid(configFile) {
|
||||||
@@ -146,29 +263,118 @@ function getConfigFileDoesNotExistErrorMessage(configFile) {
|
|||||||
return 'The configuration file "' + configFile + '" does not exist';
|
return 'The configuration file "' + configFile + '" does not exist';
|
||||||
}
|
}
|
||||||
exports.getConfigFileDoesNotExistErrorMessage = getConfigFileDoesNotExistErrorMessage;
|
exports.getConfigFileDoesNotExistErrorMessage = getConfigFileDoesNotExistErrorMessage;
|
||||||
|
function getConfigFileRepoFormatInvalidMessage(configFile) {
|
||||||
|
let error = 'The configuration file "' + configFile + '" is not a supported remote file reference.';
|
||||||
|
error += ' Expected format <owner>/<repository>/<file-path>@<ref>';
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
exports.getConfigFileRepoFormatInvalidMessage = getConfigFileRepoFormatInvalidMessage;
|
||||||
|
function getConfigFileFormatInvalidMessage(configFile) {
|
||||||
|
return 'The configuration file "' + configFile + '" could not be read';
|
||||||
|
}
|
||||||
|
exports.getConfigFileFormatInvalidMessage = getConfigFileFormatInvalidMessage;
|
||||||
|
function getConfigFileDirectoryGivenMessage(configFile) {
|
||||||
|
return 'The configuration file "' + configFile + '" looks like a directory, not a file';
|
||||||
|
}
|
||||||
|
exports.getConfigFileDirectoryGivenMessage = getConfigFileDirectoryGivenMessage;
|
||||||
function getConfigFilePropertyError(configFile, property, error) {
|
function getConfigFilePropertyError(configFile, property, error) {
|
||||||
return 'The configuration file "' + configFile + '" is invalid: property "' + property + '" ' + error;
|
return 'The configuration file "' + configFile + '" is invalid: property "' + property + '" ' + error;
|
||||||
}
|
}
|
||||||
function initConfig() {
|
/**
|
||||||
let configFile = core.getInput('config-file');
|
* Gets the set of languages in the current repository
|
||||||
const config = new Config();
|
*/
|
||||||
// If no config file was provided create an empty one
|
async function getLanguagesInRepo() {
|
||||||
if (configFile === '') {
|
var _a;
|
||||||
core.debug('No configuration file was provided');
|
// Translate between GitHub's API names for languages and ours
|
||||||
return config;
|
const codeqlLanguages = {
|
||||||
|
'C': 'cpp',
|
||||||
|
'C++': 'cpp',
|
||||||
|
'C#': 'csharp',
|
||||||
|
'Go': 'go',
|
||||||
|
'Java': 'java',
|
||||||
|
'JavaScript': 'javascript',
|
||||||
|
'TypeScript': 'javascript',
|
||||||
|
'Python': 'python',
|
||||||
|
};
|
||||||
|
let repo_nwo = (_a = process.env['GITHUB_REPOSITORY']) === null || _a === void 0 ? void 0 : _a.split("/");
|
||||||
|
if (repo_nwo) {
|
||||||
|
let owner = repo_nwo[0];
|
||||||
|
let repo = repo_nwo[1];
|
||||||
|
core.debug(`GitHub repo ${owner} ${repo}`);
|
||||||
|
const response = await api.getApiClient().request("GET /repos/:owner/:repo/languages", ({
|
||||||
|
owner,
|
||||||
|
repo
|
||||||
|
}));
|
||||||
|
core.debug("Languages API response: " + JSON.stringify(response));
|
||||||
|
// The GitHub API is going to return languages in order of popularity,
|
||||||
|
// When we pick a language to autobuild we want to pick the most popular traced language
|
||||||
|
// Since sets in javascript maintain insertion order, using a set here and then splatting it
|
||||||
|
// into an array gives us an array of languages ordered by popularity
|
||||||
|
let languages = new Set();
|
||||||
|
for (let lang in response.data) {
|
||||||
|
if (lang in codeqlLanguages) {
|
||||||
|
languages.add(codeqlLanguages[lang]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [...languages];
|
||||||
}
|
}
|
||||||
// Treat the config file as relative to the workspace
|
else {
|
||||||
const workspacePath = util.getRequiredEnvParam('GITHUB_WORKSPACE');
|
return [];
|
||||||
configFile = path.resolve(workspacePath, configFile);
|
|
||||||
// Error if the config file is now outside of the workspace
|
|
||||||
if (!(configFile + path.sep).startsWith(workspacePath + path.sep)) {
|
|
||||||
throw new Error(getConfigFileOutsideWorkspaceErrorMessage(configFile));
|
|
||||||
}
|
}
|
||||||
// Error if the file does not exist
|
}
|
||||||
if (!fs.existsSync(configFile)) {
|
/**
|
||||||
throw new Error(getConfigFileDoesNotExistErrorMessage(configFile));
|
* Get the languages to analyse.
|
||||||
|
*
|
||||||
|
* The result is obtained from the action input parameter 'languages' if that
|
||||||
|
* has been set, otherwise it is deduced as all languages in the repo that
|
||||||
|
* can be analysed.
|
||||||
|
*/
|
||||||
|
async function getLanguages() {
|
||||||
|
// Obtain from action input 'languages' if set
|
||||||
|
let languages = core.getInput('languages', { required: false })
|
||||||
|
.split(',')
|
||||||
|
.map(x => x.trim())
|
||||||
|
.filter(x => x.length > 0);
|
||||||
|
core.info("Languages from configuration: " + JSON.stringify(languages));
|
||||||
|
if (languages.length === 0) {
|
||||||
|
// Obtain languages as all languages in the repo that can be analysed
|
||||||
|
languages = await getLanguagesInRepo();
|
||||||
|
core.info("Automatically detected languages: " + JSON.stringify(languages));
|
||||||
}
|
}
|
||||||
const parsedYAML = yaml.safeLoad(fs.readFileSync(configFile, 'utf8'));
|
return languages;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get the default config for when the user has not supplied one.
|
||||||
|
*/
|
||||||
|
async function getDefaultConfig() {
|
||||||
|
const languages = await getLanguages();
|
||||||
|
const queries = {};
|
||||||
|
await addDefaultQueries(languages, queries);
|
||||||
|
return {
|
||||||
|
languages: languages,
|
||||||
|
queries: queries,
|
||||||
|
pathsIgnore: [],
|
||||||
|
paths: [],
|
||||||
|
originalUserInput: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
exports.getDefaultConfig = getDefaultConfig;
|
||||||
|
/**
|
||||||
|
* Load the config from the given file.
|
||||||
|
*/
|
||||||
|
async function loadConfig(configFile) {
|
||||||
|
let parsedYAML;
|
||||||
|
if (isLocal(configFile)) {
|
||||||
|
// Treat the config file as relative to the workspace
|
||||||
|
const workspacePath = util.getRequiredEnvParam('GITHUB_WORKSPACE');
|
||||||
|
configFile = path.resolve(workspacePath, configFile);
|
||||||
|
parsedYAML = getLocalConfig(configFile, workspacePath);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
parsedYAML = await getRemoteConfig(configFile);
|
||||||
|
}
|
||||||
|
// Validate that the 'name' property is syntactically correct,
|
||||||
|
// even though we don't use the value yet.
|
||||||
if (NAME_PROPERTY in parsedYAML) {
|
if (NAME_PROPERTY in parsedYAML) {
|
||||||
if (typeof parsedYAML[NAME_PROPERTY] !== "string") {
|
if (typeof parsedYAML[NAME_PROPERTY] !== "string") {
|
||||||
throw new Error(getNameInvalid(configFile));
|
throw new Error(getNameInvalid(configFile));
|
||||||
@@ -176,24 +382,36 @@ function initConfig() {
|
|||||||
if (parsedYAML[NAME_PROPERTY].length === 0) {
|
if (parsedYAML[NAME_PROPERTY].length === 0) {
|
||||||
throw new Error(getNameInvalid(configFile));
|
throw new Error(getNameInvalid(configFile));
|
||||||
}
|
}
|
||||||
config.name = parsedYAML[NAME_PROPERTY];
|
|
||||||
}
|
}
|
||||||
if (DISPLAY_DEFAULT_QUERIES_PROPERTY in parsedYAML) {
|
const languages = await getLanguages();
|
||||||
if (typeof parsedYAML[DISPLAY_DEFAULT_QUERIES_PROPERTY] !== "boolean") {
|
// If the languages parameter was not given and no languages were
|
||||||
|
// detected then fail here as this is a workflow configuration error.
|
||||||
|
if (languages.length === 0) {
|
||||||
|
throw new Error("Did not detect any languages to analyze. Please update input in workflow.");
|
||||||
|
}
|
||||||
|
const queries = {};
|
||||||
|
const pathsIgnore = [];
|
||||||
|
const paths = [];
|
||||||
|
let disableDefaultQueries = false;
|
||||||
|
if (DISABLE_DEFAULT_QUERIES_PROPERTY in parsedYAML) {
|
||||||
|
if (typeof parsedYAML[DISABLE_DEFAULT_QUERIES_PROPERTY] !== "boolean") {
|
||||||
throw new Error(getDisableDefaultQueriesInvalid(configFile));
|
throw new Error(getDisableDefaultQueriesInvalid(configFile));
|
||||||
}
|
}
|
||||||
config.disableDefaultQueries = parsedYAML[DISPLAY_DEFAULT_QUERIES_PROPERTY];
|
disableDefaultQueries = parsedYAML[DISABLE_DEFAULT_QUERIES_PROPERTY];
|
||||||
|
}
|
||||||
|
if (!disableDefaultQueries) {
|
||||||
|
await addDefaultQueries(languages, queries);
|
||||||
}
|
}
|
||||||
if (QUERIES_PROPERTY in parsedYAML) {
|
if (QUERIES_PROPERTY in parsedYAML) {
|
||||||
if (!(parsedYAML[QUERIES_PROPERTY] instanceof Array)) {
|
if (!(parsedYAML[QUERIES_PROPERTY] instanceof Array)) {
|
||||||
throw new Error(getQueriesInvalid(configFile));
|
throw new Error(getQueriesInvalid(configFile));
|
||||||
}
|
}
|
||||||
parsedYAML[QUERIES_PROPERTY].forEach(query => {
|
for (const query of parsedYAML[QUERIES_PROPERTY]) {
|
||||||
if (!(QUERIES_USES_PROPERTY in query) || typeof query[QUERIES_USES_PROPERTY] !== "string") {
|
if (!(QUERIES_USES_PROPERTY in query) || typeof query[QUERIES_USES_PROPERTY] !== "string") {
|
||||||
throw new Error(getQueryUsesInvalid(configFile));
|
throw new Error(getQueryUsesInvalid(configFile));
|
||||||
}
|
}
|
||||||
config.addQuery(configFile, query[QUERIES_USES_PROPERTY]);
|
await parseQueryUses(configFile, languages, queries, query[QUERIES_USES_PROPERTY]);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
if (PATHS_IGNORE_PROPERTY in parsedYAML) {
|
if (PATHS_IGNORE_PROPERTY in parsedYAML) {
|
||||||
if (!(parsedYAML[PATHS_IGNORE_PROPERTY] instanceof Array)) {
|
if (!(parsedYAML[PATHS_IGNORE_PROPERTY] instanceof Array)) {
|
||||||
@@ -203,7 +421,7 @@ function initConfig() {
|
|||||||
if (typeof path !== "string" || path === '') {
|
if (typeof path !== "string" || path === '') {
|
||||||
throw new Error(getPathsIgnoreInvalid(configFile));
|
throw new Error(getPathsIgnoreInvalid(configFile));
|
||||||
}
|
}
|
||||||
config.pathsIgnore.push(path);
|
pathsIgnore.push(validateAndSanitisePath(path, PATHS_IGNORE_PROPERTY, configFile));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (PATHS_PROPERTY in parsedYAML) {
|
if (PATHS_PROPERTY in parsedYAML) {
|
||||||
@@ -214,40 +432,123 @@ function initConfig() {
|
|||||||
if (typeof path !== "string" || path === '') {
|
if (typeof path !== "string" || path === '') {
|
||||||
throw new Error(getPathsInvalid(configFile));
|
throw new Error(getPathsInvalid(configFile));
|
||||||
}
|
}
|
||||||
config.paths.push(path);
|
paths.push(validateAndSanitisePath(path, PATHS_PROPERTY, configFile));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
|
languages,
|
||||||
|
queries,
|
||||||
|
pathsIgnore,
|
||||||
|
paths,
|
||||||
|
originalUserInput: parsedYAML
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Load and return the config.
|
||||||
|
*
|
||||||
|
* This will parse the config from the user input if present, or generate
|
||||||
|
* a default config. The parsed config is then stored to a known location.
|
||||||
|
*/
|
||||||
|
async function initConfig() {
|
||||||
|
const configFile = core.getInput('config-file');
|
||||||
|
let config;
|
||||||
|
// If no config file was provided create an empty one
|
||||||
|
if (configFile === '') {
|
||||||
|
core.debug('No configuration file was provided');
|
||||||
|
config = await getDefaultConfig();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
config = await loadConfig(configFile);
|
||||||
|
}
|
||||||
|
// Save the config so we can easily access it again in the future
|
||||||
|
await saveConfig(config);
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
function getConfigFolder() {
|
exports.initConfig = initConfig;
|
||||||
|
function isLocal(configPath) {
|
||||||
|
// If the path starts with ./, look locally
|
||||||
|
if (configPath.indexOf("./") === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return (configPath.indexOf("@") === -1);
|
||||||
|
}
|
||||||
|
function getLocalConfig(configFile, workspacePath) {
|
||||||
|
// Error if the config file is now outside of the workspace
|
||||||
|
if (!(configFile + path.sep).startsWith(workspacePath + path.sep)) {
|
||||||
|
throw new Error(getConfigFileOutsideWorkspaceErrorMessage(configFile));
|
||||||
|
}
|
||||||
|
// Error if the file does not exist
|
||||||
|
if (!fs.existsSync(configFile)) {
|
||||||
|
throw new Error(getConfigFileDoesNotExistErrorMessage(configFile));
|
||||||
|
}
|
||||||
|
return yaml.safeLoad(fs.readFileSync(configFile, 'utf8'));
|
||||||
|
}
|
||||||
|
async function getRemoteConfig(configFile) {
|
||||||
|
// retrieve the various parts of the config location, and ensure they're present
|
||||||
|
const format = new RegExp('(?<owner>[^/]+)/(?<repo>[^/]+)/(?<path>[^@]+)@(?<ref>.*)');
|
||||||
|
const pieces = format.exec(configFile);
|
||||||
|
// 5 = 4 groups + the whole expression
|
||||||
|
if (pieces === null || pieces.groups === undefined || pieces.length < 5) {
|
||||||
|
throw new Error(getConfigFileRepoFormatInvalidMessage(configFile));
|
||||||
|
}
|
||||||
|
const response = await api.getApiClient().repos.getContents({
|
||||||
|
owner: pieces.groups.owner,
|
||||||
|
repo: pieces.groups.repo,
|
||||||
|
path: pieces.groups.path,
|
||||||
|
ref: pieces.groups.ref,
|
||||||
|
});
|
||||||
|
let fileContents;
|
||||||
|
if ("content" in response.data && response.data.content !== undefined) {
|
||||||
|
fileContents = response.data.content;
|
||||||
|
}
|
||||||
|
else if (Array.isArray(response.data)) {
|
||||||
|
throw new Error(getConfigFileDirectoryGivenMessage(configFile));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error(getConfigFileFormatInvalidMessage(configFile));
|
||||||
|
}
|
||||||
|
return yaml.safeLoad(Buffer.from(fileContents, 'base64').toString('binary'));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Get the directory where the parsed config will be stored.
|
||||||
|
*/
|
||||||
|
function getPathToParsedConfigFolder() {
|
||||||
return util.getRequiredEnvParam('RUNNER_TEMP');
|
return util.getRequiredEnvParam('RUNNER_TEMP');
|
||||||
}
|
}
|
||||||
function getConfigFile() {
|
/**
|
||||||
return path.join(getConfigFolder(), 'config');
|
* Get the file path where the parsed config will be stored.
|
||||||
|
*/
|
||||||
|
function getPathToParsedConfigFile() {
|
||||||
|
return path.join(getPathToParsedConfigFolder(), 'config');
|
||||||
}
|
}
|
||||||
exports.getConfigFile = getConfigFile;
|
exports.getPathToParsedConfigFile = getPathToParsedConfigFile;
|
||||||
|
/**
|
||||||
|
* Store the given config to the path returned from getPathToParsedConfigFile.
|
||||||
|
*/
|
||||||
async function saveConfig(config) {
|
async function saveConfig(config) {
|
||||||
const configString = JSON.stringify(config);
|
const configString = JSON.stringify(config);
|
||||||
await io.mkdirP(getConfigFolder());
|
await io.mkdirP(getPathToParsedConfigFolder());
|
||||||
fs.writeFileSync(getConfigFile(), configString, 'utf8');
|
fs.writeFileSync(getPathToParsedConfigFile(), configString, 'utf8');
|
||||||
core.debug('Saved config:');
|
core.debug('Saved config:');
|
||||||
core.debug(configString);
|
core.debug(configString);
|
||||||
}
|
}
|
||||||
async function loadConfig() {
|
/**
|
||||||
const configFile = getConfigFile();
|
* Get the config.
|
||||||
if (fs.existsSync(configFile)) {
|
*
|
||||||
const configString = fs.readFileSync(configFile, 'utf8');
|
* If this is the first time in a workflow that this is being called then
|
||||||
core.debug('Loaded config:');
|
* this will parse the config from the user input. The parsed config is then
|
||||||
core.debug(configString);
|
* stored to a known location. On the second and further calls, this will
|
||||||
return JSON.parse(configString);
|
* return the contents of the parsed config from the known location.
|
||||||
}
|
*/
|
||||||
else {
|
async function getConfig() {
|
||||||
const config = initConfig();
|
const configFile = getPathToParsedConfigFile();
|
||||||
core.debug('Initialized config:');
|
if (!fs.existsSync(configFile)) {
|
||||||
core.debug(JSON.stringify(config));
|
throw new Error("Config file could not be found at expected location. Has the 'init' action been called?");
|
||||||
await saveConfig(config);
|
|
||||||
return config;
|
|
||||||
}
|
}
|
||||||
|
const configString = fs.readFileSync(configFile, 'utf8');
|
||||||
|
core.debug('Loaded config:');
|
||||||
|
core.debug(configString);
|
||||||
|
return JSON.parse(configString);
|
||||||
}
|
}
|
||||||
exports.loadConfig = loadConfig;
|
exports.getConfig = getConfig;
|
||||||
//# sourceMappingURL=config-utils.js.map
|
//# sourceMappingURL=config-utils.js.map
|
||||||
File diff suppressed because one or more lines are too long
Generated
+263
-33
@@ -1,7 +1,4 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
||||||
};
|
|
||||||
var __importStar = (this && this.__importStar) || function (mod) {
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
if (mod && mod.__esModule) return mod;
|
if (mod && mod.__esModule) return mod;
|
||||||
var result = {};
|
var result = {};
|
||||||
@@ -9,14 +6,21 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
result["default"] = mod;
|
result["default"] = mod;
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
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 });
|
||||||
|
const github = __importStar(require("@actions/github"));
|
||||||
const ava_1 = __importDefault(require("ava"));
|
const ava_1 = __importDefault(require("ava"));
|
||||||
const fs = __importStar(require("fs"));
|
const fs = __importStar(require("fs"));
|
||||||
const path = __importStar(require("path"));
|
const path = __importStar(require("path"));
|
||||||
|
const sinon_1 = __importDefault(require("sinon"));
|
||||||
|
const api = __importStar(require("./api-client"));
|
||||||
|
const CodeQL = __importStar(require("./codeql"));
|
||||||
const configUtils = __importStar(require("./config-utils"));
|
const configUtils = __importStar(require("./config-utils"));
|
||||||
const testing_utils_1 = require("./testing-utils");
|
const testing_utils_1 = require("./testing-utils");
|
||||||
const util = __importStar(require("./util"));
|
const util = __importStar(require("./util"));
|
||||||
testing_utils_1.silenceDebugOutput(ava_1.default);
|
testing_utils_1.setupTests(ava_1.default);
|
||||||
function setInput(name, value) {
|
function setInput(name, value) {
|
||||||
// Transformation copied from
|
// Transformation copied from
|
||||||
// https://github.com/actions/toolkit/blob/05e39f551d33e1688f61b209ab5cdd335198f1b8/packages/core/src/core.ts#L69
|
// https://github.com/actions/toolkit/blob/05e39f551d33e1688f61b209ab5cdd335198f1b8/packages/core/src/core.ts#L69
|
||||||
@@ -28,27 +32,60 @@ function setInput(name, value) {
|
|||||||
delete process.env[envVar];
|
delete process.env[envVar];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function mockGetContents(content) {
|
||||||
|
// Passing an auth token is required, so we just use a dummy value
|
||||||
|
let client = new github.GitHub('123');
|
||||||
|
const response = {
|
||||||
|
data: content
|
||||||
|
};
|
||||||
|
const spyGetContents = sinon_1.default.stub(client.repos, "getContents").resolves(response);
|
||||||
|
sinon_1.default.stub(api, "getApiClient").value(() => client);
|
||||||
|
return spyGetContents;
|
||||||
|
}
|
||||||
ava_1.default("load empty config", async (t) => {
|
ava_1.default("load empty config", async (t) => {
|
||||||
return await util.withTmpDir(async (tmpDir) => {
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
process.env['RUNNER_TEMP'] = tmpDir;
|
process.env['RUNNER_TEMP'] = tmpDir;
|
||||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||||
setInput('config-file', undefined);
|
setInput('config-file', undefined);
|
||||||
const config = await configUtils.loadConfig();
|
setInput('languages', 'javascript,python');
|
||||||
t.deepEqual(config, new configUtils.Config());
|
CodeQL.setCodeQL({
|
||||||
|
resolveQueries: async function () {
|
||||||
|
return {
|
||||||
|
byLanguage: {},
|
||||||
|
noDeclaredLanguage: {},
|
||||||
|
multipleDeclaredLanguages: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const config = await configUtils.initConfig();
|
||||||
|
t.deepEqual(config, await configUtils.getDefaultConfig());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ava_1.default("loading config saves config", async (t) => {
|
ava_1.default("loading config saves config", async (t) => {
|
||||||
return await util.withTmpDir(async (tmpDir) => {
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
process.env['RUNNER_TEMP'] = tmpDir;
|
process.env['RUNNER_TEMP'] = tmpDir;
|
||||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||||
const configFile = configUtils.getConfigFile();
|
setInput('config-file', undefined);
|
||||||
|
setInput('languages', 'javascript,python');
|
||||||
|
CodeQL.setCodeQL({
|
||||||
|
resolveQueries: async function () {
|
||||||
|
return {
|
||||||
|
byLanguage: {},
|
||||||
|
noDeclaredLanguage: {},
|
||||||
|
multipleDeclaredLanguages: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
// Sanity check the saved config file does not already exist
|
// Sanity check the saved config file does not already exist
|
||||||
t.false(fs.existsSync(configFile));
|
t.false(fs.existsSync(configUtils.getPathToParsedConfigFile()));
|
||||||
const config = await configUtils.loadConfig();
|
// Sanity check that getConfig throws before we have called initConfig
|
||||||
|
await t.throwsAsync(configUtils.getConfig);
|
||||||
|
const config1 = await configUtils.initConfig();
|
||||||
// The saved config file should now exist
|
// The saved config file should now exist
|
||||||
t.true(fs.existsSync(configFile));
|
t.true(fs.existsSync(configUtils.getPathToParsedConfigFile()));
|
||||||
// And the contents should parse correctly to the config that was returned
|
// And that same newly-initialised config should now be returned by getConfig
|
||||||
t.deepEqual(fs.readFileSync(configFile, 'utf8'), JSON.stringify(config));
|
const config2 = await configUtils.getConfig();
|
||||||
|
t.deepEqual(config1, config2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ava_1.default("load input outside of workspace", async (t) => {
|
ava_1.default("load input outside of workspace", async (t) => {
|
||||||
@@ -57,23 +94,39 @@ ava_1.default("load input outside of workspace", async (t) => {
|
|||||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||||
setInput('config-file', '../input');
|
setInput('config-file', '../input');
|
||||||
try {
|
try {
|
||||||
await configUtils.loadConfig();
|
await configUtils.initConfig();
|
||||||
throw new Error('loadConfig did not throw error');
|
throw new Error('initConfig did not throw error');
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
t.deepEqual(err, new Error(configUtils.getConfigFileOutsideWorkspaceErrorMessage(path.join(tmpDir, '../input'))));
|
t.deepEqual(err, new Error(configUtils.getConfigFileOutsideWorkspaceErrorMessage(path.join(tmpDir, '../input'))));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
ava_1.default("load non-local input with invalid repo syntax", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
process.env['RUNNER_TEMP'] = tmpDir;
|
||||||
|
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||||
|
// no filename given, just a repo
|
||||||
|
setInput('config-file', 'octo-org/codeql-config@main');
|
||||||
|
try {
|
||||||
|
await configUtils.initConfig();
|
||||||
|
throw new Error('initConfig did not throw error');
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
t.deepEqual(err, new Error(configUtils.getConfigFileRepoFormatInvalidMessage('octo-org/codeql-config@main')));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
ava_1.default("load non-existent input", async (t) => {
|
ava_1.default("load non-existent input", async (t) => {
|
||||||
return await util.withTmpDir(async (tmpDir) => {
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
process.env['RUNNER_TEMP'] = tmpDir;
|
process.env['RUNNER_TEMP'] = tmpDir;
|
||||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||||
t.false(fs.existsSync(path.join(tmpDir, 'input')));
|
t.false(fs.existsSync(path.join(tmpDir, 'input')));
|
||||||
setInput('config-file', 'input');
|
setInput('config-file', 'input');
|
||||||
|
setInput('languages', 'javascript');
|
||||||
try {
|
try {
|
||||||
await configUtils.loadConfig();
|
await configUtils.initConfig();
|
||||||
throw new Error('loadConfig did not throw error');
|
throw new Error('initConfig did not throw error');
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
t.deepEqual(err, new Error(configUtils.getConfigFileDoesNotExistErrorMessage(path.join(tmpDir, 'input'))));
|
t.deepEqual(err, new Error(configUtils.getConfigFileDoesNotExistErrorMessage(path.join(tmpDir, 'input'))));
|
||||||
@@ -84,10 +137,109 @@ ava_1.default("load non-empty input", async (t) => {
|
|||||||
return await util.withTmpDir(async (tmpDir) => {
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
process.env['RUNNER_TEMP'] = tmpDir;
|
process.env['RUNNER_TEMP'] = tmpDir;
|
||||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||||
|
CodeQL.setCodeQL({
|
||||||
|
resolveQueries: async function () {
|
||||||
|
return {
|
||||||
|
byLanguage: {
|
||||||
|
'javascript': {
|
||||||
|
'/foo/a.ql': {},
|
||||||
|
'/bar/b.ql': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
noDeclaredLanguage: {},
|
||||||
|
multipleDeclaredLanguages: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
// Just create a generic config object with non-default values for all fields
|
// Just create a generic config object with non-default values for all fields
|
||||||
const inputFileContents = `
|
const inputFileContents = `
|
||||||
name: my config
|
name: my config
|
||||||
disable-default-queries: true
|
disable-default-queries: true
|
||||||
|
queries:
|
||||||
|
- uses: ./foo
|
||||||
|
paths-ignore:
|
||||||
|
- a
|
||||||
|
- b
|
||||||
|
paths:
|
||||||
|
- c/d`;
|
||||||
|
fs.mkdirSync(path.join(tmpDir, 'foo'));
|
||||||
|
// And the config we expect it to parse to
|
||||||
|
const expectedConfig = {
|
||||||
|
languages: ['javascript'],
|
||||||
|
queries: { 'javascript': ['/foo/a.ql', '/bar/b.ql'] },
|
||||||
|
pathsIgnore: ['a', 'b'],
|
||||||
|
paths: ['c/d'],
|
||||||
|
originalUserInput: {
|
||||||
|
name: 'my config',
|
||||||
|
'disable-default-queries': true,
|
||||||
|
queries: [{ uses: './foo' }],
|
||||||
|
'paths-ignore': ['a', 'b'],
|
||||||
|
paths: ['c/d'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
|
||||||
|
setInput('config-file', 'input');
|
||||||
|
setInput('languages', 'javascript');
|
||||||
|
const actualConfig = await configUtils.initConfig();
|
||||||
|
// Should exactly equal the object we constructed earlier
|
||||||
|
t.deepEqual(actualConfig, expectedConfig);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
ava_1.default("default queries are used", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
process.env['RUNNER_TEMP'] = tmpDir;
|
||||||
|
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||||
|
// Check that the default behaviour is to add the default queries.
|
||||||
|
// In this case if a config file is specified but does not include
|
||||||
|
// the disable-default-queries field.
|
||||||
|
// We determine this by whether CodeQL.resolveQueries is called
|
||||||
|
// with the correct arguments.
|
||||||
|
const resolveQueriesArgs = [];
|
||||||
|
CodeQL.setCodeQL({
|
||||||
|
resolveQueries: async function (queries, extraSearchPath) {
|
||||||
|
resolveQueriesArgs.push({ queries, extraSearchPath });
|
||||||
|
return {
|
||||||
|
byLanguage: {
|
||||||
|
'javascript': {},
|
||||||
|
},
|
||||||
|
noDeclaredLanguage: {},
|
||||||
|
multipleDeclaredLanguages: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// The important point of this config is that it doesn't specify
|
||||||
|
// the disable-default-queries field.
|
||||||
|
// Any other details are hopefully irrelevant for this tetst.
|
||||||
|
const inputFileContents = `
|
||||||
|
paths:
|
||||||
|
- foo`;
|
||||||
|
fs.mkdirSync(path.join(tmpDir, 'foo'));
|
||||||
|
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
|
||||||
|
setInput('config-file', 'input');
|
||||||
|
setInput('languages', 'javascript');
|
||||||
|
await configUtils.initConfig();
|
||||||
|
// Check resolve queries was called correctly
|
||||||
|
t.deepEqual(resolveQueriesArgs.length, 1);
|
||||||
|
t.deepEqual(resolveQueriesArgs[0].queries, ['javascript-code-scanning.qls']);
|
||||||
|
t.deepEqual(resolveQueriesArgs[0].extraSearchPath, undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
ava_1.default("API client used when reading remote config", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
process.env['RUNNER_TEMP'] = tmpDir;
|
||||||
|
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||||
|
CodeQL.setCodeQL({
|
||||||
|
resolveQueries: async function () {
|
||||||
|
return {
|
||||||
|
byLanguage: {},
|
||||||
|
noDeclaredLanguage: {},
|
||||||
|
multipleDeclaredLanguages: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const inputFileContents = `
|
||||||
|
name: my config
|
||||||
|
disable-default-queries: true
|
||||||
queries:
|
queries:
|
||||||
- uses: ./
|
- uses: ./
|
||||||
- uses: ./foo
|
- uses: ./foo
|
||||||
@@ -97,21 +249,52 @@ ava_1.default("load non-empty input", async (t) => {
|
|||||||
- b
|
- b
|
||||||
paths:
|
paths:
|
||||||
- c/d`;
|
- c/d`;
|
||||||
fs.mkdirSync(path.join(tmpDir, 'foo'));
|
const dummyResponse = {
|
||||||
// And the config we expect it to parse to
|
content: Buffer.from(inputFileContents).toString("base64"),
|
||||||
const expectedConfig = new configUtils.Config();
|
};
|
||||||
expectedConfig.name = 'my config';
|
const spyGetContents = mockGetContents(dummyResponse);
|
||||||
expectedConfig.disableDefaultQueries = true;
|
// Create checkout directory for remote queries repository
|
||||||
expectedConfig.additionalQueries.push(fs.realpathSync(tmpDir));
|
fs.mkdirSync(path.join(tmpDir, 'foo/bar'), { recursive: true });
|
||||||
expectedConfig.additionalQueries.push(fs.realpathSync(path.join(tmpDir, 'foo')));
|
setInput('config-file', 'octo-org/codeql-config/config.yaml@main');
|
||||||
expectedConfig.externalQueries = [new configUtils.ExternalQuery('foo/bar', 'dev')];
|
setInput('languages', 'javascript');
|
||||||
expectedConfig.pathsIgnore = ['a', 'b'];
|
await configUtils.initConfig();
|
||||||
expectedConfig.paths = ['c/d'];
|
t.assert(spyGetContents.called);
|
||||||
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
|
});
|
||||||
setInput('config-file', 'input');
|
});
|
||||||
const actualConfig = await configUtils.loadConfig();
|
ava_1.default("Remote config handles the case where a directory is provided", async (t) => {
|
||||||
// Should exactly equal the object we constructed earlier
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
t.deepEqual(actualConfig, expectedConfig);
|
process.env['RUNNER_TEMP'] = tmpDir;
|
||||||
|
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||||
|
const dummyResponse = []; // directories are returned as arrays
|
||||||
|
mockGetContents(dummyResponse);
|
||||||
|
const repoReference = 'octo-org/codeql-config/config.yaml@main';
|
||||||
|
setInput('config-file', repoReference);
|
||||||
|
try {
|
||||||
|
await configUtils.initConfig();
|
||||||
|
throw new Error('initConfig did not throw error');
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
t.deepEqual(err, new Error(configUtils.getConfigFileDirectoryGivenMessage(repoReference)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
ava_1.default("Invalid format of remote config handled correctly", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
process.env['RUNNER_TEMP'] = tmpDir;
|
||||||
|
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||||
|
const dummyResponse = {
|
||||||
|
// note no "content" property here
|
||||||
|
};
|
||||||
|
mockGetContents(dummyResponse);
|
||||||
|
const repoReference = 'octo-org/codeql-config/config.yaml@main';
|
||||||
|
setInput('config-file', repoReference);
|
||||||
|
try {
|
||||||
|
await configUtils.initConfig();
|
||||||
|
throw new Error('initConfig did not throw error');
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
t.deepEqual(err, new Error(configUtils.getConfigFileFormatInvalidMessage(repoReference)));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
function doInvalidInputTest(testName, inputFileContents, expectedErrorMessageGenerator) {
|
function doInvalidInputTest(testName, inputFileContents, expectedErrorMessageGenerator) {
|
||||||
@@ -119,12 +302,22 @@ function doInvalidInputTest(testName, inputFileContents, expectedErrorMessageGen
|
|||||||
return await util.withTmpDir(async (tmpDir) => {
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
process.env['RUNNER_TEMP'] = tmpDir;
|
process.env['RUNNER_TEMP'] = tmpDir;
|
||||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||||
|
CodeQL.setCodeQL({
|
||||||
|
resolveQueries: async function () {
|
||||||
|
return {
|
||||||
|
byLanguage: {},
|
||||||
|
noDeclaredLanguage: {},
|
||||||
|
multipleDeclaredLanguages: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
const inputFile = path.join(tmpDir, 'input');
|
const inputFile = path.join(tmpDir, 'input');
|
||||||
fs.writeFileSync(inputFile, inputFileContents, 'utf8');
|
fs.writeFileSync(inputFile, inputFileContents, 'utf8');
|
||||||
setInput('config-file', 'input');
|
setInput('config-file', 'input');
|
||||||
|
setInput('languages', 'javascript');
|
||||||
try {
|
try {
|
||||||
await configUtils.loadConfig();
|
await configUtils.initConfig();
|
||||||
throw new Error('loadConfig did not throw error');
|
throw new Error('initConfig did not throw error');
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
t.deepEqual(err, new Error(expectedErrorMessageGenerator(inputFile)));
|
t.deepEqual(err, new Error(expectedErrorMessageGenerator(inputFile)));
|
||||||
@@ -161,4 +354,41 @@ doInvalidQueryUsesTest("foo@master", c => configUtils.getQueryUsesInvalid(c, "fo
|
|||||||
doInvalidQueryUsesTest("https://github.com/foo/bar@master", c => configUtils.getQueryUsesInvalid(c, "https://github.com/foo/bar@master"));
|
doInvalidQueryUsesTest("https://github.com/foo/bar@master", c => configUtils.getQueryUsesInvalid(c, "https://github.com/foo/bar@master"));
|
||||||
doInvalidQueryUsesTest("./foo", c => configUtils.getLocalPathDoesNotExist(c, "foo"));
|
doInvalidQueryUsesTest("./foo", c => configUtils.getLocalPathDoesNotExist(c, "foo"));
|
||||||
doInvalidQueryUsesTest("./..", c => configUtils.getLocalPathOutsideOfRepository(c, ".."));
|
doInvalidQueryUsesTest("./..", c => configUtils.getLocalPathOutsideOfRepository(c, ".."));
|
||||||
|
const validPaths = [
|
||||||
|
'foo',
|
||||||
|
'foo/',
|
||||||
|
'foo/**',
|
||||||
|
'foo/**/',
|
||||||
|
'foo/**/**',
|
||||||
|
'foo/**/bar/**/baz',
|
||||||
|
'**/',
|
||||||
|
'**/foo',
|
||||||
|
'/foo',
|
||||||
|
];
|
||||||
|
const invalidPaths = [
|
||||||
|
'a/***/b',
|
||||||
|
'a/**b',
|
||||||
|
'a/b**',
|
||||||
|
'**',
|
||||||
|
];
|
||||||
|
ava_1.default('path validations', t => {
|
||||||
|
// Dummy values to pass to validateAndSanitisePath
|
||||||
|
const propertyName = 'paths';
|
||||||
|
const configFile = './.github/codeql/config.yml';
|
||||||
|
for (const path of validPaths) {
|
||||||
|
t.truthy(configUtils.validateAndSanitisePath(path, propertyName, configFile));
|
||||||
|
}
|
||||||
|
for (const path of invalidPaths) {
|
||||||
|
t.throws(() => configUtils.validateAndSanitisePath(path, propertyName, configFile));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ava_1.default('path sanitisation', t => {
|
||||||
|
// Dummy values to pass to validateAndSanitisePath
|
||||||
|
const propertyName = 'paths';
|
||||||
|
const configFile = './.github/codeql/config.yml';
|
||||||
|
// Valid paths are not modified
|
||||||
|
t.deepEqual(configUtils.validateAndSanitisePath('foo/bar', propertyName, configFile), 'foo/bar');
|
||||||
|
// Trailing stars are stripped
|
||||||
|
t.deepEqual(configUtils.validateAndSanitisePath('foo/**', propertyName, configFile), 'foo/');
|
||||||
|
});
|
||||||
//# sourceMappingURL=config-utils.test.js.map
|
//# sourceMappingURL=config-utils.test.js.map
|
||||||
File diff suppressed because one or more lines are too long
Generated
+16
-15
@@ -12,22 +12,23 @@ const exec = __importStar(require("@actions/exec"));
|
|||||||
const fs = __importStar(require("fs"));
|
const fs = __importStar(require("fs"));
|
||||||
const path = __importStar(require("path"));
|
const path = __importStar(require("path"));
|
||||||
const util = __importStar(require("./util"));
|
const util = __importStar(require("./util"));
|
||||||
async function checkoutExternalQueries(config) {
|
/**
|
||||||
|
* Check out repository at the given ref, and return the directory of the checkout.
|
||||||
|
*/
|
||||||
|
async function checkoutExternalRepository(repository, ref) {
|
||||||
const folder = util.getRequiredEnvParam('RUNNER_TEMP');
|
const folder = util.getRequiredEnvParam('RUNNER_TEMP');
|
||||||
for (const externalQuery of config.externalQueries) {
|
core.info('Checking out ' + repository);
|
||||||
core.info('Checking out ' + externalQuery.repository);
|
const checkoutLocation = path.join(folder, repository);
|
||||||
const checkoutLocation = path.join(folder, externalQuery.repository);
|
if (!fs.existsSync(checkoutLocation)) {
|
||||||
if (!fs.existsSync(checkoutLocation)) {
|
const repoURL = 'https://github.com/' + repository + '.git';
|
||||||
const repoURL = 'https://github.com/' + externalQuery.repository + '.git';
|
await exec.exec('git', ['clone', repoURL, checkoutLocation]);
|
||||||
await exec.exec('git', ['clone', repoURL, checkoutLocation]);
|
await exec.exec('git', [
|
||||||
await exec.exec('git', [
|
'--work-tree=' + checkoutLocation,
|
||||||
'--work-tree=' + checkoutLocation,
|
'--git-dir=' + checkoutLocation + '/.git',
|
||||||
'--git-dir=' + checkoutLocation + '/.git',
|
'checkout', ref,
|
||||||
'checkout', externalQuery.ref,
|
]);
|
||||||
]);
|
|
||||||
}
|
|
||||||
config.additionalQueries.push(path.join(checkoutLocation, externalQuery.path));
|
|
||||||
}
|
}
|
||||||
|
return checkoutLocation;
|
||||||
}
|
}
|
||||||
exports.checkoutExternalQueries = checkoutExternalQueries;
|
exports.checkoutExternalRepository = checkoutExternalRepository;
|
||||||
//# sourceMappingURL=external-queries.js.map
|
//# sourceMappingURL=external-queries.js.map
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"external-queries.js","sourceRoot":"","sources":["../src/external-queries.ts"],"names":[],"mappings":";;;;;;;;;AAAA,oDAAsC;AACtC,oDAAsC;AACtC,uCAAyB;AACzB,2CAA6B;AAG7B,6CAA+B;AAExB,KAAK,UAAU,uBAAuB,CAAC,MAA0B;IACtE,MAAM,MAAM,GAAG,IAAI,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAC;IAEvD,KAAK,MAAM,aAAa,IAAI,MAAM,CAAC,eAAe,EAAE;QAClD,IAAI,CAAC,IAAI,CAAC,eAAe,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;QAEtD,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;QACrE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE;YACpC,MAAM,OAAO,GAAG,qBAAqB,GAAG,aAAa,CAAC,UAAU,GAAG,MAAM,CAAC;YAC1E,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC;YAC7D,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;gBACrB,cAAc,GAAG,gBAAgB;gBACjC,YAAY,GAAG,gBAAgB,GAAG,OAAO;gBACzC,UAAU,EAAE,aAAa,CAAC,GAAG;aAC9B,CAAC,CAAC;SACJ;QAED,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;KAChF;AACH,CAAC;AAnBD,0DAmBC"}
|
{"version":3,"file":"external-queries.js","sourceRoot":"","sources":["../src/external-queries.ts"],"names":[],"mappings":";;;;;;;;;AAAA,oDAAsC;AACtC,oDAAsC;AACtC,uCAAyB;AACzB,2CAA6B;AAE7B,6CAA+B;AAE/B;;GAEG;AACI,KAAK,UAAU,0BAA0B,CAAC,UAAkB,EAAE,GAAW;IAC9E,MAAM,MAAM,GAAG,IAAI,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAC;IAEvD,IAAI,CAAC,IAAI,CAAC,eAAe,GAAG,UAAU,CAAC,CAAC;IAExC,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACvD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE;QACpC,MAAM,OAAO,GAAG,qBAAqB,GAAG,UAAU,GAAG,MAAM,CAAC;QAC5D,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC;QAC7D,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;YACrB,cAAc,GAAG,gBAAgB;YACjC,YAAY,GAAG,gBAAgB,GAAG,OAAO;YACzC,UAAU,EAAE,GAAG;SAChB,CAAC,CAAC;KACJ;IAED,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAjBD,gEAiBC"}
|
||||||
Generated
+3
-8
@@ -13,20 +13,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||||||
const ava_1 = __importDefault(require("ava"));
|
const ava_1 = __importDefault(require("ava"));
|
||||||
const fs = __importStar(require("fs"));
|
const fs = __importStar(require("fs"));
|
||||||
const path = __importStar(require("path"));
|
const path = __importStar(require("path"));
|
||||||
const configUtils = __importStar(require("./config-utils"));
|
|
||||||
const externalQueries = __importStar(require("./external-queries"));
|
const externalQueries = __importStar(require("./external-queries"));
|
||||||
const testing_utils_1 = require("./testing-utils");
|
const testing_utils_1 = require("./testing-utils");
|
||||||
const util = __importStar(require("./util"));
|
const util = __importStar(require("./util"));
|
||||||
testing_utils_1.silenceDebugOutput(ava_1.default);
|
testing_utils_1.setupTests(ava_1.default);
|
||||||
ava_1.default("checkoutExternalQueries", async (t) => {
|
ava_1.default("checkoutExternalQueries", async (t) => {
|
||||||
let config = new configUtils.Config();
|
|
||||||
config.externalQueries = [
|
|
||||||
new configUtils.ExternalQuery("github/codeql-go", "df4c6869212341b601005567381944ed90906b6b"),
|
|
||||||
];
|
|
||||||
await util.withTmpDir(async (tmpDir) => {
|
await util.withTmpDir(async (tmpDir) => {
|
||||||
process.env["RUNNER_TEMP"] = tmpDir;
|
process.env["RUNNER_TEMP"] = tmpDir;
|
||||||
await externalQueries.checkoutExternalQueries(config);
|
await externalQueries.checkoutExternalRepository("github/codeql-go", "df4c6869212341b601005567381944ed90906b6b");
|
||||||
// COPYRIGHT file existed in df4c6869212341b601005567381944ed90906b6b but not in master
|
// COPYRIGHT file existed in df4c6869212341b601005567381944ed90906b6b but not in the default branch
|
||||||
t.true(fs.existsSync(path.join(tmpDir, "github", "codeql-go", "COPYRIGHT")));
|
t.true(fs.existsSync(path.join(tmpDir, "github", "codeql-go", "COPYRIGHT")));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"external-queries.test.js","sourceRoot":"","sources":["../src/external-queries.test.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,8CAAuB;AACvB,uCAAyB;AACzB,2CAA6B;AAE7B,4DAA8C;AAC9C,oEAAsD;AACtD,mDAAmD;AACnD,6CAA+B;AAE/B,kCAAkB,CAAC,aAAI,CAAC,CAAC;AAEzB,aAAI,CAAC,yBAAyB,EAAE,KAAK,EAAC,CAAC,EAAC,EAAE;IACxC,IAAI,MAAM,GAAG,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;IACtC,MAAM,CAAC,eAAe,GAAG;QACvB,IAAI,WAAW,CAAC,aAAa,CAAC,kBAAkB,EAAE,0CAA0C,CAAC;KAC9F,CAAC;IAEF,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,EAAC,MAAM,EAAC,EAAE;QACnC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,MAAM,CAAC;QACpC,MAAM,eAAe,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC;QAEtD,uFAAuF;QACvF,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IAC/E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
{"version":3,"file":"external-queries.test.js","sourceRoot":"","sources":["../src/external-queries.test.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,8CAAuB;AACvB,uCAAyB;AACzB,2CAA6B;AAE7B,oEAAsD;AACtD,mDAA2C;AAC3C,6CAA+B;AAE/B,0BAAU,CAAC,aAAI,CAAC,CAAC;AAEjB,aAAI,CAAC,yBAAyB,EAAE,KAAK,EAAC,CAAC,EAAC,EAAE;IACxC,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,EAAC,MAAM,EAAC,EAAE;QACnC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,MAAM,CAAC;QACpC,MAAM,eAAe,CAAC,0BAA0B,CAAC,kBAAkB,EAAE,0CAA0C,CAAC,CAAC;QAEjH,mGAAmG;QACnG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IAC/E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
||||||
Generated
+55
-136
@@ -8,185 +8,104 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const core = __importStar(require("@actions/core"));
|
const core = __importStar(require("@actions/core"));
|
||||||
const exec = __importStar(require("@actions/exec"));
|
|
||||||
const io = __importStar(require("@actions/io"));
|
const io = __importStar(require("@actions/io"));
|
||||||
const fs = __importStar(require("fs"));
|
const fs = __importStar(require("fs"));
|
||||||
const path = __importStar(require("path"));
|
const path = __importStar(require("path"));
|
||||||
|
const codeql_1 = require("./codeql");
|
||||||
const configUtils = __importStar(require("./config-utils"));
|
const configUtils = __importStar(require("./config-utils"));
|
||||||
const externalQueries = __importStar(require("./external-queries"));
|
|
||||||
const sharedEnv = __importStar(require("./shared-environment"));
|
const sharedEnv = __importStar(require("./shared-environment"));
|
||||||
const upload_lib = __importStar(require("./upload-lib"));
|
const upload_lib = __importStar(require("./upload-lib"));
|
||||||
const util = __importStar(require("./util"));
|
const util = __importStar(require("./util"));
|
||||||
/**
|
async function sendStatusReport(startedAt, queriesStats, uploadStats, error) {
|
||||||
* A list of queries from https://github.com/github/codeql that
|
var _a, _b, _c;
|
||||||
* we don't want to run. Disabling them here is a quicker alternative to
|
const status = ((_a = queriesStats) === null || _a === void 0 ? void 0 : _a.analyze_failure_language) !== undefined || error !== undefined ? 'failure' : 'success';
|
||||||
* disabling them in the code scanning query suites. Queries should also
|
const statusReportBase = await util.createStatusReportBase('finish', status, startedAt, (_b = error) === null || _b === void 0 ? void 0 : _b.message, (_c = error) === null || _c === void 0 ? void 0 : _c.stack);
|
||||||
* be disabled in the suites, and removed from this list here once the
|
const statusReport = {
|
||||||
* bundle is updated to make those suite changes live.
|
...statusReportBase,
|
||||||
*
|
...(queriesStats || {}),
|
||||||
* Format is a map from language to an array of path suffixes of .ql files.
|
...(uploadStats || {}),
|
||||||
*/
|
};
|
||||||
const DISABLED_BUILTIN_QUERIES = {
|
await util.sendStatusReport(statusReport);
|
||||||
'csharp': [
|
|
||||||
'ql/src/Security Features/CWE-937/VulnerablePackage.ql',
|
|
||||||
'ql/src/Security Features/CWE-451/MissingXFrameOptions.ql',
|
|
||||||
]
|
|
||||||
};
|
|
||||||
function queryIsDisabled(language, query) {
|
|
||||||
return (DISABLED_BUILTIN_QUERIES[language] || [])
|
|
||||||
.some(disabledQuery => query.endsWith(disabledQuery));
|
|
||||||
}
|
}
|
||||||
async function createdDBForScannedLanguages(codeqlCmd, databaseFolder) {
|
async function createdDBForScannedLanguages(databaseFolder) {
|
||||||
const scannedLanguages = process.env[sharedEnv.CODEQL_ACTION_SCANNED_LANGUAGES];
|
const scannedLanguages = process.env[sharedEnv.CODEQL_ACTION_SCANNED_LANGUAGES];
|
||||||
if (scannedLanguages) {
|
if (scannedLanguages) {
|
||||||
|
const codeql = codeql_1.getCodeQL();
|
||||||
for (const language of scannedLanguages.split(',')) {
|
for (const language of scannedLanguages.split(',')) {
|
||||||
core.startGroup('Extracting ' + language);
|
core.startGroup('Extracting ' + language);
|
||||||
// Get extractor location
|
await codeql.extractScannedLanguage(path.join(databaseFolder, language), language);
|
||||||
let extractorPath = '';
|
|
||||||
await exec.exec(codeqlCmd, ['resolve', 'extractor', '--format=json', '--language=' + language], {
|
|
||||||
silent: true,
|
|
||||||
listeners: {
|
|
||||||
stdout: (data) => { extractorPath += data.toString(); },
|
|
||||||
stderr: (data) => { process.stderr.write(data); }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Set trace command
|
|
||||||
const ext = process.platform === 'win32' ? '.cmd' : '.sh';
|
|
||||||
const traceCommand = path.resolve(JSON.parse(extractorPath), 'tools', 'autobuild' + ext);
|
|
||||||
// Run trace command
|
|
||||||
await exec.exec(codeqlCmd, ['database', 'trace-command', path.join(databaseFolder, language), '--', traceCommand]);
|
|
||||||
core.endGroup();
|
core.endGroup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function finalizeDatabaseCreation(codeqlCmd, databaseFolder) {
|
async function finalizeDatabaseCreation(databaseFolder, config) {
|
||||||
await createdDBForScannedLanguages(codeqlCmd, databaseFolder);
|
await createdDBForScannedLanguages(databaseFolder);
|
||||||
const languages = process.env[sharedEnv.CODEQL_ACTION_LANGUAGES] || '';
|
const codeql = codeql_1.getCodeQL();
|
||||||
for (const language of languages.split(',')) {
|
for (const language of config.languages) {
|
||||||
core.startGroup('Finalizing ' + language);
|
core.startGroup('Finalizing ' + language);
|
||||||
await exec.exec(codeqlCmd, ['database', 'finalize', path.join(databaseFolder, language)]);
|
await codeql.finalizeDatabase(path.join(databaseFolder, language));
|
||||||
core.endGroup();
|
core.endGroup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function runResolveQueries(codeqlCmd, queries) {
|
|
||||||
let output = '';
|
|
||||||
const options = {
|
|
||||||
listeners: {
|
|
||||||
stdout: (data) => {
|
|
||||||
output += data.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
await exec.exec(codeqlCmd, [
|
|
||||||
'resolve',
|
|
||||||
'queries',
|
|
||||||
...queries,
|
|
||||||
'--format=bylanguage'
|
|
||||||
], options);
|
|
||||||
return JSON.parse(output);
|
|
||||||
}
|
|
||||||
async function resolveQueryLanguages(codeqlCmd, config) {
|
|
||||||
let res = new Map();
|
|
||||||
if (!config.disableDefaultQueries || config.additionalSuites.length !== 0) {
|
|
||||||
const suites = [];
|
|
||||||
for (const language of await util.getLanguages()) {
|
|
||||||
if (!config.disableDefaultQueries) {
|
|
||||||
suites.push(language + '-code-scanning.qls');
|
|
||||||
}
|
|
||||||
for (const additionalSuite of config.additionalSuites) {
|
|
||||||
suites.push(language + '-' + additionalSuite + '.qls');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const resolveQueriesOutputObject = await runResolveQueries(codeqlCmd, suites);
|
|
||||||
for (const [language, queries] of Object.entries(resolveQueriesOutputObject.byLanguage)) {
|
|
||||||
if (res[language] === undefined) {
|
|
||||||
res[language] = [];
|
|
||||||
}
|
|
||||||
res[language].push(...Object.keys(queries).filter(q => !queryIsDisabled(language, q)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (config.additionalQueries.length !== 0) {
|
|
||||||
const resolveQueriesOutputObject = await runResolveQueries(codeqlCmd, config.additionalQueries);
|
|
||||||
for (const [language, queries] of Object.entries(resolveQueriesOutputObject.byLanguage)) {
|
|
||||||
if (res[language] === undefined) {
|
|
||||||
res[language] = [];
|
|
||||||
}
|
|
||||||
res[language].push(...Object.keys(queries));
|
|
||||||
}
|
|
||||||
const noDeclaredLanguage = resolveQueriesOutputObject.noDeclaredLanguage;
|
|
||||||
const noDeclaredLanguageQueries = Object.keys(noDeclaredLanguage);
|
|
||||||
if (noDeclaredLanguageQueries.length !== 0) {
|
|
||||||
throw new Error('Some queries do not declare a language, their qlpack.yml file is missing or is invalid');
|
|
||||||
}
|
|
||||||
const multipleDeclaredLanguages = resolveQueriesOutputObject.multipleDeclaredLanguages;
|
|
||||||
const multipleDeclaredLanguagesQueries = Object.keys(multipleDeclaredLanguages);
|
|
||||||
if (multipleDeclaredLanguagesQueries.length !== 0) {
|
|
||||||
throw new Error('Some queries declare multiple languages, their qlpack.yml file is missing or is invalid');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
// Runs queries and creates sarif files in the given folder
|
// Runs queries and creates sarif files in the given folder
|
||||||
async function runQueries(codeqlCmd, databaseFolder, sarifFolder, config) {
|
async function runQueries(databaseFolder, sarifFolder, config) {
|
||||||
const queriesPerLanguage = await resolveQueryLanguages(codeqlCmd, config);
|
const codeql = codeql_1.getCodeQL();
|
||||||
for (let database of fs.readdirSync(databaseFolder)) {
|
for (let language of fs.readdirSync(databaseFolder)) {
|
||||||
core.startGroup('Analyzing ' + database);
|
core.startGroup('Analyzing ' + language);
|
||||||
const queries = queriesPerLanguage[database] || [];
|
const queries = config.queries[language] || [];
|
||||||
if (queries.length === 0) {
|
if (queries.length === 0) {
|
||||||
throw new Error('Unable to analyse ' + database + ' as no queries were selected for this language');
|
throw new Error('Unable to analyse ' + language + ' as no queries were selected for this language');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// Pass the queries to codeql using a file instead of using the command
|
||||||
|
// line to avoid command line length restrictions, particularly on windows.
|
||||||
|
const querySuite = path.join(databaseFolder, language + '-queries.qls');
|
||||||
|
const querySuiteContents = queries.map(q => '- query: ' + q).join('\n');
|
||||||
|
fs.writeFileSync(querySuite, querySuiteContents);
|
||||||
|
core.debug('Query suite file for ' + language + '...\n' + querySuiteContents);
|
||||||
|
const sarifFile = path.join(sarifFolder, language + '.sarif');
|
||||||
|
await codeql.databaseAnalyze(path.join(databaseFolder, language), sarifFile, querySuite);
|
||||||
|
core.debug('SARIF results for database ' + language + ' created at "' + sarifFile + '"');
|
||||||
|
core.endGroup();
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
// For now the fields about query performance are not populated
|
||||||
|
return {
|
||||||
|
analyze_failure_language: language,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
// Pass the queries to codeql using a file instead of using the command
|
|
||||||
// line to avoid command line length restrictions, particularly on windows.
|
|
||||||
const querySuite = path.join(databaseFolder, database + '-queries.qls');
|
|
||||||
const querySuiteContents = queries.map(q => '- query: ' + q).join('\n');
|
|
||||||
fs.writeFileSync(querySuite, querySuiteContents);
|
|
||||||
core.debug('Query suite file for ' + database + '...\n' + querySuiteContents);
|
|
||||||
const sarifFile = path.join(sarifFolder, database + '.sarif');
|
|
||||||
await exec.exec(codeqlCmd, [
|
|
||||||
'database',
|
|
||||||
'analyze',
|
|
||||||
util.getMemoryFlag(),
|
|
||||||
util.getThreadsFlag(),
|
|
||||||
path.join(databaseFolder, database),
|
|
||||||
'--format=sarif-latest',
|
|
||||||
'--output=' + sarifFile,
|
|
||||||
'--no-sarif-add-snippets',
|
|
||||||
querySuite
|
|
||||||
]);
|
|
||||||
core.debug('SARIF results for database ' + database + ' created at "' + sarifFile + '"');
|
|
||||||
core.endGroup();
|
|
||||||
}
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
async function run() {
|
async function run() {
|
||||||
|
const startedAt = new Date();
|
||||||
|
let queriesStats = undefined;
|
||||||
|
let uploadStats = undefined;
|
||||||
try {
|
try {
|
||||||
if (util.should_abort('finish', true) || !await util.reportActionStarting('finish')) {
|
if (util.should_abort('finish', true) ||
|
||||||
|
!await util.sendStatusReport(await util.createStatusReportBase('finish', 'starting', startedAt), true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const config = await configUtils.loadConfig();
|
const config = await configUtils.getConfig();
|
||||||
core.exportVariable(sharedEnv.ODASA_TRACER_CONFIGURATION, '');
|
core.exportVariable(sharedEnv.ODASA_TRACER_CONFIGURATION, '');
|
||||||
delete process.env[sharedEnv.ODASA_TRACER_CONFIGURATION];
|
delete process.env[sharedEnv.ODASA_TRACER_CONFIGURATION];
|
||||||
const codeqlCmd = util.getRequiredEnvParam(sharedEnv.CODEQL_ACTION_CMD);
|
|
||||||
const databaseFolder = util.getRequiredEnvParam(sharedEnv.CODEQL_ACTION_DATABASE_DIR);
|
const databaseFolder = util.getRequiredEnvParam(sharedEnv.CODEQL_ACTION_DATABASE_DIR);
|
||||||
const sarifFolder = core.getInput('output');
|
const sarifFolder = core.getInput('output');
|
||||||
await io.mkdirP(sarifFolder);
|
await io.mkdirP(sarifFolder);
|
||||||
core.info('Finalizing database creation');
|
core.info('Finalizing database creation');
|
||||||
await finalizeDatabaseCreation(codeqlCmd, databaseFolder);
|
await finalizeDatabaseCreation(databaseFolder, config);
|
||||||
await externalQueries.checkoutExternalQueries(config);
|
|
||||||
core.info('Analyzing database');
|
core.info('Analyzing database');
|
||||||
await runQueries(codeqlCmd, databaseFolder, sarifFolder, config);
|
queriesStats = await runQueries(databaseFolder, sarifFolder, config);
|
||||||
if ('true' === core.getInput('upload')) {
|
if ('true' === core.getInput('upload')) {
|
||||||
if (!await upload_lib.upload(sarifFolder)) {
|
uploadStats = await upload_lib.upload(sarifFolder);
|
||||||
await util.reportActionFailed('finish', 'upload');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
await util.reportActionFailed('finish', error.message, error.stack);
|
await sendStatusReport(startedAt, queriesStats, uploadStats, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await util.reportActionSucceeded('finish');
|
await sendStatusReport(startedAt, queriesStats, uploadStats);
|
||||||
}
|
}
|
||||||
run().catch(e => {
|
run().catch(e => {
|
||||||
core.setFailed("analyze action failed: " + e);
|
core.setFailed("analyze action failed: " + e);
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Generated
+12
-13
@@ -146,10 +146,10 @@ function locationUpdateCallback(result, location) {
|
|||||||
result.partialFingerprints.primaryLocationLineHash = hash;
|
result.partialFingerprints.primaryLocationLineHash = hash;
|
||||||
}
|
}
|
||||||
else if (existingFingerprint !== hash) {
|
else if (existingFingerprint !== hash) {
|
||||||
core.warning("Calculated fingerprint of " + hash +
|
core.warning('Calculated fingerprint of ' + hash +
|
||||||
" for file " + location.physicalLocation.artifactLocation.uri +
|
' for file ' + location.physicalLocation.artifactLocation.uri +
|
||||||
" line " + lineNumber +
|
' line ' + lineNumber +
|
||||||
", but found existing inconsistent fingerprint value " + existingFingerprint);
|
', but found existing inconsistent fingerprint value ' + existingFingerprint);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -164,14 +164,14 @@ function resolveUriToFile(location, artifacts) {
|
|||||||
location.index < 0 ||
|
location.index < 0 ||
|
||||||
location.index >= artifacts.length ||
|
location.index >= artifacts.length ||
|
||||||
typeof artifacts[location.index].location !== 'object') {
|
typeof artifacts[location.index].location !== 'object') {
|
||||||
core.debug('Ignoring location as index "' + location.index + '" is invalid');
|
core.debug(`Ignoring location as URI "${location.index}" is invalid`);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
location = artifacts[location.index].location;
|
location = artifacts[location.index].location;
|
||||||
}
|
}
|
||||||
// Get the URI and decode
|
// Get the URI and decode
|
||||||
if (typeof location.uri !== 'string') {
|
if (typeof location.uri !== 'string') {
|
||||||
core.debug('Ignoring location as uri "' + location.uri + '" is invalid');
|
core.debug(`Ignoring location as index "${location.uri}" is invalid`);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
let uri = decodeURIComponent(location.uri);
|
let uri = decodeURIComponent(location.uri);
|
||||||
@@ -181,13 +181,13 @@ function resolveUriToFile(location, artifacts) {
|
|||||||
uri = uri.substring(fileUriPrefix.length);
|
uri = uri.substring(fileUriPrefix.length);
|
||||||
}
|
}
|
||||||
if (uri.indexOf('://') !== -1) {
|
if (uri.indexOf('://') !== -1) {
|
||||||
core.debug('Ignoring location URI "' + uri + "' as the scheme is not recognised");
|
core.debug(`Ignoring location URI "${uri}" as the scheme is not recognised`);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
// Discard any absolute paths that aren't in the src root
|
// Discard any absolute paths that aren't in the src root
|
||||||
const srcRootPrefix = process.env['GITHUB_WORKSPACE'] + '/';
|
const srcRootPrefix = process.env['GITHUB_WORKSPACE'] + '/';
|
||||||
if (uri.startsWith('/') && !uri.startsWith(srcRootPrefix)) {
|
if (uri.startsWith('/') && !uri.startsWith(srcRootPrefix)) {
|
||||||
core.debug('Ignoring location URI "' + uri + "' as it is outside of the src root");
|
core.debug(`Ignoring location URI "${uri}" as it is outside of the src root`);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
// Just assume a relative path is relative to the src root.
|
// Just assume a relative path is relative to the src root.
|
||||||
@@ -198,7 +198,7 @@ function resolveUriToFile(location, artifacts) {
|
|||||||
}
|
}
|
||||||
// Check the file exists
|
// Check the file exists
|
||||||
if (!fs.existsSync(uri)) {
|
if (!fs.existsSync(uri)) {
|
||||||
core.debug("Unable to compute fingerprint for non-existent file: " + uri);
|
core.debug(`Unable to compute fingerprint for non-existent file: ${uri}`);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return uri;
|
return uri;
|
||||||
@@ -207,6 +207,7 @@ exports.resolveUriToFile = resolveUriToFile;
|
|||||||
// Compute fingerprints for results in the given sarif file
|
// Compute fingerprints for results in the given sarif file
|
||||||
// and return an updated sarif file contents.
|
// and return an updated sarif file contents.
|
||||||
function addFingerprints(sarifContents) {
|
function addFingerprints(sarifContents) {
|
||||||
|
var _a, _b;
|
||||||
let sarif = JSON.parse(sarifContents);
|
let sarif = JSON.parse(sarifContents);
|
||||||
// Gather together results for the same file and construct
|
// Gather together results for the same file and construct
|
||||||
// callbacks to accept hashes for that file and update the location
|
// callbacks to accept hashes for that file and update the location
|
||||||
@@ -217,10 +218,8 @@ function addFingerprints(sarifContents) {
|
|||||||
for (const result of run.results || []) {
|
for (const result of run.results || []) {
|
||||||
// Check the primary location is defined correctly and is in the src root
|
// Check the primary location is defined correctly and is in the src root
|
||||||
const primaryLocation = (result.locations || [])[0];
|
const primaryLocation = (result.locations || [])[0];
|
||||||
if (!primaryLocation ||
|
if (!((_b = (_a = primaryLocation) === null || _a === void 0 ? void 0 : _a.physicalLocation) === null || _b === void 0 ? void 0 : _b.artifactLocation)) {
|
||||||
!primaryLocation.physicalLocation ||
|
core.debug(`Unable to compute fingerprint for invalid location: ${JSON.stringify(primaryLocation)}`);
|
||||||
!primaryLocation.physicalLocation.artifactLocation) {
|
|
||||||
core.debug("Unable to compute fingerprint for invalid location: " + JSON.stringify(primaryLocation));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const filepath = resolveUriToFile(primaryLocation.physicalLocation.artifactLocation, artifacts);
|
const filepath = resolveUriToFile(primaryLocation.physicalLocation.artifactLocation, artifacts);
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Generated
+1
-1
@@ -15,7 +15,7 @@ const fs = __importStar(require("fs"));
|
|||||||
const path = __importStar(require("path"));
|
const path = __importStar(require("path"));
|
||||||
const fingerprints = __importStar(require("./fingerprints"));
|
const fingerprints = __importStar(require("./fingerprints"));
|
||||||
const testing_utils_1 = require("./testing-utils");
|
const testing_utils_1 = require("./testing-utils");
|
||||||
testing_utils_1.silenceDebugOutput(ava_1.default);
|
testing_utils_1.setupTests(ava_1.default);
|
||||||
function testHash(t, input, expectedHashes) {
|
function testHash(t, input, expectedHashes) {
|
||||||
let index = 0;
|
let index = 0;
|
||||||
let callback = function (lineNumber, hash) {
|
let callback = function (lineNumber, hash) {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Generated
+41
-37
@@ -13,8 +13,8 @@ const io = __importStar(require("@actions/io"));
|
|||||||
const fs = __importStar(require("fs"));
|
const fs = __importStar(require("fs"));
|
||||||
const path = __importStar(require("path"));
|
const path = __importStar(require("path"));
|
||||||
const analysisPaths = __importStar(require("./analysis-paths"));
|
const analysisPaths = __importStar(require("./analysis-paths"));
|
||||||
|
const codeql_1 = require("./codeql");
|
||||||
const configUtils = __importStar(require("./config-utils"));
|
const configUtils = __importStar(require("./config-utils"));
|
||||||
const setuptools = __importStar(require("./setup-tools"));
|
|
||||||
const sharedEnv = __importStar(require("./shared-environment"));
|
const sharedEnv = __importStar(require("./shared-environment"));
|
||||||
const util = __importStar(require("./util"));
|
const util = __importStar(require("./util"));
|
||||||
const CRITICAL_TRACER_VARS = new Set(['SEMMLE_PRELOAD_libtrace',
|
const CRITICAL_TRACER_VARS = new Set(['SEMMLE_PRELOAD_libtrace',
|
||||||
@@ -28,12 +28,7 @@ const CRITICAL_TRACER_VARS = new Set(['SEMMLE_PRELOAD_libtrace',
|
|||||||
'SEMMLE_JAVA_TOOL_OPTIONS'
|
'SEMMLE_JAVA_TOOL_OPTIONS'
|
||||||
]);
|
]);
|
||||||
async function tracerConfig(codeql, database, compilerSpec) {
|
async function tracerConfig(codeql, database, compilerSpec) {
|
||||||
const compilerSpecArg = compilerSpec ? ["--compiler-spec=" + compilerSpec] : [];
|
const env = await codeql.getTracerEnv(database, compilerSpec);
|
||||||
let envFile = path.resolve(database, 'working', 'env.tmp');
|
|
||||||
await exec.exec(codeql.cmd, ['database', 'trace-command', database,
|
|
||||||
...compilerSpecArg,
|
|
||||||
process.execPath, path.resolve(__dirname, 'tracer-env.js'), envFile]);
|
|
||||||
const env = JSON.parse(fs.readFileSync(envFile, 'utf-8'));
|
|
||||||
const config = env['ODASA_TRACER_CONFIGURATION'];
|
const config = env['ODASA_TRACER_CONFIGURATION'];
|
||||||
const info = { spec: config, env: {} };
|
const info = { spec: config, env: {} };
|
||||||
// Extract critical tracer variables from the environment
|
// Extract critical tracer variables from the environment
|
||||||
@@ -126,34 +121,50 @@ function concatTracerConfigs(configs) {
|
|||||||
fs.writeFileSync(envPath, buffer);
|
fs.writeFileSync(envPath, buffer);
|
||||||
return { env, spec };
|
return { env, spec };
|
||||||
}
|
}
|
||||||
|
async function sendSuccessStatusReport(startedAt, config) {
|
||||||
|
const statusReportBase = await util.createStatusReportBase('init', 'success', startedAt);
|
||||||
|
const languages = config.languages.join(',');
|
||||||
|
const workflowLanguages = core.getInput('languages', { required: false });
|
||||||
|
const paths = (config.originalUserInput.paths || []).join(',');
|
||||||
|
const pathsIgnore = (config.originalUserInput['paths-ignore'] || []).join(',');
|
||||||
|
const disableDefaultQueries = config.originalUserInput['disable-default-queries'] ? languages : '';
|
||||||
|
const queries = (config.originalUserInput.queries || []).map(q => q.uses).join(',');
|
||||||
|
const statusReport = {
|
||||||
|
...statusReportBase,
|
||||||
|
languages: languages,
|
||||||
|
workflow_languages: workflowLanguages,
|
||||||
|
paths: paths,
|
||||||
|
paths_ignore: pathsIgnore,
|
||||||
|
disable_default_queries: disableDefaultQueries,
|
||||||
|
queries: queries,
|
||||||
|
};
|
||||||
|
await util.sendStatusReport(statusReport);
|
||||||
|
}
|
||||||
async function run() {
|
async function run() {
|
||||||
let languages;
|
const startedAt = new Date();
|
||||||
|
let config;
|
||||||
|
let codeql;
|
||||||
try {
|
try {
|
||||||
if (util.should_abort('init', false) || !await util.reportActionStarting('init')) {
|
if (util.should_abort('init', false) ||
|
||||||
|
!await util.sendStatusReport(await util.createStatusReportBase('init', 'starting', startedAt), true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
core.startGroup('Setup CodeQL tools');
|
||||||
|
codeql = await codeql_1.setupCodeQL();
|
||||||
|
await codeql.printVersion();
|
||||||
|
core.endGroup();
|
||||||
core.startGroup('Load language configuration');
|
core.startGroup('Load language configuration');
|
||||||
const config = await configUtils.loadConfig();
|
config = await configUtils.initConfig();
|
||||||
languages = await util.getLanguages();
|
analysisPaths.includeAndExcludeAnalysisPaths(config);
|
||||||
// If the languages parameter was not given and no languages were
|
|
||||||
// detected then fail here as this is a workflow configuration error.
|
|
||||||
if (languages.length === 0) {
|
|
||||||
throw new Error("Did not detect any languages to analyze. Please update input in workflow.");
|
|
||||||
}
|
|
||||||
analysisPaths.includeAndExcludeAnalysisPaths(config, languages);
|
|
||||||
core.endGroup();
|
core.endGroup();
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
core.setFailed(e.message);
|
core.setFailed(e.message);
|
||||||
await util.reportActionAborted('init', e.message);
|
await util.sendStatusReport(await util.createStatusReportBase('init', 'aborted', startedAt, e.message));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const sourceRoot = path.resolve();
|
const sourceRoot = path.resolve();
|
||||||
core.startGroup('Setup CodeQL tools');
|
|
||||||
const codeqlSetup = await setuptools.setupCodeQL();
|
|
||||||
await exec.exec(codeqlSetup.cmd, ['version', '--format=json']);
|
|
||||||
core.endGroup();
|
|
||||||
// Forward Go flags
|
// Forward Go flags
|
||||||
const goFlags = process.env['GOFLAGS'];
|
const goFlags = process.env['GOFLAGS'];
|
||||||
if (goFlags) {
|
if (goFlags) {
|
||||||
@@ -168,19 +179,13 @@ async function run() {
|
|||||||
let tracedLanguages = {};
|
let tracedLanguages = {};
|
||||||
let scannedLanguages = [];
|
let scannedLanguages = [];
|
||||||
// TODO: replace this code once CodeQL supports multi-language tracing
|
// TODO: replace this code once CodeQL supports multi-language tracing
|
||||||
for (let language of languages) {
|
for (let language of config.languages) {
|
||||||
const languageDatabase = path.join(databaseFolder, language);
|
const languageDatabase = path.join(databaseFolder, language);
|
||||||
// Init language database
|
// Init language database
|
||||||
await exec.exec(codeqlSetup.cmd, [
|
await codeql.databaseInit(languageDatabase, language, sourceRoot);
|
||||||
'database',
|
|
||||||
'init',
|
|
||||||
languageDatabase,
|
|
||||||
'--language=' + language,
|
|
||||||
'--source-root=' + sourceRoot,
|
|
||||||
]);
|
|
||||||
// TODO: add better detection of 'traced languages' instead of using a hard coded list
|
// TODO: add better detection of 'traced languages' instead of using a hard coded list
|
||||||
if (['cpp', 'java', 'csharp'].includes(language)) {
|
if (['cpp', 'java', 'csharp'].includes(language)) {
|
||||||
const config = await tracerConfig(codeqlSetup, languageDatabase);
|
const config = await tracerConfig(codeql, languageDatabase);
|
||||||
tracedLanguages[language] = config;
|
tracedLanguages[language] = config;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -196,16 +201,16 @@ async function run() {
|
|||||||
}
|
}
|
||||||
core.exportVariable('ODASA_TRACER_CONFIGURATION', mainTracerConfig.spec);
|
core.exportVariable('ODASA_TRACER_CONFIGURATION', mainTracerConfig.spec);
|
||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
core.exportVariable('DYLD_INSERT_LIBRARIES', path.join(codeqlSetup.tools, 'osx64', 'libtrace.dylib'));
|
core.exportVariable('DYLD_INSERT_LIBRARIES', path.join(codeql.getDir(), 'tools', 'osx64', 'libtrace.dylib'));
|
||||||
}
|
}
|
||||||
else if (process.platform === 'win32') {
|
else if (process.platform === 'win32') {
|
||||||
await exec.exec('powershell', [
|
await exec.exec('powershell', [
|
||||||
path.resolve(__dirname, '..', 'src', 'inject-tracer.ps1'),
|
path.resolve(__dirname, '..', 'src', 'inject-tracer.ps1'),
|
||||||
path.resolve(codeqlSetup.tools, 'win64', 'tracer.exe'),
|
path.resolve(codeql.getDir(), 'tools', 'win64', 'tracer.exe'),
|
||||||
], { env: { 'ODASA_TRACER_CONFIGURATION': mainTracerConfig.spec } });
|
], { env: { 'ODASA_TRACER_CONFIGURATION': mainTracerConfig.spec } });
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
core.exportVariable('LD_PRELOAD', path.join(codeqlSetup.tools, 'linux64', '${LIB}trace.so'));
|
core.exportVariable('LD_PRELOAD', path.join(codeql.getDir(), 'tools', 'linux64', '${LIB}trace.so'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,14 +218,13 @@ async function run() {
|
|||||||
core.exportVariable(sharedEnv.CODEQL_ACTION_TRACED_LANGUAGES, tracedLanguageKeys.join(','));
|
core.exportVariable(sharedEnv.CODEQL_ACTION_TRACED_LANGUAGES, tracedLanguageKeys.join(','));
|
||||||
// TODO: make this a "private" environment variable of the action
|
// TODO: make this a "private" environment variable of the action
|
||||||
core.exportVariable(sharedEnv.CODEQL_ACTION_DATABASE_DIR, databaseFolder);
|
core.exportVariable(sharedEnv.CODEQL_ACTION_DATABASE_DIR, databaseFolder);
|
||||||
core.exportVariable(sharedEnv.CODEQL_ACTION_CMD, codeqlSetup.cmd);
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
await util.reportActionFailed('init', error.message, error.stack);
|
await util.sendStatusReport(await util.createStatusReportBase('init', 'failure', startedAt, error.message, error.stack));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await util.reportActionSucceeded('init');
|
await sendSuccessStatusReport(startedAt, config);
|
||||||
core.exportVariable(sharedEnv.CODEQL_ACTION_INIT_COMPLETED, 'true');
|
core.exportVariable(sharedEnv.CODEQL_ACTION_INIT_COMPLETED, 'true');
|
||||||
}
|
}
|
||||||
run().catch(e => {
|
run().catch(e => {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Generated
+1
-3
@@ -1,8 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.CODEQL_ACTION_CMD = 'CODEQL_ACTION_CMD';
|
|
||||||
exports.CODEQL_ACTION_DATABASE_DIR = 'CODEQL_ACTION_DATABASE_DIR';
|
exports.CODEQL_ACTION_DATABASE_DIR = 'CODEQL_ACTION_DATABASE_DIR';
|
||||||
exports.CODEQL_ACTION_LANGUAGES = 'CODEQL_ACTION_LANGUAGES';
|
|
||||||
exports.CODEQL_ACTION_ANALYSIS_KEY = 'CODEQL_ACTION_ANALYSIS_KEY';
|
exports.CODEQL_ACTION_ANALYSIS_KEY = 'CODEQL_ACTION_ANALYSIS_KEY';
|
||||||
exports.ODASA_TRACER_CONFIGURATION = 'ODASA_TRACER_CONFIGURATION';
|
exports.ODASA_TRACER_CONFIGURATION = 'ODASA_TRACER_CONFIGURATION';
|
||||||
exports.CODEQL_ACTION_SCANNED_LANGUAGES = 'CODEQL_ACTION_SCANNED_LANGUAGES';
|
exports.CODEQL_ACTION_SCANNED_LANGUAGES = 'CODEQL_ACTION_SCANNED_LANGUAGES';
|
||||||
@@ -12,7 +10,7 @@ exports.CODEQL_ACTION_TRACED_LANGUAGES = 'CODEQL_ACTION_TRACED_LANGUAGES';
|
|||||||
// action (i.e. the upload action is being used by a third-party integrator)
|
// action (i.e. the upload action is being used by a third-party integrator)
|
||||||
// then this variable will be assigned the start time of the action invoked
|
// then this variable will be assigned the start time of the action invoked
|
||||||
// rather that the init action.
|
// rather that the init action.
|
||||||
exports.CODEQL_ACTION_STARTED_AT = 'CODEQL_ACTION_STARTED_AT';
|
exports.CODEQL_WORKFLOW_STARTED_AT = 'CODEQL_WORKFLOW_STARTED_AT';
|
||||||
// Populated when the init action completes successfully
|
// Populated when the init action completes successfully
|
||||||
exports.CODEQL_ACTION_INIT_COMPLETED = 'CODEQL_ACTION_INIT_COMPLETED';
|
exports.CODEQL_ACTION_INIT_COMPLETED = 'CODEQL_ACTION_INIT_COMPLETED';
|
||||||
//# sourceMappingURL=shared-environment.js.map
|
//# sourceMappingURL=shared-environment.js.map
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"shared-environment.js","sourceRoot":"","sources":["../src/shared-environment.ts"],"names":[],"mappings":";;AAAa,QAAA,iBAAiB,GAAG,mBAAmB,CAAC;AACxC,QAAA,0BAA0B,GAAG,4BAA4B,CAAC;AAC1D,QAAA,uBAAuB,GAAG,yBAAyB,CAAC;AACpD,QAAA,0BAA0B,GAAG,4BAA4B,CAAC;AAC1D,QAAA,0BAA0B,GAAG,4BAA4B,CAAC;AAC1D,QAAA,+BAA+B,GAAG,iCAAiC,CAAC;AACpE,QAAA,8BAA8B,GAAG,gCAAgC,CAAC;AAC/E,wEAAwE;AACxE,2EAA2E;AAC3E,4EAA4E;AAC5E,2EAA2E;AAC3E,+BAA+B;AAClB,QAAA,wBAAwB,GAAG,0BAA0B,CAAC;AACnE,wDAAwD;AAC3C,QAAA,4BAA4B,GAAG,8BAA8B,CAAC"}
|
{"version":3,"file":"shared-environment.js","sourceRoot":"","sources":["../src/shared-environment.ts"],"names":[],"mappings":";;AAAa,QAAA,0BAA0B,GAAG,4BAA4B,CAAC;AAC1D,QAAA,0BAA0B,GAAG,4BAA4B,CAAC;AAC1D,QAAA,0BAA0B,GAAG,4BAA4B,CAAC;AAC1D,QAAA,+BAA+B,GAAG,iCAAiC,CAAC;AACpE,QAAA,8BAA8B,GAAG,gCAAgC,CAAC;AAC/E,wEAAwE;AACxE,2EAA2E;AAC3E,4EAA4E;AAC5E,2EAA2E;AAC3E,+BAA+B;AAClB,QAAA,0BAA0B,GAAG,4BAA4B,CAAC;AACvE,wDAAwD;AAC3C,QAAA,4BAA4B,GAAG,8BAA8B,CAAC"}
|
||||||
Generated
+29
-2
@@ -1,5 +1,17 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||||
|
result["default"] = mod;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const sinon_1 = __importDefault(require("sinon"));
|
||||||
|
const CodeQL = __importStar(require("./codeql"));
|
||||||
function wrapOutput(context) {
|
function wrapOutput(context) {
|
||||||
// Function signature taken from Socket.write.
|
// Function signature taken from Socket.write.
|
||||||
// Note there are two overloads:
|
// Note there are two overloads:
|
||||||
@@ -25,9 +37,13 @@ function wrapOutput(context) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
function silenceDebugOutput(test) {
|
function setupTests(test) {
|
||||||
const typedTest = test;
|
const typedTest = test;
|
||||||
typedTest.beforeEach(t => {
|
typedTest.beforeEach(t => {
|
||||||
|
// Set an empty CodeQL object so that all method calls will fail
|
||||||
|
// unless the test explicitly sets one up.
|
||||||
|
CodeQL.setCodeQL({});
|
||||||
|
// Replace stdout and stderr so we can record output during tests
|
||||||
t.context.testOutput = "";
|
t.context.testOutput = "";
|
||||||
const processStdoutWrite = process.stdout.write.bind(process.stdout);
|
const processStdoutWrite = process.stdout.write.bind(process.stdout);
|
||||||
t.context.stdoutWrite = processStdoutWrite;
|
t.context.stdoutWrite = processStdoutWrite;
|
||||||
@@ -35,14 +51,25 @@ function silenceDebugOutput(test) {
|
|||||||
const processStderrWrite = process.stderr.write.bind(process.stderr);
|
const processStderrWrite = process.stderr.write.bind(process.stderr);
|
||||||
t.context.stderrWrite = processStderrWrite;
|
t.context.stderrWrite = processStderrWrite;
|
||||||
process.stderr.write = wrapOutput(t.context);
|
process.stderr.write = wrapOutput(t.context);
|
||||||
|
// Many tests modify environment variables. Take a copy now so that
|
||||||
|
// we reset them after the test to keep tests independent of each other.
|
||||||
|
// process.env only has strings fields, so a shallow copy is fine.
|
||||||
|
t.context.env = {};
|
||||||
|
Object.assign(t.context.env, process.env);
|
||||||
});
|
});
|
||||||
typedTest.afterEach.always(t => {
|
typedTest.afterEach.always(t => {
|
||||||
|
// Restore stdout and stderr
|
||||||
|
// The captured output is only replayed if the test failed
|
||||||
process.stdout.write = t.context.stdoutWrite;
|
process.stdout.write = t.context.stdoutWrite;
|
||||||
process.stderr.write = t.context.stderrWrite;
|
process.stderr.write = t.context.stderrWrite;
|
||||||
if (!t.passed) {
|
if (!t.passed) {
|
||||||
process.stdout.write(t.context.testOutput);
|
process.stdout.write(t.context.testOutput);
|
||||||
}
|
}
|
||||||
|
// Undo any modifications made by sinon
|
||||||
|
sinon_1.default.restore();
|
||||||
|
// Undo any modifications to the env
|
||||||
|
process.env = t.context.env;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.silenceDebugOutput = silenceDebugOutput;
|
exports.setupTests = setupTests;
|
||||||
//# sourceMappingURL=testing-utils.js.map
|
//# sourceMappingURL=testing-utils.js.map
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"testing-utils.js","sourceRoot":"","sources":["../src/testing-utils.ts"],"names":[],"mappings":";;AAIA,SAAS,UAAU,CAAC,OAAoB;IACtC,8CAA8C;IAC9C,gCAAgC;IAChC,2EAA2E;IAC3E,2FAA2F;IAC3F,OAAO,CAAC,KAA0B,EAAE,QAAiB,EAAE,EAA0B,EAAW,EAAE;QAC5F,2CAA2C;QAC3C,IAAI,EAAE,KAAK,SAAS,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE;YACtD,EAAE,GAAG,QAAQ,CAAC;YACd,QAAQ,GAAG,SAAS,CAAC;SACtB;QAED,oBAAoB;QACpB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;YAC7B,OAAO,CAAC,UAAU,IAAI,KAAK,CAAC;SAC7B;aAAM;YACL,OAAO,CAAC,UAAU,IAAI,IAAI,WAAW,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;SAC1E;QAED,iDAAiD;QACjD,IAAI,EAAE,KAAK,SAAS,IAAI,OAAO,EAAE,KAAK,UAAU,EAAE;YAChD,EAAE,EAAE,CAAC;SACN;QAED,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC;AAED,SAAgB,kBAAkB,CAAC,IAAwB;IACzD,MAAM,SAAS,GAAG,IAAkC,CAAC;IAErD,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;QACvB,CAAC,CAAC,OAAO,CAAC,UAAU,GAAG,EAAE,CAAC;QAE1B,MAAM,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACrE,CAAC,CAAC,OAAO,CAAC,WAAW,GAAG,kBAAkB,CAAC;QAC3C,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,OAAO,CAAQ,CAAC;QAEpD,MAAM,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACrE,CAAC,CAAC,OAAO,CAAC,WAAW,GAAG,kBAAkB,CAAC;QAC3C,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,OAAO,CAAQ,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;QAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;QAC7C,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;QAE7C,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE;YACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;SAC5C;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAvBD,gDAuBC"}
|
{"version":3,"file":"testing-utils.js","sourceRoot":"","sources":["../src/testing-utils.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,kDAA0B;AAE1B,iDAAmC;AAInC,SAAS,UAAU,CAAC,OAAoB;IACtC,8CAA8C;IAC9C,gCAAgC;IAChC,2EAA2E;IAC3E,2FAA2F;IAC3F,OAAO,CAAC,KAA0B,EAAE,QAAiB,EAAE,EAA0B,EAAW,EAAE;QAC5F,2CAA2C;QAC3C,IAAI,EAAE,KAAK,SAAS,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE;YACtD,EAAE,GAAG,QAAQ,CAAC;YACd,QAAQ,GAAG,SAAS,CAAC;SACtB;QAED,oBAAoB;QACpB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;YAC7B,OAAO,CAAC,UAAU,IAAI,KAAK,CAAC;SAC7B;aAAM;YACL,OAAO,CAAC,UAAU,IAAI,IAAI,WAAW,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;SAC1E;QAED,iDAAiD;QACjD,IAAI,EAAE,KAAK,SAAS,IAAI,OAAO,EAAE,KAAK,UAAU,EAAE;YAChD,EAAE,EAAE,CAAC;SACN;QAED,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC;AAED,SAAgB,UAAU,CAAC,IAAwB;IACjD,MAAM,SAAS,GAAG,IAAkC,CAAC;IAErD,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;QACvB,gEAAgE;QAChE,0CAA0C;QAC1C,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAErB,iEAAiE;QACjE,CAAC,CAAC,OAAO,CAAC,UAAU,GAAG,EAAE,CAAC;QAC1B,MAAM,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACrE,CAAC,CAAC,OAAO,CAAC,WAAW,GAAG,kBAAkB,CAAC;QAC3C,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,OAAO,CAAQ,CAAC;QACpD,MAAM,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACrE,CAAC,CAAC,OAAO,CAAC,WAAW,GAAG,kBAAkB,CAAC;QAC3C,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,OAAO,CAAQ,CAAC;QAEpD,mEAAmE;QACnE,wEAAwE;QACxE,kEAAkE;QAClE,CAAC,CAAC,OAAO,CAAC,GAAG,GAAG,EAAE,CAAC;QACnB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;QAC7B,4BAA4B;QAC5B,0DAA0D;QAC1D,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;QAC7C,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;QAC7C,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE;YACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;SAC5C;QAED,uCAAuC;QACvC,eAAK,CAAC,OAAO,EAAE,CAAC;QAEhB,oCAAoC;QACpC,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;IAC9B,CAAC,CAAC,CAAC;AACL,CAAC;AAvCD,gCAuCC"}
|
||||||
Generated
+42
-45
@@ -11,13 +11,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const core = __importStar(require("@actions/core"));
|
const core = __importStar(require("@actions/core"));
|
||||||
const http = __importStar(require("@actions/http-client"));
|
|
||||||
const auth = __importStar(require("@actions/http-client/auth"));
|
|
||||||
const file_url_1 = __importDefault(require("file-url"));
|
const file_url_1 = __importDefault(require("file-url"));
|
||||||
const fs = __importStar(require("fs"));
|
const fs = __importStar(require("fs"));
|
||||||
const jsonschema = __importStar(require("jsonschema"));
|
const jsonschema = __importStar(require("jsonschema"));
|
||||||
const path = __importStar(require("path"));
|
const path = __importStar(require("path"));
|
||||||
const zlib_1 = __importDefault(require("zlib"));
|
const zlib_1 = __importDefault(require("zlib"));
|
||||||
|
const api = __importStar(require("./api-client"));
|
||||||
const fingerprints = __importStar(require("./fingerprints"));
|
const fingerprints = __importStar(require("./fingerprints"));
|
||||||
const sharedEnv = __importStar(require("./shared-environment"));
|
const sharedEnv = __importStar(require("./shared-environment"));
|
||||||
const util = __importStar(require("./util"));
|
const util = __importStar(require("./util"));
|
||||||
@@ -49,37 +48,37 @@ async function uploadPayload(payload) {
|
|||||||
// If in test mode we don't want to upload the results
|
// If in test mode we don't want to upload the results
|
||||||
const testMode = process.env['TEST_MODE'] === 'true' || false;
|
const testMode = process.env['TEST_MODE'] === 'true' || false;
|
||||||
if (testMode) {
|
if (testMode) {
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
const githubToken = core.getInput('token');
|
const [owner, repo] = util.getRequiredEnvParam("GITHUB_REPOSITORY").split("/");
|
||||||
const ph = new auth.BearerCredentialHandler(githubToken);
|
|
||||||
const client = new http.HttpClient('Code Scanning : Upload SARIF', [ph]);
|
|
||||||
const url = 'https://api.github.com/repos/' + process.env['GITHUB_REPOSITORY'] + '/code-scanning/analysis';
|
|
||||||
// Make up to 4 attempts to upload, and sleep for these
|
// Make up to 4 attempts to upload, and sleep for these
|
||||||
// number of seconds between each attempt.
|
// number of seconds between each attempt.
|
||||||
// We don't want to backoff too much to avoid wasting action
|
// We don't want to backoff too much to avoid wasting action
|
||||||
// minutes, but just waiting a little bit could maybe help.
|
// minutes, but just waiting a little bit could maybe help.
|
||||||
const backoffPeriods = [1, 5, 15];
|
const backoffPeriods = [1, 5, 15];
|
||||||
for (let attempt = 0; attempt <= backoffPeriods.length; attempt++) {
|
for (let attempt = 0; attempt <= backoffPeriods.length; attempt++) {
|
||||||
const res = await client.put(url, payload);
|
const response = await api.getApiClient().request("PUT /repos/:owner/:repo/code-scanning/analysis", ({
|
||||||
core.debug('response status: ' + res.message.statusCode);
|
owner: owner,
|
||||||
const statusCode = res.message.statusCode;
|
repo: repo,
|
||||||
|
data: payload,
|
||||||
|
}));
|
||||||
|
core.debug('response status: ' + response.status);
|
||||||
|
const statusCode = response.status;
|
||||||
if (statusCode === 202) {
|
if (statusCode === 202) {
|
||||||
core.info("Successfully uploaded results");
|
core.info("Successfully uploaded results");
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
const requestID = res.message.headers["x-github-request-id"];
|
const requestID = response.headers["x-github-request-id"];
|
||||||
// On any other status code that's not 5xx mark the upload as failed
|
// On any other status code that's not 5xx mark the upload as failed
|
||||||
if (!statusCode || statusCode < 500 || statusCode >= 600) {
|
if (!statusCode || statusCode < 500 || statusCode >= 600) {
|
||||||
core.setFailed('Upload failed (' + requestID + '): (' + statusCode + ') ' + await res.readBody());
|
throw new Error('Upload failed (' + requestID + '): (' + statusCode + ') ' + JSON.stringify(response.data));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
// On a 5xx status code we may retry the request
|
// On a 5xx status code we may retry the request
|
||||||
if (attempt < backoffPeriods.length) {
|
if (attempt < backoffPeriods.length) {
|
||||||
// Log the failure as a warning but don't mark the action as failed yet
|
// Log the failure as a warning but don't mark the action as failed yet
|
||||||
core.warning('Upload attempt (' + (attempt + 1) + ' of ' + (backoffPeriods.length + 1) +
|
core.warning('Upload attempt (' + (attempt + 1) + ' of ' + (backoffPeriods.length + 1) +
|
||||||
') failed (' + requestID + '). Retrying in ' + backoffPeriods[attempt] +
|
') failed (' + requestID + '). Retrying in ' + backoffPeriods[attempt] +
|
||||||
' seconds: (' + statusCode + ') ' + await res.readBody());
|
' seconds: (' + statusCode + ') ' + JSON.stringify(response.data));
|
||||||
// Sleep for the backoff period
|
// Sleep for the backoff period
|
||||||
await new Promise(r => setTimeout(r, backoffPeriods[attempt] * 1000));
|
await new Promise(r => setTimeout(r, backoffPeriods[attempt] * 1000));
|
||||||
continue;
|
continue;
|
||||||
@@ -88,11 +87,12 @@ async function uploadPayload(payload) {
|
|||||||
// If the upload fails with 5xx then we assume it is a temporary problem
|
// If the upload fails with 5xx then we assume it is a temporary problem
|
||||||
// and not an error that the user has caused or can fix.
|
// and not an error that the user has caused or can fix.
|
||||||
// We avoid marking the job as failed to avoid breaking CI workflows.
|
// We avoid marking the job as failed to avoid breaking CI workflows.
|
||||||
core.error('Upload failed (' + requestID + '): (' + statusCode + ') ' + await res.readBody());
|
throw new Error('Upload failed (' + requestID + '): (' + statusCode + ') ' + JSON.stringify(response.data));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
// This case shouldn't ever happen as the final iteration of the loop
|
||||||
|
// will always throw an error instead of exiting to here.
|
||||||
|
throw new Error('Upload failed');
|
||||||
}
|
}
|
||||||
// Uploads a single sarif file or a directory of sarif files
|
// Uploads a single sarif file or a directory of sarif files
|
||||||
// depending on what the path happens to refer to.
|
// depending on what the path happens to refer to.
|
||||||
@@ -103,8 +103,7 @@ async function upload(input) {
|
|||||||
.filter(f => f.endsWith(".sarif"))
|
.filter(f => f.endsWith(".sarif"))
|
||||||
.map(f => path.resolve(input, f));
|
.map(f => path.resolve(input, f));
|
||||||
if (sarifFiles.length === 0) {
|
if (sarifFiles.length === 0) {
|
||||||
core.setFailed("No SARIF files found to upload in \"" + input + "\".");
|
throw new Error("No SARIF files found to upload in \"" + input + "\".");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return await uploadFiles(sarifFiles);
|
return await uploadFiles(sarifFiles);
|
||||||
}
|
}
|
||||||
@@ -123,27 +122,22 @@ function countResultsInSarif(sarif) {
|
|||||||
}
|
}
|
||||||
exports.countResultsInSarif = countResultsInSarif;
|
exports.countResultsInSarif = countResultsInSarif;
|
||||||
// Validates that the given file path refers to a valid SARIF file.
|
// Validates that the given file path refers to a valid SARIF file.
|
||||||
// Returns a non-empty list of error message if the file is invalid,
|
// Throws an error if the file is invalid.
|
||||||
// otherwise returns the empty list if the file is valid.
|
|
||||||
function validateSarifFileSchema(sarifFilePath) {
|
function validateSarifFileSchema(sarifFilePath) {
|
||||||
const sarif = JSON.parse(fs.readFileSync(sarifFilePath, 'utf8'));
|
const sarif = JSON.parse(fs.readFileSync(sarifFilePath, 'utf8'));
|
||||||
const schema = JSON.parse(fs.readFileSync(__dirname + '/../src/sarif_v2.1.0_schema.json', 'utf8'));
|
const schema = JSON.parse(fs.readFileSync(__dirname + '/../src/sarif_v2.1.0_schema.json', 'utf8'));
|
||||||
const result = new jsonschema.Validator().validate(sarif, schema);
|
const result = new jsonschema.Validator().validate(sarif, schema);
|
||||||
if (result.valid) {
|
if (!result.valid) {
|
||||||
return true;
|
// Output the more verbose error messages in groups as these may be very large.
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Set the failure message to the stacks of all the errors.
|
|
||||||
// This should be of a manageable size and may even give enough to fix the error.
|
|
||||||
const errorMessages = result.errors.map(e => "- " + e.stack);
|
|
||||||
core.setFailed("Unable to upload \"" + sarifFilePath + "\" as it is not valid SARIF:\n" + errorMessages.join("\n"));
|
|
||||||
// Also output the more verbose error messages in groups as these may be very large.
|
|
||||||
for (const error of result.errors) {
|
for (const error of result.errors) {
|
||||||
core.startGroup("Error details: " + error.stack);
|
core.startGroup("Error details: " + error.stack);
|
||||||
core.info(JSON.stringify(error, null, 2));
|
core.info(JSON.stringify(error, null, 2));
|
||||||
core.endGroup();
|
core.endGroup();
|
||||||
}
|
}
|
||||||
return false;
|
// Set the main error message to the stacks of all the errors.
|
||||||
|
// This should be of a manageable size and may even give enough to fix the error.
|
||||||
|
const sarifErrors = result.errors.map(e => "- " + e.stack);
|
||||||
|
throw new Error("Unable to upload \"" + sarifFilePath + "\" as it is not valid SARIF:\n" + sarifErrors.join("\n"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.validateSarifFileSchema = validateSarifFileSchema;
|
exports.validateSarifFileSchema = validateSarifFileSchema;
|
||||||
@@ -154,22 +148,19 @@ async function uploadFiles(sarifFiles) {
|
|||||||
core.info("Uploading sarif files: " + JSON.stringify(sarifFiles));
|
core.info("Uploading sarif files: " + JSON.stringify(sarifFiles));
|
||||||
const sentinelEnvVar = "CODEQL_UPLOAD_SARIF";
|
const sentinelEnvVar = "CODEQL_UPLOAD_SARIF";
|
||||||
if (process.env[sentinelEnvVar]) {
|
if (process.env[sentinelEnvVar]) {
|
||||||
core.error("Aborting upload: only one run of the codeql/analyze or codeql/upload-sarif actions is allowed per job");
|
throw new Error("Aborting upload: only one run of the codeql/analyze or codeql/upload-sarif actions is allowed per job");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
core.exportVariable(sentinelEnvVar, sentinelEnvVar);
|
core.exportVariable(sentinelEnvVar, sentinelEnvVar);
|
||||||
// Validate that the files we were asked to upload are all valid SARIF files
|
// Validate that the files we were asked to upload are all valid SARIF files
|
||||||
for (const file of sarifFiles) {
|
for (const file of sarifFiles) {
|
||||||
if (!validateSarifFileSchema(file)) {
|
validateSarifFileSchema(file);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const commitOid = await util.getCommitOid();
|
const commitOid = await util.getCommitOid();
|
||||||
const workflowRunIDStr = util.getRequiredEnvParam('GITHUB_RUN_ID');
|
const workflowRunIDStr = util.getRequiredEnvParam('GITHUB_RUN_ID');
|
||||||
const ref = util.getRef();
|
const ref = util.getRef();
|
||||||
const analysisKey = await util.getAnalysisKey();
|
const analysisKey = await util.getAnalysisKey();
|
||||||
const analysisName = util.getRequiredEnvParam('GITHUB_WORKFLOW');
|
const analysisName = util.getRequiredEnvParam('GITHUB_WORKFLOW');
|
||||||
const startedAt = process.env[sharedEnv.CODEQL_ACTION_STARTED_AT];
|
const startedAt = process.env[sharedEnv.CODEQL_WORKFLOW_STARTED_AT];
|
||||||
let sarifPayload = combineSarifFiles(sarifFiles);
|
let sarifPayload = combineSarifFiles(sarifFiles);
|
||||||
sarifPayload = fingerprints.addFingerprints(sarifPayload);
|
sarifPayload = fingerprints.addFingerprints(sarifPayload);
|
||||||
const zipped_sarif = zlib_1.default.gzipSync(sarifPayload).toString('base64');
|
const zipped_sarif = zlib_1.default.gzipSync(sarifPayload).toString('base64');
|
||||||
@@ -177,8 +168,7 @@ async function uploadFiles(sarifFiles) {
|
|||||||
let checkoutURI = file_url_1.default(checkoutPath);
|
let checkoutURI = file_url_1.default(checkoutPath);
|
||||||
const workflowRunID = parseInt(workflowRunIDStr, 10);
|
const workflowRunID = parseInt(workflowRunIDStr, 10);
|
||||||
if (Number.isNaN(workflowRunID)) {
|
if (Number.isNaN(workflowRunID)) {
|
||||||
core.setFailed('GITHUB_RUN_ID must define a non NaN workflow run ID');
|
throw new Error('GITHUB_RUN_ID must define a non NaN workflow run ID');
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
let matrix = core.getInput('matrix');
|
let matrix = core.getInput('matrix');
|
||||||
if (matrix === "null" || matrix === "") {
|
if (matrix === "null" || matrix === "") {
|
||||||
@@ -198,12 +188,19 @@ async function uploadFiles(sarifFiles) {
|
|||||||
"tool_names": toolNames,
|
"tool_names": toolNames,
|
||||||
});
|
});
|
||||||
// Log some useful debug info about the info
|
// Log some useful debug info about the info
|
||||||
core.debug("Raw upload size: " + sarifPayload.length + " bytes");
|
const rawUploadSizeBytes = sarifPayload.length;
|
||||||
core.debug("Base64 zipped upload size: " + zipped_sarif.length + " bytes");
|
core.debug("Raw upload size: " + rawUploadSizeBytes + " bytes");
|
||||||
core.debug("Number of results in upload: " + countResultsInSarif(sarifPayload));
|
const zippedUploadSizeBytes = zipped_sarif.length;
|
||||||
|
core.debug("Base64 zipped upload size: " + zippedUploadSizeBytes + " bytes");
|
||||||
|
const numResultInSarif = countResultsInSarif(sarifPayload);
|
||||||
|
core.debug("Number of results in upload: " + numResultInSarif);
|
||||||
// Make the upload
|
// Make the upload
|
||||||
const succeeded = await uploadPayload(payload);
|
await uploadPayload(payload);
|
||||||
core.endGroup();
|
core.endGroup();
|
||||||
return succeeded;
|
return {
|
||||||
|
raw_upload_size_bytes: rawUploadSizeBytes,
|
||||||
|
zipped_upload_size_bytes: zippedUploadSizeBytes,
|
||||||
|
num_results_in_sarif: numResultInSarif,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
//# sourceMappingURL=upload-lib.js.map
|
//# sourceMappingURL=upload-lib.js.map
|
||||||
File diff suppressed because one or more lines are too long
Generated
+3
-5
@@ -13,15 +13,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||||||
const ava_1 = __importDefault(require("ava"));
|
const ava_1 = __importDefault(require("ava"));
|
||||||
const testing_utils_1 = require("./testing-utils");
|
const testing_utils_1 = require("./testing-utils");
|
||||||
const uploadLib = __importStar(require("./upload-lib"));
|
const uploadLib = __importStar(require("./upload-lib"));
|
||||||
testing_utils_1.silenceDebugOutput(ava_1.default);
|
testing_utils_1.setupTests(ava_1.default);
|
||||||
ava_1.default('validateSarifFileSchema - valid', t => {
|
ava_1.default('validateSarifFileSchema - valid', t => {
|
||||||
const inputFile = __dirname + '/../src/testdata/valid-sarif.sarif';
|
const inputFile = __dirname + '/../src/testdata/valid-sarif.sarif';
|
||||||
t.true(uploadLib.validateSarifFileSchema(inputFile));
|
t.notThrows(() => uploadLib.validateSarifFileSchema(inputFile));
|
||||||
});
|
});
|
||||||
ava_1.default('validateSarifFileSchema - invalid', t => {
|
ava_1.default('validateSarifFileSchema - invalid', t => {
|
||||||
const inputFile = __dirname + '/../src/testdata/invalid-sarif.sarif';
|
const inputFile = __dirname + '/../src/testdata/invalid-sarif.sarif';
|
||||||
t.false(uploadLib.validateSarifFileSchema(inputFile));
|
t.throws(() => uploadLib.validateSarifFileSchema(inputFile));
|
||||||
// validateSarifFileSchema calls core.setFailed which sets the exit code on error
|
|
||||||
process.exitCode = 0;
|
|
||||||
});
|
});
|
||||||
//# sourceMappingURL=upload-lib.test.js.map
|
//# sourceMappingURL=upload-lib.test.js.map
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"upload-lib.test.js","sourceRoot":"","sources":["../src/upload-lib.test.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,8CAAuB;AAEvB,mDAAmD;AACnD,wDAA0C;AAE1C,kCAAkB,CAAC,aAAI,CAAC,CAAC;AAEzB,aAAI,CAAC,iCAAiC,EAAE,CAAC,CAAC,EAAE;IAC1C,MAAM,SAAS,GAAG,SAAS,GAAG,oCAAoC,CAAC;IACnE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC,CAAC;AACvD,CAAC,CAAC,CAAC;AAEH,aAAI,CAAC,mCAAmC,EAAE,CAAC,CAAC,EAAE;IAC5C,MAAM,SAAS,GAAG,SAAS,GAAG,sCAAsC,CAAC;IACrE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC,CAAC;IACtD,iFAAiF;IACjF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
|
{"version":3,"file":"upload-lib.test.js","sourceRoot":"","sources":["../src/upload-lib.test.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,8CAAuB;AAEvB,mDAA2C;AAC3C,wDAA0C;AAE1C,0BAAU,CAAC,aAAI,CAAC,CAAC;AAEjB,aAAI,CAAC,iCAAiC,EAAE,CAAC,CAAC,EAAE;IAC1C,MAAM,SAAS,GAAG,SAAS,GAAG,oCAAoC,CAAC;IACnE,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC,CAAC;AAClE,CAAC,CAAC,CAAC;AAEH,aAAI,CAAC,mCAAmC,EAAE,CAAC,CAAC,EAAE;IAC5C,MAAM,SAAS,GAAG,SAAS,GAAG,sCAAsC,CAAC;IACrE,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC,CAAC;AAC/D,CAAC,CAAC,CAAC"}
|
||||||
Generated
+14
-8
@@ -10,21 +10,27 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||||||
const core = __importStar(require("@actions/core"));
|
const core = __importStar(require("@actions/core"));
|
||||||
const upload_lib = __importStar(require("./upload-lib"));
|
const upload_lib = __importStar(require("./upload-lib"));
|
||||||
const util = __importStar(require("./util"));
|
const util = __importStar(require("./util"));
|
||||||
|
async function sendSuccessStatusReport(startedAt, uploadStats) {
|
||||||
|
const statusReportBase = await util.createStatusReportBase('upload-sarif', 'success', startedAt);
|
||||||
|
const statusReport = {
|
||||||
|
...statusReportBase,
|
||||||
|
...uploadStats,
|
||||||
|
};
|
||||||
|
await util.sendStatusReport(statusReport);
|
||||||
|
}
|
||||||
async function run() {
|
async function run() {
|
||||||
if (util.should_abort('upload-sarif', false) || !await util.reportActionStarting('upload-sarif')) {
|
const startedAt = new Date();
|
||||||
|
if (util.should_abort('upload-sarif', false) ||
|
||||||
|
!await util.sendStatusReport(await util.createStatusReportBase('upload-sarif', 'starting', startedAt), true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (await upload_lib.upload(core.getInput('sarif_file'))) {
|
const uploadStats = await upload_lib.upload(core.getInput('sarif_file'));
|
||||||
await util.reportActionSucceeded('upload-sarif');
|
await sendSuccessStatusReport(startedAt, uploadStats);
|
||||||
}
|
|
||||||
else {
|
|
||||||
await util.reportActionFailed('upload-sarif', 'upload');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
await util.reportActionFailed('upload-sarif', error.message, error.stack);
|
await util.sendStatusReport(await util.createStatusReportBase('upload-sarif', 'failure', startedAt, error.message, error.stack));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"upload-sarif.js","sourceRoot":"","sources":["../src/upload-sarif.ts"],"names":[],"mappings":";;;;;;;;;AAAA,oDAAsC;AAEtC,yDAA2C;AAC3C,6CAA+B;AAE/B,KAAK,UAAU,GAAG;IAChB,IAAI,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,oBAAoB,CAAC,cAAc,CAAC,EAAE;QAChG,OAAO;KACR;IAED,IAAI;QACF,IAAI,MAAM,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,EAAE;YACxD,MAAM,IAAI,CAAC,qBAAqB,CAAC,cAAc,CAAC,CAAC;SAClD;aAAM;YACL,MAAM,IAAI,CAAC,kBAAkB,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;SACzD;KACF;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC9B,MAAM,IAAI,CAAC,kBAAkB,CAAC,cAAc,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1E,OAAO;KACR;AACH,CAAC;AAED,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IACd,IAAI,CAAC,SAAS,CAAC,qCAAqC,GAAG,CAAC,CAAC,CAAC;IAC1D,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC"}
|
{"version":3,"file":"upload-sarif.js","sourceRoot":"","sources":["../src/upload-sarif.ts"],"names":[],"mappings":";;;;;;;;;AAAA,oDAAsC;AAEtC,yDAA2C;AAC3C,6CAA+B;AAI/B,KAAK,UAAU,uBAAuB,CAAC,SAAe,EAAE,WAA0C;IAChG,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,sBAAsB,CAAC,cAAc,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IACjG,MAAM,YAAY,GAA4B;QAC5C,GAAG,gBAAgB;QACnB,GAAI,WAAW;KAChB,CAAC;IACF,MAAM,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC;AAC5C,CAAC;AAED,KAAK,UAAU,GAAG;IAChB,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;IAC7B,IAAI,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,KAAK,CAAC;QACxC,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,IAAI,CAAC,sBAAsB,CAAC,cAAc,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,EAAE;QAChH,OAAO;KACR;IAED,IAAI;QACF,MAAM,WAAW,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;QACzE,MAAM,uBAAuB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;KAEvD;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC9B,MAAM,IAAI,CAAC,gBAAgB,CAAC,MAAM,IAAI,CAAC,sBAAsB,CAC3D,cAAc,EACd,SAAS,EACT,SAAS,EACT,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;QAChB,OAAO;KACR;AACH,CAAC;AAED,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;IACd,IAAI,CAAC,SAAS,CAAC,qCAAqC,GAAG,CAAC,CAAC,CAAC;IAC1D,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC"}
|
||||||
Generated
+70
-181
@@ -6,19 +6,13 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
result["default"] = mod;
|
result["default"] = mod;
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
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 });
|
||||||
const core = __importStar(require("@actions/core"));
|
const core = __importStar(require("@actions/core"));
|
||||||
const exec = __importStar(require("@actions/exec"));
|
const exec = __importStar(require("@actions/exec"));
|
||||||
const http = __importStar(require("@actions/http-client"));
|
|
||||||
const auth = __importStar(require("@actions/http-client/auth"));
|
|
||||||
const octokit = __importStar(require("@octokit/rest"));
|
|
||||||
const console_log_level_1 = __importDefault(require("console-log-level"));
|
|
||||||
const fs = __importStar(require("fs"));
|
const fs = __importStar(require("fs"));
|
||||||
const os = __importStar(require("os"));
|
const os = __importStar(require("os"));
|
||||||
const path = __importStar(require("path"));
|
const path = __importStar(require("path"));
|
||||||
|
const api = __importStar(require("./api-client"));
|
||||||
const sharedEnv = __importStar(require("./shared-environment"));
|
const sharedEnv = __importStar(require("./shared-environment"));
|
||||||
/**
|
/**
|
||||||
* Should the current action be aborted?
|
* Should the current action be aborted?
|
||||||
@@ -47,108 +41,39 @@ exports.should_abort = should_abort;
|
|||||||
*/
|
*/
|
||||||
function getRequiredEnvParam(paramName) {
|
function getRequiredEnvParam(paramName) {
|
||||||
const value = process.env[paramName];
|
const value = process.env[paramName];
|
||||||
if (value === undefined) {
|
if (value === undefined || value.length === 0) {
|
||||||
throw new Error(paramName + ' environment variable must be set');
|
throw new Error(paramName + ' environment variable must be set');
|
||||||
}
|
}
|
||||||
core.debug(paramName + '=' + value);
|
core.debug(paramName + '=' + value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
exports.getRequiredEnvParam = getRequiredEnvParam;
|
exports.getRequiredEnvParam = getRequiredEnvParam;
|
||||||
/**
|
|
||||||
* Gets the set of languages in the current repository
|
|
||||||
*/
|
|
||||||
async function getLanguagesInRepo() {
|
|
||||||
var _a;
|
|
||||||
// Translate between GitHub's API names for languages and ours
|
|
||||||
const codeqlLanguages = {
|
|
||||||
'C': 'cpp',
|
|
||||||
'C++': 'cpp',
|
|
||||||
'C#': 'csharp',
|
|
||||||
'Go': 'go',
|
|
||||||
'Java': 'java',
|
|
||||||
'JavaScript': 'javascript',
|
|
||||||
'TypeScript': 'javascript',
|
|
||||||
'Python': 'python',
|
|
||||||
};
|
|
||||||
let repo_nwo = (_a = process.env['GITHUB_REPOSITORY']) === null || _a === void 0 ? void 0 : _a.split("/");
|
|
||||||
if (repo_nwo) {
|
|
||||||
let owner = repo_nwo[0];
|
|
||||||
let repo = repo_nwo[1];
|
|
||||||
core.debug(`GitHub repo ${owner} ${repo}`);
|
|
||||||
let ok = new octokit.Octokit({
|
|
||||||
auth: core.getInput('token'),
|
|
||||||
userAgent: "CodeQL Action",
|
|
||||||
log: console_log_level_1.default({ level: "debug" })
|
|
||||||
});
|
|
||||||
const response = await ok.request("GET /repos/:owner/:repo/languages", ({
|
|
||||||
owner,
|
|
||||||
repo
|
|
||||||
}));
|
|
||||||
core.debug("Languages API response: " + JSON.stringify(response));
|
|
||||||
// The GitHub API is going to return languages in order of popularity,
|
|
||||||
// When we pick a language to autobuild we want to pick the most popular traced language
|
|
||||||
// Since sets in javascript maintain insertion order, using a set here and then splatting it
|
|
||||||
// into an array gives us an array of languages ordered by popularity
|
|
||||||
let languages = new Set();
|
|
||||||
for (let lang in response.data) {
|
|
||||||
if (lang in codeqlLanguages) {
|
|
||||||
languages.add(codeqlLanguages[lang]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [...languages];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Get the languages to analyse.
|
|
||||||
*
|
|
||||||
* The result is obtained from the environment parameter CODEQL_ACTION_LANGUAGES
|
|
||||||
* if that has been set, otherwise it is obtained from the action input parameter
|
|
||||||
* 'languages' if that has been set, otherwise it is deduced as all languages in the
|
|
||||||
* repo that can be analysed.
|
|
||||||
*
|
|
||||||
* If the languages are obtained from either of the second choices, the
|
|
||||||
* CODEQL_ACTION_LANGUAGES environment variable will be exported with the
|
|
||||||
* deduced list.
|
|
||||||
*/
|
|
||||||
async function getLanguages() {
|
|
||||||
// Obtain from CODEQL_ACTION_LANGUAGES if set
|
|
||||||
const langsVar = process.env[sharedEnv.CODEQL_ACTION_LANGUAGES];
|
|
||||||
if (langsVar) {
|
|
||||||
return langsVar.split(',')
|
|
||||||
.map(x => x.trim())
|
|
||||||
.filter(x => x.length > 0);
|
|
||||||
}
|
|
||||||
// Obtain from action input 'languages' if set
|
|
||||||
let languages = core.getInput('languages', { required: false })
|
|
||||||
.split(',')
|
|
||||||
.map(x => x.trim())
|
|
||||||
.filter(x => x.length > 0);
|
|
||||||
core.info("Languages from configuration: " + JSON.stringify(languages));
|
|
||||||
if (languages.length === 0) {
|
|
||||||
// Obtain languages as all languages in the repo that can be analysed
|
|
||||||
languages = await getLanguagesInRepo();
|
|
||||||
core.info("Automatically detected languages: " + JSON.stringify(languages));
|
|
||||||
}
|
|
||||||
core.exportVariable(sharedEnv.CODEQL_ACTION_LANGUAGES, languages.join(','));
|
|
||||||
return languages;
|
|
||||||
}
|
|
||||||
exports.getLanguages = getLanguages;
|
|
||||||
/**
|
/**
|
||||||
* Gets the SHA of the commit that is currently checked out.
|
* Gets the SHA of the commit that is currently checked out.
|
||||||
*/
|
*/
|
||||||
async function getCommitOid() {
|
async function getCommitOid() {
|
||||||
let commitOid = '';
|
// Try to use git to get the current commit SHA. If that fails then
|
||||||
await exec.exec('git', ['rev-parse', 'HEAD'], {
|
// log but otherwise silently fall back to using the SHA from the environment.
|
||||||
silent: true,
|
// The only time these two values will differ is during analysis of a PR when
|
||||||
listeners: {
|
// the workflow has changed the current commit to the head commit instead of
|
||||||
stdout: (data) => { commitOid += data.toString(); },
|
// the merge commit, which must mean that git is available.
|
||||||
stderr: (data) => { process.stderr.write(data); }
|
// Even if this does go wrong, it's not a huge problem for the alerts to
|
||||||
}
|
// reported on the merge commit.
|
||||||
});
|
try {
|
||||||
return commitOid.trim();
|
let commitOid = '';
|
||||||
|
await exec.exec('git', ['rev-parse', 'HEAD'], {
|
||||||
|
silent: true,
|
||||||
|
listeners: {
|
||||||
|
stdout: (data) => { commitOid += data.toString(); },
|
||||||
|
stderr: (data) => { process.stderr.write(data); }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return commitOid.trim();
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
core.info("Failed to call git to get current commit. Continuing with data from environment: " + e);
|
||||||
|
return getRequiredEnvParam('GITHUB_SHA');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exports.getCommitOid = getCommitOid;
|
exports.getCommitOid = getCommitOid;
|
||||||
/**
|
/**
|
||||||
@@ -158,19 +83,15 @@ async function getWorkflowPath() {
|
|||||||
const repo_nwo = getRequiredEnvParam('GITHUB_REPOSITORY').split("/");
|
const repo_nwo = getRequiredEnvParam('GITHUB_REPOSITORY').split("/");
|
||||||
const owner = repo_nwo[0];
|
const owner = repo_nwo[0];
|
||||||
const repo = repo_nwo[1];
|
const repo = repo_nwo[1];
|
||||||
const run_id = getRequiredEnvParam('GITHUB_RUN_ID');
|
const run_id = Number(getRequiredEnvParam('GITHUB_RUN_ID'));
|
||||||
const ok = new octokit.Octokit({
|
const apiClient = api.getApiClient();
|
||||||
auth: core.getInput('token'),
|
const runsResponse = await apiClient.request('GET /repos/:owner/:repo/actions/runs/:run_id', {
|
||||||
userAgent: "CodeQL Action",
|
|
||||||
log: console_log_level_1.default({ level: 'debug' })
|
|
||||||
});
|
|
||||||
const runsResponse = await ok.request('GET /repos/:owner/:repo/actions/runs/:run_id', {
|
|
||||||
owner,
|
owner,
|
||||||
repo,
|
repo,
|
||||||
run_id
|
run_id
|
||||||
});
|
});
|
||||||
const workflowUrl = runsResponse.data.workflow_url;
|
const workflowUrl = runsResponse.data.workflow_url;
|
||||||
const workflowResponse = await ok.request('GET ' + workflowUrl);
|
const workflowResponse = await apiClient.request('GET ' + workflowUrl);
|
||||||
return workflowResponse.data.path;
|
return workflowResponse.data.path;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -217,10 +138,11 @@ exports.getRef = getRef;
|
|||||||
*
|
*
|
||||||
* @param actionName The name of the action, e.g. 'init', 'finish', 'upload-sarif'
|
* @param actionName The name of the action, e.g. 'init', 'finish', 'upload-sarif'
|
||||||
* @param status The status. Must be 'success', 'failure', or 'starting'
|
* @param status The status. Must be 'success', 'failure', or 'starting'
|
||||||
|
* @param startedAt The time this action started executing.
|
||||||
* @param cause Cause of failure (only supply if status is 'failure')
|
* @param cause Cause of failure (only supply if status is 'failure')
|
||||||
* @param exception Exception (only supply if status is 'failure')
|
* @param exception Exception (only supply if status is 'failure')
|
||||||
*/
|
*/
|
||||||
async function createStatusReport(actionName, status, cause, exception) {
|
async function createStatusReportBase(actionName, status, actionStartedAt, cause, exception) {
|
||||||
const commitOid = process.env['GITHUB_SHA'] || '';
|
const commitOid = process.env['GITHUB_SHA'] || '';
|
||||||
const ref = getRef();
|
const ref = getRef();
|
||||||
const workflowRunIDStr = process.env['GITHUB_RUN_ID'];
|
const workflowRunIDStr = process.env['GITHUB_RUN_ID'];
|
||||||
@@ -230,19 +152,23 @@ async function createStatusReport(actionName, status, cause, exception) {
|
|||||||
}
|
}
|
||||||
const workflowName = process.env['GITHUB_WORKFLOW'] || '';
|
const workflowName = process.env['GITHUB_WORKFLOW'] || '';
|
||||||
const jobName = process.env['GITHUB_JOB'] || '';
|
const jobName = process.env['GITHUB_JOB'] || '';
|
||||||
const languages = (await getLanguages()).sort().join(',');
|
const analysis_key = await getAnalysisKey();
|
||||||
const startedAt = process.env[sharedEnv.CODEQL_ACTION_STARTED_AT] || new Date().toISOString();
|
let workflowStartedAt = process.env[sharedEnv.CODEQL_WORKFLOW_STARTED_AT];
|
||||||
core.exportVariable(sharedEnv.CODEQL_ACTION_STARTED_AT, startedAt);
|
if (workflowStartedAt === undefined) {
|
||||||
|
workflowStartedAt = actionStartedAt.toISOString();
|
||||||
|
core.exportVariable(sharedEnv.CODEQL_WORKFLOW_STARTED_AT, workflowStartedAt);
|
||||||
|
}
|
||||||
let statusReport = {
|
let statusReport = {
|
||||||
workflow_run_id: workflowRunID,
|
workflow_run_id: workflowRunID,
|
||||||
workflow_name: workflowName,
|
workflow_name: workflowName,
|
||||||
job_name: jobName,
|
job_name: jobName,
|
||||||
languages: languages,
|
analysis_key: analysis_key,
|
||||||
commit_oid: commitOid,
|
commit_oid: commitOid,
|
||||||
ref: ref,
|
ref: ref,
|
||||||
action_name: actionName,
|
action_name: actionName,
|
||||||
action_oid: "unknown",
|
action_oid: "unknown",
|
||||||
started_at: startedAt,
|
started_at: workflowStartedAt,
|
||||||
|
action_started_at: actionStartedAt.toISOString(),
|
||||||
status: status
|
status: status
|
||||||
};
|
};
|
||||||
// Add optional parameters
|
// Add optional parameters
|
||||||
@@ -252,7 +178,7 @@ async function createStatusReport(actionName, status, cause, exception) {
|
|||||||
if (exception) {
|
if (exception) {
|
||||||
statusReport.exception = exception;
|
statusReport.exception = exception;
|
||||||
}
|
}
|
||||||
if (status === 'success' || status === 'failure') {
|
if (status === 'success' || status === 'failure' || status === 'aborted') {
|
||||||
statusReport.completed_at = new Date().toISOString();
|
statusReport.completed_at = new Date().toISOString();
|
||||||
}
|
}
|
||||||
let matrix = core.getInput('matrix');
|
let matrix = core.getInput('matrix');
|
||||||
@@ -261,82 +187,45 @@ async function createStatusReport(actionName, status, cause, exception) {
|
|||||||
}
|
}
|
||||||
return statusReport;
|
return statusReport;
|
||||||
}
|
}
|
||||||
|
exports.createStatusReportBase = createStatusReportBase;
|
||||||
/**
|
/**
|
||||||
* Send a status report to the code_scanning/analysis/status endpoint.
|
* Send a status report to the code_scanning/analysis/status endpoint.
|
||||||
*
|
*
|
||||||
* Returns the status code of the response to the status request, or
|
* Optionally checks the response from the API endpoint and sets the action
|
||||||
* undefined if the given statusReport is undefined or no response was
|
* as failed if the status report failed. This is only expected to be used
|
||||||
* received.
|
* when sending a 'starting' report.
|
||||||
|
*
|
||||||
|
* Returns whether sending the status report was successful of not.
|
||||||
*/
|
*/
|
||||||
async function sendStatusReport(statusReport) {
|
async function sendStatusReport(statusReport, ignoreFailures) {
|
||||||
var _a;
|
|
||||||
const statusReportJSON = JSON.stringify(statusReport);
|
const statusReportJSON = JSON.stringify(statusReport);
|
||||||
core.debug('Sending status report: ' + statusReportJSON);
|
core.debug('Sending status report: ' + statusReportJSON);
|
||||||
const githubToken = core.getInput('token');
|
const nwo = getRequiredEnvParam("GITHUB_REPOSITORY");
|
||||||
const ph = new auth.BearerCredentialHandler(githubToken);
|
const [owner, repo] = nwo.split("/");
|
||||||
const client = new http.HttpClient('Code Scanning : Status Report', [ph]);
|
const statusResponse = await api.getApiClient().request('PUT /repos/:owner/:repo/code-scanning/analysis/status', {
|
||||||
const url = 'https://api.github.com/repos/' + process.env['GITHUB_REPOSITORY']
|
owner: owner,
|
||||||
+ '/code-scanning/analysis/status';
|
repo: repo,
|
||||||
const res = await client.put(url, statusReportJSON);
|
data: statusReportJSON,
|
||||||
return (_a = res.message) === null || _a === void 0 ? void 0 : _a.statusCode;
|
});
|
||||||
}
|
if (!ignoreFailures) {
|
||||||
/**
|
// If the status report request fails with a 403 or a 404, then this is a deliberate
|
||||||
* Send a status report that an action is starting.
|
// message from the endpoint that the SARIF upload can be expected to fail too,
|
||||||
*
|
// so the action should fail to avoid wasting actions minutes.
|
||||||
* If the action is `init` then this also records the start time in the environment,
|
//
|
||||||
* and ensures that the analysed languages are also recorded in the envirenment.
|
// Other failure responses (or lack thereof) could be transitory and should not
|
||||||
*
|
// cause the action to fail.
|
||||||
* Returns true unless a problem occurred and the action should abort.
|
if (statusResponse.status === 403) {
|
||||||
*/
|
core.setFailed('The repo on which this action is running is not opted-in to CodeQL code scanning.');
|
||||||
async function reportActionStarting(action) {
|
return false;
|
||||||
const statusCode = await sendStatusReport(await createStatusReport(action, 'starting'));
|
}
|
||||||
// If the status report request fails with a 403 or a 404, then this is a deliberate
|
if (statusResponse.status === 404) {
|
||||||
// message from the endpoint that the SARIF upload can be expected to fail too,
|
core.setFailed('Not authorized to used the CodeQL code scanning feature on this repo.');
|
||||||
// so the action should fail to avoid wasting actions minutes.
|
return false;
|
||||||
//
|
}
|
||||||
// Other failure responses (or lack thereof) could be transitory and should not
|
|
||||||
// cause the action to fail.
|
|
||||||
if (statusCode === 403) {
|
|
||||||
core.setFailed('The repo on which this action is running is not opted-in to CodeQL code scanning.');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (statusCode === 404) {
|
|
||||||
core.setFailed('Not authorized to used the CodeQL code scanning feature on this repo.');
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
exports.reportActionStarting = reportActionStarting;
|
exports.sendStatusReport = sendStatusReport;
|
||||||
/**
|
|
||||||
* Report that an action has failed.
|
|
||||||
*
|
|
||||||
* Note that the started_at date is always that of the `init` action, since
|
|
||||||
* this is likely to give a more useful duration when inspecting events.
|
|
||||||
*/
|
|
||||||
async function reportActionFailed(action, cause, exception) {
|
|
||||||
await sendStatusReport(await createStatusReport(action, 'failure', cause, exception));
|
|
||||||
}
|
|
||||||
exports.reportActionFailed = reportActionFailed;
|
|
||||||
/**
|
|
||||||
* Report that an action has succeeded.
|
|
||||||
*
|
|
||||||
* Note that the started_at date is always that of the `init` action, since
|
|
||||||
* this is likely to give a more useful duration when inspecting events.
|
|
||||||
*/
|
|
||||||
async function reportActionSucceeded(action) {
|
|
||||||
await sendStatusReport(await createStatusReport(action, 'success'));
|
|
||||||
}
|
|
||||||
exports.reportActionSucceeded = reportActionSucceeded;
|
|
||||||
/**
|
|
||||||
* Report that an action has been aborted.
|
|
||||||
*
|
|
||||||
* Note that the started_at date is always that of the `init` action, since
|
|
||||||
* this is likely to give a more useful duration when inspecting events.
|
|
||||||
*/
|
|
||||||
async function reportActionAborted(action, cause) {
|
|
||||||
await sendStatusReport(await createStatusReport(action, 'aborted', cause));
|
|
||||||
}
|
|
||||||
exports.reportActionAborted = reportActionAborted;
|
|
||||||
/**
|
/**
|
||||||
* Get the array of all the tool names contained in the given sarif contents.
|
* Get the array of all the tool names contained in the given sarif contents.
|
||||||
*
|
*
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
Generated
+8
-6
@@ -15,7 +15,7 @@ const fs = __importStar(require("fs"));
|
|||||||
const os = __importStar(require("os"));
|
const os = __importStar(require("os"));
|
||||||
const testing_utils_1 = require("./testing-utils");
|
const testing_utils_1 = require("./testing-utils");
|
||||||
const util = __importStar(require("./util"));
|
const util = __importStar(require("./util"));
|
||||||
testing_utils_1.silenceDebugOutput(ava_1.default);
|
testing_utils_1.setupTests(ava_1.default);
|
||||||
ava_1.default('getToolNames', t => {
|
ava_1.default('getToolNames', t => {
|
||||||
const input = fs.readFileSync(__dirname + '/../src/testdata/tool-names.sarif', 'utf8');
|
const input = fs.readFileSync(__dirname + '/../src/testdata/tool-names.sarif', 'utf8');
|
||||||
const toolNames = util.getToolNames(input);
|
const toolNames = util.getToolNames(input);
|
||||||
@@ -53,10 +53,12 @@ ava_1.default('getThreadsFlag() should return the correct --threads flag', t =>
|
|||||||
t.deepEqual(flag, expectedFlag);
|
t.deepEqual(flag, expectedFlag);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ava_1.default('getThreadsFlag() throws if the ram input is < 0 or NaN', t => {
|
ava_1.default('getThreadsFlag() throws if the threads input is not an integer', t => {
|
||||||
for (const input of ["hello!"]) {
|
process.env['INPUT_THREADS'] = "hello!";
|
||||||
process.env['INPUT_THREADS'] = input;
|
t.throws(util.getThreadsFlag);
|
||||||
t.throws(util.getThreadsFlag);
|
});
|
||||||
}
|
ava_1.default('getRef() throws on the empty string', t => {
|
||||||
|
process.env["GITHUB_REF"] = "";
|
||||||
|
t.throws(util.getRef);
|
||||||
});
|
});
|
||||||
//# sourceMappingURL=util.test.js.map
|
//# sourceMappingURL=util.test.js.map
|
||||||
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"util.test.js","sourceRoot":"","sources":["../src/util.test.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,8CAAuB;AACvB,uCAAyB;AACzB,uCAAyB;AAEzB,mDAAmD;AACnD,6CAA+B;AAE/B,kCAAkB,CAAC,aAAI,CAAC,CAAC;AAEzB,aAAI,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE;IACvB,MAAM,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,GAAG,mCAAmC,EAAE,MAAM,CAAC,CAAC;IACvF,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,+BAA+B,EAAE,QAAQ,CAAC,CAAC,CAAC;AACtE,CAAC,CAAC,CAAC;AAEH,aAAI,CAAC,sDAAsD,EAAE,CAAC,CAAC,EAAE;IAE/D,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC;IAE3D,MAAM,KAAK,GAAG;QACZ,EAAE,EAAE,SAAS,QAAQ,GAAG,GAAG,EAAE;QAC7B,KAAK,EAAE,WAAW;KACnB,CAAC;IAEF,KAAK,MAAM,CAAC,KAAK,EAAE,YAAY,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;QAEzD,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,KAAK,CAAC;QAEjC,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QAClC,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;KACjC;AACH,CAAC,CAAC,CAAC;AAEH,aAAI,CAAC,uDAAuD,EAAE,CAAC,CAAC,EAAE;IAChE,KAAK,MAAM,KAAK,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE;QACpC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,KAAK,CAAC;QACjC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;KAC9B;AACH,CAAC,CAAC,CAAC;AAEH,aAAI,CAAC,2DAA2D,EAAE,CAAC,CAAC,EAAE;IAEpE,MAAM,OAAO,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC;IAEjC,MAAM,KAAK,GAAG;QACZ,GAAG,EAAE,aAAa;QAClB,GAAG,EAAE,aAAa;QAClB,CAAC,GAAG,OAAO,GAAG,CAAC,EAAE,CAAC,EAAE,aAAa,OAAO,EAAE;QAC1C,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,OAAO,EAAE;KAC7C,CAAC;IAEF,KAAK,MAAM,CAAC,KAAK,EAAE,YAAY,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;QAEzD,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,KAAK,CAAC;QAErC,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QACnC,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;KACjC;AACH,CAAC,CAAC,CAAC;AAEH,aAAI,CAAC,wDAAwD,EAAE,CAAC,CAAC,EAAE;IACjE,KAAK,MAAM,KAAK,IAAI,CAAC,QAAQ,CAAC,EAAE;QAC9B,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,KAAK,CAAC;QACrC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;KAC/B;AACH,CAAC,CAAC,CAAC"}
|
{"version":3,"file":"util.test.js","sourceRoot":"","sources":["../src/util.test.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,8CAAuB;AACvB,uCAAyB;AACzB,uCAAyB;AAEzB,mDAA2C;AAC3C,6CAA+B;AAE/B,0BAAU,CAAC,aAAI,CAAC,CAAC;AAEjB,aAAI,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE;IACvB,MAAM,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,GAAG,mCAAmC,EAAE,MAAM,CAAC,CAAC;IACvF,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,+BAA+B,EAAE,QAAQ,CAAC,CAAC,CAAC;AACtE,CAAC,CAAC,CAAC;AAEH,aAAI,CAAC,sDAAsD,EAAE,CAAC,CAAC,EAAE;IAE/D,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC;IAE3D,MAAM,KAAK,GAAG;QACZ,EAAE,EAAE,SAAS,QAAQ,GAAG,GAAG,EAAE;QAC7B,KAAK,EAAE,WAAW;KACnB,CAAC;IAEF,KAAK,MAAM,CAAC,KAAK,EAAE,YAAY,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;QAEzD,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,KAAK,CAAC;QAEjC,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QAClC,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;KACjC;AACH,CAAC,CAAC,CAAC;AAEH,aAAI,CAAC,uDAAuD,EAAE,CAAC,CAAC,EAAE;IAChE,KAAK,MAAM,KAAK,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE;QACpC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,KAAK,CAAC;QACjC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;KAC9B;AACH,CAAC,CAAC,CAAC;AAEH,aAAI,CAAC,2DAA2D,EAAE,CAAC,CAAC,EAAE;IAEpE,MAAM,OAAO,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC;IAEjC,MAAM,KAAK,GAAG;QACZ,GAAG,EAAE,aAAa;QAClB,GAAG,EAAE,aAAa;QAClB,CAAC,GAAG,OAAO,GAAG,CAAC,EAAE,CAAC,EAAE,aAAa,OAAO,EAAE;QAC1C,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,OAAO,EAAE;KAC7C,CAAC;IAEF,KAAK,MAAM,CAAC,KAAK,EAAE,YAAY,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;QAEzD,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,KAAK,CAAC;QAErC,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QACnC,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;KACjC;AACH,CAAC,CAAC,CAAC;AAEH,aAAI,CAAC,gEAAgE,EAAE,CAAC,CAAC,EAAE;IACzE,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,QAAQ,CAAC;IACxC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;AAChC,CAAC,CAAC,CAAC;AAEH,aAAI,CAAC,qCAAqC,EAAE,CAAC,CAAC,EAAE;IAC9C,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC;IAC/B,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACxB,CAAC,CAAC,CAAC"}
|
||||||
+74
@@ -0,0 +1,74 @@
|
|||||||
|
# `@actions/github`
|
||||||
|
|
||||||
|
> A hydrated Octokit client.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Returns an authenticated Octokit client that follows the machine [proxy settings](https://help.github.com/en/actions/hosting-your-own-runners/using-a-proxy-server-with-self-hosted-runners). See https://octokit.github.io/rest.js for the API.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const github = require('@actions/github');
|
||||||
|
const core = require('@actions/core');
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
// This should be a token with access to your repository scoped in as a secret.
|
||||||
|
// The YML workflow will need to set myToken with the GitHub Secret Token
|
||||||
|
// myToken: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
// https://help.github.com/en/actions/automating-your-workflow-with-github-actions/authenticating-with-the-github_token#about-the-github_token-secret
|
||||||
|
const myToken = core.getInput('myToken');
|
||||||
|
|
||||||
|
const octokit = new github.GitHub(myToken);
|
||||||
|
|
||||||
|
const { data: pullRequest } = await octokit.pulls.get({
|
||||||
|
owner: 'octokit',
|
||||||
|
repo: 'rest.js',
|
||||||
|
pull_number: 123,
|
||||||
|
mediaType: {
|
||||||
|
format: 'diff'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(pullRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
||||||
|
```
|
||||||
|
|
||||||
|
You can pass client options, as specified by [Octokit](https://octokit.github.io/rest.js/), as a second argument to the `GitHub` constructor.
|
||||||
|
|
||||||
|
You can also make GraphQL requests. See https://github.com/octokit/graphql.js for the API.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const result = await octokit.graphql(query, variables);
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, you can get the context of the current action:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const github = require('@actions/github');
|
||||||
|
|
||||||
|
const context = github.context;
|
||||||
|
|
||||||
|
const newIssue = await octokit.issues.create({
|
||||||
|
...context.repo,
|
||||||
|
title: 'New issue!',
|
||||||
|
body: 'Hello Universe!'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Webhook payload typescript definitions
|
||||||
|
|
||||||
|
The npm module `@octokit/webhooks` provides type definitions for the response payloads. You can cast the payload to these types for better type information.
|
||||||
|
|
||||||
|
First, install the npm module `npm install @octokit/webhooks`
|
||||||
|
|
||||||
|
Then, assert the type based on the eventName
|
||||||
|
```ts
|
||||||
|
import * as core from '@actions/core'
|
||||||
|
import * as github from '@actions/github'
|
||||||
|
import * as Webhooks from '@octokit/webhooks'
|
||||||
|
if (github.context.eventName === 'push') {
|
||||||
|
const pushPayload = github.context.payload as Webhooks.WebhookPayloadPush
|
||||||
|
core.info(`The head commit is: ${pushPayload.head}`)
|
||||||
|
}
|
||||||
|
```
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
import { WebhookPayload } from './interfaces';
|
||||||
|
export declare class Context {
|
||||||
|
/**
|
||||||
|
* Webhook payload object that triggered the workflow
|
||||||
|
*/
|
||||||
|
payload: WebhookPayload;
|
||||||
|
eventName: string;
|
||||||
|
sha: string;
|
||||||
|
ref: string;
|
||||||
|
workflow: string;
|
||||||
|
action: string;
|
||||||
|
actor: string;
|
||||||
|
/**
|
||||||
|
* Hydrate the context from the environment
|
||||||
|
*/
|
||||||
|
constructor();
|
||||||
|
get issue(): {
|
||||||
|
owner: string;
|
||||||
|
repo: string;
|
||||||
|
number: number;
|
||||||
|
};
|
||||||
|
get repo(): {
|
||||||
|
owner: string;
|
||||||
|
repo: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const fs_1 = require("fs");
|
||||||
|
const os_1 = require("os");
|
||||||
|
class Context {
|
||||||
|
/**
|
||||||
|
* Hydrate the context from the environment
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
this.payload = {};
|
||||||
|
if (process.env.GITHUB_EVENT_PATH) {
|
||||||
|
if (fs_1.existsSync(process.env.GITHUB_EVENT_PATH)) {
|
||||||
|
this.payload = JSON.parse(fs_1.readFileSync(process.env.GITHUB_EVENT_PATH, { encoding: 'utf8' }));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const path = process.env.GITHUB_EVENT_PATH;
|
||||||
|
process.stdout.write(`GITHUB_EVENT_PATH ${path} does not exist${os_1.EOL}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.eventName = process.env.GITHUB_EVENT_NAME;
|
||||||
|
this.sha = process.env.GITHUB_SHA;
|
||||||
|
this.ref = process.env.GITHUB_REF;
|
||||||
|
this.workflow = process.env.GITHUB_WORKFLOW;
|
||||||
|
this.action = process.env.GITHUB_ACTION;
|
||||||
|
this.actor = process.env.GITHUB_ACTOR;
|
||||||
|
}
|
||||||
|
get issue() {
|
||||||
|
const payload = this.payload;
|
||||||
|
return Object.assign(Object.assign({}, this.repo), { number: (payload.issue || payload.pull_request || payload).number });
|
||||||
|
}
|
||||||
|
get repo() {
|
||||||
|
if (process.env.GITHUB_REPOSITORY) {
|
||||||
|
const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/');
|
||||||
|
return { owner, repo };
|
||||||
|
}
|
||||||
|
if (this.payload.repository) {
|
||||||
|
return {
|
||||||
|
owner: this.payload.repository.owner.login,
|
||||||
|
repo: this.payload.repository.name
|
||||||
|
};
|
||||||
|
}
|
||||||
|
throw new Error("context.repo requires a GITHUB_REPOSITORY environment variable like 'owner/repo'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.Context = Context;
|
||||||
|
//# sourceMappingURL=context.js.map
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":";;AAEA,2BAA2C;AAC3C,2BAAsB;AAEtB,MAAa,OAAO;IAalB;;OAEG;IACH;QACE,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;QACjB,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE;YACjC,IAAI,eAAU,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE;gBAC7C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CACvB,iBAAY,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,EAAC,QAAQ,EAAE,MAAM,EAAC,CAAC,CAChE,CAAA;aACF;iBAAM;gBACL,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAA;gBAC1C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qBAAqB,IAAI,kBAAkB,QAAG,EAAE,CAAC,CAAA;aACvE;SACF;QACD,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,iBAA2B,CAAA;QACxD,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,UAAoB,CAAA;QAC3C,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,UAAoB,CAAA;QAC3C,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,eAAyB,CAAA;QACrD,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,aAAuB,CAAA;QACjD,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,YAAsB,CAAA;IACjD,CAAC;IAED,IAAI,KAAK;QACP,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAA;QAE5B,uCACK,IAAI,CAAC,IAAI,KACZ,MAAM,EAAE,CAAC,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,CAAC,MAAM,IAClE;IACH,CAAC;IAED,IAAI,IAAI;QACN,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE;YACjC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YAC9D,OAAO,EAAC,KAAK,EAAE,IAAI,EAAC,CAAA;SACrB;QAED,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;YAC3B,OAAO;gBACL,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK;gBAC1C,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI;aACnC,CAAA;SACF;QAED,MAAM,IAAI,KAAK,CACb,kFAAkF,CACnF,CAAA;IACH,CAAC;CACF;AA9DD,0BA8DC"}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
import { graphql as GraphQL } from '@octokit/graphql/dist-types/types';
|
||||||
|
import { Octokit } from '@octokit/rest';
|
||||||
|
import * as Context from './context';
|
||||||
|
export declare const context: Context.Context;
|
||||||
|
export declare class GitHub extends Octokit {
|
||||||
|
graphql: GraphQL;
|
||||||
|
/**
|
||||||
|
* Sets up the REST client and GraphQL client with auth and proxy support.
|
||||||
|
* The parameter `token` or `opts.auth` must be supplied. The GraphQL client
|
||||||
|
* authorization is not setup when `opts.auth` is a function or object.
|
||||||
|
*
|
||||||
|
* @param token Auth token
|
||||||
|
* @param opts Octokit options
|
||||||
|
*/
|
||||||
|
constructor(token: string, opts?: Omit<Octokit.Options, 'auth'>);
|
||||||
|
constructor(opts: Octokit.Options);
|
||||||
|
/**
|
||||||
|
* Disambiguates the constructor overload parameters
|
||||||
|
*/
|
||||||
|
private static disambiguate;
|
||||||
|
private static getOctokitOptions;
|
||||||
|
private static getGraphQL;
|
||||||
|
private static getAuthString;
|
||||||
|
private static getProxyAgent;
|
||||||
|
private static getApiBaseUrl;
|
||||||
|
private static getGraphQLBaseUrl;
|
||||||
|
}
|
||||||
+108
@@ -0,0 +1,108 @@
|
|||||||
|
"use strict";
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||||
|
result["default"] = mod;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
// Originally pulled from https://github.com/JasonEtco/actions-toolkit/blob/master/src/github.ts
|
||||||
|
const graphql_1 = require("@octokit/graphql");
|
||||||
|
const rest_1 = require("@octokit/rest");
|
||||||
|
const Context = __importStar(require("./context"));
|
||||||
|
const httpClient = __importStar(require("@actions/http-client"));
|
||||||
|
// We need this in order to extend Octokit
|
||||||
|
rest_1.Octokit.prototype = new rest_1.Octokit();
|
||||||
|
exports.context = new Context.Context();
|
||||||
|
class GitHub extends rest_1.Octokit {
|
||||||
|
constructor(token, opts) {
|
||||||
|
super(GitHub.getOctokitOptions(GitHub.disambiguate(token, opts)));
|
||||||
|
this.graphql = GitHub.getGraphQL(GitHub.disambiguate(token, opts));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Disambiguates the constructor overload parameters
|
||||||
|
*/
|
||||||
|
static disambiguate(token, opts) {
|
||||||
|
return [
|
||||||
|
typeof token === 'string' ? token : '',
|
||||||
|
typeof token === 'object' ? token : opts || {}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
static getOctokitOptions(args) {
|
||||||
|
const token = args[0];
|
||||||
|
const options = Object.assign({}, args[1]); // Shallow clone - don't mutate the object provided by the caller
|
||||||
|
// Base URL - GHES or Dotcom
|
||||||
|
options.baseUrl = options.baseUrl || this.getApiBaseUrl();
|
||||||
|
// Auth
|
||||||
|
const auth = GitHub.getAuthString(token, options);
|
||||||
|
if (auth) {
|
||||||
|
options.auth = auth;
|
||||||
|
}
|
||||||
|
// Proxy
|
||||||
|
const agent = GitHub.getProxyAgent(options.baseUrl, options);
|
||||||
|
if (agent) {
|
||||||
|
// Shallow clone - don't mutate the object provided by the caller
|
||||||
|
options.request = options.request ? Object.assign({}, options.request) : {};
|
||||||
|
// Set the agent
|
||||||
|
options.request.agent = agent;
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
static getGraphQL(args) {
|
||||||
|
const defaults = {};
|
||||||
|
defaults.baseUrl = this.getGraphQLBaseUrl();
|
||||||
|
const token = args[0];
|
||||||
|
const options = args[1];
|
||||||
|
// Authorization
|
||||||
|
const auth = this.getAuthString(token, options);
|
||||||
|
if (auth) {
|
||||||
|
defaults.headers = {
|
||||||
|
authorization: auth
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Proxy
|
||||||
|
const agent = GitHub.getProxyAgent(defaults.baseUrl, options);
|
||||||
|
if (agent) {
|
||||||
|
defaults.request = { agent };
|
||||||
|
}
|
||||||
|
return graphql_1.graphql.defaults(defaults);
|
||||||
|
}
|
||||||
|
static getAuthString(token, options) {
|
||||||
|
// Validate args
|
||||||
|
if (!token && !options.auth) {
|
||||||
|
throw new Error('Parameter token or opts.auth is required');
|
||||||
|
}
|
||||||
|
else if (token && options.auth) {
|
||||||
|
throw new Error('Parameters token and opts.auth may not both be specified');
|
||||||
|
}
|
||||||
|
return typeof options.auth === 'string' ? options.auth : `token ${token}`;
|
||||||
|
}
|
||||||
|
static getProxyAgent(destinationUrl, options) {
|
||||||
|
var _a;
|
||||||
|
if (!((_a = options.request) === null || _a === void 0 ? void 0 : _a.agent)) {
|
||||||
|
if (httpClient.getProxyUrl(destinationUrl)) {
|
||||||
|
const hc = new httpClient.HttpClient();
|
||||||
|
return hc.getAgent(destinationUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
static getApiBaseUrl() {
|
||||||
|
return process.env['GITHUB_API_URL'] || 'https://api.github.com';
|
||||||
|
}
|
||||||
|
static getGraphQLBaseUrl() {
|
||||||
|
let url = process.env['GITHUB_GRAPHQL_URL'] || 'https://api.github.com/graphql';
|
||||||
|
// Shouldn't be a trailing slash, but remove if so
|
||||||
|
if (url.endsWith('/')) {
|
||||||
|
url = url.substr(0, url.length - 1);
|
||||||
|
}
|
||||||
|
// Remove trailing "/graphql"
|
||||||
|
if (url.toUpperCase().endsWith('/GRAPHQL')) {
|
||||||
|
url = url.substr(0, url.length - '/graphql'.length);
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.GitHub = GitHub;
|
||||||
|
//# sourceMappingURL=github.js.map
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"github.js","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":";;;;;;;;;AAAA,gGAAgG;AAChG,8CAAwC;AAUxC,wCAAqC;AACrC,mDAAoC;AAEpC,iEAAkD;AAElD,0CAA0C;AAC1C,cAAO,CAAC,SAAS,GAAG,IAAI,cAAO,EAAE,CAAA;AAEpB,QAAA,OAAO,GAAG,IAAI,OAAO,CAAC,OAAO,EAAE,CAAA;AAE5C,MAAa,MAAO,SAAQ,cAAO;IAiBjC,YAAY,KAA+B,EAAE,IAAsB;QACjE,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;QAEjE,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAA;IACpE,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,YAAY,CACzB,KAA+B,EAC/B,IAAsB;QAEtB,OAAO;YACL,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;YACtC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE;SAC/C,CAAA;IACH,CAAC;IAEO,MAAM,CAAC,iBAAiB,CAC9B,IAA+B;QAE/B,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;QACrB,MAAM,OAAO,qBAAO,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA,CAAC,iEAAiE;QAE9F,4BAA4B;QAC5B,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,aAAa,EAAE,CAAA;QAEzD,OAAO;QACP,MAAM,IAAI,GAAG,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;QACjD,IAAI,IAAI,EAAE;YACR,OAAO,CAAC,IAAI,GAAG,IAAI,CAAA;SACpB;QAED,QAAQ;QACR,MAAM,KAAK,GAAG,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAC5D,IAAI,KAAK,EAAE;YACT,iEAAiE;YACjE,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,mBAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,CAAA;YAE7D,gBAAgB;YAChB,OAAO,CAAC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAA;SAC9B;QAED,OAAO,OAAO,CAAA;IAChB,CAAC;IAEO,MAAM,CAAC,UAAU,CAAC,IAA+B;QACvD,MAAM,QAAQ,GAA6B,EAAE,CAAA;QAC7C,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAA;QAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;QACrB,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;QAEvB,gBAAgB;QAChB,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;QAC/C,IAAI,IAAI,EAAE;YACR,QAAQ,CAAC,OAAO,GAAG;gBACjB,aAAa,EAAE,IAAI;aACpB,CAAA;SACF;QAED,QAAQ;QACR,MAAM,KAAK,GAAG,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAC7D,IAAI,KAAK,EAAE;YACT,QAAQ,CAAC,OAAO,GAAG,EAAC,KAAK,EAAC,CAAA;SAC3B;QAED,OAAO,iBAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;IACnC,CAAC;IAEO,MAAM,CAAC,aAAa,CAC1B,KAAa,EACb,OAAwB;QAExB,gBAAgB;QAChB,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;YAC3B,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAA;SAC5D;aAAM,IAAI,KAAK,IAAI,OAAO,CAAC,IAAI,EAAE;YAChC,MAAM,IAAI,KAAK,CACb,0DAA0D,CAC3D,CAAA;SACF;QAED,OAAO,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,KAAK,EAAE,CAAA;IAC3E,CAAC;IAEO,MAAM,CAAC,aAAa,CAC1B,cAAsB,EACtB,OAAwB;;QAExB,IAAI,QAAC,OAAO,CAAC,OAAO,0CAAE,KAAK,CAAA,EAAE;YAC3B,IAAI,UAAU,CAAC,WAAW,CAAC,cAAc,CAAC,EAAE;gBAC1C,MAAM,EAAE,GAAG,IAAI,UAAU,CAAC,UAAU,EAAE,CAAA;gBACtC,OAAO,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAA;aACnC;SACF;QAED,OAAO,SAAS,CAAA;IAClB,CAAC;IAEO,MAAM,CAAC,aAAa;QAC1B,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,wBAAwB,CAAA;IAClE,CAAC;IAEO,MAAM,CAAC,iBAAiB;QAC9B,IAAI,GAAG,GACL,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,gCAAgC,CAAA;QAEvE,kDAAkD;QAClD,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;YACrB,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;SACpC;QAED,6BAA6B;QAC7B,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;YAC1C,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAA;SACpD;QACD,OAAO,GAAG,CAAA;IACZ,CAAC;CACF;AAxID,wBAwIC"}
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
export interface PayloadRepository {
|
||||||
|
[key: string]: any;
|
||||||
|
full_name?: string;
|
||||||
|
name: string;
|
||||||
|
owner: {
|
||||||
|
[key: string]: any;
|
||||||
|
login: string;
|
||||||
|
name?: string;
|
||||||
|
};
|
||||||
|
html_url?: string;
|
||||||
|
}
|
||||||
|
export interface WebhookPayload {
|
||||||
|
[key: string]: any;
|
||||||
|
repository?: PayloadRepository;
|
||||||
|
issue?: {
|
||||||
|
[key: string]: any;
|
||||||
|
number: number;
|
||||||
|
html_url?: string;
|
||||||
|
body?: string;
|
||||||
|
};
|
||||||
|
pull_request?: {
|
||||||
|
[key: string]: any;
|
||||||
|
number: number;
|
||||||
|
html_url?: string;
|
||||||
|
body?: string;
|
||||||
|
};
|
||||||
|
sender?: {
|
||||||
|
[key: string]: any;
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
action?: string;
|
||||||
|
installation?: {
|
||||||
|
id: number;
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
"use strict";
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
//# sourceMappingURL=interfaces.js.map
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":";AAAA,uDAAuD"}
|
||||||
Generated
Vendored
Generated
Vendored
+7
-10
@@ -99,17 +99,14 @@ If your target runtime environments supports async iterators (such as most moder
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const parameters = {
|
const parameters = {
|
||||||
owner: "octocat",
|
owner: "octocat",
|
||||||
repo: "hello-world",
|
repo: "hello-world",
|
||||||
since: "2010-10-01",
|
since: "2010-10-01",
|
||||||
per_page: 100
|
per_page: 100
|
||||||
};
|
}
|
||||||
for await (const response of octokit.paginate.iterator(
|
for await (const response of octokit.paginate.iterator("GET /repos/:owner/:repo/issues", parameters)) {
|
||||||
"GET /repos/:owner/:repo/issues",
|
|
||||||
parameters
|
|
||||||
)) {
|
|
||||||
// do whatever you want with each response, break out of the loop, etc.
|
// do whatever you want with each response, break out of the loop, etc.
|
||||||
console.log(response.data.title);
|
console.log(response.data.title)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Generated
Vendored
+21
-8
@@ -2,26 +2,32 @@
|
|||||||
|
|
||||||
Object.defineProperty(exports, '__esModule', { value: true });
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
const VERSION = "2.0.2";
|
const VERSION = "1.1.2";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some “list” response that can be paginated have a different response structure
|
* Some “list” response that can be paginated have a different response structure
|
||||||
*
|
*
|
||||||
* They have a `total_count` key in the response (search also has `incomplete_results`,
|
* They have a `total_count` key in the response (search also has `incomplete_results`,
|
||||||
* /installation/repositories also has `repository_selection`), as well as a key with
|
* /installation/repositories also has `repository_selection`), as well as a key with
|
||||||
* the list of the items which name varies from endpoint to endpoint.
|
* the list of the items which name varies from endpoint to endpoint:
|
||||||
|
*
|
||||||
|
* - https://developer.github.com/v3/search/#example (key `items`)
|
||||||
|
* - https://developer.github.com/v3/checks/runs/#response-3 (key: `check_runs`)
|
||||||
|
* - https://developer.github.com/v3/checks/suites/#response-1 (key: `check_suites`)
|
||||||
|
* - https://developer.github.com/v3/apps/installations/#list-repositories (key: `repositories`)
|
||||||
|
* - https://developer.github.com/v3/apps/installations/#list-installations-for-a-user (key `installations`)
|
||||||
*
|
*
|
||||||
* Octokit normalizes these responses so that paginated results are always returned following
|
* Octokit normalizes these responses so that paginated results are always returned following
|
||||||
* the same structure. One challenge is that if the list response has only one page, no Link
|
* the same structure. One challenge is that if the list response has only one page, no Link
|
||||||
* header is provided, so this header alone is not sufficient to check wether a response is
|
* header is provided, so this header alone is not sufficient to check wether a response is
|
||||||
* paginated or not.
|
* paginated or not. For the exceptions with the namespace, a fallback check for the route
|
||||||
*
|
* paths has to be added in order to normalize the response. We cannot check for the total_count
|
||||||
* We check if a "total_count" key is present in the response data, but also make sure that
|
* property because it also exists in the response of Get the combined status for a specific ref.
|
||||||
* a "url" property is not, as the "Get the combined status for a specific ref" endpoint would
|
|
||||||
* otherwise match: https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref
|
|
||||||
*/
|
*/
|
||||||
|
const REGEX = [/^\/search\//, /^\/repos\/[^/]+\/[^/]+\/commits\/[^/]+\/(check-runs|check-suites)([^/]|$)/, /^\/installation\/repositories([^/]|$)/, /^\/user\/installations([^/]|$)/, /^\/repos\/[^/]+\/[^/]+\/actions\/secrets([^/]|$)/, /^\/repos\/[^/]+\/[^/]+\/actions\/workflows(\/[^/]+\/runs)?([^/]|$)/, /^\/repos\/[^/]+\/[^/]+\/actions\/runs(\/[^/]+\/(artifacts|jobs))?([^/]|$)/];
|
||||||
function normalizePaginatedListResponse(octokit, url, response) {
|
function normalizePaginatedListResponse(octokit, url, response) {
|
||||||
const responseNeedsNormalization = "total_count" in response.data && !("url" in response.data);
|
const path = url.replace(octokit.request.endpoint.DEFAULTS.baseUrl, "");
|
||||||
|
const responseNeedsNormalization = REGEX.find(regex => regex.test(path));
|
||||||
if (!responseNeedsNormalization) return; // keep the additional properties intact as there is currently no other way
|
if (!responseNeedsNormalization) return; // keep the additional properties intact as there is currently no other way
|
||||||
// to retrieve the same information.
|
// to retrieve the same information.
|
||||||
|
|
||||||
@@ -44,6 +50,13 @@ function normalizePaginatedListResponse(octokit, url, response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
response.data.total_count = totalCount;
|
response.data.total_count = totalCount;
|
||||||
|
Object.defineProperty(response.data, namespaceKey, {
|
||||||
|
get() {
|
||||||
|
octokit.log.warn(`[@octokit/paginate-rest] "response.data.${namespaceKey}" is deprecated for "GET ${path}". Get the results directly from "response.data"`);
|
||||||
|
return Array.from(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function iterator(octokit, route, parameters) {
|
function iterator(octokit, route, parameters) {
|
||||||
Generated
Vendored
+1
File diff suppressed because one or more lines are too long
Generated
Vendored
Generated
Vendored
+27
-7
@@ -3,19 +3,33 @@
|
|||||||
*
|
*
|
||||||
* They have a `total_count` key in the response (search also has `incomplete_results`,
|
* They have a `total_count` key in the response (search also has `incomplete_results`,
|
||||||
* /installation/repositories also has `repository_selection`), as well as a key with
|
* /installation/repositories also has `repository_selection`), as well as a key with
|
||||||
* the list of the items which name varies from endpoint to endpoint.
|
* the list of the items which name varies from endpoint to endpoint:
|
||||||
|
*
|
||||||
|
* - https://developer.github.com/v3/search/#example (key `items`)
|
||||||
|
* - https://developer.github.com/v3/checks/runs/#response-3 (key: `check_runs`)
|
||||||
|
* - https://developer.github.com/v3/checks/suites/#response-1 (key: `check_suites`)
|
||||||
|
* - https://developer.github.com/v3/apps/installations/#list-repositories (key: `repositories`)
|
||||||
|
* - https://developer.github.com/v3/apps/installations/#list-installations-for-a-user (key `installations`)
|
||||||
*
|
*
|
||||||
* Octokit normalizes these responses so that paginated results are always returned following
|
* Octokit normalizes these responses so that paginated results are always returned following
|
||||||
* the same structure. One challenge is that if the list response has only one page, no Link
|
* the same structure. One challenge is that if the list response has only one page, no Link
|
||||||
* header is provided, so this header alone is not sufficient to check wether a response is
|
* header is provided, so this header alone is not sufficient to check wether a response is
|
||||||
* paginated or not.
|
* paginated or not. For the exceptions with the namespace, a fallback check for the route
|
||||||
*
|
* paths has to be added in order to normalize the response. We cannot check for the total_count
|
||||||
* We check if a "total_count" key is present in the response data, but also make sure that
|
* property because it also exists in the response of Get the combined status for a specific ref.
|
||||||
* a "url" property is not, as the "Get the combined status for a specific ref" endpoint would
|
|
||||||
* otherwise match: https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref
|
|
||||||
*/
|
*/
|
||||||
|
const REGEX = [
|
||||||
|
/^\/search\//,
|
||||||
|
/^\/repos\/[^/]+\/[^/]+\/commits\/[^/]+\/(check-runs|check-suites)([^/]|$)/,
|
||||||
|
/^\/installation\/repositories([^/]|$)/,
|
||||||
|
/^\/user\/installations([^/]|$)/,
|
||||||
|
/^\/repos\/[^/]+\/[^/]+\/actions\/secrets([^/]|$)/,
|
||||||
|
/^\/repos\/[^/]+\/[^/]+\/actions\/workflows(\/[^/]+\/runs)?([^/]|$)/,
|
||||||
|
/^\/repos\/[^/]+\/[^/]+\/actions\/runs(\/[^/]+\/(artifacts|jobs))?([^/]|$)/
|
||||||
|
];
|
||||||
export function normalizePaginatedListResponse(octokit, url, response) {
|
export function normalizePaginatedListResponse(octokit, url, response) {
|
||||||
const responseNeedsNormalization = "total_count" in response.data && !("url" in response.data);
|
const path = url.replace(octokit.request.endpoint.DEFAULTS.baseUrl, "");
|
||||||
|
const responseNeedsNormalization = REGEX.find(regex => regex.test(path));
|
||||||
if (!responseNeedsNormalization)
|
if (!responseNeedsNormalization)
|
||||||
return;
|
return;
|
||||||
// keep the additional properties intact as there is currently no other way
|
// keep the additional properties intact as there is currently no other way
|
||||||
@@ -36,4 +50,10 @@ export function normalizePaginatedListResponse(octokit, url, response) {
|
|||||||
response.data.repository_selection = repositorySelection;
|
response.data.repository_selection = repositorySelection;
|
||||||
}
|
}
|
||||||
response.data.total_count = totalCount;
|
response.data.total_count = totalCount;
|
||||||
|
Object.defineProperty(response.data, namespaceKey, {
|
||||||
|
get() {
|
||||||
|
octokit.log.warn(`[@octokit/paginate-rest] "response.data.${namespaceKey}" is deprecated for "GET ${path}". Get the results directly from "response.data"`);
|
||||||
|
return Array.from(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Generated
Vendored
Generated
Vendored
Generated
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
export const VERSION = "1.1.2";
|
||||||
Generated
Vendored
Generated
Vendored
+10
-6
@@ -3,16 +3,20 @@
|
|||||||
*
|
*
|
||||||
* They have a `total_count` key in the response (search also has `incomplete_results`,
|
* They have a `total_count` key in the response (search also has `incomplete_results`,
|
||||||
* /installation/repositories also has `repository_selection`), as well as a key with
|
* /installation/repositories also has `repository_selection`), as well as a key with
|
||||||
* the list of the items which name varies from endpoint to endpoint.
|
* the list of the items which name varies from endpoint to endpoint:
|
||||||
|
*
|
||||||
|
* - https://developer.github.com/v3/search/#example (key `items`)
|
||||||
|
* - https://developer.github.com/v3/checks/runs/#response-3 (key: `check_runs`)
|
||||||
|
* - https://developer.github.com/v3/checks/suites/#response-1 (key: `check_suites`)
|
||||||
|
* - https://developer.github.com/v3/apps/installations/#list-repositories (key: `repositories`)
|
||||||
|
* - https://developer.github.com/v3/apps/installations/#list-installations-for-a-user (key `installations`)
|
||||||
*
|
*
|
||||||
* Octokit normalizes these responses so that paginated results are always returned following
|
* Octokit normalizes these responses so that paginated results are always returned following
|
||||||
* the same structure. One challenge is that if the list response has only one page, no Link
|
* the same structure. One challenge is that if the list response has only one page, no Link
|
||||||
* header is provided, so this header alone is not sufficient to check wether a response is
|
* header is provided, so this header alone is not sufficient to check wether a response is
|
||||||
* paginated or not.
|
* paginated or not. For the exceptions with the namespace, a fallback check for the route
|
||||||
*
|
* paths has to be added in order to normalize the response. We cannot check for the total_count
|
||||||
* We check if a "total_count" key is present in the response data, but also make sure that
|
* property because it also exists in the response of Get the combined status for a specific ref.
|
||||||
* a "url" property is not, as the "Get the combined status for a specific ref" endpoint would
|
|
||||||
* otherwise match: https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref
|
|
||||||
*/
|
*/
|
||||||
import { Octokit } from "@octokit/core";
|
import { Octokit } from "@octokit/core";
|
||||||
import { OctokitResponse } from "./types";
|
import { OctokitResponse } from "./types";
|
||||||
Generated
Vendored
Generated
Vendored
Generated
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
export declare const VERSION = "1.1.2";
|
||||||
Generated
Vendored
+28
-8
@@ -1,23 +1,37 @@
|
|||||||
const VERSION = "2.0.2";
|
const VERSION = "1.1.2";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some “list” response that can be paginated have a different response structure
|
* Some “list” response that can be paginated have a different response structure
|
||||||
*
|
*
|
||||||
* They have a `total_count` key in the response (search also has `incomplete_results`,
|
* They have a `total_count` key in the response (search also has `incomplete_results`,
|
||||||
* /installation/repositories also has `repository_selection`), as well as a key with
|
* /installation/repositories also has `repository_selection`), as well as a key with
|
||||||
* the list of the items which name varies from endpoint to endpoint.
|
* the list of the items which name varies from endpoint to endpoint:
|
||||||
|
*
|
||||||
|
* - https://developer.github.com/v3/search/#example (key `items`)
|
||||||
|
* - https://developer.github.com/v3/checks/runs/#response-3 (key: `check_runs`)
|
||||||
|
* - https://developer.github.com/v3/checks/suites/#response-1 (key: `check_suites`)
|
||||||
|
* - https://developer.github.com/v3/apps/installations/#list-repositories (key: `repositories`)
|
||||||
|
* - https://developer.github.com/v3/apps/installations/#list-installations-for-a-user (key `installations`)
|
||||||
*
|
*
|
||||||
* Octokit normalizes these responses so that paginated results are always returned following
|
* Octokit normalizes these responses so that paginated results are always returned following
|
||||||
* the same structure. One challenge is that if the list response has only one page, no Link
|
* the same structure. One challenge is that if the list response has only one page, no Link
|
||||||
* header is provided, so this header alone is not sufficient to check wether a response is
|
* header is provided, so this header alone is not sufficient to check wether a response is
|
||||||
* paginated or not.
|
* paginated or not. For the exceptions with the namespace, a fallback check for the route
|
||||||
*
|
* paths has to be added in order to normalize the response. We cannot check for the total_count
|
||||||
* We check if a "total_count" key is present in the response data, but also make sure that
|
* property because it also exists in the response of Get the combined status for a specific ref.
|
||||||
* a "url" property is not, as the "Get the combined status for a specific ref" endpoint would
|
|
||||||
* otherwise match: https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref
|
|
||||||
*/
|
*/
|
||||||
|
const REGEX = [
|
||||||
|
/^\/search\//,
|
||||||
|
/^\/repos\/[^/]+\/[^/]+\/commits\/[^/]+\/(check-runs|check-suites)([^/]|$)/,
|
||||||
|
/^\/installation\/repositories([^/]|$)/,
|
||||||
|
/^\/user\/installations([^/]|$)/,
|
||||||
|
/^\/repos\/[^/]+\/[^/]+\/actions\/secrets([^/]|$)/,
|
||||||
|
/^\/repos\/[^/]+\/[^/]+\/actions\/workflows(\/[^/]+\/runs)?([^/]|$)/,
|
||||||
|
/^\/repos\/[^/]+\/[^/]+\/actions\/runs(\/[^/]+\/(artifacts|jobs))?([^/]|$)/
|
||||||
|
];
|
||||||
function normalizePaginatedListResponse(octokit, url, response) {
|
function normalizePaginatedListResponse(octokit, url, response) {
|
||||||
const responseNeedsNormalization = "total_count" in response.data && !("url" in response.data);
|
const path = url.replace(octokit.request.endpoint.DEFAULTS.baseUrl, "");
|
||||||
|
const responseNeedsNormalization = REGEX.find(regex => regex.test(path));
|
||||||
if (!responseNeedsNormalization)
|
if (!responseNeedsNormalization)
|
||||||
return;
|
return;
|
||||||
// keep the additional properties intact as there is currently no other way
|
// keep the additional properties intact as there is currently no other way
|
||||||
@@ -38,6 +52,12 @@ function normalizePaginatedListResponse(octokit, url, response) {
|
|||||||
response.data.repository_selection = repositorySelection;
|
response.data.repository_selection = repositorySelection;
|
||||||
}
|
}
|
||||||
response.data.total_count = totalCount;
|
response.data.total_count = totalCount;
|
||||||
|
Object.defineProperty(response.data, namespaceKey, {
|
||||||
|
get() {
|
||||||
|
octokit.log.warn(`[@octokit/paginate-rest] "response.data.${namespaceKey}" is deprecated for "GET ${path}". Get the results directly from "response.data"`);
|
||||||
|
return Array.from(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function iterator(octokit, route, parameters) {
|
function iterator(octokit, route, parameters) {
|
||||||
Generated
Vendored
+1
File diff suppressed because one or more lines are too long
Generated
Vendored
+7
-7
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@octokit/plugin-paginate-rest",
|
"name": "@octokit/plugin-paginate-rest",
|
||||||
"description": "Octokit plugin to paginate REST API endpoint responses",
|
"description": "Octokit plugin to paginate REST API endpoint responses",
|
||||||
"version": "2.0.2",
|
"version": "1.1.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"files": [
|
"files": [
|
||||||
"dist-*/",
|
"dist-*/",
|
||||||
@@ -22,18 +22,18 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@octokit/core": "^2.0.0",
|
"@octokit/core": "^2.0.0",
|
||||||
"@pika/pack": "^0.5.0",
|
"@pika/pack": "^0.5.0",
|
||||||
"@pika/plugin-build-node": "^0.9.0",
|
"@pika/plugin-build-node": "^0.8.1",
|
||||||
"@pika/plugin-build-web": "^0.9.0",
|
"@pika/plugin-build-web": "^0.8.1",
|
||||||
"@pika/plugin-ts-standard-pkg": "^0.9.0",
|
"@pika/plugin-ts-standard-pkg": "^0.8.1",
|
||||||
"@types/fetch-mock": "^7.3.1",
|
"@types/fetch-mock": "^7.3.1",
|
||||||
"@types/jest": "^25.1.0",
|
"@types/jest": "^24.0.18",
|
||||||
"@types/node": "^13.1.0",
|
"@types/node": "^13.1.0",
|
||||||
"fetch-mock": "^9.0.0",
|
"fetch-mock": "^8.0.0",
|
||||||
"jest": "^24.9.0",
|
"jest": "^24.9.0",
|
||||||
"prettier": "^1.18.2",
|
"prettier": "^1.18.2",
|
||||||
"semantic-release": "^17.0.0",
|
"semantic-release": "^17.0.0",
|
||||||
"semantic-release-plugin-update-version-in-files": "^1.0.0",
|
"semantic-release-plugin-update-version-in-files": "^1.0.0",
|
||||||
"ts-jest": "^25.1.0",
|
"ts-jest": "^24.1.0",
|
||||||
"typescript": "^3.7.2"
|
"typescript": "^3.7.2"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
Generated
Vendored
Generated
Vendored
+2717
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+13196
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+1
File diff suppressed because one or more lines are too long
Generated
Vendored
+6624
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+38
@@ -0,0 +1,38 @@
|
|||||||
|
import { Deprecation } from "deprecation";
|
||||||
|
import endpointsByScope from "./generated/endpoints";
|
||||||
|
import { VERSION } from "./version";
|
||||||
|
import { registerEndpoints } from "./register-endpoints";
|
||||||
|
/**
|
||||||
|
* This plugin is a 1:1 copy of internal @octokit/rest plugins. The primary
|
||||||
|
* goal is to rebuild @octokit/rest on top of @octokit/core. Once that is
|
||||||
|
* done, we will remove the registerEndpoints methods and return the methods
|
||||||
|
* directly as with the other plugins. At that point we will also remove the
|
||||||
|
* legacy workarounds and deprecations.
|
||||||
|
*
|
||||||
|
* See the plan at
|
||||||
|
* https://github.com/octokit/plugin-rest-endpoint-methods.js/pull/1
|
||||||
|
*/
|
||||||
|
export function restEndpointMethods(octokit) {
|
||||||
|
// @ts-ignore
|
||||||
|
octokit.registerEndpoints = registerEndpoints.bind(null, octokit);
|
||||||
|
registerEndpoints(octokit, endpointsByScope);
|
||||||
|
// Aliasing scopes for backward compatibility
|
||||||
|
// See https://github.com/octokit/rest.js/pull/1134
|
||||||
|
[
|
||||||
|
["gitdata", "git"],
|
||||||
|
["authorization", "oauthAuthorizations"],
|
||||||
|
["pullRequests", "pulls"]
|
||||||
|
].forEach(([deprecatedScope, scope]) => {
|
||||||
|
Object.defineProperty(octokit, deprecatedScope, {
|
||||||
|
get() {
|
||||||
|
octokit.log.warn(
|
||||||
|
// @ts-ignore
|
||||||
|
new Deprecation(`[@octokit/plugin-rest-endpoint-methods] "octokit.${deprecatedScope}.*" methods are deprecated, use "octokit.${scope}.*" instead`));
|
||||||
|
// @ts-ignore
|
||||||
|
return octokit[scope];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
restEndpointMethods.VERSION = VERSION;
|
||||||
Generated
Vendored
+60
@@ -0,0 +1,60 @@
|
|||||||
|
import { Deprecation } from "deprecation";
|
||||||
|
export function registerEndpoints(octokit, routes) {
|
||||||
|
Object.keys(routes).forEach(namespaceName => {
|
||||||
|
if (!octokit[namespaceName]) {
|
||||||
|
octokit[namespaceName] = {};
|
||||||
|
}
|
||||||
|
Object.keys(routes[namespaceName]).forEach(apiName => {
|
||||||
|
const apiOptions = routes[namespaceName][apiName];
|
||||||
|
const endpointDefaults = ["method", "url", "headers"].reduce((map, key) => {
|
||||||
|
if (typeof apiOptions[key] !== "undefined") {
|
||||||
|
map[key] = apiOptions[key];
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}, {});
|
||||||
|
endpointDefaults.request = {
|
||||||
|
validate: apiOptions.params
|
||||||
|
};
|
||||||
|
let request = octokit.request.defaults(endpointDefaults);
|
||||||
|
// patch request & endpoint methods to support deprecated parameters.
|
||||||
|
// Not the most elegant solution, but we don’t want to move deprecation
|
||||||
|
// logic into octokit/endpoint.js as it’s out of scope
|
||||||
|
const hasDeprecatedParam = Object.keys(apiOptions.params || {}).find(key => apiOptions.params[key].deprecated);
|
||||||
|
if (hasDeprecatedParam) {
|
||||||
|
const patch = patchForDeprecation.bind(null, octokit, apiOptions);
|
||||||
|
request = patch(octokit.request.defaults(endpointDefaults), `.${namespaceName}.${apiName}()`);
|
||||||
|
request.endpoint = patch(request.endpoint, `.${namespaceName}.${apiName}.endpoint()`);
|
||||||
|
request.endpoint.merge = patch(request.endpoint.merge, `.${namespaceName}.${apiName}.endpoint.merge()`);
|
||||||
|
}
|
||||||
|
if (apiOptions.deprecated) {
|
||||||
|
octokit[namespaceName][apiName] = Object.assign(function deprecatedEndpointMethod() {
|
||||||
|
octokit.log.warn(new Deprecation(`[@octokit/rest] ${apiOptions.deprecated}`));
|
||||||
|
octokit[namespaceName][apiName] = request;
|
||||||
|
return request.apply(null, arguments);
|
||||||
|
}, request);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
octokit[namespaceName][apiName] = request;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function patchForDeprecation(octokit, apiOptions, method, methodName) {
|
||||||
|
const patchedMethod = (options) => {
|
||||||
|
options = Object.assign({}, options);
|
||||||
|
Object.keys(options).forEach(key => {
|
||||||
|
if (apiOptions.params[key] && apiOptions.params[key].deprecated) {
|
||||||
|
const aliasKey = apiOptions.params[key].alias;
|
||||||
|
octokit.log.warn(new Deprecation(`[@octokit/rest] "${key}" parameter is deprecated for "${methodName}". Use "${aliasKey}" instead`));
|
||||||
|
if (!(aliasKey in options)) {
|
||||||
|
options[aliasKey] = options[key];
|
||||||
|
}
|
||||||
|
delete options[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return method(options);
|
||||||
|
};
|
||||||
|
Object.keys(method).forEach(key => {
|
||||||
|
patchedMethod[key] = method[key];
|
||||||
|
});
|
||||||
|
return patchedMethod;
|
||||||
|
}
|
||||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
export const VERSION = "2.4.0";
|
||||||
Generated
Vendored
+13085
File diff suppressed because it is too large
Load Diff
+6683
-926
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
export declare function registerEndpoints(octokit: any, routes: any): void;
|
||||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
import { RestEndpointMethods } from "./generated/rest-endpoint-methods-types";
|
||||||
|
export declare type Api = {
|
||||||
|
registerEndpoints: (endpoints: any) => void;
|
||||||
|
} & RestEndpointMethods;
|
||||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
export declare const VERSION = "2.4.0";
|
||||||
Generated
Vendored
+6726
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+1
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user