Skip to content

Commit ce550b4

Browse files
committed
Add release automation and label sync
1 parent 4769b7d commit ce550b4

File tree

7 files changed

+403
-0
lines changed

7 files changed

+403
-0
lines changed

.github/labels.json

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
[
2+
{
3+
"name": "frontend",
4+
"color": "0e7490",
5+
"description": "Changes focused on the Next.js app or UI flows."
6+
},
7+
{
8+
"name": "ui",
9+
"color": "0891b2",
10+
"description": "Visual presentation, overlays, or interaction changes."
11+
},
12+
{
13+
"name": "backend",
14+
"color": "166534",
15+
"description": "Changes focused on the FastAPI service or vision logic."
16+
},
17+
{
18+
"name": "api",
19+
"color": "15803d",
20+
"description": "OpenAPI contract, schemas, or request-response behavior."
21+
},
22+
{
23+
"name": "ci",
24+
"color": "4f46e5",
25+
"description": "Continuous integration or workflow changes."
26+
},
27+
{
28+
"name": "release",
29+
"color": "7c3aed",
30+
"description": "Release automation, packaging, or publish flow changes."
31+
},
32+
{
33+
"name": "infra",
34+
"color": "4338ca",
35+
"description": "Developer tooling, scripts, or environment setup changes."
36+
},
37+
{
38+
"name": "docs",
39+
"color": "ca8a04",
40+
"description": "Documentation-only changes."
41+
},
42+
{
43+
"name": "chore",
44+
"color": "6b7280",
45+
"description": "Maintenance work with little or no product impact."
46+
},
47+
{
48+
"name": "patch",
49+
"color": "1d4ed8",
50+
"description": "Patch-level release bump."
51+
},
52+
{
53+
"name": "minor",
54+
"color": "2563eb",
55+
"description": "Minor release bump."
56+
},
57+
{
58+
"name": "major",
59+
"color": "b91c1c",
60+
"description": "Major release bump."
61+
}
62+
]

.github/release-drafter.yml

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
name-template: "v$NEXT_PATCH_VERSION"
2+
tag-template: "v$NEXT_PATCH_VERSION"
3+
change-template: "- $TITLE @$AUTHOR (#$NUMBER)"
4+
template: |
5+
## Changes
6+
7+
$CHANGES
8+
9+
## Docker Images
10+
11+
Replace `<repo-owner>` with the GitHub user or org that owns the repository.
12+
13+
- `ghcr.io/<repo-owner>/nextjs-python-computer-vision-kit-backend:$RESOLVED_VERSION`
14+
- `ghcr.io/<repo-owner>/nextjs-python-computer-vision-kit-frontend:$RESOLVED_VERSION`
15+
16+
categories:
17+
- title: "Frontend"
18+
labels:
19+
- frontend
20+
- ui
21+
- title: "Backend"
22+
labels:
23+
- backend
24+
- api
25+
- title: "CI/CD"
26+
labels:
27+
- ci
28+
- release
29+
- infra
30+
- title: "Docs"
31+
labels:
32+
- docs
33+
- title: "Maintenance"
34+
labels:
35+
- chore
36+
37+
change-title-escapes: '\<*_&'
38+
39+
version-resolver:
40+
major:
41+
labels:
42+
- major
43+
minor:
44+
labels:
45+
- minor
46+
patch:
47+
labels:
48+
- patch
49+
default: patch
50+
51+
autolabeler:
52+
- label: frontend
53+
files:
54+
- "frontend/**"
55+
- label: ui
56+
files:
57+
- "frontend/src/**"
58+
- "docs/assets/**"
59+
- label: backend
60+
files:
61+
- "backend/**"
62+
- label: api
63+
files:
64+
- "docs/openapi.yaml"
65+
- "backend/app/**"
66+
- "backend/tests/test_inference_route.py"
67+
- "frontend/src/generated/openapi.ts"
68+
- "frontend/src/lib/api.ts"
69+
- label: ci
70+
files:
71+
- ".github/workflows/**"
72+
- label: release
73+
files:
74+
- ".github/release-drafter.yml"
75+
- ".github/workflows/release-drafter.yml"
76+
- ".github/workflows/release.yml"
77+
- ".github/workflows/sync-labels.yml"
78+
- ".github/labels.json"
79+
- label: infra
80+
files:
81+
- "scripts/**"
82+
- "backend/Dockerfile"
83+
- "backend/.dockerignore"
84+
- "frontend/Dockerfile"
85+
- "frontend/.dockerignore"
86+
- "docker-compose.yml"
87+
- label: docs
88+
files:
89+
- "README.md"
90+
- "CONTRIBUTING.md"
91+
- "AGENTS.md"
92+
- "SECURITY.md"
93+
- "soon.md"
94+
- "docs/**"
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Release Drafter
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request_target:
8+
types:
9+
- opened
10+
- reopened
11+
- synchronize
12+
- ready_for_review
13+
workflow_dispatch:
14+
15+
permissions:
16+
contents: write
17+
pull-requests: write
18+
19+
jobs:
20+
update-release-draft:
21+
name: Update Release Draft
22+
runs-on: ubuntu-latest
23+
steps:
24+
- name: Update draft release notes
25+
uses: release-drafter/release-drafter@v6
26+
env:
27+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/release.yml

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*.*.*"
7+
8+
permissions:
9+
contents: write
10+
packages: write
11+
12+
jobs:
13+
verify:
14+
name: Verify Release Commit
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v4
19+
20+
- name: Setup Node
21+
uses: actions/setup-node@v4
22+
with:
23+
node-version-file: .nvmrc
24+
cache: npm
25+
cache-dependency-path: |
26+
package-lock.json
27+
frontend/package-lock.json
28+
29+
- name: Setup Python
30+
uses: actions/setup-python@v5
31+
with:
32+
python-version: "3.12"
33+
cache: pip
34+
cache-dependency-path: backend/pyproject.toml
35+
36+
- name: Install root tooling
37+
run: npm ci
38+
39+
- name: Install frontend dependencies
40+
run: npm ci
41+
working-directory: frontend
42+
43+
- name: Install backend dependencies
44+
run: |
45+
python -m pip install --upgrade pip
46+
python -m pip install -e ./backend[dev]
47+
48+
- name: Verify generated API types
49+
run: npm run check:contract
50+
51+
- name: Run release verification
52+
run: npm run check
53+
54+
publish-images:
55+
name: Publish GHCR Images
56+
needs: verify
57+
runs-on: ubuntu-latest
58+
steps:
59+
- name: Checkout
60+
uses: actions/checkout@v4
61+
62+
- name: Set lowercase owner
63+
id: vars
64+
run: echo "owner=${GITHUB_REPOSITORY_OWNER,,}" >> "$GITHUB_OUTPUT"
65+
shell: bash
66+
67+
- name: Set up Docker Buildx
68+
uses: docker/setup-buildx-action@v3
69+
70+
- name: Log in to GHCR
71+
uses: docker/login-action@v3
72+
with:
73+
registry: ghcr.io
74+
username: ${{ github.actor }}
75+
password: ${{ secrets.GITHUB_TOKEN }}
76+
77+
- name: Docker metadata for backend
78+
id: meta-backend
79+
uses: docker/metadata-action@v5
80+
with:
81+
images: ghcr.io/${{ steps.vars.outputs.owner }}/nextjs-python-computer-vision-kit-backend
82+
tags: |
83+
type=ref,event=tag
84+
type=semver,pattern={{version}}
85+
type=semver,pattern={{major}}.{{minor}}
86+
type=semver,pattern={{major}}
87+
88+
- name: Docker metadata for frontend
89+
id: meta-frontend
90+
uses: docker/metadata-action@v5
91+
with:
92+
images: ghcr.io/${{ steps.vars.outputs.owner }}/nextjs-python-computer-vision-kit-frontend
93+
tags: |
94+
type=ref,event=tag
95+
type=semver,pattern={{version}}
96+
type=semver,pattern={{major}}.{{minor}}
97+
type=semver,pattern={{major}}
98+
99+
- name: Build and push backend image
100+
uses: docker/build-push-action@v6
101+
with:
102+
context: ./backend
103+
file: ./backend/Dockerfile
104+
target: runner
105+
push: true
106+
tags: ${{ steps.meta-backend.outputs.tags }}
107+
labels: ${{ steps.meta-backend.outputs.labels }}
108+
cache-from: type=gha
109+
cache-to: type=gha,mode=max
110+
111+
- name: Build and push frontend image
112+
uses: docker/build-push-action@v6
113+
with:
114+
context: ./frontend
115+
file: ./frontend/Dockerfile
116+
target: runner
117+
push: true
118+
tags: ${{ steps.meta-frontend.outputs.tags }}
119+
labels: ${{ steps.meta-frontend.outputs.labels }}
120+
cache-from: type=gha
121+
cache-to: type=gha,mode=max
122+
123+
github-release:
124+
name: Publish GitHub Release
125+
needs: publish-images
126+
runs-on: ubuntu-latest
127+
steps:
128+
- name: Set lowercase owner
129+
id: vars
130+
run: echo "owner=${GITHUB_REPOSITORY_OWNER,,}" >> "$GITHUB_OUTPUT"
131+
shell: bash
132+
133+
- name: Publish release
134+
uses: softprops/action-gh-release@v2
135+
with:
136+
generate_release_notes: true
137+
append_body: true
138+
body: |
139+
## Published Images
140+
141+
- `ghcr.io/${{ steps.vars.outputs.owner }}/nextjs-python-computer-vision-kit-backend:${{ github.ref_name }}`
142+
- `ghcr.io/${{ steps.vars.outputs.owner }}/nextjs-python-computer-vision-kit-frontend:${{ github.ref_name }}`

.github/workflows/sync-labels.yml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
name: Sync Labels
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- ".github/labels.json"
9+
- ".github/workflows/sync-labels.yml"
10+
workflow_dispatch:
11+
12+
permissions:
13+
contents: read
14+
issues: write
15+
16+
jobs:
17+
sync:
18+
name: Sync Repository Labels
19+
runs-on: ubuntu-latest
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v4
23+
24+
- name: Sync labels from config
25+
uses: actions/github-script@v7
26+
with:
27+
script: |
28+
const fs = require("fs");
29+
const labels = JSON.parse(fs.readFileSync(".github/labels.json", "utf8"));
30+
const { owner, repo } = context.repo;
31+
const existing = await github.paginate(github.rest.issues.listLabelsForRepo, {
32+
owner,
33+
repo,
34+
per_page: 100,
35+
});
36+
const existingMap = new Map(existing.map((label) => [label.name, label]));
37+
38+
for (const label of labels) {
39+
if (existingMap.has(label.name)) {
40+
await github.rest.issues.updateLabel({
41+
owner,
42+
repo,
43+
name: label.name,
44+
new_name: label.name,
45+
color: label.color,
46+
description: label.description,
47+
});
48+
core.info(`Updated label: ${label.name}`);
49+
continue;
50+
}
51+
52+
await github.rest.issues.createLabel({
53+
owner,
54+
repo,
55+
name: label.name,
56+
color: label.color,
57+
description: label.description,
58+
});
59+
core.info(`Created label: ${label.name}`);
60+
}

0 commit comments

Comments
 (0)