From 4094f70b1c842161cda7a20c8d0784764876b789 Mon Sep 17 00:00:00 2001 From: Timo Rothenpieler Date: Tue, 9 Jun 2020 14:30:31 +0200 Subject: [PATCH] Update Github Actions support --- coveralls/api.py | 26 ++++++++++++--------- docs/usage/configuration.rst | 40 ++++++++++++++++++++++++++++----- docs/usage/tox.rst | 2 ++ tests/api/configuration_test.py | 22 ++++++++++++++---- 4 files changed, 70 insertions(+), 20 deletions(-) diff --git a/coveralls/api.py b/coveralls/api.py index da276851..d7fd186b 100644 --- a/coveralls/api.py +++ b/coveralls/api.py @@ -52,13 +52,7 @@ def __init__(self, token_required=True, service_name=None, **kwargs): name, job, pr = self.load_config_from_ci_environment() self.config['service_name'] = self.config.get('service_name', name) if job: - # N.B. Github Actions uses a different chunk of the Coveralls - # config when running parallel builds, ie. `service_number` instead - # of `service_job_id`. - if name.startswith('github'): - self.config['service_number'] = job - else: - self.config['service_job_id'] = job + self.config['service_job_id'] = job if pr: self.config['service_pull_request'] = pr @@ -68,6 +62,17 @@ def ensure_token(self): if self.config.get('repo_token') or not self._token_required: return + service = self.config.get('service_name') or '' + if self._token_required and service.startswith('github'): + gh_token = os.environ.get('GITHUB_TOKEN') + if gh_token: + self.config['repo_token'] = gh_token + return + raise CoverallsException( + 'Running on Github Actions but GITHUB_TOKEN is not set. ' + 'Add "env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}" to ' + 'your step config.') + raise CoverallsException( 'Not on TravisCI. You have to provide either repo_token in {} or ' 'set the COVERALLS_REPO_TOKEN env var.'.format( @@ -92,12 +97,13 @@ def load_config_from_circle(): @staticmethod def load_config_from_github(): - service_number = os.environ.get('GITHUB_SHA') + service = 'github' + if 'COVERALLS_REPO_TOKEN' in os.environ: + service = 'github-actions' pr = None if os.environ.get('GITHUB_REF', '').startswith('refs/pull/'): pr = os.environ.get('GITHUB_REF', '//').split('/')[2] - service_number += '-PR-{}'.format(pr) - return 'github-actions', service_number, pr + return service, os.environ.get('GITHUB_RUN_ID'), pr @staticmethod def load_config_from_jenkins(): diff --git a/docs/usage/configuration.rst b/docs/usage/configuration.rst index bb35eb1c..836d1541 100644 --- a/docs/usage/configuration.rst +++ b/docs/usage/configuration.rst @@ -53,13 +53,41 @@ Sample ``.coveralls.yml`` file:: Github Actions Gotcha --------------------- -There's something weird with using Github Actions that we've not yet been able to entirely sort out -- if you find you're getting a 422 error on Github Actions which looks like this:: - - Could not submit coverage: 422 Client Error: Unprocessable Entity for url: https://coveralls.io/api/v1/jobs - -Then you may be able to solve it by ensuring your ``secret`` is named ``COVERALLS_REPO_TOKEN``; it seems like Github Actions may do Magic(tm) to some environment variables based on their name. The following config block seems to work properly:: +Coveralls natively supports jobs running on Github Actions. You can directly pass the default-provided secret GITHUB_TOKEN:: env: - COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | coveralls + +For parallel builds you have to specify a unique flag-name for every step/job. You can use the official coveralls action to finalize the build:: + + jobs: + test: + strategy: + matrix: + test-name: + - test1 + - test2 + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Test + run: | + ./run_tests.sh ${{ matrix.test-name }} + coveralls + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COVERALLS_PARALLEL: true + COVERALLS_FLAG_NAME: test-${{ matrix.test-env }} + coveralls: + name: Coveralls + needs: test + runs-on: ubuntu-latest + steps: + - name: Finished + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + parallel-finished: true diff --git a/docs/usage/tox.rst b/docs/usage/tox.rst index 82aed24c..d1724aac 100644 --- a/docs/usage/tox.rst +++ b/docs/usage/tox.rst @@ -68,6 +68,8 @@ All variables: - ``GITHUB_REF`` - ``GITHUB_SHA`` - ``GITHUB_HEAD_REF`` +- ``GITHUB_RUN_ID`` +- ``GITHUB_TOKEN`` Jenkins ------- diff --git a/tests/api/configuration_test.py b/tests/api/configuration_test.py index c70c0ee1..86f61e42 100644 --- a/tests/api/configuration_test.py +++ b/tests/api/configuration_test.py @@ -66,6 +66,14 @@ def test_misconfigured(self): 'Not on TravisCI. You have to provide either repo_token in ' '.coveralls.mock or set the COVERALLS_REPO_TOKEN env var.') + @mock.patch.dict(os.environ, {'GITHUB_ACTIONS': 'true'}, clear=True) + def test_misconfigured_github(self): + with pytest.raises(Exception) as excinfo: + Coveralls() + + assert str(excinfo.value).startswith( + 'Running on Github Actions but GITHUB_TOKEN is not set.') + @mock.patch.dict(os.environ, {'APPVEYOR': 'True', 'APPVEYOR_BUILD_ID': '1234567', 'APPVEYOR_PULL_REQUEST_NUMBER': '1234'}, @@ -113,24 +121,30 @@ def test_circleci_no_config(self): {'GITHUB_ACTIONS': 'true', 'GITHUB_REF': 'refs/pull/1234/merge', 'GITHUB_SHA': 'bb0e00166b28f49db04d6a8b8cb4bddb5afa529f', - 'GITHUB_HEAD_REF': 'fixup-branch'}, + 'GITHUB_RUN_ID': '123456789', + 'GITHUB_HEAD_REF': 'fixup-branch', + 'COVERALLS_REPO_TOKEN': 'xxx'}, clear=True) def test_github_no_config(self): - cover = Coveralls(repo_token='xxx') + cover = Coveralls() assert cover.config['service_name'] == 'github-actions' assert cover.config['service_pull_request'] == '1234' + assert cover.config['service_number'] == '123456789' assert 'service_job_id' not in cover.config @mock.patch.dict( os.environ, {'GITHUB_ACTIONS': 'true', + 'GITHUB_TOKEN': 'xxx', 'GITHUB_REF': 'refs/heads/master', 'GITHUB_SHA': 'bb0e00166b28f49db04d6a8b8cb4bddb5afa529f', + 'GITHUB_RUN_ID': '987654321', 'GITHUB_HEAD_REF': ''}, clear=True) def test_github_no_config_no_pr(self): - cover = Coveralls(repo_token='xxx') - assert cover.config['service_name'] == 'github-actions' + cover = Coveralls() + assert cover.config['service_name'] == 'github' + assert cover.config['service_number'] == '987654321' assert 'service_pull_request' not in cover.config assert 'service_job_id' not in cover.config