Skip to content

Commit 365741c

Browse files
committed
feat: add common workflow for python libraries
Refs: KEH-282
1 parent 3223075 commit 365741c

2 files changed

Lines changed: 180 additions & 0 deletions

File tree

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Reusable CI workflow for Python libraries
2+
3+
This reusable workflow is part of the City of Helsinki's GitHub Actions setup, specifically designed to provide an opinionated and consistent CI process for City of Helsinki's Python library projects.
4+
5+
## Key Features
6+
7+
- **Commit Linting**: Enforces commit message standards using [commitlint](https://commitlint.js.org/).
8+
- **Code Style Checks**: Verifies code style and formatting using [pre-commit](https://pre-commit.com/).
9+
- **Automated Testing**: Runs project tests across multiple Python versions using [hatch](https://hatch.pypa.io/).
10+
- **Code Quality Analysis**: Performs a [SonarQube Cloud](https://sonarcloud.io/) scan.
11+
12+
## Requirements for Projects Using the Workflow
13+
14+
- **commitlint** [config file](https://commitlint.js.org/reference/configuration.html#config-via-file) is present in the root of the project.
15+
- **pre-commit** is set up with a `.pre-commit-config.yaml` file in the root of the project.
16+
- **hatch** is used for testing, with a `pyproject.toml` that defines the test environments.
17+
- **SonarQube Cloud** is configured with `SONAR_TOKEN` and `GITHUB_TOKEN` set in the repository secrets.
18+
19+
## Usage Instructions
20+
21+
To use this reusable workflow, create a project-specific workflow file in your `.github/workflows` directory. Set the `uses` value to `City-of-Helsinki/.github/.github/workflows/ci-python-library.yml@main` and provide the following inputs and secrets as needed:
22+
23+
### Required Inputs
24+
25+
- **`python-matrix`** (string): Python versions to use in the test matrix. Must be an array inside a string, e.g. `"['3.12', '3.13']"`.
26+
27+
### Optional Inputs
28+
29+
- **`python-version`** (string): Python version to use for pre-commit checks. Defaults to `"3.x"`.
30+
- **`enable-sonar`** (boolean): Whether to run the SonarQube Cloud Scan job after tests. Defaults to `true`.
31+
32+
### Secrets
33+
34+
- **`sonar-token`**: Token for SonarQube Cloud Scan. Required if `enable-sonar` is `true`.
35+
- **`github-token`**: `GITHUB_TOKEN` for SonarQube Cloud PR decoration. Required if `enable-sonar` is `true`.
36+
37+
### Example usage (`<own project>/.github/workflows/ci.yml`)
38+
39+
```yaml
40+
name: CI
41+
42+
on:
43+
push:
44+
branches: [main]
45+
pull_request:
46+
branches: [main]
47+
workflow_dispatch:
48+
49+
concurrency:
50+
group: ${{ github.workflow }}-${{ github.ref }}
51+
cancel-in-progress: true
52+
53+
jobs:
54+
common:
55+
uses: City-of-Helsinki/.github/.github/workflows/ci-python-library.yml@main
56+
secrets:
57+
sonar-token: ${{ secrets.SONAR_TOKEN }}
58+
github-token: ${{ secrets.GITHUB_TOKEN }}
59+
with:
60+
python-matrix: "['3.10', '3.11', '3.12', '3.13', '3.14']"
61+
```
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
name: Common CI for Python libraries
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
python-matrix:
7+
description: "Python versions to use in the test matrix. This needs to be an array inside of a string, e.g. \"['3.10', '3.11']\", due to GHA not supporting array inputs."
8+
required: true
9+
type: string
10+
python-version:
11+
description: "Python version to use for pre-commit checks."
12+
required: false
13+
type: string
14+
default: "3.x"
15+
enable-sonar:
16+
description: "Whether to run the SonarQube Cloud Scan job after tests or not. Enabled by default."
17+
required: false
18+
type: boolean
19+
default: true
20+
secrets:
21+
sonar-token:
22+
description: "Token for SonarQube Cloud Scan. Required if enable-sonar is set to true."
23+
required: false
24+
github-token:
25+
description: "GITHUB_TOKEN. Required if enable-sonar is set to true."
26+
required: false
27+
28+
jobs:
29+
commitlint:
30+
name: Check commit messages
31+
runs-on: ubuntu-latest
32+
33+
steps:
34+
- name: Checkout
35+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
36+
37+
- name: Run commitlint
38+
uses: wagoid/commitlint-github-action@b948419dd99f3fd78a6548d48f94e3df7f6bf3ed # v6.2.1
39+
40+
pre-commit:
41+
name: Run pre-commit hooks
42+
runs-on: ubuntu-latest
43+
steps:
44+
- name: Checkout
45+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
46+
47+
- name: Setup Python ${{ inputs.python-version }}
48+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
49+
with:
50+
python-version: ${{ inputs.python-version }}
51+
52+
- name: Run pre-commit
53+
uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
54+
55+
tests:
56+
name: Python ${{ matrix.python_version }}
57+
runs-on: ubuntu-latest
58+
strategy:
59+
matrix:
60+
python_version: ${{ fromJSON(inputs.python-matrix) }}
61+
62+
steps:
63+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
64+
65+
- name: Set up Python ${{ matrix.python_version }}
66+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
67+
with:
68+
python-version: ${{ matrix.python_version }}
69+
70+
- name: Set up pip cache
71+
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
72+
env:
73+
cache-name: cache-pip-modules
74+
with:
75+
path: ~/.cache/pip
76+
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('pyproject.toml') }}
77+
restore-keys: |
78+
${{ runner.os }}-build-${{ env.cache-name }}-
79+
${{ runner.os }}-build-
80+
${{ runner.os }}-
81+
82+
- name: Install hatch
83+
run: python -m pip install hatch
84+
85+
- name: Run tests
86+
run: hatch test -c -i py=${{ matrix.python_version }}
87+
88+
- name: Generate coverage report
89+
run: hatch run coverage xml -o coverage-${{ matrix.python_version }}.xml
90+
91+
- name: Upload coverage report
92+
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
93+
with:
94+
name: coverage-${{ matrix.python_version }}
95+
path: coverage-${{ matrix.python_version }}.xml
96+
97+
sonarcloud:
98+
name: Run SonarQube Cloud Scan
99+
runs-on: ubuntu-latest
100+
needs: tests
101+
if: ${{ inputs.enable-sonar }}
102+
103+
steps:
104+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
105+
with:
106+
# Required by SonarQube Cloud
107+
fetch-depth: 0
108+
109+
- name: Download coverage reports
110+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
111+
with:
112+
merge-multiple: true
113+
path: .coverage-reports
114+
115+
- name: SonarQube Cloud Scan
116+
uses: SonarSource/sonarqube-scan-action@fd88b7d7ccbaefd23d8f36f73b59db7a3d246602 # v6.0.0
117+
env:
118+
GITHUB_TOKEN: ${{ secrets.github-token }}
119+
SONAR_TOKEN: ${{ secrets.sonar-token }}

0 commit comments

Comments
 (0)