andreoliwa/nitpick

View on GitHub
.github/workflows/python.yaml

Summary

Maintainability
Test Coverage
# Based on https://github.com/actions/starter-workflows/blob/main/ci/python-package.yml

# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: Python

on: [push, pull_request]

jobs:
  # Adapted from https://github.com/marketplace/actions/skip-duplicate-actions
  pre_job:
    # continue-on-error: true # TODO: Uncomment once integration is finished
    runs-on: ubuntu-latest
    # Map a step output to a job output
    outputs:
      should_skip: ${{ steps.skip_check.outputs.should_skip }}
    steps:
      - id: skip_check
        uses: fkirc/skip-duplicate-actions@v5
        with:
          # https://github.com/marketplace/actions/skip-duplicate-actions#skip-concurrent-workflow-runs
          concurrent_skipping: "same_content_newer"

  build:
    needs: pre_job
    # Always run the build step when pushing to master
    if: needs.pre_job.outputs.should_skip != 'true' || (github.event_name == 'push' && github.ref == 'refs/heads/master')
    name: "${{ matrix.python-version }} ${{ matrix.os }}"
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.12", "3.11", "3.10", "3.9", "3.8"]
        # ubuntu-latest is being moved from ubuntu-18.04 to ubuntu-20.04
        # See https://github.com/actions/virtual-environments/issues/1816
        os: [ubuntu-latest, windows-latest, macos-latest]
    runs-on: ${{ matrix.os }}
    env:
      PYTHONUNBUFFERED: 1
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}

      # https://github.com/ymyzk/tox-gh-actions
      # This action didn't work: https://github.com/marketplace/actions/run-tox-gh-actions ¯\_(ツ)_/¯
      # Error: Unable to resolve action `ymyzk/tox-gh-actions@main`, unable to find version `main`
      - name: Install tox
        run: python -m pip install tox

      - name: "Set LINT_DOCS"
        if: matrix.python-version == '3.9'
        run: |
          echo "LINT_DOCS=,lint,docs" >> $GITHUB_ENV

      - name: "Set TOX_ENV on Windows"
        if: matrix.os == 'windows-latest'
        run: |
          $pythonVersion = "${{ matrix.python-version }}"
          $TOX_ENV = "py" + $pythonVersion.Replace('.', '')
          echo "TOX_ENV=$TOX_ENV" | Out-File -FilePath $env:GITHUB_ENV -Append

      - name: "Set TOX_ENV on Linux/macOS"
        if: matrix.os != 'windows-latest'
        run: |
          echo "TOX_ENV=$(echo py${{ matrix.python-version }} | tr -d .)" >> $GITHUB_ENV

      - name: "Run tests on ${{ matrix.os }}"
        run: |
          tox -e clean,${{env.TOX_ENV}}${{env.LINT_DOCS}},report

      # https://github.com/marketplace/actions/coveralls-python
      # The official coverallsapp/github-action@master doesn't work: https://github.com/marketplace/actions/coveralls-github-action
      # It fails with "Error: Lcov file not found."
      # Solution here: https://github.com/coverallsapp/github-action/issues/30#issuecomment-612523058
      - name: Coveralls
        # TODO: ci: run code coverage on all platforms to fix missing coverage
        #   Example: https://github.com/andreoliwa/nitpick/pull/479#issuecomment-1082074275
        # This condition is needed otherwise it fails with "Error: Container action is only supported on Linux"
        if: matrix.os == 'ubuntu-latest'
        uses: AndreMiras/coveralls-python-action@develop
        with:
          parallel: true
          flag-name: Unit Test

  # https://github.com/marketplace/actions/coveralls-python
  coveralls_finish:
    name: Coveralls (finish)
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Coveralls Finished
        uses: AndreMiras/coveralls-python-action@develop
        with:
          parallel-finished: true

  # This cannot be a separate workflow yet, because a workflow cannot depend on another workflow. See this topic:
  # Depend on another workflow - Code to Cloud / GitHub Actions - GitHub Support Community
  # https://github.com/orgs/community/discussions/26632
  release:
    needs: coveralls_finish
    # https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsif
    # https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#determining-when-to-use-contexts
    if: github.event_name == 'push' && github.ref == 'refs/heads/master'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          persist-credentials: false
      # https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#adding-a-system-path
      - name: Add to PATH
        run: echo "$HOME/.local/bin" >> $GITHUB_PATH
      - name: Install pip/setuptools first
        run: python3 -m pip install --upgrade pip setuptools
      - name: Install pre-commit bumpversion twine
        run: python3 -m pip install --upgrade poetry pre-commit bumpversion twine
      - name: Display versions
        run: |
          node --version
          npm --version
          python --version
          python3 --version
          python3 -m pip --version
          pre-commit --version
          twine --version
          python3 -m pip freeze
      - name: Semantic Release
        # https://github.com/marketplace/actions/action-for-semantic-release#semantic_version
        uses: cycjimmy/semantic-release-action@v3
        id: semantic # Need an `id` for output variables
        with:
          # Don't pin the version here... it didn't work
          # https://github.com/semantic-release/semantic-release/releases
          # semantic_version: 20.0.0

          # To debug, see these options:
          # https://github.com/marketplace/actions/action-for-semantic-release#dry_run
          # dry_run: true

          # https://github.com/marketplace/actions/action-for-semantic-release#branches
          # branches: |
          #   ['you-debug-branch-name-here']

          # https://github.com/marketplace/actions/action-for-semantic-release#extra_plugins
          # https://github.com/semantic-release/changelog/releases
          # https://github.com/semantic-release/git/releases
          # https://github.com/semantic-release/exec/releases
          # Don't pin versions anymore; let's see how this goes for the next releases
          extra_plugins: |
            @semantic-release/changelog
            @semantic-release/git
            @semantic-release/exec
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
          PYPI_TEST_PASSWORD: ${{ secrets.PYPI_TEST_PASSWORD }}
      - name: New release published
        if: steps.semantic.outputs.new_release_published == 'true'
        run: |
          echo "Release = ${{ steps.semantic.outputs.new_release_version }}"
          echo "Major = ${{ steps.semantic.outputs.new_release_major_version }}"
          echo "Minor = ${{ steps.semantic.outputs.new_release_minor_version }}"
          echo "Patch = ${{ steps.semantic.outputs.new_release_patch_version }}"
          echo "Channel = ${{ steps.semantic.outputs.new_release_channel }}"
          echo "Notes = ${{ steps.semantic.outputs.new_release_notes }}"

# TODO: the workflow might fail with "rate limit" error but the release itself apparently works.
#  The follow-up actions are not executed though. See:
#  HttpError: You have exceeded a secondary rate limit https://github.com/semantic-release/semantic-release/issues/2204
#  Rate limit reached on big release https://github.com/semantic-release/semantic-release/issues/843
#  replace custom throttling code with @octokit/plugin-throttling https://github.com/semantic-release/github/issues/299
#  fix: use retry and throttle octokit plugins https://github.com/semantic-release/github/pull/487