feat: Use new Codecov uploader

This commit is contained in:
Tom Hu
2021-06-24 10:50:37 -04:00
parent b215992d02
commit 635d4e88ad
21 changed files with 45214 additions and 3633 deletions

View File

@@ -5,7 +5,9 @@
"es2021": true "es2021": true
}, },
"extends": [ "extends": [
"google" "google",
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
], ],
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",
"parserOptions": { "parserOptions": {
@@ -15,5 +17,6 @@
"@typescript-eslint" "@typescript-eslint"
], ],
"rules": { "rules": {
"linebreak-style": 0
} }
} }

View File

@@ -2,7 +2,10 @@ name: Workflow for Codecov Action
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
run: run:
runs-on: ubuntu-latest runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
@@ -12,16 +15,16 @@ jobs:
run: npm run lint run: npm run lint
- name: Run tests and collect coverage - name: Run tests and collect coverage
run: npm run test run: npm run test
- name: Upload coverage to Codecov (script)
uses: ./
with:
files: ./coverage/script/coverage-final.json
flags: script,${{ matrix.os }}
name: codecov-script
- name: Upload coverage to Codecov (demo) - name: Upload coverage to Codecov (demo)
uses: ./ uses: ./
with: with:
files: ./coverage/calculator/coverage-final.json,./coverage/coverage-test/coverage-final.json files: ./coverage/calculator/coverage-final.json,./coverage/coverage-test/coverage-final.json
file: ./coverage/coverage-final.json file: ./coverage/coverage-final.json
flags: demo flags: demo,${{ matrix.os }}
name: codecov-demo name: codecov-demo
- name: Upload coverage to Codecov (script)
uses: ./
with:
files: ./coverage/script/coverage-final.json
flags: script
name: codecov-script

View File

@@ -1,3 +1,19 @@
## 2.0.0
On February 1, 2022, the `v1` uploader will be full sunset and no longer function. This is due
to the deprecation of the underlying bash uploader. This version uses the new [uploader](https://github.com/codecov/uploader).
The `v2` Action downloads, verifies, and runs the Codecov binary.
### Breaking Changes
- Multiple fields have not been transferred from the bash uploader or have been deprecated. Notably
many of the `functionalities` and `gcov_` arguments have been removed. Please check the documentation
for the full list.
### Features
- `dry-run` argument allows Codecov flow without uploading reports to Codecov
- (Enterprise only) `slug` allows specifying the repository slug manually
- (Enterprise only) `url` allows changing the upload host
## 1.5.2 ## 1.5.2
### Fixes ### Fixes
- # fix: Import version properly as string not object - # fix: Import version properly as string not object

View File

@@ -7,9 +7,24 @@
>The latest release of this Action adds support for tokenless uploads from GitHub Actions! >The latest release of this Action adds support for tokenless uploads from GitHub Actions!
## ⚠️ Deprecration of v1
**On February 1, 2022, this version will be fully sunset and no longer function**
Due to the [deprecation](https://about.codecov.io/blog/introducting-codecovs-new-uploader/) of the underlying bash uploader,
the Codecov GitHub Action has released `v2` which will use the new [uploader](https://github.com/codecov/uploader). You can learn
more about our deprecation plan and the new uploader on our [blog](https://about.codecov.io/blog/introducing-codecovs-new-uploader/).
We will be restricting any updates to the `v1` Action to security updates and hotfixes.
### Migration from `v1` to `v2`
The `v2` uploader has a few breaking changes for users
- Multiple fields have not been transferred from the bash uploader or have been deprecated. Notably
many of the `functionalities` and `gcov_` arguments have been removed. Please check the documentation
below for the full list.
## Usage ## Usage
To integrate Codecov with your Actions pipeline, specify the name of this repository with a tag number (`@v1` is recommended) as a `step` within your `workflow.yml` file. To integrate Codecov with your Actions pipeline, specify the name of this repository with a tag number (`@v2` is recommended) as a `step` within your `workflow.yml` file.
If you have a *private repository*, this Action also requires you to [provide an upload token](https://docs.codecov.io/docs/frequently-asked-questions#section-where-is-the-repository-upload-token-found-) from [codecov.io](https://www.codecov.io) (tip: in order to avoid exposing your token, store it as a `secret`). Optionally, you can choose to include up to four additional inputs to customize the upload context. **For public repositories, no token is needed** If you have a *private repository*, this Action also requires you to [provide an upload token](https://docs.codecov.io/docs/frequently-asked-questions#section-where-is-the-repository-upload-token-found-) from [codecov.io](https://www.codecov.io) (tip: in order to avoid exposing your token, store it as a `secret`). Optionally, you can choose to include up to four additional inputs to customize the upload context. **For public repositories, no token is needed**
@@ -18,7 +33,7 @@ Inside your `.github/workflows/workflow.yml` file:
```yaml ```yaml
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- uses: codecov/codecov-action@v1 - uses: codecov/codecov-action@v2
with: with:
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
files: ./coverage1.xml,./coverage2.xml # optional files: ./coverage1.xml,./coverage2.xml # optional
@@ -38,29 +53,14 @@ Codecov's Action currently supports five inputs from the user: `token`, `file`,
| `token` | Used to authorize coverage report uploads | *Required for private repos* | | `token` | Used to authorize coverage report uploads | *Required for private repos* |
| `files` | Comma-separated paths to the coverage report(s) | Optional | `files` | Comma-separated paths to the coverage report(s) | Optional
| `directory` | Directory to search for coverage reports. | Optional | `directory` | Directory to search for coverage reports. | Optional
| `dry_run` | Don't upload files to Codecov | Optional
| `flags` | Flag the upload to group coverage metrics (unittests, uitests, etc.). Multiple flags are separated by a comma (ui,chrome) | Optional | `flags` | Flag the upload to group coverage metrics (unittests, uitests, etc.). Multiple flags are separated by a comma (ui,chrome) | Optional
| | | | | |
| `aws_curl_args` | Extra curl arguments to communicate with AWS. | Optional
| `codecov_curl_args` | Extra curl arguments to communicate with Codecov. e.g., -U "--proxy http://http-proxy" | Optional
| `commit_parent` | The commit SHA of the parent for which you are uploading coverage. If not present, the parent will be determined using the API of your repository provider. When using the repository provider's API, the parent is determined via finding the closest ancestor to the commit. | Optional | `commit_parent` | The commit SHA of the parent for which you are uploading coverage. If not present, the parent will be determined using the API of your repository provider. When using the repository provider's API, the parent is determined via finding the closest ancestor to the commit. | Optional
| `env_vars` | Environment variables to tag the upload with. Multiple env variables can be separated with commas (e.g. `OS,PYTHON`) | Optional | `env_vars` | Environment variables to tag the upload with. Multiple env variables can be separated with commas (e.g. `OS,PYTHON`) | Optional
| `fail_ci_if_error` | Specify if CI pipeline should fail when Codecov runs into errors during upload. *Defaults to **false*** | Optional | `fail_ci_if_error` | Specify if CI pipeline should fail when Codecov runs into errors during upload. *Defaults to **false*** | Optional
| `functionalities` | Toggle functionalities | Optional -| `functionalities` | Toggle functionalities | Optional
| | `coveragepy` Disable python coverage | -| | `network` Disable uploading the file network |
| | `fix` Disable report fixing |
| | `gcov` Disable gcov |
| | `gcovout` Disable gcov output |
| | `html` Enable coverage for HTML files |
| | `network` Disable uploading the file network |
| | `recursesubs` Enable recurse submodules in git projects when searching for source files | |
| | `search` Disable searching for reports |
| | `xcode` Disable xcode processing |
| `gcov_path_include` | Paths to include during gcov gathering (as a glob) | Optional
| `gcov_args` | extra arguments to pass to gcov | Optional
| `gcov_executable` | gcov executable to run. Defaults to 'gcov' | Optional
| `gcov_path_exclude` | Paths to ignore during gcov gathering (as a glob) | Optional
| `gcov_prefix` | Prefix filepaths to help resolve path fixing | Optional
| `gcov_root_dir` | Project root directory, also used when preparing gcov | Optional
| `move_coverage_to_trash` | Move discovered coverage reports to the trash | Optional | `move_coverage_to_trash` | Move discovered coverage reports to the trash | Optional
| `name` | Custom defined name for the upload | Optional | `name` | Custom defined name for the upload | Optional
| `override_branch` | Specify the branch name | Optional | `override_branch` | Specify the branch name | Optional
@@ -70,10 +70,10 @@ Codecov's Action currently supports five inputs from the user: `token`, `file`,
| `override_tag` | Specify the git tag | Optional | `override_tag` | Specify the git tag | Optional
| `path_to_write_report` | Write upload file to path before uploading | Optional | `path_to_write_report` | Write upload file to path before uploading | Optional
| `root_dir` | Used when not in git/hg project to identify project root directory | Optional | `root_dir` | Used when not in git/hg project to identify project root directory | Optional
| `slug` | Specify the slug manually (Enterprise use) | Optional
| `url` | Change the upload host (Enterprise use) | Optional
| `verbose` | Specify whether the Codecov output should be verbose | Optional | `verbose` | Specify whether the Codecov output should be verbose | Optional
| `working-directory` | Directory in which to execute `codecov.sh` | Optional | `working-directory` | Directory in which to execute `codecov.sh` | Optional
| `xcode_derived_data` | Custom Derived Data Path for Coverage.profdata and gcov processing | Optional
| `xcode_package` | Specify packages to build coverage. Uploader will only build these packages. This can significantly reduces time to build coverage reports. -J 'MyAppName' Will match "MyAppName" and "MyAppNameTests" -J '^ExampleApp$' Will match only "ExampleApp" not "ExampleAppTests" | Optional
### Example `workflow.yml` with Codecov Action ### Example `workflow.yml` with Codecov Action
@@ -101,15 +101,15 @@ jobs:
pip install pytest-cov pip install pytest-cov
pytest --cov=./ --cov-report=xml pytest --cov=./ --cov-report=xml
- name: Upload coverage to Codecov - name: Upload coverage to Codecov
uses: codecov/codecov-action@v1 uses: codecov/codecov-action@v2
with: with:
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage1.xml,./coverage2.xml
directory: ./coverage/reports/ directory: ./coverage/reports/
flags: unittests
env_vars: OS,PYTHON env_vars: OS,PYTHON
name: codecov-umbrella
fail_ci_if_error: true fail_ci_if_error: true
files: ./coverage1.xml,./coverage2.xml
flags: unittests
name: codecov-umbrella
path_to_write_report: ./coverage/codecov_report.txt path_to_write_report: ./coverage/codecov_report.txt
verbose: true verbose: true
``` ```

View File

@@ -14,15 +14,12 @@ inputs:
flags: flags:
description: 'Flag upload to group coverage metrics (e.g. unittests | integration | ui,chrome)' description: 'Flag upload to group coverage metrics (e.g. unittests | integration | ui,chrome)'
required: false required: false
aws_curl_args:
description: 'Extra curl arguments to communicate with AWS.'
required: false
codecov_curl_args:
description: 'Extra curl arguments to communicate with Codecov. e.g., -U "--proxy http://http-proxy"'
required: false
commit_parent: commit_parent:
description: 'The commit SHA of the parent for which you are uploading coverage. If not present, the parent will be determined using the API of your repository provider. When using the repository providers API, the parent is determined via finding the closest ancestor to the commit.' description: 'The commit SHA of the parent for which you are uploading coverage. If not present, the parent will be determined using the API of your repository provider. When using the repository providers API, the parent is determined via finding the closest ancestor to the commit.'
required: false required: false
dry_run:
description: "Don't upload files to Codecov"
required: false
env_vars: env_vars:
description: 'Environment variables to tag the upload with (e.g. PYTHON | OS,PYTHON)' description: 'Environment variables to tag the upload with (e.g. PYTHON | OS,PYTHON)'
required: false required: false
@@ -35,33 +32,12 @@ inputs:
functionalities: functionalities:
description: 'Comma-separated list, see the README for options and their usage' description: 'Comma-separated list, see the README for options and their usage'
required: false required: false
gcov_args:
description: 'extra arguments to pass to gcov'
required: false
gcov_executable:
description: 'gcov executable to run. Defaults to gcov'
required: false
gcov_path_exclude:
description: 'Paths to ignore during gcov gathering (as a glob)'
required: false
gcov_path_include:
description: 'Paths to include during gcov gathering (as a glob)'
required: false
gcov_prefix:
description: 'Prefix filepaths to help resolve path fixing'
required: false
gcov_root_dir:
description: 'Project root directory, also used when preparing gcov'
required: false
move_coverage_to_trash: move_coverage_to_trash:
description: 'Move discovered coverage reports to the trash' description: 'Move discovered coverage reports to the trash'
required: false required: false
name: name:
description: 'User defined upload name. Visible in Codecov UI' description: 'User defined upload name. Visible in Codecov UI'
required: false required: false
network_filter:
description: 'Used to restrict the set of git/hg files that can be matched with filenames in the coverage report. This is useful for monorepos or other setups where a full filepath may not be specified in the coverage report, and that shortened filepath may appear multiple times in a directory structure (e.g. __init__.py)'
required: false
override_branch: override_branch:
description: 'Specify the branch name' description: 'Specify the branch name'
required: false required: false
@@ -77,24 +53,21 @@ inputs:
override_tag: override_tag:
description: 'Specify the git tag' description: 'Specify the git tag'
required: false required: false
path_to_write_report:
description: 'Write upload file to path before uploading'
required: false
root_dir: root_dir:
description: 'Used when not in git/hg project to identify project root directory' description: 'Used when not in git/hg project to identify project root directory'
required: false required: false
slug:
description: 'Specify the slug manually (Enterprise use)'
required: false
url:
description: 'Change the upload host (Enterprise use)'
required: false
verbose: verbose:
description: 'Specify whether the Codecov output should be verbose' description: 'Specify whether the Codecov output should be verbose'
required: false required: false
working-directory: working-directory:
description: 'Directory in which to execute codecov.sh' description: 'Directory in which to execute codecov.sh'
required: false required: false
xcode_derived_data:
description: 'Custom Derived Data Path for Coverage.profdata and gcov processing'
required: false
xcode_package:
description: 'Specify packages to build coverage. Uploader will only build these packages'
required: false
branding: branding:
color: 'red' color: 'red'
icon: 'umbrella' icon: 'umbrella'

1883
codecov

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,11 @@
import Calculator from './calculator' import Calculator from './calculator';
test('adds 2 + 3 to equal 5', () => { test('adds 2 + 3 to equal 5', () => {
const calc = new Calculator() const calc = new Calculator();
expect(calc.add(2, 3)).toBe(5); expect(calc.add(2, 3)).toBe(5);
}); });
test('subtracts 2 - 3 to equal -1', () => { test('subtracts 2 - 3 to equal -1', () => {
const calc = new Calculator() const calc = new Calculator();
expect(calc.subtract(2, 3)).toBe(-1); expect(calc.subtract(2, 3)).toBe(-1);
}); });

View File

@@ -1,4 +1,4 @@
import Coverage from "./coverage"; import Coverage from './coverage';
test('test uncovered if', () => { test('test uncovered if', () => {
const coverageObj = new Coverage(); const coverageObj = new Coverage();

44755
dist/index.js vendored

File diff suppressed because one or more lines are too long

52
dist/pgp_keys.asc vendored Normal file
View File

@@ -0,0 +1,52 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=ch7z
-----END PGP PUBLIC KEY BLOCK-----

View File

@@ -1,4 +1,4 @@
module.exports = { module.exports = {
preset: 'ts-jest', preset: 'ts-jest',
testEnvironment: 'node', testEnvironment: 'node',
} };

1572
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,15 @@
{ {
"name": "codecov-action", "name": "codecov-action",
"version": "1.5.2", "version": "2.0.0",
"description": "Upload coverage reports to Codecov from GitHub Actions", "description": "Upload coverage reports to Codecov from GitHub Actions",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"lint": "eslint src/*.*", "build": "ncc build src/index.ts",
"lint": "eslint src/**/*.ts",
"test": "npm run test-script && npm run test-calculator && npm run test-coverage", "test": "npm run test-script && npm run test-calculator && npm run test-coverage",
"test-calculator": "jest --testPathPattern=demo/calculator/ --coverage --coverageDirectory=coverage/calculator", "test-calculator": "jest --testPathPattern=demo/calculator/ --coverage --coverageDirectory=coverage/calculator",
"test-coverage": "jest --testPathPattern=demo/coverage-test/ --coverage --coverageDirectory=coverage/coverage-test", "test-coverage": "jest --testPathPattern=demo/coverage-test/ --coverage --coverageDirectory=coverage/coverage-test",
"test-script": "jest --testPathPattern=src/ --coverage --coverageDirectory=coverage/script", "test-script": "jest --testPathPattern=src/ --coverage --coverageDirectory=coverage/script"
"build": "ncc build src/index.ts"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -25,7 +25,9 @@
"dependencies": { "dependencies": {
"@actions/core": "^1.4.0", "@actions/core": "^1.4.0",
"@actions/exec": "^1.1.0", "@actions/exec": "^1.1.0",
"@actions/github": "^5.0.0" "@actions/github": "^5.0.0",
"node-fetch": "^2.6.1",
"openpgp": "^4.10.10"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^26.0.24", "@types/jest": "^26.0.24",

View File

@@ -1,6 +1,8 @@
import buildExec from './buildExec'; import * as github from '@actions/github';
const github = require('@actions/github');
import buildExec from './buildExec';
/* eslint-disable @typescript-eslint/no-var-requires */
const {version} = require('../package.json'); const {version} = require('../package.json');
const context = github.context; const context = github.context;
@@ -9,11 +11,8 @@ test('no arguments', () => {
const {execArgs, failCi} = buildExec(); const {execArgs, failCi} = buildExec();
const args = [ const args = [
'codecov',
'-n', '-n',
'', '',
'-F',
'',
'-Q', '-Q',
`github-action-${version}`, `github-action-${version}`,
]; ];
@@ -26,38 +25,30 @@ test('no arguments', () => {
test('all arguments', () => { test('all arguments', () => {
const envs = { const envs = {
'move_coverage_to_trash': 'true',
'commit_parent': '83231650328f11695dfb754ca0f540516f188d27', 'commit_parent': '83231650328f11695dfb754ca0f540516f188d27',
'aws_curl_args': '--timeout 1', 'directory': 'coverage/',
'codecov_curl_args': '--timeout 2', 'dry_run': 'true',
'env_vars': 'OS,PYTHON', 'env_vars': 'OS,PYTHON',
'fail_ci_if_error': 'true', 'fail_ci_if_error': 'true',
'file': 'coverage.xml', 'file': 'coverage.xml',
'files': 'dir1/coverage.xml,dir2/coverage.xml', 'files': 'dir1/coverage.xml,dir2/coverage.xml',
'flags': 'test', 'flags': 'test,test2',
'functionalities': 'functionalities':
'gcov,coveragepy,fix,search,code,network,gcovout,html,recursesubs', 'network',
'gcov_args': '--timeout 3', 'move_coverage_to_trash': 'true',
'gcov_root_dr': 'gcov_dir/',
'gcov_path_exclude': '**/exclude-dir/*.*',
'gcov_executable': 'gcov',
'gcov_path_include': '**/include-dir/*.*',
'gcov_prefix': 'demo',
'name': 'codecov', 'name': 'codecov',
'network_filter': 'dir1',
'override_branch': 'thomasrockhu/test', 'override_branch': 'thomasrockhu/test',
'override_build': '1', 'override_build': '1',
'override_commit': '9caabca5474b49de74ef5667deabaf74cdacc244', 'override_commit': '9caabca5474b49de74ef5667deabaf74cdacc244',
'override_pr': '2', 'override_pr': '2',
'override_tag': 'v1.2', 'override_tag': 'v1.2',
'path_to_write_report': 'codecov/',
'root_dir': 'root/', 'root_dir': 'root/',
'directory': 'coverage/', 'slug': 'fakeOwner/fakeRepo',
'token': 'd3859757-ab80-4664-924d-aef22fa7557b', 'token': 'd3859757-ab80-4664-924d-aef22fa7557b',
'url': 'https://codecov.enterprise.com',
'verbose': 't', 'verbose': 't',
'working-directory': 'src', 'working-directory': 'src',
'path_to_write_report': 'codecov/',
'xcode_derived_data': '~/Library/Developer/Xcode/DerivedData',
'xcode_package': 'MyApp',
}; };
for (const env of Object.keys(envs)) { for (const env of Object.keys(envs)) {
@@ -66,22 +57,18 @@ test('all arguments', () => {
const {execArgs, failCi} = buildExec(); const {execArgs, failCi} = buildExec();
expect(execArgs).toEqual([ expect(execArgs).toEqual([
'src/codecov',
'-n', '-n',
'codecov', 'codecov',
'-F',
'test',
'-Q', '-Q',
`github-action-${version}`, `github-action-${version}`,
'-c', '-c',
'-N', '-N',
'83231650328f11695dfb754ca0f540516f188d27', '83231650328f11695dfb754ca0f540516f188d27',
'-A', '-d',
'--timeout 1',
'-U',
'--timeout 2',
'-e', '-e',
'OS,PYTHON', 'OS,PYTHON',
'-X',
'network',
'-Z', '-Z',
'-f', '-f',
'coverage.xml', 'coverage.xml',
@@ -89,36 +76,10 @@ test('all arguments', () => {
'dir1/coverage.xml', 'dir1/coverage.xml',
'-f', '-f',
'dir2/coverage.xml', 'dir2/coverage.xml',
'-X', '-F',
'gcov', 'test',
'-X', '-F',
'coveragepy', 'test2',
'-X',
'fix',
'-X',
'search',
'-X',
'code',
'-X',
'network',
'-X',
'gcovout',
'-X',
'html',
'-X',
'recursesubs',
'-a',
'--timeout 3',
'-g',
'**/exclude-dir/*.*',
'-x',
'gcov',
'-G',
'**/include-dir/*.*',
'-k',
'demo',
'-i',
'dir1',
'-B', '-B',
'thomasrockhu/test', 'thomasrockhu/test',
'-b', '-b',
@@ -133,13 +94,11 @@ test('all arguments', () => {
'root/', 'root/',
'-s', '-s',
'coverage/', 'coverage/',
'-r',
'fakeOwner/fakeRepo',
'-u',
'https://codecov.enterprise.com',
'-v', '-v',
'-q',
'codecov/',
'-D',
'~/Library/Developer/Xcode/DerivedData',
'-J',
'MyApp',
]); ]);
expect(failCi).toBeTruthy(); expect(failCi).toBeTruthy();

View File

@@ -1,6 +1,7 @@
const core = require('@actions/core'); import * as core from '@actions/core';
const github = require('@actions/github'); import * as github from '@actions/github';
/* eslint-disable @typescript-eslint/no-var-requires */
const {version} = require('../package.json'); const {version} = require('../package.json');
const context = github.context; const context = github.context;
@@ -19,22 +20,14 @@ const isTrue = (variable) => {
const buildExec = () => { const buildExec = () => {
const clean = core.getInput('move_coverage_to_trash'); const clean = core.getInput('move_coverage_to_trash');
const commitParent = core.getInput('commit_parent'); const commitParent = core.getInput('commit_parent');
const curlAwsArgs = core.getInput('aws_curl_args');
const curlCodecovArgs = core.getInput('codecov_curl_args');
const envVars = core.getInput('env_vars'); const envVars = core.getInput('env_vars');
const dryRun = isTrue(core.getInput('dry_run'));
const failCi = isTrue(core.getInput('fail_ci_if_error')); const failCi = isTrue(core.getInput('fail_ci_if_error'));
const file = core.getInput('file'); const file = core.getInput('file');
const files = core.getInput('files'); const files = core.getInput('files');
const flags = core.getInput('flags'); const flags = core.getInput('flags');
const functionalities = core.getInput('functionalities'); const functionalities = core.getInput('functionalities');
const gcovArgs = core.getInput('gcov_args');
const gcovDir = core.getInput('gcov_root_dir');
const gcovExclude = core.getInput('gcov_path_exclude');
const gcovExec = core.getInput('gcov_executable');
const gcovInclude = core.getInput('gcov_path_include');
const gcovPrefix = core.getInput('gcov_prefix');
const name = core.getInput('name'); const name = core.getInput('name');
const networkFilter = core.getInput('network_filter');
const overrideBranch = core.getInput('override_branch'); const overrideBranch = core.getInput('override_branch');
const overrideBuild = core.getInput('override_build'); const overrideBuild = core.getInput('override_build');
const overrideCommit = core.getInput('override_commit'); const overrideCommit = core.getInput('override_commit');
@@ -42,22 +35,16 @@ const buildExec = () => {
const overrideTag = core.getInput('override_tag'); const overrideTag = core.getInput('override_tag');
const rootDir = core.getInput('root_dir'); const rootDir = core.getInput('root_dir');
const searchDir = core.getInput('directory'); const searchDir = core.getInput('directory');
const slug = core.getInput('slug');
const token = core.getInput('token'); const token = core.getInput('token');
const verbose = isTrue(core.getInput('verbose')); const verbose = isTrue(core.getInput('verbose'));
const url = core.getInput('url');
const workingDir = core.getInput('working-directory'); const workingDir = core.getInput('working-directory');
const writePath = core.getInput('path_to_write_report');
const xcodeDerivedData = core.getInput('xcode_derived_data');
const xcodePackage = core.getInput('xcode_package');
const filepath = workingDir ? const execArgs = [];
workingDir + '/codecov' : 'codecov';
const execArgs = [filepath];
execArgs.push( execArgs.push(
'-n', '-n',
`${name}`, `${name}`,
'-F',
`${flags}`,
'-Q', '-Q',
`github-action-${version}`, `github-action-${version}`,
); );
@@ -90,15 +77,17 @@ const buildExec = () => {
if (commitParent) { if (commitParent) {
execArgs.push('-N', `${commitParent}`); execArgs.push('-N', `${commitParent}`);
} }
if (curlAwsArgs) { if (dryRun) {
execArgs.push('-A', `${curlAwsArgs}`); execArgs.push('-d');
}
if (curlCodecovArgs) {
execArgs.push('-U', `${curlCodecovArgs}`);
} }
if (envVarsArg.length) { if (envVarsArg.length) {
execArgs.push('-e', envVarsArg.join(',')); execArgs.push('-e', envVarsArg.join(','));
} }
if (functionalities) {
functionalities.split(',').forEach((f) => {
execArgs.push('-X', `${f}`);
});
}
if (failCi) { if (failCi) {
execArgs.push('-Z'); execArgs.push('-Z');
} }
@@ -110,32 +99,11 @@ const buildExec = () => {
execArgs.push('-f', `${f}`); execArgs.push('-f', `${f}`);
}); });
} }
if (functionalities) { if (flags) {
functionalities.split(',').forEach((f) => { flags.split(',').forEach((f) => {
execArgs.push('-X', `${f}`); execArgs.push('-F', `${f}`);
}); });
} }
if (gcovArgs) {
execArgs.push('-a', `${gcovArgs}`);
}
if (gcovDir) {
execArgs.push('-p', `${gcovDir}`);
}
if (gcovExclude) {
execArgs.push('-g', `${gcovExclude}`);
}
if (gcovExec) {
execArgs.push('-x', `${gcovExec}`);
}
if (gcovInclude) {
execArgs.push('-G', `${gcovInclude}`);
}
if (gcovPrefix) {
execArgs.push('-k', `${gcovPrefix}`);
}
if (networkFilter) {
execArgs.push('-i', `${networkFilter}`);
}
if (overrideBranch) { if (overrideBranch) {
execArgs.push('-B', `${overrideBranch}`); execArgs.push('-B', `${overrideBranch}`);
} }
@@ -166,21 +134,18 @@ const buildExec = () => {
if (searchDir) { if (searchDir) {
execArgs.push('-s', `${searchDir}`); execArgs.push('-s', `${searchDir}`);
} }
if (slug) {
execArgs.push('-r', `${slug}`);
}
if (url) {
execArgs.push('-u', `${url}`);
}
if (verbose) { if (verbose) {
execArgs.push('-v'); execArgs.push('-v');
} }
if (workingDir) { if (workingDir) {
options.cwd = workingDir; options.cwd = workingDir;
} }
if (writePath) {
execArgs.push('-q', `${writePath}`);
}
if (xcodeDerivedData) {
execArgs.push('-D', `${xcodeDerivedData}`);
}
if (xcodePackage) {
execArgs.push('-J', `${xcodePackage}`);
}
return {execArgs, options, failCi}; return {execArgs, options, failCi};
}; };

41
src/helpers.ts Normal file
View File

@@ -0,0 +1,41 @@
import * as core from '@actions/core';
const PLATFORMS = ['alpine', 'linux', 'macos', 'windows'];
const setFailure = (message: string, failCi: boolean): void => {
failCi ? core.setFailed(message) : core.warning(message);
if (failCi) {
process.exit();
}
};
const getUploaderName = (): string => {
if (isWindows()) {
return 'codecov.exe';
} else {
return 'codecov';
}
};
const isValidPlatform = (): boolean => {
return PLATFORMS.includes(getPlatform());
};
const isWindows = (): boolean => {
return getPlatform() === 'windows';
};
const getPlatform = (): string => {
return process.env.RUNNER_OS.toLowerCase();
};
const BASEURL = `https://uploader.codecov.io/latest/${getPlatform()}/${getUploaderName()}`;
export {
BASEURL,
getPlatform,
getUploaderName,
isValidPlatform,
isWindows,
setFailure,
};

View File

@@ -1,17 +1,69 @@
const core = require('@actions/core'); import * as fs from 'fs';
const exec = require('@actions/exec'); import * as https from 'https';
import * as path from 'path';
import * as exec from '@actions/exec';
import buildExec from './buildExec'; import buildExec from './buildExec';
import {
BASEURL,
getPlatform,
getUploaderName,
isValidPlatform,
setFailure,
} from './helpers';
const {execArgs, options, failCi} = buildExec(); import verify from './validate';
exec.exec('bash', execArgs, options) let failCi;
.catch((err) => {
if (failCi) { try {
core.setFailed( const {execArgs, options, failCi} = buildExec();
`Codecov failed with the following error: ${err.message}`, const platform = getPlatform();
); if (!isValidPlatform()) {
} else { setFailure(
core.warning(`Codecov warning: ${err.message}`); `Codecov: Encountered an unexpected platform: ${platform}`,
} failCi,
}); );
}
const filename = path.join( __dirname, getUploaderName());
https.get(BASEURL, (res) => {
// Image will be stored at this path
const filePath = fs.createWriteStream(filename);
res.pipe(filePath);
filePath
.on('error', (err) => {
setFailure(
`Codecov: Failed to write uploader binary: ${err.message}`,
true,
);
}).on('finish', async () => {
filePath.close();
await verify(filename);
await fs.chmodSync(filename, '777');
const unlink = () => {
fs.unlink(filename, (err) => {
if (err) {
setFailure(
`Codecov: Could not unlink uploader: ${err.message}`,
failCi,
);
}
});
};
await exec.exec(filename, execArgs, options)
.catch((err) => {
setFailure(
`Codecov: Failed to properly upload: ${err.message}`,
failCi,
);
}).then(() => {
unlink();
});
});
});
} catch (err) {
setFailure(`Codecov: Encountered an unexpected error ${err.message}`, failCi);
}

52
src/pgp_keys.asc Normal file
View File

@@ -0,0 +1,52 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=ch7z
-----END PGP PUBLIC KEY BLOCK-----

69
src/validate.ts Normal file
View File

@@ -0,0 +1,69 @@
import * as crypto from 'crypto';
import * as fs from 'fs';
import * as path from 'path';
import * as core from '@actions/core';
import * as openpgp from 'openpgp';
import * as fetch from 'node-fetch';
import {
BASEURL,
getUploaderName,
setFailure,
} from './helpers';
const verify = async (filename: string) => {
try {
const uploaderName = getUploaderName();
// Read in public key
const publicKeyArmored = await fs.readFileSync(
path.join(__dirname, 'pgp_keys.asc'),
'utf-8',
);
// Get SHASUM and SHASUM signature files
const shasumRes = await fetch( `${BASEURL}.SHA256SUM`);
const shasum = await shasumRes.text();
const shaSigRes = await fetch( `${BASEURL}.SHA256SUM.sig`);
const shaSig = await shaSigRes.text();
// Verify shasum
const verified = await openpgp.verify({
message: await openpgp.cleartext.fromText(shasum),
signature: await openpgp.signature.readArmored(shaSig),
publicKeys: (await openpgp.key.readArmored(publicKeyArmored)).keys,
});
const {valid} = verified.signatures[0];
if (valid) {
core.info('==> SHASUM file signed by key id ' +
verified.signatures[0].keyid.toHex(),
);
} else {
setFailure('Codecov: Error validating SHASUM signature', true);
}
// Verify uploader
const uploaderSha = crypto.createHash(`sha256`);
const stream = fs.createReadStream(filename);
await stream
.on('data', (data) => {
uploaderSha.update(data);
}).on('end', async () => {
const hash = `${uploaderSha.digest('hex')} ${uploaderName}`;
if (hash !== shasum) {
setFailure(
'Codecov: Uploader shasum does not match ' +
`uploader hash: ${hash}, public hash: ${shasum}`,
true,
);
} else {
core.info('==> Uploader SHASUM verified');
}
});
} catch (err) {
setFailure(`Codecov: Error validating uploader: ${err.message}`, true);
}
};
export default verify;

View File

@@ -1,5 +1,15 @@
{ {
"compilerOptions": {
"esModuleInterop": true,
"moduleResolution": "node",
"outDir": "./dist",
"rootDir": "./src",
"sourceMap": true
},
"include": [ "include": [
"src" "src/**/*.ts"
],
"exclude": [
"src/**/*.test.ts"
] ]
} }