summaryrefslogtreecommitdiffstats
path: root/.github/workflows
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.github/workflows/ci.yml142
-rw-r--r--.github/workflows/github-release.yml14
-rw-r--r--.github/workflows/publish-docker.yml79
-rw-r--r--.github/workflows/publish-release.yml176
-rw-r--r--.github/workflows/test-release.yml95
5 files changed, 506 insertions, 0 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..403dcc4
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,142 @@
+name: Tests and Checks
+
+# Only run CI on pushes to main and pull requests
+# We don't run CI on other branches, but those should be merged into main via a PR anyways which will trigger CI before the merge.
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ branches:
+ - main
+
+concurrency:
+ group: ci-${{ github.ref }}-1
+ cancel-in-progress: true
+
+jobs:
+ checks:
+ runs-on: "ubuntu-latest"
+ strategy:
+ matrix:
+ python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", pypy-3.9]
+ os: ["macos-latest", "ubuntu-latest", "windows-latest"]
+ steps:
+ - uses: actions/checkout@v3.3.0
+ with:
+ ref: ${{ github.event.pull_request.head.sha }} # Checkout pull request HEAD commit instead of merge commit
+ fetch-depth: 0 # checkout all history, needed for hatch versioning
+
+ - name: Setup python
+ uses: actions/setup-python@v4.5.0
+ with:
+ python-version: ${{ matrix.python-version }}
+
+ - name: Install pypa/build
+ run: python -m pip install build==0.10.0
+
+ - name: Install Hatch
+ run: python -m pip install hatch==1.6.3
+
+ - name: Unit Tests
+ run: hatch run test:unit-tests
+
+ - name: Code formatting (black)
+ run: hatch run test:format
+
+ - name: Code linting (ruff)
+ run: hatch run test:lint
+
+ - name: Install local gitlint for integration tests
+ run: |
+ hatch run qa:install-local
+
+ - name: Integration tests (default -> GITLINT_USE_SH_LIB=1)
+ run: |
+ hatch run qa:integration-tests
+ if: matrix.os != 'windows-latest'
+
+ - name: Integration tests (GITLINT_USE_SH_LIB=1)
+ run: |
+ hatch run qa:integration-tests
+ env:
+ GITLINT_USE_SH_LIB: 1
+ if: matrix.os != 'windows-latest'
+
+ - name: Integration tests (GITLINT_QA_USE_SH_LIB=0)
+ run: |
+ hatch run qa:integration-tests -k "not(test_commit_hook_continue or test_commit_hook_abort or test_commit_hook_edit)" qa
+ env:
+ GITLINT_QA_USE_SH_LIB: 0
+ if: matrix.os != 'windows-latest'
+
+ - name: Integration tests (Windows)
+ run: |
+ hatch run qa:integration-tests -k "not (test_commit_hook_continue or test_commit_hook_abort or test_commit_hook_edit or test_lint_staged_stdin or test_stdin_file or test_stdin_pipe_empty)" qa
+ if: matrix.os == 'windows-latest'
+
+ - name: Build test (gitlint)
+ run: |
+ python -m build
+ hatch clean
+
+ - name: Build test (gitlint-core)
+ run: |
+ python -m build
+ hatch clean
+ working-directory: ./gitlint-core
+
+ - name: Docs build (mkdocs)
+ run: hatch run docs:build
+
+ # Run gitlint. Skip during PR runs, since PR commit messages are transient and usually full of gitlint violations.
+ # PRs get squashed and get a proper commit message during merge.
+ - name: gitlint --debug
+ run: hatch run dev:gitlint --debug
+ continue-on-error: ${{ github.event_name == 'pull_request' }} # Don't enforce gitlint in PRs
+
+ - name: Code Coverage (coveralls)
+ uses: coverallsapp/github-action@master
+ with:
+ path-to-lcov: ".coverage.lcov"
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ git-commit: ${{ github.event.pull_request.head.sha }}
+ flag-name: gitlint-${{ matrix.os }}-${{ matrix.python-version }}
+ parallel: true
+
+ upload_coveralls:
+ needs: checks
+ runs-on: ubuntu-latest
+ steps:
+ - name: Upload coverage to coveralls
+ uses: coverallsapp/github-action@master
+ with:
+ path-to-lcov: ".coverage.lcov"
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ parallel-finished: true
+
+ check: # This job does nothing and is only used for the branch protection
+ if: always() # Ref: https://github.com/marketplace/actions/alls-green#why
+
+ needs:
+ - upload_coveralls
+ - checks
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Decide whether the needed jobs succeeded or failed
+ uses: re-actors/alls-green@release/v1
+ with:
+ jobs: ${{ toJSON(needs) }}
+
+ # When on main, auto publish dev build
+ auto-publish-dev:
+ needs:
+ - check
+ if: github.ref == 'refs/heads/main'
+ uses: ./.github/workflows/publish-release.yml
+ secrets: inherit # pass all secrets (required to access secrets in a called workflow)
+ with:
+ pypi_target: "pypi.org"
+ repo_release_ref: "main"
diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml
new file mode 100644
index 0000000..e5e40c9
--- /dev/null
+++ b/.github/workflows/github-release.yml
@@ -0,0 +1,14 @@
+name: Github Release Publish
+run-name: "Github Release Publish (tag=${{github.ref_name}})"
+
+on:
+ release:
+ types: [published]
+
+jobs:
+ publish-release:
+ uses: ./.github/workflows/publish-release.yml
+ secrets: inherit # pass all secrets (required to access secrets in a called workflow)
+ with:
+ pypi_target: "pypi.org"
+ repo_release_ref: ${{ github.ref_name }}
diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml
new file mode 100644
index 0000000..092b6b3
--- /dev/null
+++ b/.github/workflows/publish-docker.yml
@@ -0,0 +1,79 @@
+name: Publish Docker
+run-name: "Publish Docker (gitlint_version=${{ inputs.gitlint_version }})"
+
+on:
+ workflow_call:
+ inputs:
+ gitlint_version:
+ description: "Gitlint version to build docker image for"
+ required: true
+ type: string
+ docker_image_tag:
+ description: "Docker image tag"
+ required: true
+ type: string
+ push_to_dockerhub:
+ description: "Push to dockerhub.com"
+ required: false
+ type: boolean
+ default: false
+ workflow_dispatch:
+ inputs:
+ gitlint_version:
+ description: "Gitlint version to build docker image for"
+ type: string
+ docker_image_tag:
+ description: "Docker image tag"
+ required: true
+ type: choice
+ options:
+ - "latest_dev"
+ - "latest"
+ - "Use $gitlint_version"
+ default: "Use $gitlint_version"
+ push_to_dockerhub:
+ description: "Push to dockerhub.com"
+ required: false
+ type: boolean
+ default: false
+
+jobs:
+ publish_docker:
+ runs-on: "ubuntu-latest"
+ steps:
+ - name: Determine docker tag
+ id: set_tag
+ run: |
+ if [[ "${{ inputs.docker_image_tag }}" == "Use $gitlint_version" ]]; then
+ echo "docker_image_tag=${{ inputs.gitlint_version }}" >> $GITHUB_OUTPUT
+ else
+ echo "docker_image_tag=${{ inputs.docker_image_tag }}" >> $GITHUB_OUTPUT
+ fi
+
+ - name: Login to Docker Hub
+ uses: docker/login-action@v2
+ with:
+ username: jorisroovers
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Build docker image
+ uses: docker/build-push-action@v4
+ with:
+ build-args: GITLINT_VERSION=${{ inputs.gitlint_version }}
+ tags: jorisroovers/gitlint:${{ steps.set_tag.outputs.docker_image_tag }}
+
+ - name: Test docker image
+ run: |
+ gitlint_version=$(docker run --ulimit nofile=1024 -v $(pwd):/repo jorisroovers/gitlint:${{ steps.set_tag.outputs.docker_image_tag }} --version)
+ [ "$gitlint_version" == "gitlint, version ${{ inputs.gitlint_version }}" ]
+
+
+ # This won't actually rebuild the docker image, but just push the previously built and cached image
+ - name: Push docker image
+ uses: docker/build-push-action@v4
+ with:
+ push: ${{ inputs.push_to_dockerhub }}
+ build-args: GITLINT_VERSION=${{ inputs.gitlint_version }}
+ tags: jorisroovers/gitlint:${{ steps.set_tag.outputs.docker_image_tag }}
+ if: inputs.push_to_dockerhub
+ \ No newline at end of file
diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml
new file mode 100644
index 0000000..22ac4be
--- /dev/null
+++ b/.github/workflows/publish-release.yml
@@ -0,0 +1,176 @@
+name: Publish Release
+run-name: "Publish Release (pypi_target=${{ inputs.pypi_target }}, repo_release_ref=${{ inputs.repo_release_ref }})"
+
+on:
+ # Trigger release workflow from other workflows (e.g. release dev build as part of CI)
+ workflow_call:
+ inputs:
+ pypi_target:
+ description: "PyPI repository to publish to"
+ required: true
+ type: string
+ default: "test.pypi.org"
+ repo_release_ref:
+ description: "Gitlint git reference to publish release for"
+ type: string
+ default: "main"
+
+ # Manually trigger a release
+ workflow_dispatch:
+ inputs:
+ pypi_target:
+ description: "PyPI repository to publish to"
+ required: true
+ type: choice
+ options:
+ - "pypi.org"
+ - "test.pypi.org"
+ default: "test.pypi.org"
+ repo_release_ref:
+ description: "Gitlint git reference to publish release for"
+ type: string
+ default: "main"
+
+jobs:
+ publish:
+ timeout-minutes: 15
+ runs-on: "ubuntu-latest"
+ outputs:
+ gitlint_version: ${{ steps.set_version.outputs.gitlint_version }}
+ steps:
+ - name: Setup python
+ uses: actions/setup-python@v4.5.0
+ with:
+ python-version: "3.11"
+
+ - name: Install pypa/build
+ run: python -m pip install build==0.10.0
+
+ - name: Install Hatch
+ run: python -m pip install hatch==1.6.3
+
+ - uses: actions/checkout@v3.3.0
+ with:
+ ref: ${{ inputs.repo_release_ref }}
+ fetch-depth: 0 # checkout all history, needed for hatch versioning
+
+ # Run hatch version once to avoid additional output ("Setting up build environment for missing dependencies")
+ # during the next step
+ - name: Hatch version
+ run: hatch version
+
+ # Hatch versioning is based on git (using hatch-vcs). If there is no explicit tag for the commit we're trying to
+ # publish, hatch versioning strings will have this format: 0.19.0.dev52+g9f7dc7d
+ # With the string after '+' being the 'g<short-sha>' of the commit.
+ #
+ # However, PyPI doesn't allow '+' in version numbers (no PEP440 local versions allowed on PyPI).
+ # To work around this, we override the version string by setting the SETUPTOOLS_SCM_PRETEND_VERSION env var
+ # to the version string without the '+' and everything after it.
+ # We do this by setting the `gitlint_version` step output here and re-using it later to
+ # set SETUPTOOLS_SCM_PRETEND_VERSION.
+ #
+ # We only actually publish such releases on the main branch to guarantee the dev numbering scheme remains
+ # unique.
+ # Note that when a tag *is* present (i.e. v0.19.0), hatch versioning will return the tag name (i.e. 0.19.0)
+ # and this step has no effect, ie. SETUPTOOLS_SCM_PRETEND_VERSION will be the same as `hatch version`.
+ - name: Set SETUPTOOLS_SCM_PRETEND_VERSION
+ id: set_version
+ run: |
+ echo "gitlint_version=$(hatch version | cut -d+ -f1)" >> $GITHUB_OUTPUT
+
+ - name: Build (gitlint-core)
+ run: python -m build
+ working-directory: ./gitlint-core
+ env:
+ SETUPTOOLS_SCM_PRETEND_VERSION: ${{ steps.set_version.outputs.gitlint_version }}
+
+ - name: Build (gitlint)
+ run: python -m build
+ env:
+ SETUPTOOLS_SCM_PRETEND_VERSION: ${{ steps.set_version.outputs.gitlint_version }}
+
+ - name: Publish gitlint-core (pypi.org)
+ run: hatch publish
+ working-directory: ./gitlint-core
+ env:
+ HATCH_INDEX_USER: ${{ secrets.PYPI_GITLINT_CORE_USERNAME }}
+ HATCH_INDEX_AUTH: ${{ secrets.PYPI_GITLINT_CORE_PASSWORD }}
+ if: inputs.pypi_target == 'pypi.org'
+
+ - name: Publish gitlint (pypi.org)
+ run: hatch publish
+ env:
+ HATCH_INDEX_USER: ${{ secrets.PYPI_GITLINT_USERNAME }}
+ HATCH_INDEX_AUTH: ${{ secrets.PYPI_GITLINT_PASSWORD }}
+ if: inputs.pypi_target == 'pypi.org'
+
+ - name: Publish gitlint-core (test.pypi.org)
+ run: hatch publish -r test
+ working-directory: ./gitlint-core
+ env:
+ HATCH_INDEX_USER: ${{ secrets.TEST_PYPI_GITLINT_CORE_USERNAME }}
+ HATCH_INDEX_AUTH: ${{ secrets.TEST_PYPI_GITLINT_CORE_PASSWORD }}
+ if: inputs.pypi_target == 'test.pypi.org'
+
+ - name: Publish gitlint (test.pypi.org)
+ run: hatch publish -r test
+ env:
+ HATCH_INDEX_USER: ${{ secrets.TEST_PYPI_GITLINT_USERNAME }}
+ HATCH_INDEX_AUTH: ${{ secrets.TEST_PYPI_GITLINT_PASSWORD }}
+ if: inputs.pypi_target == 'test.pypi.org'
+
+ # Wait for gitlint package to be available in PyPI for installation
+ wait-for-package:
+ needs:
+ - publish
+ runs-on: "ubuntu-latest"
+ steps:
+ - name: Install gitlint
+ uses: nick-fields/retry@v2.8.3
+ with:
+ timeout_minutes: 1
+ max_attempts: 10
+ command: |
+ python -m pip install gitlint==${{ needs.publish.outputs.gitlint_version }}
+ if: inputs.pypi_target == 'pypi.org'
+
+ - name: Install gitlint (test.pypi.org)
+ uses: nick-fields/retry@v2.8.3
+ with:
+ timeout_minutes: 1
+ max_attempts: 10
+ command: |
+ pip install --no-cache-dir -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple gitlint==${{ needs.publish.outputs.gitlint_version }}
+ if: inputs.pypi_target == 'test.pypi.org'
+
+ - name: gitlint --version
+ run: |
+ gitlint --version
+ [ "$(gitlint --version)" == "gitlint, version ${{ needs.publish.outputs.gitlint_version }}" ]
+
+ # Unfortunately, it's not because the newly published package installation worked once that replication
+ # has finished amongst all PyPI servers (subsequent installations might still fail). We sleep for 10 min here
+ # to increase the odds that replication has finished.
+ - name: Sleep
+ run: sleep 600
+
+ test-release:
+ needs:
+ - publish
+ - wait-for-package
+ uses: ./.github/workflows/test-release.yml
+ with:
+ gitlint_version: ${{ needs.publish.outputs.gitlint_version }}
+ pypi_source: ${{ inputs.pypi_target }}
+ repo_test_ref: ${{ inputs.repo_release_ref }}
+
+ publish-docker:
+ needs:
+ - publish
+ - test-release
+ uses: ./.github/workflows/publish-docker.yml
+ secrets: inherit # pass all secrets (required to access secrets in a called workflow)
+ with:
+ gitlint_version: ${{ needs.publish.outputs.gitlint_version }}
+ docker_image_tag: "latest_dev"
+ push_to_dockerhub: true
diff --git a/.github/workflows/test-release.yml b/.github/workflows/test-release.yml
new file mode 100644
index 0000000..caf00dd
--- /dev/null
+++ b/.github/workflows/test-release.yml
@@ -0,0 +1,95 @@
+name: Test Release
+run-name: "Test Release (${{ inputs.gitlint_version }}, pypi_source=${{ inputs.pypi_source }}, repo_test_ref=${{ inputs.repo_test_ref }})"
+on:
+ workflow_call:
+ inputs:
+ gitlint_version:
+ description: "Gitlint version to test"
+ required: true
+ default: "0.18.0"
+ type: string
+ pypi_source:
+ description: "PyPI repository to use"
+ required: true
+ type: string
+ repo_test_ref:
+ description: "Git reference to checkout for integration tests"
+ default: "main"
+ type: string
+ workflow_dispatch:
+ inputs:
+ gitlint_version:
+ description: "Gitlint version to test"
+ required: true
+ default: "0.18.0"
+ pypi_source:
+ description: "PyPI repository to use"
+ required: true
+ type: choice
+ options:
+ - "pypi.org"
+ - "test.pypi.org"
+ default: "pypi.org"
+ repo_test_ref:
+ description: "Git reference to checkout for integration tests"
+ default: "main"
+
+jobs:
+ test-release:
+ timeout-minutes: 10
+ runs-on: "ubuntu-latest"
+ strategy:
+ matrix:
+ python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", pypy-3.9]
+ os: ["macos-latest", "ubuntu-latest", "windows-latest"]
+ steps:
+ - name: Setup python
+ uses: actions/setup-python@v4.5.0
+ with:
+ python-version: ${{ matrix.python-version }}
+
+ - name: Install Hatch
+ run: python -m pip install hatch==1.6.3
+
+ - name: Install gitlint
+ run: |
+ python -m pip install gitlint==${{ inputs.gitlint_version }}
+ if: inputs.pypi_source == 'pypi.org'
+
+ - name: Install gitlint (test.pypi.org)
+ run: |
+ pip install --no-cache-dir -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple gitlint==${{ inputs.gitlint_version }}
+ if: inputs.pypi_source == 'test.pypi.org'
+
+ - name: gitlint --version
+ run: |
+ gitlint --version
+ [ "$(gitlint --version)" == "gitlint, version ${{ inputs.gitlint_version }}" ]
+
+ - uses: actions/checkout@v3.3.0
+ with:
+ ref: ${{ inputs.repo_test_ref }}
+
+ - name: Integration tests (default -> GITLINT_USE_SH_LIB=1)
+ run: |
+ hatch run qa:integration-tests
+ if: matrix.os != 'windows-latest'
+
+ - name: Integration tests (GITLINT_USE_SH_LIB=1)
+ run: |
+ hatch run qa:integration-tests
+ env:
+ GITLINT_USE_SH_LIB: 1
+ if: matrix.os != 'windows-latest'
+
+ - name: Integration tests (GITLINT_QA_USE_SH_LIB=0)
+ run: |
+ hatch run qa:integration-tests -k "not(test_commit_hook_continue or test_commit_hook_abort or test_commit_hook_edit)" qa
+ env:
+ GITLINT_QA_USE_SH_LIB: 0
+ if: matrix.os != 'windows-latest'
+
+ - name: Integration tests (Windows)
+ run: |
+ hatch run qa:integration-tests -k "not (test_commit_hook_continue or test_commit_hook_abort or test_commit_hook_edit or test_lint_staged_stdin or test_stdin_file or test_stdin_pipe_empty)" qa
+ if: matrix.os == 'windows-latest'