Skip to content

Commit 90eea8b

Browse files
committed
refactor: update GitHub workflows for release management and image building
- Added new workflows for creating releases, preparing releases, and publishing libraries on merge. - Implemented logic to derive version from pull request titles and create Git tags/releases accordingly. - Enhanced image building workflows to include digest capturing and improved error handling. - Refactored existing workflows to streamline the process of bumping versions for internal libraries and services. - Introduced scripts for bumping chart versions and updating pyproject dependencies. - Removed obsolete scripts and workflows to clean up the repository.
1 parent 5d453c5 commit 90eea8b

14 files changed

Lines changed: 687 additions & 240 deletions

.github/workflows/build-images.yml

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
name: build-images
2+
run-name: build-images ${{ github.event.release.tag_name }}
3+
on:
4+
release:
5+
types: [published]
6+
7+
permissions:
8+
contents: read
9+
packages: write
10+
11+
jobs:
12+
prepare:
13+
if: ${{ github.event_name == 'release' }}
14+
runs-on: ubuntu-latest
15+
outputs:
16+
tag: ${{ steps.release_tag.outputs.tag }}
17+
version: ${{ steps.release_tag.outputs.version }}
18+
steps:
19+
- uses: actions/checkout@v4
20+
with:
21+
fetch-depth: 0
22+
- name: Resolve release tag & version
23+
id: release_tag
24+
run: |
25+
git fetch --tags --force
26+
TAG="${{ github.event.release.tag_name }}"
27+
if [ -z "$TAG" ]; then
28+
echo "No Git tag found to check out" >&2
29+
exit 1
30+
fi
31+
VER_NO_V="${TAG#v}"
32+
echo "tag=$TAG" >> $GITHUB_OUTPUT
33+
echo "version=$VER_NO_V" >> $GITHUB_OUTPUT
34+
35+
build-image:
36+
needs: prepare
37+
runs-on: ubuntu-latest
38+
strategy:
39+
fail-fast: false
40+
matrix:
41+
include:
42+
- name: rag-backend
43+
dockerfile: services/rag-backend/Dockerfile
44+
- name: admin-backend
45+
dockerfile: services/admin-backend/Dockerfile
46+
- name: document-extractor
47+
dockerfile: services/document-extractor/Dockerfile
48+
- name: mcp-server
49+
dockerfile: services/mcp-server/Dockerfile
50+
- name: frontend
51+
dockerfile: services/frontend/apps/chat-app/Dockerfile
52+
- name: admin-frontend
53+
dockerfile: services/frontend/apps/admin-app/Dockerfile
54+
env:
55+
REGISTRY: ghcr.io
56+
IMAGE_NS: ${{ github.repository }}
57+
VERSION: ${{ needs.prepare.outputs.version }}
58+
TAG: ${{ needs.prepare.outputs.tag }}
59+
steps:
60+
- uses: actions/checkout@v4
61+
with:
62+
fetch-depth: 0
63+
- name: Checkout release tag
64+
run: git checkout "$TAG"
65+
- name: Normalize IMAGE_NS to lowercase
66+
run: echo "IMAGE_NS=$(echo '${{ env.IMAGE_NS }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
67+
- name: Login to GHCR
68+
uses: docker/login-action@v3
69+
with:
70+
registry: ghcr.io
71+
username: ${{ github.actor }}
72+
password: ${{ secrets.GHCR_PAT }}
73+
- name: Set up Buildx
74+
uses: docker/setup-buildx-action@v3
75+
- name: Build & push ${{ matrix.name }}
76+
run: |
77+
docker buildx build --push \
78+
-t "$REGISTRY/$IMAGE_NS/${{ matrix.name }}:${VERSION}" \
79+
-t "$REGISTRY/$IMAGE_NS/${{ matrix.name }}:latest" \
80+
-f "${{ matrix.dockerfile }}" .
81+
- name: Capture digest
82+
run: |
83+
sudo apt-get update && sudo apt-get install -y jq
84+
ref="$REGISTRY/$IMAGE_NS/${{ matrix.name }}:${VERSION}"
85+
digest=$(docker buildx imagetools inspect "$ref" --format '{{json .Manifest.Digest}}' | jq -r . || true)
86+
jq -n --arg name "${{ matrix.name }}" --arg tag "$VERSION" --arg digest "$digest" '{($name): {tag: $tag, digest: $digest}}' > digest.json
87+
- name: Upload digest artifact
88+
uses: actions/upload-artifact@v4
89+
with:
90+
name: image-digest-${{ matrix.name }}
91+
path: digest.json
92+
93+
collect-digests:
94+
needs: [build-image]
95+
runs-on: ubuntu-latest
96+
steps:
97+
- name: Download digest artifacts
98+
uses: actions/download-artifact@v4
99+
with:
100+
pattern: image-digest-*
101+
merge-multiple: false
102+
- name: Merge digests
103+
run: |
104+
sudo apt-get update && sudo apt-get install -y jq
105+
jq -s 'reduce .[] as $item ({}; . * $item)' image-digest-*/digest.json > image-digests.json
106+
- name: Upload merged digests
107+
uses: actions/upload-artifact@v4
108+
with:
109+
name: image-digests
110+
path: image-digests.json
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: create-release
2+
on:
3+
pull_request_target:
4+
types: [closed]
5+
branches: [main]
6+
7+
permissions:
8+
contents: write
9+
10+
jobs:
11+
release:
12+
if: >-
13+
${{
14+
github.event.pull_request.merged == true &&
15+
contains(github.event.pull_request.labels.*.name, 'refresh-locks')
16+
}}
17+
runs-on: ubuntu-latest
18+
steps:
19+
- uses: actions/checkout@v4
20+
with:
21+
fetch-depth: 0
22+
23+
- name: Derive version from PR title
24+
id: ver
25+
run: |
26+
TITLE="${{ github.event.pull_request.title }}"
27+
VERSION=$(echo "$TITLE" | sed -nE 's/.*([0-9]+\.[0-9]+\.[0-9]+(\.post[0-9]+)?).*/\1/p' || true)
28+
if [ -z "$VERSION" ]; then
29+
echo "Could not extract version from PR title: $TITLE" >&2
30+
exit 1
31+
fi
32+
echo "version=$VERSION" >> $GITHUB_OUTPUT
33+
34+
- name: Create Git tag
35+
run: |
36+
git config user.name "github-actions"
37+
git config user.email "github-actions@github.com"
38+
git tag -a "v${{ steps.ver.outputs.version }}" -m "Release v${{ steps.ver.outputs.version }}"
39+
git push origin "v${{ steps.ver.outputs.version }}"
40+
41+
- name: Create GitHub Release
42+
uses: softprops/action-gh-release@v2
43+
with:
44+
tag_name: v${{ steps.ver.outputs.version }}
45+
name: v${{ steps.ver.outputs.version }}
46+
generate_release_notes: true
47+
token: ${{ secrets.GHCR_PAT }}

.github/workflows/lint-and-test.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ env:
1212

1313
jobs:
1414
changes:
15+
if: >-
16+
${{
17+
!contains(github.event.pull_request.labels.*.name, 'prepare-release') &&
18+
!contains(github.event.pull_request.labels.*.name, 'refresh-locks') &&
19+
!contains(github.event.pull_request.labels.*.name, 'chart-bump')
20+
}}
1521
name: Detect Changes
1622
runs-on: ubuntu-latest
1723
outputs:
@@ -81,7 +87,7 @@ jobs:
8187

8288
- name: Build Docker image
8389
run: |
84-
docker build -t $IMAGE_NAME --build-arg dev=1 -f services/${{ matrix.service }}/Dockerfile .
90+
docker build -t $IMAGE_NAME -f services/${{ matrix.service }}/Dockerfile.dev .
8591
8692
- name: Run linting
8793
run: |
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
name: prepare-release
2+
on:
3+
pull_request:
4+
types: [closed]
5+
branches:
6+
- main
7+
8+
permissions:
9+
contents: write
10+
pull-requests: write
11+
12+
jobs:
13+
prepare:
14+
if: >-
15+
${{
16+
github.event.pull_request.merged &&
17+
!contains(github.event.pull_request.labels.*.name, 'prepare-release') &&
18+
!contains(github.event.pull_request.labels.*.name, 'refresh-locks') &&
19+
!contains(github.event.pull_request.labels.*.name, 'chart-bump')
20+
}}
21+
runs-on: ubuntu-latest
22+
steps:
23+
- uses: actions/checkout@v4
24+
with:
25+
fetch-depth: 0
26+
27+
- name: Setup Node
28+
uses: actions/setup-node@v4
29+
with:
30+
node-version: '20'
31+
32+
- name: Install semantic-release deps
33+
run: npm ci
34+
35+
- name: verify-dependencies-integrity
36+
run: npm audit signatures
37+
38+
- name: Compute next version (dry-run)
39+
id: semrel
40+
env:
41+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
42+
run: |
43+
npx semantic-release --dry-run --no-ci | tee semrel.log
44+
BASE_VERSION=$(grep -Eo "next release version is [0-9]+\.[0-9]+\.[0-9]+" semrel.log | awk '{print $5}')
45+
if [ -z "$BASE_VERSION" ]; then echo "No new release required"; exit 1; fi
46+
VERSION="${BASE_VERSION}.post$(date +%Y%m%d%H%M%S)"
47+
echo "version=$VERSION" >> $GITHUB_OUTPUT
48+
49+
- name: Setup Python
50+
uses: actions/setup-python@v5
51+
with:
52+
python-version: '3.13'
53+
54+
- name: Install bump script deps
55+
run: |
56+
python -m pip install --upgrade pip
57+
python -m pip install "tomlkit==0.13.3" "pyyaml==6.0.2" "packaging==25.0"
58+
59+
- name: Bump internal libs only (no service pins)
60+
run: |
61+
python tools/bump_pyproject_deps.py --version "${{ steps.semrel.outputs.version }}" --bump-libs
62+
63+
- name: Commit and open PR
64+
uses: peter-evans/create-pull-request@v6
65+
with:
66+
branch: chore/release-${{ steps.semrel.outputs.version }}
67+
title: "chore(release): prepare ${{ steps.semrel.outputs.version }}"
68+
body: |
69+
Prepare release ${{ steps.semrel.outputs.version }}
70+
- bump internal libs versions only
71+
commit-message: "chore(release): prepare ${{ steps.semrel.outputs.version }}"
72+
add-paths: |
73+
libs/**/pyproject.toml
74+
labels: prepare-release
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
name: publish-chart
2+
run-name: publish-chart (post-build-images)
3+
on:
4+
workflow_run:
5+
workflows: [build-images]
6+
types: [completed]
7+
8+
permissions:
9+
contents: write
10+
pull-requests: write
11+
packages: write
12+
13+
jobs:
14+
chart:
15+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@v4
19+
with:
20+
fetch-depth: 0
21+
22+
- name: Checkout release tag from triggering run
23+
run: |
24+
git fetch --tags --force
25+
HEAD_SHA="${{ github.event.workflow_run.head_sha }}"
26+
if [ -n "$HEAD_SHA" ]; then
27+
TAG=$(git tag --points-at "$HEAD_SHA" | head -n 1 || true)
28+
if [ -z "$TAG" ]; then
29+
TAG=$(git describe --tags --abbrev=0 "$HEAD_SHA" 2>/dev/null || true)
30+
fi
31+
fi
32+
if [ -z "$TAG" ]; then
33+
echo "No tag found (head_sha=$HEAD_SHA)" >&2
34+
exit 1
35+
fi
36+
git checkout "$TAG"
37+
echo "RELEASE_TAG=$TAG" >> $GITHUB_ENV
38+
echo "APP_VERSION=${TAG#v}" >> $GITHUB_ENV
39+
40+
- name: Expose app version
41+
id: meta
42+
run: echo "app_version=${APP_VERSION}" >> $GITHUB_OUTPUT
43+
44+
- name: Setup Helm
45+
uses: azure/setup-helm@v4
46+
47+
- name: Login to GHCR for Helm OCI
48+
run: echo ${{ secrets.GHCR_PAT }} | helm registry login ghcr.io -u ${{ github.actor }} --password-stdin
49+
50+
- name: Setup Python (for bump script)
51+
uses: actions/setup-python@v5
52+
with:
53+
python-version: '3.13'
54+
55+
- name: Install bump script deps
56+
run: |
57+
python -m pip install --upgrade pip
58+
python -m pip install "pyyaml==6.0.2" "packaging==25.0"
59+
60+
- name: Bump Chart.yaml (set release version)
61+
env:
62+
APP_VERSION: ${{ env.APP_VERSION }}
63+
run: |
64+
python tools/bump_chart_versions.py --app-version "$APP_VERSION"
65+
66+
- name: Package and push rag chart
67+
env:
68+
APP_VERSION: ${{ env.APP_VERSION }}
69+
run: |
70+
set -euo pipefail
71+
export HELM_EXPERIMENTAL_OCI=1
72+
CHART_DIR="infrastructure/rag"
73+
if [ ! -f "$CHART_DIR/Chart.yaml" ]; then
74+
echo "Expected chart at $CHART_DIR/Chart.yaml not found" >&2
75+
exit 1
76+
fi
77+
mkdir -p dist
78+
helm dependency update "$CHART_DIR" || true
79+
helm package "$CHART_DIR" --destination dist
80+
PKG=$(ls dist/*.tgz)
81+
helm show chart "$PKG" | grep -E "^version: "
82+
helm push "$PKG" oci://ghcr.io/${{ github.repository_owner }}/charts
83+
84+
- name: Create PR for chart version bumps
85+
uses: peter-evans/create-pull-request@v6
86+
with:
87+
base: main
88+
branch: chore/chart-bump-${{ steps.meta.outputs.app_version }}
89+
title: "chore(release): bump chart versions to ${{ steps.meta.outputs.app_version }}"
90+
body: |
91+
Persist Chart.yaml appVersion/version to match release ${{ steps.meta.outputs.app_version }}.
92+
commit-message: "chore(release): bump charts to ${{ steps.meta.outputs.app_version }}"
93+
add-paths: |
94+
infrastructure/**/Chart.yaml
95+
labels: chart-bump

0 commit comments

Comments
 (0)