Skip to content

Commit 546532e

Browse files
committed
ci: centralize Docker build workflows and improve reusability
- Introduced `docker-build.yml` reusable workflow to handle common Docker build and push tasks. - Refactored `build-prod-images.yml` and `build-images.yml` to leverage the reusable workflow. - Upgraded various GitHub Actions versions (e.g., actions/checkout, setup-python, setup-uv) for improved performance and compatibility. - Added caching for UV dependencies in `test-backend.yml`. - Simplified tag generation and metadata extraction processes.
1 parent 9b44b81 commit 546532e

File tree

4 files changed

+147
-169
lines changed

4 files changed

+147
-169
lines changed

.github/workflows/build-images.yml

Lines changed: 17 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ on:
44
pull_request:
55
branches:
66
- master
7-
types: [opened]
7+
types: [opened, synchronize]
88
workflow_dispatch:
99

1010
jobs:
@@ -20,7 +20,7 @@ jobs:
2020
uses: actions/checkout@v5
2121

2222
- name: Get changes
23-
uses: tj-actions/changed-files@90a06d6ba9543371ab4df8eeca0be07ca6054959
23+
uses: tj-actions/changed-files@v45
2424
id: changed_files
2525
with:
2626
files_yaml: |
@@ -34,84 +34,26 @@ jobs:
3434

3535
- name: Set lowercase repository variable
3636
id: lowercase_repo
37+
env:
38+
REPOSITORY: ${{ github.repository }}
3739
run: |
38-
REPO_LC=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
40+
REPO_LC=$(echo "$REPOSITORY" | tr '[:upper:]' '[:lower:]')
3941
echo "REPO_LC=$REPO_LC" >> $GITHUB_OUTPUT
4042
41-
build-and-push-backend:
43+
build-backend:
4244
needs: setup_build
43-
runs-on: ubuntu-latest
44-
environment: production
45-
permissions:
46-
packages: write
47-
contents: read
48-
attestations: write
49-
id-token: write
5045
if: ${{ needs.setup_build.outputs.backend_changed == 'true' }}
46+
uses: ./.github/workflows/docker-build.yml
47+
with:
48+
image_name: backend
49+
context: backend
50+
additional_tags: ghcr.io/${{ needs.setup_build.outputs.repo_lc }}-backend-preview:${{ github.event.pull_request.number || github.ref_name }}
5151

52-
steps:
53-
- name: Checkout repo
54-
uses: actions/checkout@v5
55-
56-
- name: Login to Github Container Registry
57-
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
58-
with:
59-
registry: ghcr.io
60-
username: ${{ github.actor }}
61-
password: ${{ secrets.GITHUB_TOKEN }}
62-
63-
- name: Extract metadata (tags, labels) for backend image
64-
id: meta_backend
65-
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
66-
with:
67-
images: |
68-
ghcr.io/${{ github.repository }}-backend
69-
70-
- name: Build and push Backend
71-
uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
72-
with:
73-
context: backend
74-
push: true
75-
tags: |
76-
${{ steps.meta_backend.outputs.tags }}
77-
ghcr.io/${{ needs.setup_build.outputs.repo_lc }}-backend-preview:${{ github.event.pull_request.number || github.ref_name }}
78-
labels: ${{ steps.meta_backend.outputs.labels }}
79-
80-
build-and-push-frontend:
52+
build-frontend:
8153
needs: setup_build
82-
runs-on: ubuntu-latest
83-
environment: production
84-
permissions:
85-
packages: write
86-
contents: read
87-
attestations: write
88-
id-token: write
8954
if: ${{ needs.setup_build.outputs.frontend_changed == 'true' }}
90-
91-
steps:
92-
- name: Checkout repo
93-
uses: actions/checkout@v5
94-
95-
- name: Login to Github Container Registry
96-
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
97-
with:
98-
registry: ghcr.io
99-
username: ${{ github.actor }}
100-
password: ${{ secrets.GITHUB_TOKEN }}
101-
102-
- name: Extract metadata (tags, labels) for frontend image
103-
id: meta_frontend
104-
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
105-
with:
106-
images: |
107-
ghcr.io/${{ github.repository }}-frontend
108-
109-
- name: Build and push Frontend
110-
uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
111-
with:
112-
context: frontend
113-
push: true
114-
tags: |
115-
${{ steps.meta_frontend.outputs.tags }}
116-
ghcr.io/${{ needs.setup_build.outputs.repo_lc }}-frontend-preview:${{ github.event.pull_request.number || github.ref_name }}
117-
labels: ${{ steps.meta_frontend.outputs.labels }}
55+
uses: ./.github/workflows/docker-build.yml
56+
with:
57+
image_name: frontend
58+
context: frontend
59+
additional_tags: ghcr.io/${{ needs.setup_build.outputs.repo_lc }}-frontend-preview:${{ github.event.pull_request.number || github.ref_name }}

.github/workflows/build-prod-images.yml

Lines changed: 48 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -14,103 +14,60 @@ on:
1414
type: boolean
1515

1616
jobs:
17-
build-and-push-backend:
17+
setup:
1818
runs-on: ubuntu-latest
19-
environment: production
20-
permissions:
21-
packages: write
22-
contents: read
23-
attestations: write
24-
id-token: write
19+
outputs:
20+
repo_lc: ${{ steps.normalize.outputs.repo_lc }}
21+
version: ${{ steps.normalize.outputs.version }}
22+
backend_tags: ${{ steps.tags.outputs.backend }}
23+
frontend_tags: ${{ steps.tags.outputs.frontend }}
2524

2625
steps:
27-
- name: Checkout repo
28-
uses: actions/checkout@v5
29-
- name: Normalize version
30-
id: normalize_version
26+
- name: Normalize inputs
27+
id: normalize
28+
env:
29+
VERSION_INPUT: ${{ inputs.version }}
30+
REPOSITORY: ${{ github.repository }}
3131
run: |
32-
echo "normalized_version=$(echo '${{ github.event.inputs.version }}' | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9.]/-/g')" >> $GITHUB_OUTPUT
33-
REPO_LC=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
34-
echo "REPO_LC=$REPO_LC" >> $GITHUB_OUTPUT
35-
- name: Login to Github Container Registry
36-
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
37-
with:
38-
registry: ghcr.io
39-
username: ${{ github.actor }}
40-
password: ${{ secrets.GITHUB_TOKEN }}
32+
VERSION=$(echo "$VERSION_INPUT" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9.]/-/g')
33+
REPO_LC=$(echo "$REPOSITORY" | tr '[:upper:]' '[:lower:]')
34+
echo "version=$VERSION" >> $GITHUB_OUTPUT
35+
echo "repo_lc=$REPO_LC" >> $GITHUB_OUTPUT
4136
42-
- name: Extract metadata for backend image
43-
id: meta_backend
44-
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
45-
with:
46-
images: |
47-
ghcr.io/${{ steps.normalize_version.outputs.repo_lc }}-backend
48-
- name: Set latest tag
49-
id: latest_tag
37+
- name: Build tag strings
38+
id: tags
39+
env:
40+
REPO_LC: ${{ steps.normalize.outputs.repo_lc }}
41+
VERSION: ${{ steps.normalize.outputs.version }}
42+
SET_LATEST: ${{ inputs.set_latest_tag }}
5043
run: |
51-
if [[ "${{ github.event.inputs.set_latest_tag }}" == true ]]; then
52-
echo "latest_tag=ghcr.io/${{ steps.normalize_version.outputs.repo_lc }}-backend:latest" >> $GITHUB_OUTPUT
53-
else
54-
echo "latest_tag=" >> $GITHUB_OUTPUT
44+
BACKEND_TAGS="ghcr.io/${REPO_LC}-backend:${VERSION}"
45+
FRONTEND_TAGS="ghcr.io/${REPO_LC}-frontend:${VERSION}"
46+
if [[ "$SET_LATEST" == "true" ]]; then
47+
BACKEND_TAGS="${BACKEND_TAGS}
48+
ghcr.io/${REPO_LC}-backend:latest"
49+
FRONTEND_TAGS="${FRONTEND_TAGS}
50+
ghcr.io/${REPO_LC}-frontend:latest"
5551
fi
56-
- name: Build and push Backend
57-
uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
58-
with:
59-
context: backend
60-
push: true
61-
tags: |
62-
${{ steps.meta_backend.outputs.tags }}
63-
ghcr.io/${{ steps.normalize_version.outputs.repo_lc }}-backend:${{ steps.normalize_version.outputs.normalized_version }}
64-
${{ steps.latest_tag.outputs.latest_tag }}
65-
labels: ${{ steps.meta_backend.outputs.labels }}
52+
echo "backend<<EOF" >> $GITHUB_OUTPUT
53+
echo "$BACKEND_TAGS" >> $GITHUB_OUTPUT
54+
echo "EOF" >> $GITHUB_OUTPUT
55+
echo "frontend<<EOF" >> $GITHUB_OUTPUT
56+
echo "$FRONTEND_TAGS" >> $GITHUB_OUTPUT
57+
echo "EOF" >> $GITHUB_OUTPUT
6658
67-
build-and-push-frontend:
68-
runs-on: ubuntu-latest
69-
environment: production
70-
permissions:
71-
packages: write
72-
contents: read
73-
attestations: write
74-
id-token: write
75-
76-
steps:
77-
- name: Checkout repo
78-
uses: actions/checkout@v5
59+
build-backend:
60+
needs: setup
61+
uses: ./.github/workflows/docker-build.yml
62+
with:
63+
image_name: backend
64+
context: backend
65+
additional_tags: ${{ needs.setup.outputs.backend_tags }}
7966

80-
- name: Normalize version
81-
id: normalize_version
82-
run: |
83-
echo "normalized_version=$(echo '${{ github.event.inputs.version }}' | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9.]/-/g')" >> $GITHUB_OUTPUT
84-
REPO_LC=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
85-
echo "REPO_LC=$REPO_LC" >> $GITHUB_OUTPUT
86-
- name: Login to Github Container Registry
87-
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
88-
with:
89-
registry: ghcr.io
90-
username: ${{ github.actor }}
91-
password: ${{ secrets.GITHUB_TOKEN }}
92-
93-
- name: Extract metadata for frontend image
94-
id: meta_frontend
95-
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
96-
with:
97-
images: |
98-
ghcr.io/${{ steps.normalize_version.outputs.repo_lc }}-frontend
99-
- name: Set latest tag
100-
id: latest_tag
101-
run: |
102-
if [[ "${{ github.event.inputs.set_latest_tag }}" == true ]]; then
103-
echo "latest_tag=ghcr.io/${{ steps.normalize_version.outputs.repo_lc }}-frontend:latest" >> $GITHUB_OUTPUT
104-
else
105-
echo "latest_tag=" >> $GITHUB_OUTPUT
106-
fi
107-
- name: Build and push Frontend
108-
uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
109-
with:
110-
context: frontend
111-
push: true
112-
tags: |
113-
${{ steps.meta_frontend.outputs.tags }}
114-
ghcr.io/${{ steps.normalize_version.outputs.repo_lc }}-frontend:${{ steps.normalize_version.outputs.normalized_version }}
115-
${{ steps.latest_tag.outputs.latest_tag }}
116-
labels: ${{ steps.meta_frontend.outputs.labels }}
67+
build-frontend:
68+
needs: setup
69+
uses: ./.github/workflows/docker-build.yml
70+
with:
71+
image_name: frontend
72+
context: frontend
73+
additional_tags: ${{ needs.setup.outputs.frontend_tags }}

.github/workflows/docker-build.yml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
name: Reusable Docker Build
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
image_name:
7+
description: 'Image name suffix (backend/frontend)'
8+
required: true
9+
type: string
10+
context:
11+
description: 'Docker build context path'
12+
required: true
13+
type: string
14+
additional_tags:
15+
description: 'Additional tags (newline-separated)'
16+
required: false
17+
type: string
18+
default: ''
19+
push:
20+
description: 'Push image to registry'
21+
required: false
22+
type: boolean
23+
default: true
24+
25+
jobs:
26+
build:
27+
runs-on: ubuntu-latest
28+
environment: production
29+
permissions:
30+
packages: write
31+
contents: read
32+
attestations: write
33+
id-token: write
34+
35+
steps:
36+
- name: Checkout repo
37+
uses: actions/checkout@v5
38+
39+
- name: Set up Docker Buildx
40+
uses: docker/setup-buildx-action@v3
41+
42+
- name: Normalize repository name
43+
id: repo
44+
env:
45+
REPOSITORY: ${{ github.repository }}
46+
run: |
47+
echo "name=$(echo "$REPOSITORY" | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
48+
49+
- name: Login to GitHub Container Registry
50+
uses: docker/login-action@v3
51+
with:
52+
registry: ghcr.io
53+
username: ${{ github.actor }}
54+
password: ${{ secrets.GITHUB_TOKEN }}
55+
56+
- name: Extract metadata (tags, labels)
57+
id: meta
58+
uses: docker/metadata-action@v5
59+
with:
60+
images: ghcr.io/${{ steps.repo.outputs.name }}-${{ inputs.image_name }}
61+
62+
- name: Build and push
63+
uses: docker/build-push-action@v6
64+
with:
65+
context: ${{ inputs.context }}
66+
push: ${{ inputs.push }}
67+
tags: |
68+
${{ steps.meta.outputs.tags }}
69+
${{ inputs.additional_tags }}
70+
labels: ${{ steps.meta.outputs.labels }}
71+
cache-from: type=gha
72+
cache-to: type=gha,mode=max

.github/workflows/test-backend.yml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,25 @@ jobs:
3131
3232
steps:
3333
- name: Checkout repository
34-
uses: actions/checkout@v4
34+
uses: actions/checkout@v5
3535

3636
- name: Set up Python
3737
uses: actions/setup-python@v5
3838
with:
3939
python-version: '3.13'
4040

4141
- name: Install uv
42-
uses: astral-sh/setup-uv@v4
42+
uses: astral-sh/setup-uv@v5
4343
with:
4444
version: "0.5.16"
4545

46+
- name: Cache uv dependencies
47+
uses: actions/cache@v4
48+
with:
49+
path: ~/.cache/uv
50+
key: uv-${{ runner.os }}-${{ hashFiles('backend/uv.lock') }}
51+
restore-keys: uv-${{ runner.os }}-
52+
4653
- name: Install dependencies
4754
run: uv sync --extra test --extra migrations
4855

@@ -53,4 +60,4 @@ jobs:
5360
APP_DEBUG: "true"
5461
APP_CORS_DOMAINS: '["http://test"]'
5562
APP_ALLOW_CORS_WILDCARD: "false"
56-
run: uv run pytest
63+
run: uv run pytest

0 commit comments

Comments
 (0)