Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 31 additions & 35 deletions coveralls/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
import json
import logging
import os
import random
import re
import sys

import coverage
import requests
Expand Down Expand Up @@ -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')
Expand All @@ -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():
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down
33 changes: 18 additions & 15 deletions docs/usage/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <https://github.com/TheKevJames/coveralls-python/issues/252>`_ 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 <https://github.com/TheKevJames/coveralls-python/issues/252>`_ and
`coveralls-public#1710 <https://github.com/lemurheavy/coveralls-public/issues/1710>`_.

For parallel builds, you have to add a final step to let coveralls.io know the
parallel build is finished::
Expand All @@ -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 }}
Expand All @@ -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 }}

Expand Down
8 changes: 4 additions & 4 deletions tests/api/configuration_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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(
Expand Down