Skip to content

Commit b876a74

Browse files
Merge pull request #21 from NHSDigital/DTOSS-12157-create-application-package-script
[DTOSS-12157] - Add application package script and restructure CI/CD pipeline
2 parents caa6d4b + 1b12324 commit b876a74

16 files changed

Lines changed: 494 additions & 181 deletions

.editorconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,14 @@ indent_size = 4
1616

1717
[{Makefile,*.mk}]
1818
indent_style = tab
19+
20+
[*.sh]
21+
indent_size = 4
22+
23+
[**dist**]
24+
indent_size = unset
25+
indent_style = unset
26+
charset = unset
27+
end_of_line = unset
28+
insert_final_newline = unset
29+
trim_trailing_whitespace = unset

.github/dependabot.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,14 @@ updates:
2121
labels:
2222
- "dependencies"
2323
- "github-actions"
24+
25+
# Pre-commit hooks
26+
- package-ecosystem: "pre-commit"
27+
directory: "/"
28+
schedule:
29+
interval: "weekly"
30+
day: "monday"
31+
open-pull-requests-limit: 5
32+
labels:
33+
- "dependencies"
34+
- "pre-commit"
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: "CI/CD: Pull Request"
2+
3+
on:
4+
pull_request:
5+
6+
concurrency:
7+
group: cicd-${{ github.ref }}
8+
cancel-in-progress: true
9+
10+
permissions:
11+
contents: read
12+
security-events: write
13+
14+
jobs:
15+
commit-stage:
16+
uses: ./.github/workflows/stage-1-commit.yaml
17+
secrets: inherit
18+
19+
test-stage:
20+
needs: commit-stage
21+
uses: ./.github/workflows/stage-2-test.yaml
22+
secrets: inherit
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: "CI/CD: Main Branch"
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
9+
concurrency:
10+
group: cicd-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
permissions:
14+
contents: read
15+
id-token: write
16+
attestations: write
17+
security-events: write
18+
19+
jobs:
20+
commit-stage:
21+
uses: ./.github/workflows/stage-1-commit.yaml
22+
secrets: inherit
23+
24+
test-stage:
25+
needs: commit-stage
26+
uses: ./.github/workflows/stage-2-test.yaml
27+
secrets: inherit
28+
29+
build-stage:
30+
needs: test-stage
31+
uses: ./.github/workflows/stage-3-build.yaml
32+
secrets: inherit

.github/workflows/lint.yaml

Lines changed: 0 additions & 78 deletions
This file was deleted.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: "Stage 1: Commit"
2+
3+
on:
4+
workflow_call:
5+
6+
permissions:
7+
contents: read
8+
security-events: write
9+
10+
jobs:
11+
scan-secrets:
12+
name: Secret scanning
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
17+
with:
18+
# Fetch full history so gitleaks can scan all commits on the branch,
19+
# but not all branches/tags (which would let unrelated bad commits block PRs).
20+
fetch-depth: 0
21+
22+
- name: Scan secrets
23+
uses: ./.github/actions/scan-secrets
24+
25+
analyze:
26+
name: CodeQL Analysis
27+
runs-on: ubuntu-latest
28+
strategy:
29+
fail-fast: false
30+
matrix:
31+
language: [ 'python' ]
32+
steps:
33+
- name: Checkout repository
34+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
35+
36+
- name: Initialize CodeQL
37+
uses: github/codeql-action/init@8c78abb9b62512e3c45dea6559ffd924ed8549c8 # v3.28.0
38+
with:
39+
languages: ${{ matrix.language }}
40+
41+
- name: Perform CodeQL Analysis
42+
uses: github/codeql-action/analyze@8c78abb9b62512e3c45dea6559ffd924ed8549c8 # v3.28.0
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
name: "Stage 2: Test"
2+
3+
on:
4+
workflow_call:
5+
6+
permissions:
7+
contents: read
8+
security-events: write
9+
10+
jobs:
11+
test-unit:
12+
name: Unit tests
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
17+
18+
- name: Read tool versions
19+
id: tool-versions
20+
run: |
21+
echo "python=$(awk '/^python / {print $2}' .tool-versions)" >> "$GITHUB_OUTPUT"
22+
echo "uv=$(awk '/^uv / {print $2}' .tool-versions)" >> "$GITHUB_OUTPUT"
23+
24+
- name: Set up Python
25+
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
26+
with:
27+
python-version: ${{ steps.tool-versions.outputs.python }}
28+
29+
- name: Install uv
30+
uses: astral-sh/setup-uv@887a942a15af3a7626099df99e897a18d9e5ab3a # v5.1.0
31+
with:
32+
version: ${{ steps.tool-versions.outputs.uv }}
33+
enable-cache: true
34+
35+
- name: Install dependencies
36+
run: uv sync --all-extras
37+
38+
- name: Run tests
39+
run: uv run pytest
40+
41+
- name: Upload coverage reports
42+
uses: codecov/codecov-action@cb6530fbecd68d5f1ee7a3dcd113450ea8d5d6d4 # v5.1.2
43+
if: always()
44+
with:
45+
files: ./coverage.xml
46+
flags: unittests
47+
name: codecov-umbrella
48+
fail_ci_if_error: false
49+
50+
test-lint:
51+
name: Lint and type checking
52+
runs-on: ubuntu-latest
53+
steps:
54+
- name: Checkout code
55+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
56+
57+
- name: Read tool versions
58+
id: tool-versions
59+
run: |
60+
echo "python=$(awk '/^python / {print $2}' .tool-versions)" >> "$GITHUB_OUTPUT"
61+
echo "uv=$(awk '/^uv / {print $2}' .tool-versions)" >> "$GITHUB_OUTPUT"
62+
63+
- name: Set up Python
64+
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
65+
with:
66+
python-version: ${{ steps.tool-versions.outputs.python }}
67+
68+
- name: Install uv
69+
uses: astral-sh/setup-uv@887a942a15af3a7626099df99e897a18d9e5ab3a # v5.1.0
70+
with:
71+
version: ${{ steps.tool-versions.outputs.uv }}
72+
enable-cache: true
73+
74+
- name: Install dependencies
75+
run: uv sync --all-extras
76+
77+
- name: Run ruff check (SARIF)
78+
id: ruff
79+
run: |
80+
# Run ruff and capture output. If it fails or is empty, provide a valid empty SARIF.
81+
if uv run ruff check . --format sarif > ruff-results.sarif; then
82+
echo "Results generated."
83+
else
84+
echo "Ruff failed or returned non-zero. Checking if file is valid..."
85+
fi
86+
87+
# If the file is empty or missing, create a valid empty SARIF object
88+
if [ ! -s ruff-results.sarif ]; then
89+
echo '{"version": "2.1.0", "$schema": "https://json.schemastore.org/sarif-2.1.0-rtm.5.json", "runs": [{"tool": {"driver": {"name": "Ruff"}}, "results": []}]}' > ruff-results.sarif
90+
fi
91+
continue-on-error: true
92+
93+
- name: Upload ruff SARIF
94+
uses: github/codeql-action/upload-sarif@8c78abb9b62512e3c45dea6559ffd924ed8549c8 # v3.28.0
95+
with:
96+
sarif_file: ruff-results.sarif
97+
if: always()
98+
99+
- name: Run ruff format check
100+
run: uv run ruff format --check .
101+
102+
- name: Run pyright
103+
run: uv run pyright
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
name: "Stage 3: Build"
2+
3+
on:
4+
workflow_call:
5+
6+
permissions:
7+
contents: read
8+
id-token: write
9+
attestations: write
10+
11+
jobs:
12+
build:
13+
name: Build release package
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
18+
19+
- name: Determine version
20+
id: version
21+
run: |
22+
SHORT_HASH="$(git rev-parse --short HEAD)"
23+
echo "short_hash=${SHORT_HASH}" >> "$GITHUB_OUTPUT"
24+
echo "artifact_name=gateway-${SHORT_HASH}.zip" >> "$GITHUB_OUTPUT"
25+
26+
- name: Build package
27+
run: ./scripts/bash/package_release.sh "${{ runner.temp }}/dist"
28+
29+
- name: Read tool versions
30+
id: tool-versions
31+
run: |
32+
echo "python=$(awk '/^python / {print $2}' .tool-versions)" >> "$GITHUB_OUTPUT"
33+
echo "uv=$(awk '/^uv / {print $2}' .tool-versions)" >> "$GITHUB_OUTPUT"
34+
35+
- name: Set up Python
36+
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
37+
with:
38+
python-version: ${{ steps.tool-versions.outputs.python }}
39+
40+
- name: Install uv
41+
uses: astral-sh/setup-uv@887a942a15af3a7626099df99e897a18d9e5ab3a # v5.1.0
42+
with:
43+
version: ${{ steps.tool-versions.outputs.uv }}
44+
enable-cache: true
45+
46+
- name: Smoke test
47+
run: |
48+
WORK_DIR="${{ runner.temp }}/smoke-test"
49+
mkdir -p "$WORK_DIR"
50+
unzip "${{ runner.temp }}/dist/${{ steps.version.outputs.artifact_name }}" -d "$WORK_DIR"
51+
cd "$WORK_DIR"
52+
uv sync --frozen --no-dev
53+
PYTHONPATH=src uv run python -c "
54+
import pacs_main
55+
import mwl_main
56+
import upload_main
57+
import relay_listener
58+
print('All service modules imported successfully')
59+
"
60+
61+
- name: Upload artifact
62+
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
63+
with:
64+
name: gateway-package
65+
path: |
66+
${{ runner.temp }}/dist/gateway-*.zip
67+
${{ runner.temp }}/dist/gateway-*.zip.sha256
68+
retention-days: 90
69+
70+
- name: Attest build provenance
71+
uses: actions/attest-build-provenance@520d128f165991a6c774bcb264f323e3d70747f4 # v2.2.0
72+
with:
73+
subject-path: ${{ runner.temp }}/dist/${{ steps.version.outputs.artifact_name }}

0 commit comments

Comments
 (0)