From 76da54d04194acc5932de375ad92835cb58cabfc Mon Sep 17 00:00:00 2001 From: Andre Miras Date: Sat, 11 Apr 2020 13:25:49 +0200 Subject: [PATCH 1/8] Migrate to Python --- Dockerfile | 9 +++++---- Makefile | 10 ++++++++++ entrypoint.py | 21 +++++++++++++++++++++ entrypoint.sh | 5 ----- 4 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 Makefile create mode 100755 entrypoint.py delete mode 100755 entrypoint.sh diff --git a/Dockerfile b/Dockerfile index fa0188a..0027ac9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,9 @@ # Container image that runs your code -FROM alpine:3.10 +FROM python:3.8 # Copies your code file from your action repository to the filesystem path `/` of the container -COPY entrypoint.sh /entrypoint.sh +COPY entrypoint.py /entrypoint.py +RUN pip install coveralls -# Code file to execute when the docker container starts up (`entrypoint.sh`) -ENTRYPOINT ["/entrypoint.sh"] +# Code file to execute when the docker container starts up (`entrypoint.py`) +ENTRYPOINT ["/entrypoint.py"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ce2df30 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +DOCKER_IMAGE_LINUX=andremiras/coveralls-python-action + +docker/build: + docker build --tag=$(DOCKER_IMAGE_LINUX) . + +docker/run: + docker run -it --rm $(DOCKER_IMAGE_LINUX) + +docker/run/shell: + docker run -it --rm --entrypoint /bin/sh $(DOCKER_IMAGE_LINUX) diff --git a/entrypoint.py b/entrypoint.py new file mode 100755 index 0000000..a11e737 --- /dev/null +++ b/entrypoint.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 + +import sys +from datetime import datetime +import argparse + +def main(who_to_greet): + print(f"Hello {who_to_greet} from Python") + time = datetime.now().isoformat() + print(f"::set-output name=time::{time}") + + +def parse_args(): + parser = argparse.ArgumentParser(description='Greetings') + parser.add_argument('who_to_greet', help='Who to greet', nargs="?", default="World") + return parser.parse_args() + +if __name__ == "__main__": + args = parse_args() + who_to_greet = args.who_to_greet + main(who_to_greet) diff --git a/entrypoint.sh b/entrypoint.sh deleted file mode 100755 index 7636076..0000000 --- a/entrypoint.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -l - -echo "Hello $1" -time=$(date) -echo "::set-output name=time::$time" From ecec65cea1a39993b48d0249784f0d3ca488b628 Mon Sep 17 00:00:00 2001 From: Andre Miras Date: Sat, 11 Apr 2020 19:05:16 +0200 Subject: [PATCH 2/8] First working POC --- .dockerignore | 5 ++ .github/workflows/push.yml | 20 ++++++ .gitignore | 139 +++++++++++++++++++++++++++++++++++++ Dockerfile | 5 +- Makefile | 48 +++++++++++++ README.md | 24 +------ requirements.txt | 5 ++ setup.cfg | 10 +++ src/entrypoint.py | 82 ++++++++++++++++++++++ tests/test_entrypoint.py | 10 +++ 10 files changed, 323 insertions(+), 25 deletions(-) create mode 100644 .dockerignore create mode 100644 .github/workflows/push.yml create mode 100644 .gitignore create mode 100644 requirements.txt create mode 100644 setup.cfg create mode 100755 src/entrypoint.py create mode 100644 tests/test_entrypoint.py diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3073528 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +venv/ +.git/ +**/.pytest_cache/ +*.pyc +**/__pycache__ diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml new file mode 100644 index 0000000..3d521b4 --- /dev/null +++ b/.github/workflows/push.yml @@ -0,0 +1,20 @@ +name: push +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: echo test + + self: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Self + uses: ./ + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b26ab7e --- /dev/null +++ b/.gitignore @@ -0,0 +1,139 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ diff --git a/Dockerfile b/Dockerfile index 0027ac9..c597274 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,8 +2,9 @@ FROM python:3.8 # Copies your code file from your action repository to the filesystem path `/` of the container -COPY entrypoint.py /entrypoint.py +COPY src/ /src/ +# TODO: use setup.py RUN pip install coveralls # Code file to execute when the docker container starts up (`entrypoint.py`) -ENTRYPOINT ["/entrypoint.py"] +ENTRYPOINT ["/src/entrypoint.py"] diff --git a/Makefile b/Makefile index ce2df30..3809220 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,53 @@ +VIRTUAL_ENV ?= venv +PYTHON_MAJOR_VERSION=3 +PYTHON_MINOR_VERSION=8 +PYTHON_VERSION=$(PYTHON_MAJOR_VERSION).$(PYTHON_MINOR_VERSION) +PYTHON_WITH_VERSION=python$(PYTHON_VERSION) +PYTHON=$(VIRTUAL_ENV)/bin/python +PIP=$(VIRTUAL_ENV)/bin/pip +ISORT=$(VIRTUAL_ENV)/bin/isort +FLAKE8=$(VIRTUAL_ENV)/bin/flake8 +PYTEST=$(VIRTUAL_ENV)/bin/pytest +COVERAGE=$(VIRTUAL_ENV)/bin/coverage +BLACK=$(VIRTUAL_ENV)/bin/black +SOURCES=src/ tests/ DOCKER_IMAGE_LINUX=andremiras/coveralls-python-action + +$(VIRTUAL_ENV): + virtualenv --python $(PYTHON_WITH_VERSION) $(VIRTUAL_ENV) + $(PIP) install --requirement requirements.txt + +virtualenv: $(VIRTUAL_ENV) + +run: virtualenv + $(PYTHON) src/entrypoint.py + +pytest: virtualenv + PYTHONPATH=src/ $(COVERAGE) run --source src/ -m pytest tests/ + $(COVERAGE) report -m + +test: pytest lint + +lint/isort: virtualenv + $(ISORT) --check-only --recursive --diff $(SOURCES) + +lint/flake8: virtualenv + $(FLAKE8) $(SOURCES) + +lint/black: virtualenv + $(BLACK) --check $(SOURCES) + +lint: lint/isort lint/flake8 lint/black + +format/isort: virtualenv + $(ISORT) --recursive $(SOURCES) + +format/black: virtualenv + $(BLACK) $(SOURCES) + +format: format/isort format/black + docker/build: docker build --tag=$(DOCKER_IMAGE_LINUX) . diff --git a/README.md b/README.md index 48527ea..6a543db 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,2 @@ -# WIP coveralls-python-action +# coveralls-python-action GitHub Action for Python Coveralls.io - -# Hello world docker action - -This action prints "Hello World" or "Hello" + the name of a person to greet to the log. - -## Inputs - -### `who-to-greet` - -**Required** The name of the person to greet. Default `"World"`. - -## Outputs - -### `time` - -The time we greeted you. - -## Example usage - -uses: actions/hello-world-docker-action@v1 -with: - who-to-greet: 'Mona the Octocat' diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a1772ba --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +black +coveralls +flake8 +isort +pytest diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..b92e626 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,10 @@ +[flake8] +max-line-length = 88 +extend-ignore = E203 + +[isort] +multi_line_output=3 +include_trailing_comma=True +force_grid_wrap=0 +use_parentheses=True +line_length=88 diff --git a/src/entrypoint.py b/src/entrypoint.py new file mode 100755 index 0000000..5a10933 --- /dev/null +++ b/src/entrypoint.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 + +import argparse +import logging +import os +import sys +from datetime import datetime +from enum import Enum + +from coveralls.api import Coveralls, CoverallsException + +log = logging.getLogger(__name__) + + +class ExitCode(Enum): + SUCCESS = 0 + FAILURE = 1 + + +def set_failed(message): + log.error(message) + sys.exit(ExitCode.FAILURE) + + +def run_coveralls(): + """Submits to coveralls using either GITHUB_TOKEN or COVERALLS_REPO_TOKEN.""" + # note that coveralls.io "service_name" can either be: + # - "github-actions" (local development?) + # - "github" (from GitHub jobs?) + GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN") + COVERALLS_REPO_TOKEN = os.environ.get("COVERALLS_REPO_TOKEN") + repo_token = GITHUB_TOKEN or COVERALLS_REPO_TOKEN + if GITHUB_TOKEN and COVERALLS_REPO_TOKEN: + log.warning("Both GITHUB_TOKEN and COVERALLS_REPO_TOKEN defined.") + assert repo_token, "Either GITHUB_TOKEN or COVERALLS_REPO_TOKEN must be set." + # for some reasons the "service_name" can be one or the other + # (depending on where it's ran from?) + service_names = ("github", "github-actions") + kwargs = {"repo_token": repo_token} + for service_name in service_names: + log.info(f"Trying submitting coverage with service_name: {service_name}...") + coveralls = Coveralls(service_name=service_name, **kwargs) + try: + result = coveralls.wear() + break + except CoverallsException as e: + log.warning(f"Failed submitting coverage with service_name: {service_name}") + log.warning(e) + if result is None: + set_failed("Failed to submit coverage") + log.info(result) + + +def parse_args(): + parser = argparse.ArgumentParser(description="Greetings") + parser.add_argument("who_to_greet", help="Who to greet", nargs="?", default="World") + parser.add_argument("--verbose", action="store_true") + return parser.parse_args() + + +def set_log_level(verbose): + level = logging.DEBUG if verbose else logging.INFO + log.addHandler(logging.StreamHandler()) + log.setLevel(level) + + +def main(): + args = parse_args() + verbose = args.verbose + set_log_level(verbose) + who_to_greet = args.who_to_greet + print(f"Hello {who_to_greet} from Python") + time = datetime.now().isoformat() + print(f"::set-output name=time::{time}") + run_coveralls() + + +if __name__ == "__main__": + try: + main() + except Exception as e: + set_failed(e) diff --git a/tests/test_entrypoint.py b/tests/test_entrypoint.py new file mode 100644 index 0000000..824b28d --- /dev/null +++ b/tests/test_entrypoint.py @@ -0,0 +1,10 @@ +from unittest import mock + +import entrypoint + + +class TestEntryPoint: + def test_main(self): + with mock.patch("entrypoint.run_coveralls") as m_run_coveralls: + entrypoint.main() + assert m_run_coveralls.call_args_list == [mock.call()] From db3126d9d2abb43de71d3e9da0dbc09b13410a03 Mon Sep 17 00:00:00 2001 From: Andre Miras Date: Sat, 11 Apr 2020 19:05:16 +0200 Subject: [PATCH 3/8] First working POC --- .dockerignore | 5 ++ .github/workflows/push.yml | 20 ++++++ .gitignore | 139 +++++++++++++++++++++++++++++++++++++ Dockerfile | 5 +- Makefile | 48 +++++++++++++ README.md | 24 +------ entrypoint.py | 21 ------ requirements.txt | 5 ++ setup.cfg | 10 +++ src/entrypoint.py | 82 ++++++++++++++++++++++ tests/test_entrypoint.py | 10 +++ 11 files changed, 323 insertions(+), 46 deletions(-) create mode 100644 .dockerignore create mode 100644 .github/workflows/push.yml create mode 100644 .gitignore delete mode 100755 entrypoint.py create mode 100644 requirements.txt create mode 100644 setup.cfg create mode 100755 src/entrypoint.py create mode 100644 tests/test_entrypoint.py diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3073528 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +venv/ +.git/ +**/.pytest_cache/ +*.pyc +**/__pycache__ diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml new file mode 100644 index 0000000..3d521b4 --- /dev/null +++ b/.github/workflows/push.yml @@ -0,0 +1,20 @@ +name: push +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: echo test + + self: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Self + uses: ./ + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b26ab7e --- /dev/null +++ b/.gitignore @@ -0,0 +1,139 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ diff --git a/Dockerfile b/Dockerfile index 0027ac9..c597274 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,8 +2,9 @@ FROM python:3.8 # Copies your code file from your action repository to the filesystem path `/` of the container -COPY entrypoint.py /entrypoint.py +COPY src/ /src/ +# TODO: use setup.py RUN pip install coveralls # Code file to execute when the docker container starts up (`entrypoint.py`) -ENTRYPOINT ["/entrypoint.py"] +ENTRYPOINT ["/src/entrypoint.py"] diff --git a/Makefile b/Makefile index ce2df30..3809220 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,53 @@ +VIRTUAL_ENV ?= venv +PYTHON_MAJOR_VERSION=3 +PYTHON_MINOR_VERSION=8 +PYTHON_VERSION=$(PYTHON_MAJOR_VERSION).$(PYTHON_MINOR_VERSION) +PYTHON_WITH_VERSION=python$(PYTHON_VERSION) +PYTHON=$(VIRTUAL_ENV)/bin/python +PIP=$(VIRTUAL_ENV)/bin/pip +ISORT=$(VIRTUAL_ENV)/bin/isort +FLAKE8=$(VIRTUAL_ENV)/bin/flake8 +PYTEST=$(VIRTUAL_ENV)/bin/pytest +COVERAGE=$(VIRTUAL_ENV)/bin/coverage +BLACK=$(VIRTUAL_ENV)/bin/black +SOURCES=src/ tests/ DOCKER_IMAGE_LINUX=andremiras/coveralls-python-action + +$(VIRTUAL_ENV): + virtualenv --python $(PYTHON_WITH_VERSION) $(VIRTUAL_ENV) + $(PIP) install --requirement requirements.txt + +virtualenv: $(VIRTUAL_ENV) + +run: virtualenv + $(PYTHON) src/entrypoint.py + +pytest: virtualenv + PYTHONPATH=src/ $(COVERAGE) run --source src/ -m pytest tests/ + $(COVERAGE) report -m + +test: pytest lint + +lint/isort: virtualenv + $(ISORT) --check-only --recursive --diff $(SOURCES) + +lint/flake8: virtualenv + $(FLAKE8) $(SOURCES) + +lint/black: virtualenv + $(BLACK) --check $(SOURCES) + +lint: lint/isort lint/flake8 lint/black + +format/isort: virtualenv + $(ISORT) --recursive $(SOURCES) + +format/black: virtualenv + $(BLACK) $(SOURCES) + +format: format/isort format/black + docker/build: docker build --tag=$(DOCKER_IMAGE_LINUX) . diff --git a/README.md b/README.md index 48527ea..6a543db 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,2 @@ -# WIP coveralls-python-action +# coveralls-python-action GitHub Action for Python Coveralls.io - -# Hello world docker action - -This action prints "Hello World" or "Hello" + the name of a person to greet to the log. - -## Inputs - -### `who-to-greet` - -**Required** The name of the person to greet. Default `"World"`. - -## Outputs - -### `time` - -The time we greeted you. - -## Example usage - -uses: actions/hello-world-docker-action@v1 -with: - who-to-greet: 'Mona the Octocat' diff --git a/entrypoint.py b/entrypoint.py deleted file mode 100755 index a11e737..0000000 --- a/entrypoint.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python3 - -import sys -from datetime import datetime -import argparse - -def main(who_to_greet): - print(f"Hello {who_to_greet} from Python") - time = datetime.now().isoformat() - print(f"::set-output name=time::{time}") - - -def parse_args(): - parser = argparse.ArgumentParser(description='Greetings') - parser.add_argument('who_to_greet', help='Who to greet', nargs="?", default="World") - return parser.parse_args() - -if __name__ == "__main__": - args = parse_args() - who_to_greet = args.who_to_greet - main(who_to_greet) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a1772ba --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +black +coveralls +flake8 +isort +pytest diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..b92e626 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,10 @@ +[flake8] +max-line-length = 88 +extend-ignore = E203 + +[isort] +multi_line_output=3 +include_trailing_comma=True +force_grid_wrap=0 +use_parentheses=True +line_length=88 diff --git a/src/entrypoint.py b/src/entrypoint.py new file mode 100755 index 0000000..5a10933 --- /dev/null +++ b/src/entrypoint.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 + +import argparse +import logging +import os +import sys +from datetime import datetime +from enum import Enum + +from coveralls.api import Coveralls, CoverallsException + +log = logging.getLogger(__name__) + + +class ExitCode(Enum): + SUCCESS = 0 + FAILURE = 1 + + +def set_failed(message): + log.error(message) + sys.exit(ExitCode.FAILURE) + + +def run_coveralls(): + """Submits to coveralls using either GITHUB_TOKEN or COVERALLS_REPO_TOKEN.""" + # note that coveralls.io "service_name" can either be: + # - "github-actions" (local development?) + # - "github" (from GitHub jobs?) + GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN") + COVERALLS_REPO_TOKEN = os.environ.get("COVERALLS_REPO_TOKEN") + repo_token = GITHUB_TOKEN or COVERALLS_REPO_TOKEN + if GITHUB_TOKEN and COVERALLS_REPO_TOKEN: + log.warning("Both GITHUB_TOKEN and COVERALLS_REPO_TOKEN defined.") + assert repo_token, "Either GITHUB_TOKEN or COVERALLS_REPO_TOKEN must be set." + # for some reasons the "service_name" can be one or the other + # (depending on where it's ran from?) + service_names = ("github", "github-actions") + kwargs = {"repo_token": repo_token} + for service_name in service_names: + log.info(f"Trying submitting coverage with service_name: {service_name}...") + coveralls = Coveralls(service_name=service_name, **kwargs) + try: + result = coveralls.wear() + break + except CoverallsException as e: + log.warning(f"Failed submitting coverage with service_name: {service_name}") + log.warning(e) + if result is None: + set_failed("Failed to submit coverage") + log.info(result) + + +def parse_args(): + parser = argparse.ArgumentParser(description="Greetings") + parser.add_argument("who_to_greet", help="Who to greet", nargs="?", default="World") + parser.add_argument("--verbose", action="store_true") + return parser.parse_args() + + +def set_log_level(verbose): + level = logging.DEBUG if verbose else logging.INFO + log.addHandler(logging.StreamHandler()) + log.setLevel(level) + + +def main(): + args = parse_args() + verbose = args.verbose + set_log_level(verbose) + who_to_greet = args.who_to_greet + print(f"Hello {who_to_greet} from Python") + time = datetime.now().isoformat() + print(f"::set-output name=time::{time}") + run_coveralls() + + +if __name__ == "__main__": + try: + main() + except Exception as e: + set_failed(e) diff --git a/tests/test_entrypoint.py b/tests/test_entrypoint.py new file mode 100644 index 0000000..824b28d --- /dev/null +++ b/tests/test_entrypoint.py @@ -0,0 +1,10 @@ +from unittest import mock + +import entrypoint + + +class TestEntryPoint: + def test_main(self): + with mock.patch("entrypoint.run_coveralls") as m_run_coveralls: + entrypoint.main() + assert m_run_coveralls.call_args_list == [mock.call()] From c110aad84f193fe29743c3f13d5e3e0970eece7d Mon Sep 17 00:00:00 2001 From: Andre Miras Date: Sat, 11 Apr 2020 19:23:22 +0200 Subject: [PATCH 4/8] Runs unit tests and checks different configurations --- .github/workflows/push.yml | 24 ++++++++++++++++-------- Makefile | 7 ++++++- entrypoint.py | 21 --------------------- 3 files changed, 22 insertions(+), 30 deletions(-) delete mode 100755 entrypoint.py diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 3d521b4..d97e7a8 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -6,15 +6,23 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - run: echo test + - uses: actions/setup-python@v1 - self: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Self + - name: Unit tests + run: make test + + - name: With GITHUB_TOKEN + uses: ./ + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: With COVERALLS_REPO_TOKEN + uses: ./ + env: + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + + - name: With GITHUB_TOKEN and COVERALLS_REPO_TOKEN uses: ./ env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} diff --git a/Makefile b/Makefile index 3809220..b4cfe08 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ DOCKER_IMAGE_LINUX=andremiras/coveralls-python-action $(VIRTUAL_ENV): - virtualenv --python $(PYTHON_WITH_VERSION) $(VIRTUAL_ENV) + $(PYTHON_WITH_VERSION) -m venv $(VIRTUAL_ENV) $(PIP) install --requirement requirements.txt virtualenv: $(VIRTUAL_ENV) @@ -48,6 +48,11 @@ format/black: virtualenv format: format/isort format/black +clean: + rm -rf .pytest_cache/ + find . -type d -name "__pycache__" -exec rm -r {} + + find . -type d -name "*.egg-info" -exec rm -r {} + + docker/build: docker build --tag=$(DOCKER_IMAGE_LINUX) . diff --git a/entrypoint.py b/entrypoint.py deleted file mode 100755 index a11e737..0000000 --- a/entrypoint.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python3 - -import sys -from datetime import datetime -import argparse - -def main(who_to_greet): - print(f"Hello {who_to_greet} from Python") - time = datetime.now().isoformat() - print(f"::set-output name=time::{time}") - - -def parse_args(): - parser = argparse.ArgumentParser(description='Greetings') - parser.add_argument('who_to_greet', help='Who to greet', nargs="?", default="World") - return parser.parse_args() - -if __name__ == "__main__": - args = parse_args() - who_to_greet = args.who_to_greet - main(who_to_greet) From f53b95d6681cbfa1d880d80f14e5d3ac170608b8 Mon Sep 17 00:00:00 2001 From: Andre Miras Date: Sat, 11 Apr 2020 19:54:58 +0200 Subject: [PATCH 5/8] Usage documentation --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/README.md b/README.md index 6a543db..e3e3311 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,30 @@ # coveralls-python-action GitHub Action for Python Coveralls.io + +## Usage +You simply need to set one of the following two environment variables: +- `GITHUB_TOKEN` +- `COVERALLS_REPO_TOKEN` + +## Example usage +Assuming you have a `make test` that runs coverage testing. +The following will upload it to coveralls.io. +```yml +name: push +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v1 + + - name: Unit tests + run: make test + + - name: Coveralls + uses: AndreMiras/coveralls-python-action@develop + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +``` From 0bee5f504463871ad1189b4d7d9595a12862f5dc Mon Sep 17 00:00:00 2001 From: Andre Miras Date: Sat, 11 Apr 2020 20:01:30 +0200 Subject: [PATCH 6/8] Status badge --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index e3e3311..db6e023 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ # coveralls-python-action + +[![push](https://github.com/AndreMiras/coveralls-python-action/workflows/push/badge.svg?branch=develop)](https://github.com/AndreMiras/coveralls-python-action/actions?query=workflow%3Apush) + GitHub Action for Python Coveralls.io ## Usage From 59d2c683f6eec8ee2309b23cbe11ff72700d217b Mon Sep 17 00:00:00 2001 From: Andre Miras Date: Sat, 11 Apr 2020 20:33:18 +0200 Subject: [PATCH 7/8] Report via relative files This is needed because we're mounting docker volumes and the absolute paths are not the same from within/out. --- .env | 2 ++ Makefile | 4 ++-- action.yml | 6 ++++-- setup.cfg | 3 +++ 4 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 .env diff --git a/.env b/.env new file mode 100644 index 0000000..79cde8e --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +GITHUB_TOKEN +COVERALLS_REPO_TOKEN diff --git a/Makefile b/Makefile index b4cfe08..0380589 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,7 @@ docker/build: docker build --tag=$(DOCKER_IMAGE_LINUX) . docker/run: - docker run -it --rm $(DOCKER_IMAGE_LINUX) + docker run -it --rm --env-file .env $(DOCKER_IMAGE_LINUX) docker/run/shell: - docker run -it --rm --entrypoint /bin/sh $(DOCKER_IMAGE_LINUX) + docker run -it --rm --env-file .env --entrypoint /bin/sh $(DOCKER_IMAGE_LINUX) diff --git a/action.yml b/action.yml index 9b136f8..296273b 100644 --- a/action.yml +++ b/action.yml @@ -11,5 +11,7 @@ outputs: runs: using: 'docker' image: 'Dockerfile' - args: - - ${{ inputs.who-to-greet }} + # args: + # - ${{ inputs.who-to-greet }} + volumes: + - my_docker_volume:/volume_mount diff --git a/setup.cfg b/setup.cfg index b92e626..78cb676 100644 --- a/setup.cfg +++ b/setup.cfg @@ -8,3 +8,6 @@ include_trailing_comma=True force_grid_wrap=0 use_parentheses=True line_length=88 + +[coverage:run] +relative_files = True From b5b6a5c50fb46e625ce6679aad9310734a5842ae Mon Sep 17 00:00:00 2001 From: Andre Miras Date: Sat, 11 Apr 2020 23:18:52 +0200 Subject: [PATCH 8/8] Code cleaning --- action.yml | 16 ++-------------- src/entrypoint.py | 5 ----- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/action.yml b/action.yml index 296273b..d13a6e2 100644 --- a/action.yml +++ b/action.yml @@ -1,17 +1,5 @@ -name: 'Hello World' -description: 'Greet someone and record the time' -inputs: - who-to-greet: # id of input - description: 'Who to greet' - required: true - default: 'World' -outputs: - time: # id of output - description: 'The time we greeted you' +name: 'Coveralls' +description: 'Reports to coveralls.io' runs: using: 'docker' image: 'Dockerfile' - # args: - # - ${{ inputs.who-to-greet }} - volumes: - - my_docker_volume:/volume_mount diff --git a/src/entrypoint.py b/src/entrypoint.py index 5a10933..2fd4d5e 100755 --- a/src/entrypoint.py +++ b/src/entrypoint.py @@ -4,7 +4,6 @@ import logging import os import sys -from datetime import datetime from enum import Enum from coveralls.api import Coveralls, CoverallsException @@ -68,10 +67,6 @@ def main(): args = parse_args() verbose = args.verbose set_log_level(verbose) - who_to_greet = args.who_to_greet - print(f"Hello {who_to_greet} from Python") - time = datetime.now().isoformat() - print(f"::set-output name=time::{time}") run_coveralls()