Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 62 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,67 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}

# ============================================
# JOB 5: Sentry - upload source maps (automatic on main, manual on any branch)
# JOB 5: Assets - push static assets to the OVH S3 bucket (automatic on main, manual on any branch)
# ============================================
# Runs alongside the Docker build, reusing the same `build-output` artifact. Because the actual
# rollout is triggered by `create-deploy-release.yml` on `workflow_run: CI completed (success)`,
# the new container is only deployed once this job succeeds — so the assets are always on the
# bucket before the new HTML referencing them is served.
upload-assets:
needs: [quality_and_test, e2e]
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch'
permissions:
contents: read
env:
# Bucket itself (CORS, lifecycle) is configured at the infra level. Public readability
# is carried by the per-object `public-read` ACL set below, not by a bucket policy.
AWS_ACCESS_KEY_ID: ${{ secrets.ASSETS_S3_ACCESS_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.ASSETS_S3_SECRET_KEY }}
AWS_DEFAULT_REGION: ${{ vars.ASSETS_S3_REGION }}
S3_ENDPOINT: ${{ vars.ASSETS_S3_ENDPOINT }}
S3_BUCKET: ${{ vars.ASSETS_S3_BUCKET }}
steps:
- name: Download build artifacts
uses: actions/download-artifact@v8
with:
name: build-output
path: .output

- name: Push hashed build assets to S3
run: |
# `_nuxt/` and `_fonts/` filenames are content-hashed, so they are immutable: cache
# them forever. No `--delete`: old chunks must stay available for clients still on the
# previous version during a rolling deploy; stale assets are purged by an infra
# lifecycle rule. `.map` files stay out of the bucket (they are shipped to Sentry
# instead), and so do `.br`/`.gz`: S3 has no content negotiation, so a browser asking
# for `foo.js` always gets the plain object and the compressed variants are dead weight.
aws s3 sync .output/public/_nuxt "s3://${S3_BUCKET}/_nuxt" \
--endpoint-url "$S3_ENDPOINT" \
--acl public-read \
--cache-control "public, max-age=31536000, immutable" \
--exclude "*.map" --exclude "*.br" --exclude "*.gz" \
--no-progress

aws s3 sync .output/public/_fonts "s3://${S3_BUCKET}/_fonts" \
--endpoint-url "$S3_ENDPOINT" \
--acl public-read \
--cache-control "public, max-age=31536000, immutable" \
--no-progress

- name: Push remaining public files to S3
run: |
# Non-hashed files (favicon, nuxt_images, ...) get a short TTL so they can be updated.
aws s3 sync .output/public "s3://${S3_BUCKET}" \
--endpoint-url "$S3_ENDPOINT" \
--acl public-read \
--cache-control "public, max-age=3600" \
--exclude "_nuxt/*" --exclude "_fonts/*" \
--exclude "*.map" --exclude "*.br" --exclude "*.gz" \
--no-progress

# ============================================
# JOB 6: Sentry - upload source maps (automatic on main, manual on any branch)
# ============================================
sentry:
needs: [quality_and_test, e2e]
Expand Down Expand Up @@ -425,7 +485,7 @@ jobs:
ignore_missing: true

# ============================================
# JOB 6: Publish datagouv-components (automatic on main, manual on any branch)
# JOB 7: Publish datagouv-components (automatic on main, manual on any branch)
# ============================================
publish-datagouv-components:
needs: [quality_and_test, e2e]
Expand Down
4 changes: 4 additions & 0 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export default defineNuxtConfig({
devtools: { enabled: true, componentInspector: false },

app: {
// Build assets (`/_nuxt/`) and public files are served from a CDN/S3 bucket in production.
// Empty by default and overridden at runtime via the `NUXT_APP_CDN_URL` env var, so the very
// same build runs with or without the CDN (e.g. E2E tests start the server without it).
cdnURL: '',
head: {
bodyAttrs: {
class: 'datagouv-components font-marianne',
Expand Down
Loading