From 44e95634387b1145cada5888d63dd062a0b9bef9 Mon Sep 17 00:00:00 2001 From: Kevin James Date: Mon, 29 Apr 2024 15:08:42 +0100 Subject: [PATCH] fix(gha): s/github-actions/github/ (#427) Thanks to @andy-maier for the research on this one! --- coveralls/api.py | 66 ++++++++++++++++----------------- docs/usage/configuration.rst | 33 +++++++++-------- tests/api/configuration_test.py | 8 ++-- 3 files changed, 53 insertions(+), 54 deletions(-) diff --git a/coveralls/api.py b/coveralls/api.py index f8f98f5..48a1e75 100644 --- a/coveralls/api.py +++ b/coveralls/api.py @@ -2,9 +2,7 @@ import json import logging import os -import random import re -import sys import coverage import requests @@ -107,6 +105,8 @@ def load_config_from_circle(): return 'circleci', job, number, pr def load_config_from_github(self): + # See https://github.com/lemurheavy/coveralls-public/issues/1710 + # Github tokens and standard Coveralls tokens are almost but not quite # the same -- forceibly using Github's flow seems to be more stable self.config['repo_token'] = os.environ.get('GITHUB_TOKEN') @@ -115,11 +115,24 @@ def load_config_from_github(self): if os.environ.get('GITHUB_REF', '').startswith('refs/pull/'): pr = os.environ.get('GITHUB_REF', '//').split('/')[2] - # N.B. some users require this to be 'github' and some require it to - # be 'github-actions'. Defaulting to 'github-actions' as it seems more - # common -- users can specify the service name manually to override - # this. - return 'github-actions', None, os.environ.get('GITHUB_RUN_ID'), pr + # TODO: coveralls suggests using the RUN_ID for both these values: + # https://github.com/lemurheavy/coveralls-public/issues/1710#issuecomment-1539203555 + # However, they also suggest following this successful config approach: + # https://github.com/lemurheavy/coveralls-public/issues/1710#issuecomment-1913696022 + # which instead sets: + # COVERALLS_SERVICE_JOB_ID: $GITHUB_RUN_ID + # COVERALLS_SERVICE_NUMBER: $GITHUB_WORKFLOW-$GITHUB_RUN_NUMBER + # should we do the same? + job = os.environ.get('GITHUB_RUN_ID') + number = os.environ.get('GITHUB_RUN_ID') + + # N.B. per Coveralls: + # > When you want to identify the repo at Coveralls by its + # > GITHUB_TOKEN, you should choose github, and when you want to + # > identify it by its Coveralls Repo Token, you should choose + # > github-action. + # https://github.com/lemurheavy/coveralls-public/issues/1710#issuecomment-1539203555 + return 'github', job, number, pr @staticmethod def load_config_from_jenkins(): @@ -189,9 +202,6 @@ def load_config_from_ci_environment(self): elif os.environ.get('CIRCLECI'): name, job, number, pr = self.load_config_from_circle() elif os.environ.get('GITHUB_ACTIONS'): - # N.B. Github Actions fails if this is not set even when null. - # Other services fail if this is set to null. Sigh. - self.config['service_job_id'] = None name, job, number, pr = self.load_config_from_github() elif os.environ.get('JENKINS_HOME'): name, job, number, pr = self.load_config_from_jenkins() @@ -271,32 +281,18 @@ def submit_report(self, json_string): endpoint, files={'json_file': json_string}, verify=verify, ) - # check and adjust/resubmit if submission looks like it failed due to - # resubmission (non-unique) if response.status_code == 422: - # attach a random value to ensure uniqueness - # TODO: an auto-incrementing integer might be easier to reason - # about if we could fetch the previous value - # N.B. Github Actions fails if this is not set to null. - # Other services fail if this is set to null. Sigh x2. - if os.environ.get('GITHUB_REPOSITORY'): - new_id = None - else: - new_id = '-'.join(( - self.config.get('service_job_id', '42'), - str(random.randint(0, sys.maxsize)), - )) - print(f'resubmitting with id {new_id}') - - self.config['service_job_id'] = new_id - self._data = None # force create_report to use updated data - json_string = self.create_report() - - response = requests.post( - endpoint, - files={'json_file': json_string}, - verify=verify, - ) + if self.config['service_name'].startswith('github'): + print( + 'Received 422 submitting job via Github Actions. By ' + 'default, coveralls-python uses the "github" service ' + 'name, which requires you to set the $GITHUB_TOKEN ' + 'environment variable. If you want to use a ' + 'COVERALLS_REPO_TOKEN instead, please manually override ' + '$COVERALLS_SERVICE_NAME to "github-actions". For more ' + 'info, see https://coveralls-python.readthedocs.io/en' + '/latest/usage/configuration.html#github-actions-support', + ) try: response.raise_for_status() diff --git a/docs/usage/configuration.rst b/docs/usage/configuration.rst index 7d1f5e8..0350b01 100644 --- a/docs/usage/configuration.rst +++ b/docs/usage/configuration.rst @@ -74,24 +74,27 @@ Github Actions support Coveralls natively supports jobs running on Github Actions. You can directly pass the default-provided secret GITHUB_TOKEN:: + run: coveralls env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - coveralls --service=github Passing a coveralls.io token via the ``COVERALLS_REPO_TOKEN`` environment variable (or via the ``repo_token`` parameter in the config file) is not needed for -Github Actions. - -Sometimes Github Actions gets a little picky about the service name which needs -to be used in various cases. If you run into issues, try setting the -``COVERALLS_SERVICE_NAME`` explicitly to either ``github`` or -``github-actions``. It seems to be the case that you should use the -``--service=github`` value if you are also planning to use the ``GITHUB_TOKEN`` -env var, and ``github-actions`` (which is the default) in any other case, but -we've have conflicting reports on this: YMMV! See -`#452 `_ for more -info. +Github Actions by default (eg. with the default value of ``--service=github``). + +Github Actions can get a bit finicky as to how coverage is submitted. If you +find yourself getting 422 error responses, you can also try specifying the +``github-actions`` service name instead. If you do so, you will need to proved +a ``COVERALLS_REPO_TOKEN`` *instead* of a ``GITHUB_TOKEN``:: + + run: coveralls --service=github-actions + env: + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + +If you're still having issues after tryingt both of the above, please read through +the following issues for more information: +`#252 `_ and +`coveralls-public#1710 `_. For parallel builds, you have to add a final step to let coveralls.io know the parallel build is finished:: @@ -110,7 +113,7 @@ parallel build is finished:: - name: Test run: ./run_tests.sh ${{ matrix.test-name }} - name: Upload coverage data to coveralls.io - run: coveralls --service=github + run: coveralls env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} COVERALLS_FLAG_NAME: ${{ matrix.test-name }} @@ -124,7 +127,7 @@ parallel build is finished:: - name: Install coveralls run: pip3 install --upgrade coveralls - name: Finished - run: coveralls --service=github --finish + run: coveralls --finish env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/tests/api/configuration_test.py b/tests/api/configuration_test.py index bf05e87..b3efbb5 100644 --- a/tests/api/configuration_test.py +++ b/tests/api/configuration_test.py @@ -173,10 +173,10 @@ def test_circleci_parallel_no_config(self): ) def test_github_no_config(self): cover = Coveralls() - assert cover.config['service_name'] == 'github-actions' + assert cover.config['service_name'] == 'github' assert cover.config['service_pull_request'] == '1234' assert cover.config['service_number'] == '123456789' - assert 'service_job_id' in cover.config + assert cover.config['service_job_id'] == '123456789' @mock.patch.dict( os.environ, @@ -193,9 +193,9 @@ def test_github_no_config(self): ) def test_github_no_config_no_pr(self): cover = Coveralls() - assert cover.config['service_name'] == 'github-actions' + assert cover.config['service_name'] == 'github' assert cover.config['service_number'] == '987654321' - assert 'service_job_id' in cover.config + assert cover.config['service_job_id'] == '987654321' assert 'service_pull_request' not in cover.config @mock.patch.dict(