Skip to content
This repository has been archived by the owner on Feb 18, 2021. It is now read-only.

Commit

Permalink
feat!: initial implementation (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
bcoe committed Mar 5, 2020
1 parent 8ab4d54 commit f7e5ef8
Show file tree
Hide file tree
Showing 8 changed files with 297 additions and 12 deletions.
7 changes: 2 additions & 5 deletions .github/workflows/ci.yaml
Expand Up @@ -33,10 +33,7 @@ jobs:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: 12
node-version: 13
- run: npm install
- run: npm test
- run: npm run coverage
env:
COVERALLS_REPO_TOKEN: "${{ secrets.COVERALLS_REPO_TOKEN }}"
COVERALLS_GIT_BRANCH: "${{ github.ref }}"
- run: ./node_modules/.bin/c8 report --reporter=text-lcov | npx codecovorg -a ${{ secrets.CODECOV_API_KEY }} --pipe
3 changes: 2 additions & 1 deletion .gitignore
@@ -1,5 +1,6 @@
node_modules
.DS_Store
package-lock.json

.coverage
coverage

5 changes: 5 additions & 0 deletions .mocharc.json
@@ -0,0 +1,5 @@
{
"enable-source-maps": true,
"throw-deprecation": true,
"timeout": 10000
}
19 changes: 19 additions & 0 deletions README.md
@@ -0,0 +1,19 @@
# codecovorg

A thin wrapper for [codecov](https://www.npmjs.com/package/codecov) designed
for organizations that manage a large number of repos.

Provide the `api-key` parameter to `codecovorg`, it will in turn use this to
populate a `token` for `codecov`.

## Usage

### with c8

```bash
c8 report --reporter=text-lcov | npx codecovorg -a ${{ secrets.CODECOV_API_KEY }} --pipe
```

## License

Apache-2.0
149 changes: 149 additions & 0 deletions bin/codecovorg.js
@@ -0,0 +1,149 @@
#!/usr/bin/env node
// Copyright 2020 Benjamin Coe
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

const codecov = require('codecov/lib/codecov');
const { getUploadToken } = require('../');
const argv = require('yargs')
.usage('$0 [opts]')
.option('api-key', {
alias: 'a',
type: 'string',
description: 'API key used to dynamically generate repository tokens'
})
.option('token', {
alias: 't',
type: 'string',
description: 'Private repository token. Not required for public repos on Travis, CircleCI and AppVeyor'
})
.option('file', {
alias: 'f',
type: 'string',
normalize: true,
description: 'Target a specific file for uploading and disabling automatic detection of coverage files.'
})
.option('env', {
alias: 'e',
type: 'string',
description: 'Store environment variables to help distinguish CI builds. Example: http://bit.ly/1ElohCu'
})
.option('root', {
alias: 'p',
type: 'string',
normalize: true,
description: 'Project root, if not current directory'
})
.option('gcov-root', {
type: 'string',
normalize: true,
description: 'Project root directory when preparing gcov'
})
.option('gcov-glob', {
type: 'string',
description: 'Paths to ignore during gcov gathering'
})
.option('gcov-exec', {
type: 'string',
description: "gcov executable to run. Defaults to 'gcov'"
})
.option('gcov-args', {
type: 'string',
description: 'extra arguments to pass to gcov'
})
.option('disable', {
alias: 'X',
type: 'string',
description: 'Disable features. Accepting `search` to disable crawling through directories, `detect` to disable detecting CI provider, `gcov` disable gcov commands'
})
.option('commit', {
alias: 'c',
type: 'string',
description: 'Commit sha, set automatically'
})
.option('clear', {
alias: 'C',
type: 'boolean',
description: 'Remove all discovered reports after uploading'
})
.option('branch', {
alias: 'b',
type: 'string',
description: 'Branch name'
})
.option('build', {
alias: 'B',
type: 'string',
description: 'Specify a custom build number to distinguish ci jobs, provided automatically for supported ci companies'
})
.option('slug', {
alias: 'r',
type: 'string',
description: 'Specify repository slug for Enterprise ex. owner/repo'
})
.option('url', {
alias: 'u',
type: 'string',
description: 'Your Codecov endpoint'
})
.option('flags', {
alias: 'F',
type: 'string',
description: 'Codecov Flags'
})
.option('dump', {
type: 'boolean',
description: 'Dump collected data and do not send to Codecov'
})
.option('pipe', {
alias: 'l',
type: 'boolean',
description: 'Listen to stdin for coverage data'
})
.option('yml', {
alias: 'y',
type: 'string',
description: 'Configuration file Used to specify the location of the .codecov.yml config file. Defaults to codecov.yml and .codecov.yml'
})
.epilog('wraps codecov, using API to generate repository tokens for uploading')
.argv;

// Match the format of the argv parser used by codecov:
const args = {
options: argv
};

if (args.options.pipe) {
process.stdin.setEncoding('utf8');
args.options.pipe = [];

process.stdin.on('data', (report) => {
args.options.pipe.push(report);
});

process.stdin.on('end', async () => {
const token = await getUploadToken(args);
if (token) args.options.token = token;
codecov.upload(args);
});
} else {
upload().catch((err) => {
console.error(err.message);
});
}

async function upload () {
const token = await getUploadToken(args);
if (token) args.options.token = token;
codecov.upload(args);
}
51 changes: 51 additions & 0 deletions index.js
@@ -0,0 +1,51 @@
// Copyright 2020 Benjamin Coe
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
const detectProvider = require('codecov/lib/detect');
const fetch = require('node-fetch');

// Returns a per-repository upload token, in exchange for a codecov API key:
async function getUploadToken (args) {
const codecovEndpoint = getCodecovEndpoint(args);
const provider = detectProvider();
const slug = args.options.slug || provider.slug;
const apiKey = args.options['api-key'] ||
process.env.codecov_api_key ||
process.env.CODECOV_API_KEY;
if (!slug || !apiKey) {
if (!slug) console.warn('no repository slug was provided');
return null;
} else {
try {
const body = await fetch(`${codecovEndpoint}/api/pub/gh/${slug}/settings`, {
headers: {
Authorization: apiKey
}
}).then(res => res.json());
return body.repo.upload_token;
} catch (err) {
console.error(`failed to fetch upload token, err = ${err.message}`);
}
}
}

function getCodecovEndpoint (args) {
return args.options.url ||
process.env.codecov_url ||
process.env.CODECOV_URL ||
'https://codecov.io';
}

module.exports = {
getUploadToken
};
24 changes: 18 additions & 6 deletions package.json
Expand Up @@ -3,13 +3,17 @@
"version": "0.1.0",
"description": "wrapper for codecov that fetches repo tokens based on API key",
"main": "index.js",
"bin": "./bin/codecovorg.js",
"scripts": {
"test": "c8 mocha test.js"
},
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/bcoe/codecovorg.git"
"test": "c8 mocha test.js",
"posttest": "semistandard",
"fix": "semistandard --fix"
},
"files": [
"bin/",
"index.js"
],
"repository": "bcoe/codecovorg",
"keywords": [
"codecov",
"org",
Expand All @@ -24,6 +28,14 @@
"homepage": "https://github.com/bcoe/codecovorg#readme",
"dependencies": {
"codecov": "^3.6.5",
"yargs": "^15.1.0"
"node-fetch": "^2.6.0",
"yargs": "^15.3.0-beta.0"
},
"devDependencies": {
"c8": "^7.1.0",
"chai": "^4.2.0",
"mocha": "^7.1.0",
"nock": "^12.0.2",
"semistandard": "^14.2.0"
}
}
51 changes: 51 additions & 0 deletions test.js
@@ -0,0 +1,51 @@
// Copyright 2020 Benjamin Coe
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

const { describe, it } = require('mocha');
const { expect } = require('chai');
const { getUploadToken } = require('./');

const nock = require('nock');
nock.disableNetConnect();

describe('codecovorg', () => {
describe('getUploadToken', () => {
it('fetches upload token if API key and slug are provided', async () => {
const req = nock('https://codecov.io')
.get('/api/pub/gh/fake/fake/settings')
.reply(200, {
repo: {
upload_token: 'deadbeef'
}
});
const token = await getUploadToken({
options: {
slug: 'fake/fake',
'api-key': 'abc123'
}
});
expect(token).to.equal('deadbeef');
req.done();
});

it('returns null if no slug is set', async () => {
const token = await getUploadToken({
options: {
'api-key': 'abc123'
}
});
expect(token).to.equal(null);
});
});
});

0 comments on commit f7e5ef8

Please sign in to comment.