-
Notifications
You must be signed in to change notification settings - Fork 3
227 lines (188 loc) · 8.65 KB
/
Copy pathrelease.yml
File metadata and controls
227 lines (188 loc) · 8.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
name: LibreFolio Release
run-name: Release ${{ github.event.release.tag_name }}
on:
push:
branches:
- dev
workflow_dispatch:
release:
types: [published]
permissions:
contents: write # Required to push to the gh-pages branch with mkdocs gh-deploy
packages: write # Required to push images to GHCR
jobs:
release-pipeline:
name: Full Release Pipeline
runs-on: ubuntu-latest
steps:
# ==========================================
# 1. BASE SETUP (Checkout & Environments)
# ==========================================
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 0 # Required for mkdocs gh-deploy (history and branches)
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Install Pipenv
run: pip install pipenv
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: '24'
# ==========================================
# 2. CACHES
# ==========================================
- name: Cache Pipenv
uses: actions/cache@v5
with:
path: ~/.local/share/virtualenvs
key: ${{ runner.os }}-pipenv-${{ hashFiles('**/Pipfile.lock') }}
restore-keys: |
${{ runner.os }}-pipenv-
- name: Cache NPM
uses: actions/cache@v5
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
# For Playwright we use a fixed cache per version
- name: Get Playwright version (from package.json)
id: playwright-version
working-directory: ./frontend
run: echo "PLAYWRIGHT_VERSION=$(node -p "require('./package.json').devDependencies['@playwright/test'].replace(/[\^~]/g, '')" || echo 'fallback')" >> $GITHUB_ENV
- name: Cache Playwright Browsers
uses: actions/cache@v5
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
# ==========================================
# 3. INSTALLATION & ASSETS BUILD
# ==========================================
- name: Install Python Dependencies
run: pipenv install --dev
- name: "[INFO] Environment summary before install"
run: |
pwd
ls -la
node -v
npm -v
python --version
pipenv --version
git log -1 --oneline
git status --short
node -p "require('./package.json').devDependencies?.['@playwright/test'] || require('./package.json').dependencies?.['@playwright/test'] || 'None'" || true
node -p "require('./frontend/package.json').devDependencies?.['@playwright/test'] || require('./frontend/package.json').dependencies?.['@playwright/test'] || 'None'" || true
ls -la ~/.cache/ms-playwright || true
find ~/.cache/ms-playwright -maxdepth 2 -type d | sort || true
- name: Install Frontend & Playwright Dependencies (via dev.py)
timeout-minutes: 15
run: pipenv run ./dev.py install
- name: "[INFO] Playwright installation check"
run: |
npm --prefix frontend exec -- playwright --version || true
- name: Build SvelteKit Frontend
# Essential for the gallery and the Dockerfile which COPYs frontend/build/
run: pipenv run ./dev.py front build
- name: Check MkDocs translation structure consistency
continue-on-error: ${{ github.ref_name == 'dev' }}
run: pipenv run ./dev.py mkdocs translate-diff --issues-only
- name: Validate broken MkDocs translation links
continue-on-error: ${{ github.ref_name == 'dev' }}
run: pipenv run ./dev.py mkdocs translate-validate --hide-localized
- name: Validate cross-boundary links
continue-on-error: ${{ github.ref_name == 'dev' }}
run: pipenv run ./dev.py mkdocs check-links
- name: Generate Screenshots with Playwright
continue-on-error: ${{ github.ref_name == 'dev' }}
timeout-minutes: 120
# ubuntu-latest (public repo) runners have 4 vCPU. --workers 8 was 2x
# oversubscribed, causing heavy CPU contention across Chromium instances
# + backend uvicorn workers + node build processes — this was the root
# cause of inconsistent per-test timeouts (a different test would time
# out on each run). Matched to actual CPU count for stable, predictable
# per-test timing (verified locally: --workers 2-3 gives a constant,
# non-degrading ~21s/interaction rate with zero flakiness).
run: pipenv run ./dev.py mkdocs gallery --workers 4
- name: Build MkDocs Documentation
continue-on-error: ${{ github.ref_name == 'dev' }}
run: pipenv run ./dev.py mkdocs build
- name: Generate requirements.txt for Docker
# The Dockerfile installs dependencies from a native requirements.txt
run: pipenv requirements > requirements.txt
- name: Generate VERSION file for Docker
# The Dockerfile COPYs a VERSION file (gitignored build artifact) so the
# image can report its version at runtime — the image has no .git/, so
# git describe cannot run there. Freeze it here on the host (fetch-depth:0
# gives us tags) reusing the same get_git_version() the app uses.
run: pipenv run python -c "from pathlib import Path; from backend.app.utils.version import get_git_version; get_git_version.cache_clear(); Path('VERSION').write_text(get_git_version())"
# ==========================================
# 4. DOCKER BUILD & PUSH (Single Image)
# ==========================================
- name: Setup QEMU
uses: docker/setup-qemu-action@v4
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v4
- name: GHCR Authentication
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract Docker Metadata (Version)
id: meta
uses: docker/metadata-action@v6
with:
images: ghcr.io/librefolio/librefolio
tags: |
type=semver,pattern={{version}}
type=raw,value=latest,enable=${{ github.ref_name == 'main' }}
type=raw,value=nightly,enable=${{ github.ref_name == 'dev' }}
labels: |
org.opencontainers.image.title=LibreFolio
org.opencontainers.image.description=LibreFolio: Open Source Personal Finance & Portfolio Tracker
- name: Build and Push Docker Image
uses: docker/build-push-action@v7
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# ==========================================
# 5. GITHUB PAGES DEPLOY
# ==========================================
- name: Setup Git User
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
- name: Deploy to gh-pages branch
if: github.ref_name == 'main' || github.event_name == 'release'
run: pipenv run ./dev.py mkdocs deploy
# ==========================================
# 6. ARTIFACTS (Optional, for archival)
# ==========================================
- name: Archive Generated Screenshots
uses: actions/upload-artifact@v6
with:
name: playwright-screenshots
path: |
mkdocs_src/docs/gallery/**/*.png
retention-days: 1
# ==========================================
# 7. RELEASE NOTES UPDATE
# ==========================================
- name: Append Docker info to Release Notes
if: github.event.release.tag_name != ''
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG_NAME="${{ github.event.release.tag_name }}"
DOCKER_CMD=$(printf '\n\n## 📦 Docker Installation\n\n```bash\n# Install the latest version\ndocker pull ghcr.io/librefolio/librefolio:latest\n\n# Or install this specific release\ndocker pull ghcr.io/librefolio/librefolio:%s\n```\n' "$TAG_NAME")
# gh CLI has no --notes-append flag: fetch current notes and append manually
CURRENT_NOTES=$(gh release view "$TAG_NAME" --json body -q .body)
gh release edit "$TAG_NAME" --notes "${CURRENT_NOTES}${DOCKER_CMD}"