From cbe0035e2cee57a04bdeea2aec348cdb44d8ebae Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Tue, 17 Nov 2020 23:20:45 +0100 Subject: [PATCH] Switch from Travis CI to GitHub Actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Travis CI has a new pricing model since Nov'2020 with "credits" per build-minutes. The credits were depleted quite fast. There is no clear way to buy more credits, there is no clear way to request more for an open-source project, there are no clear criteria on what counts as open-source. And even if requested, the build-minutes are used fast (mostly by nightly builds) — 10'000 credits were depleted in two weeks. That might work for tiny project, but for K8s tests matrix, those credits are not enough. Besides, Travis CI has introduced the limited capacity for open-source builds, so there were a few cases when the builds were waiting for 1 hour in the backlog to be executed. This kills all the optimisations made to get the PR feedback faster, in ~5 mins. GitHub Actions offer unlimited build-minutes for public repositories, i.e. for open-source. The pricing model is clear, if it would be ever needed. If and when GitHub will cancel free builds for open-source/public repositories, that approach can be revised again in favour of Travis CI or maybe other CI tools. --- .github/workflows/publish.yaml | 27 +++ .github/workflows/tests.yaml | 155 ++++++++++++++++++ .travis.yml | 111 ------------- README.md | 2 +- docs/contributing.rst | 20 --- examples/09-testing/test_example_09.py | 2 +- .../11-filtering-handlers/test_example_11.py | 2 +- tests/e2e/conftest.py | 4 +- tools/install-kind.sh | 2 +- tools/install-kubectl.sh | 2 +- 10 files changed, 189 insertions(+), 138 deletions(-) create mode 100644 .github/workflows/publish.yaml create mode 100644 .github/workflows/tests.yaml delete mode 100644 .travis.yml diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 00000000..5484c629 --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,27 @@ +name: Publish to PyPI +on: + workflow_dispatch: + release: + types: + - published +# push: +# tags: +# - "[0-9]+.[0-9]+*" + +jobs: + publish: + name: Build and publish + if: startsWith(github.event.ref, 'refs/tags') + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: 3.9 + - run: pip install --upgrade setuptools wheel twine + - run: python setup.py sdist bdist_wheel + - uses: pypa/gh-action-pypi-publish@master + with: + user: __token__ + password: ${{ secrets.pypi_token }} + skip_existing: true diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 00000000..11511cd3 --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,155 @@ +name: Tests +on: + workflow_dispatch: + push: + branches: + - master + - release/** + paths-ignore: + - "*.md" + - "docs/**" + pull_request: + branches: + - master + schedule: + - cron: "13 3 * * *" + +jobs: + linters: + name: Linting and static analysis + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: "3.9" + - run: pip install -r requirements.txt + - run: isort . --check --diff + continue-on-error: true + - run: isort examples --settings=examples --check --diff + continue-on-error: true + + unit-tests: + strategy: + fail-fast: false + matrix: + python-version: [ "3.7", "3.8", "3.9" ] + name: Python ${{ matrix.python-version }} + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - run: pip install -r requirements.txt + - run: mypy kopf --strict --pretty + - run: pytest --cov=kopf --cov-branch --junit-xml=junit.xml + - run: coveralls || true + if: ${{ success() }} + - run: codecov --flags unit + if: ${{ success() }} +# - uses: actions/upload-artifact@v2 +# with: +# name: JUnit for ${{ matrix.python-version }} +# path: junit.xml +# if: ${{ always() }} + + functional: + strategy: + fail-fast: false + matrix: + k3s: [latest, v1.18.8+k3s1, v1.16.14+k3s1] + client: [true, false] + crdapi: ["", v1beta1] + exclude: + - client: true + - crdapi: v1beta1 + include: + - k3s: v1.16.14+k3s1 + crdapi: v1beta1 + client: false + - k3s: latest + crdapi: "" + client: true + name: >- + K3s ${{matrix.k3s}} + ${{matrix.crdapi && format('CRD={0}', matrix.crdapi) || ''}} + ${{matrix.client && '+client' || ''}} + runs-on: ubuntu-20.04 + env: + K3S: ${{ matrix.k3s }} + CLIENT: ${{ matrix.client || '' }} + CRDAPI: ${{ matrix.crdapi || '' }} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: "3.9" + - run: pip install -r requirements.txt + - run: tools/install-clients.sh + - run: tools/install-kubectl.sh + - run: tools/install-k3d-k3s.sh + - run: pytest --only-e2e + + full-scale-crd-v1: +# if: ${{ github.event_name == 'schedule' }} # TODO + strategy: + fail-fast: false + matrix: + k8s: [latest, v1.19.0, v1.18.8, v1.17.11, v1.16.14] + client: [true, false] + crdapi: [""] + python-version: ["3.9"] + exclude: + - client: true + include: + - k8s: latest + client: true + name: >- + K8s ${{matrix.k8s}} + ${{matrix.crdapi && format('CRD={0}', matrix.crdapi) || ''}} + ${{matrix.client && '+client' || ''}} + runs-on: ubuntu-20.04 + env: + K8S: ${{ matrix.k8s }} + CLIENT: ${{ matrix.client || '' }} + CRDAPI: ${{ matrix.crdapi || '' }} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - run: pip install -r requirements.txt + - run: tools/install-clients.sh + - run: tools/install-kubectl.sh + - run: tools/install-minikube.sh + - run: pytest --only-e2e + + full-scale-crd-v1beta1: +# if: ${{ github.event_name == 'schedule' }} # TODO + strategy: + fail-fast: false + matrix: + k8s: [v1.16.14, v1.15.12, v1.14.10, v1.13.12] + client: [false] + crdapi: [v1beta1] + python-version: ["3.9"] + name: >- + K8s ${{matrix.k8s}} + ${{matrix.crdapi && format('CRD={0}', matrix.crdapi) || ''}} + ${{matrix.client && '+client' || ''}} + runs-on: ubuntu-20.04 + env: + K8S: ${{ matrix.k8s }} + CLIENT: ${{ matrix.client || '' }} + CRDAPI: ${{ matrix.crdapi || '' }} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - run: pip install -r requirements.txt + - run: tools/install-clients.sh + - run: tools/install-kubectl.sh + - run: tools/install-minikube.sh + - run: pytest --only-e2e diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 608590e6..00000000 --- a/.travis.yml +++ /dev/null @@ -1,111 +0,0 @@ -# The primary environment for testing. Some jobs selectively override these settings. -os: linux -arch: amd64 -dist: focal -language: python -python: "3.9" - -# Only test the final merges and releases. The work-in-progress branches are tested by PR builds. -branches: - only: - - master - - /^release\/.*$/ - - /^\d+\.\d+(\.\d+)?(\.?(rc|dev|pre|post)\d+)?(-\S*)?(\+\S*)?$/ - -# Linting is super-fast and lightweight, gives the near-instant feedback if code is wrong. -# It does not depend on the environment (services, dependencies, even the framework itself). -# Currently, most linters are optional and performed manually from time to time. This will change. -_linting: &linting -# install: [] # no requirements.txt # TODO: Uncomment again when pre-commit is used (saves ~15s) - services: [] # no docker & co - before_script: [] - script: - - isort . --check --diff || true - - isort examples --settings=examples --check --diff || true - -# Unit-tests depend on a lightweight environment of the framework and its dependencies only, no K8s. -# Type-checking also needs the dependencies installed, but it goes first for faster failure. -_unittests: &unittests - services: [] # no docker & co - before_script: [] - script: - - mypy kopf --strict --pretty - - pytest --cov=kopf --cov-branch - after_success: - - coveralls || true - - codecov --flags unit - -# Realistic tests are heavy, slow, but needed even for PRs. They use real K8s of different versions. -# Coverage is not measured in these tests, as all lines will be covered anyway, even if some -# potentially buggy scenarios/edge-cases are missing -- such coverage is not trustworthy. -_integration: &realistic - services: - - docker - before_script: - - tools/install-clients.sh - - tools/install-kubectl.sh - - tools/install-k3d-k3s.sh - script: - - pytest --only-e2e - -# Full-scale tests run all setups and all K8s versions (including those not supported by lightweight -# K3d/K3s in PR/branch-tests). They are too slow and too numerous for PRs, so they run by cron only. -# To run/debug in a PR, comment out the `if:` line. Uncomment it back before merging. -_nightly: &fullscale - if: type == cron - services: - - docker - before_script: - - tools/install-clients.sh - - tools/install-kubectl.sh - - tools/install-minikube.sh - script: - - pytest --only-e2e - -# The job matrix combines all scripts with all intended setups. -# Only one Python version is tested with all supported K8s versions: to check for API compatibility. -# Other Python versions are tested with only one K8s version: if it works for one, it works for all. -# Ordering is important: 4 heavy jobs (5m) start asap, 3 fast jobs (1+2+2 min) run sequentially, -# thus fitting into Travis's 5-job limit with the fastest possible outcome. For cron, ignore timing. -jobs: - include: - - # Regular (daily/nightly) tests for all and old K8s versions. Very slow (8m). - - { <<: *fullscale, env: K8S=latest CLIENT=yes } - - { <<: *fullscale, env: K8S=latest } - - { <<: *fullscale, env: K8S=v1.19.0 } - - { <<: *fullscale, env: K8S=v1.18.8 } - - { <<: *fullscale, env: K8S=v1.17.11 } - - { <<: *fullscale, env: K8S=v1.16.14 } - - { <<: *fullscale, env: K8S=v1.16.14 CRDAPI=v1beta1 } - - { <<: *fullscale, env: K8S=v1.15.12 CRDAPI=v1beta1 } - - { <<: *fullscale, env: K8S=v1.14.10 CRDAPI=v1beta1 } - - { <<: *fullscale, env: K8S=v1.13.12 CRDAPI=v1beta1 } - - # Integration tests are slow (5-6m). Limit to 4 representative setups for faster PR feedbacks. - - { <<: *realistic, env: K3S=latest CLIENT=yes } - - { <<: *realistic, env: K3S=v1.18.8+k3s1 } - - { <<: *realistic, env: K3S=v1.16.14+k3s1 } - - { <<: *realistic, env: K3S=v1.16.14+k3s1 CRDAPI=v1beta1 } - - # Linting is super-fast and lightweight (40s), gives the near-instant feedback. - # Unit-tests are relatively fast (2m), but no integration tests, no k8s installed. - # This pack of jobs takes roughly 5m, which is a duration of one realistic job. - - { <<: *linting, name: Linting and static analysis } - - { <<: *unittests, python: "3.7" } - - { <<: *unittests, python: "3.8" } - - { <<: *unittests, python: "3.9" } - - fast_finish: true - allow_failures: - - python: "3.10-dev" - -deploy: - provider: pypi - username: "__token__" - password: - secure: "jkf7ncg2doyqEkASa4NFtNt9BfOcFvGvFIAj/jU55sCkKGfvavzC262/kmJnTZpF1ZStjL+z3AwSLT09cYtlujA/FRdPmuNzyRgr2j4D20Txx5whHj8zYdklquhEHbXo7FU+nQTDxkLqr35KEnMBIzoesz7xHoOH/MLzK5w2Ow8DprAjVVSY0Dv+glJ15qWo/pwNp1xetMGYjdO4ys4amdsvRlU4LmCcuMf5LsnuJyuR7yHsBs6CqmnitJezZ+fgGKqJDEC+jy/+q7aOc6V2iCDsOH5NNniUeVKTuDhmvK+1y146VVqWw+RqIG27cMyYbocmJhYRBQoLbwCKLPKF2l2YtgjKdt9izyYbjjBAVIUtsavGrsNSk08ujS8OCs9/4YXFFMjTTKwF+Hy0RqmIMNK2ymn8pWpo9HTJT2td9b0HkVikDX3D8sezD1koSxDTWYFs3MMVDPTA9lWL3sIFVHhQRr3rlk+qsoSsP5/SvVMGJv4NIjIi+SZaLvqR+aPaO1H92zVkhcMbNN3cNHE8ak1LXUmnr008xjJzsT+Y+wthx6G1zpFRSLH4dP7myxF0Zk7uJQPhaQTflICseVW4mp72HeraTKc+QHKZthTXwFeMVVSTdgNpVMpfYnjolkGXdubDbhhDhz6B4OzIRZXqiIUANHsT5zGiS0OjN7Pa4lY=" - distributions: sdist bdist_wheel - skip_existing: true - on: - tags: true # prohibit local versions not on the releases diff --git a/README.md b/README.md index 23ddb921..f7a88fb2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Kubernetes Operator Pythonic Framework (Kopf) -[![Build Status](https://travis-ci.org/nolar/kopf.svg?branch=master)](https://travis-ci.org/nolar/kopf) +[![Tests](https://github.com/nolar/kopf/workflows/Tests/badge.svg)](https://github.com/nolar/kopf/actions) [![codecov](https://codecov.io/gh/nolar/kopf/branch/master/graph/badge.svg)](https://codecov.io/gh/nolar/kopf) [![Coverage Status](https://coveralls.io/repos/github/nolar/kopf/badge.svg?branch=master)](https://coveralls.io/github/nolar/kopf?branch=master) [![Total alerts](https://img.shields.io/lgtm/alerts/g/nolar/kopf.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/nolar/kopf/alerts/) diff --git a/docs/contributing.rst b/docs/contributing.rst index ddac8557..c82e95b7 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -105,23 +105,3 @@ Code reviews You can use one of the existing or closed issues that match your topic best. * The PRs can be reviewed and commented by anyone, but can be approved only by the project maintainers. - - -Private CI/CD -============= - -The existing setup runs the Travis CI builds on every push -to the existing pull requests of the upstream repository. - -In case you do not want to create a pull request yet, -but want to run the builds for your branch, -enable Travis CI for your own fork: - -* Create a `Travis CI `_ account. -* Find your fork in the list of repos. -* Click the toggle. -* Push a feature branch to ``origin`` (see above). -* Observe how Travis runs the tests in Travis CI in your account. - -When ready, create a PR to the upstream repository. -This will run the tests in the upstream's Travis account. diff --git a/examples/09-testing/test_example_09.py b/examples/09-testing/test_example_09.py index 42d08bb3..1ccf1d18 100644 --- a/examples/09-testing/test_example_09.py +++ b/examples/09-testing/test_example_09.py @@ -11,7 +11,7 @@ @pytest.fixture(scope='session') def crd_yaml(): - crd_api = os.environ.get('CRDAPI', 'v1') + crd_api = os.environ.get('CRDAPI') or 'v1' crd_file = 'crd.yaml' if crd_api == 'v1' else f'crd-{crd_api}.yaml' return os.path.relpath(os.path.join(os.path.dirname(__file__), '..', crd_file)) diff --git a/examples/11-filtering-handlers/test_example_11.py b/examples/11-filtering-handlers/test_example_11.py index 38e24cbb..dd7377f0 100644 --- a/examples/11-filtering-handlers/test_example_11.py +++ b/examples/11-filtering-handlers/test_example_11.py @@ -11,7 +11,7 @@ @pytest.fixture(scope='session') def crd_yaml(): - crd_api = os.environ.get('CRDAPI', 'v1') + crd_api = os.environ.get('CRDAPI') or 'v1' crd_file = 'crd.yaml' if crd_api == 'v1' else f'crd-{crd_api}.yaml' return os.path.relpath(os.path.join(os.path.dirname(__file__), '..', crd_file)) diff --git a/tests/e2e/conftest.py b/tests/e2e/conftest.py index c7d11807..5e6efc20 100644 --- a/tests/e2e/conftest.py +++ b/tests/e2e/conftest.py @@ -18,14 +18,14 @@ def exampledir(request): @pytest.fixture(scope='session') def peering_yaml(): - crd_api = os.environ.get('CRDAPI', 'v1') + crd_api = os.environ.get('CRDAPI') or 'v1' crd_file = 'peering.yaml' if crd_api == 'v1' else f'peering-{crd_api}.yaml' return f'{crd_file}' @pytest.fixture(scope='session') def crd_yaml(): - crd_api = os.environ.get('CRDAPI', 'v1') + crd_api = os.environ.get('CRDAPI') or 'v1' crd_file = 'crd.yaml' if crd_api == 'v1' else f'crd-{crd_api}.yaml' return f'examples/{crd_file}' diff --git a/tools/install-kind.sh b/tools/install-kind.sh index 83c5d510..be9e85d6 100755 --- a/tools/install-kind.sh +++ b/tools/install-kind.sh @@ -19,7 +19,7 @@ if [[ "$K8S" == latest ]] ; then K8S="$( curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt )" fi -curl -Lo ./kind https://kind.sigs.k8s.io/dl/"$KIND"/kind-linux-"$TRAVIS_CPU_ARCH" +curl -Lo ./kind https://kind.sigs.k8s.io/dl/"$KIND"/kind-linux-amd64 chmod +x ./kind sudo mv ./kind /usr/local/bin/ diff --git a/tools/install-kubectl.sh b/tools/install-kubectl.sh index 8f045f7c..d7ffdf0c 100755 --- a/tools/install-kubectl.sh +++ b/tools/install-kubectl.sh @@ -13,6 +13,6 @@ if [[ "$K8S" == latest ]] ; then K8S="$( curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt )" fi -curl -Lo kubectl https://storage.googleapis.com/kubernetes-release/release/"$K8S"/bin/linux/"$TRAVIS_CPU_ARCH"/kubectl +curl -Lo kubectl https://storage.googleapis.com/kubernetes-release/release/"$K8S"/bin/linux/amd64/kubectl chmod +x kubectl sudo mv kubectl /usr/local/bin/