Skip to content

Commit b5c9771

Browse files
authored
[FIX]: publish working public Docker images for every service to ghcr.io (#453)
2 parents cc76b42 + 10774f7 commit b5c9771

29 files changed

Lines changed: 1028 additions & 312 deletions

.dockerignore

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,34 @@ lerna-debug.log*
77
**/v6y-logs/**
88

99
# Coverage directory used by tools like istanbul
10-
coverage
10+
**/coverage
1111
*.lcov
1212

13-
# Dependency directories
14-
node_modules/
13+
# Dependency directories. The recursive pattern matters: a bare "node_modules/"
14+
# only matches the repository root and would let pnpm's nested symlinked
15+
# workspace node_modules leak into the build context and corrupt the install.
16+
**/node_modules
1517

1618
# Optional npm cache directory
1719
.npm
1820

1921
# Optional eslint cache
20-
.eslintcache
22+
**/.eslintcache
2123

2224
# Optional stylelint cache
23-
.stylelintcache
25+
**/.stylelintcache
2426

2527
# ignore all markdown files (md) beside all README*.md other than README-secret.md
2628
*.md
2729
!README*.md
2830
README-secret.md
2931

32+
# git metadata: the runtime images copy the working tree, and the repository
33+
# history would otherwise be shipped inside every published image
34+
.git
35+
.gitignore
36+
.husky
37+
3038
# github related files
3139
.github/
3240

@@ -38,10 +46,14 @@ README-secret.md
3846
.env.local
3947

4048
# Next.js build output
41-
.next
49+
**/.next
4250

4351
# Build cache
44-
.nx
52+
**/.nx
53+
54+
# Compiled output: gitignored, so absent in CI. Excluding it here keeps local
55+
# builds byte-identical to CI ones instead of reusing stale local artifacts.
56+
**/dist
4557

4658
# Others
4759
database/psql/**
Lines changed: 76 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,114 +1,108 @@
1-
name: Docker Compose Deploy
1+
name: Publish Docker images
2+
3+
# Builds every v6y service image and pushes it to the GitHub Container Registry
4+
# so a deployment target can pull them.
5+
#
6+
# Tagging:
7+
# push to main -> main, sha-<short>, latest
8+
# release -> <release tag>, latest
9+
# latest tracks main because releases are cut rarely; pin to sha-<short> or to a
10+
# release tag when a deployment must not move.
11+
#
12+
# This workflow only builds and pushes. It deliberately performs no deployment:
13+
# the previous version ran "docker-compose up -d" on the ephemeral GitHub
14+
# runner, which started containers that were destroyed along with the runner.
215

316
on:
417
push:
518
branches: ["main"]
619
release:
7-
types: ["created"]
8-
branches: ["main"]
20+
types: ["published"]
21+
workflow_dispatch:
922

1023
env:
1124
REGISTRY: ghcr.io
1225

26+
# A superseded main build is never worth finishing.
27+
concurrency:
28+
group: docker-publish-${{ github.ref }}
29+
cancel-in-progress: true
30+
1331
jobs:
14-
deploy:
32+
publish:
1533
runs-on: ubuntu-latest
1634

1735
permissions:
1836
contents: read
1937
packages: write
20-
id-token: write
2138

2239
steps:
2340
- name: Checkout repository
2441
uses: actions/checkout@v4
2542

26-
- name: Resolve environment secrets
27-
uses: ./.github/actions/resolve-env-secrets
28-
with:
29-
prod-psql-db-host: ${{ secrets.PROD_PSQL_DB_HOST }}
30-
prod-psql-db-name: ${{ secrets.PROD_PSQL_DB_NAME }}
31-
prod-psql-db-user: ${{ secrets.PROD_PSQL_DB_USER }}
32-
prod-psql-db-password: ${{ secrets.PROD_PSQL_DB_PASSWORD }}
33-
prod-psql-db-port: ${{ secrets.PROD_PSQL_DB_PORT }}
34-
prod-gitlab-private-token: ${{ secrets.PROD_GITLAB_PRIVATE_TOKEN }}
35-
prod-github-private-token: ${{ secrets.PROD_GITHUB_PRIVATE_TOKEN }}
36-
prod-jwt-secret: ${{ secrets.PROD_JWT_SECRET }}
37-
prod-v6y-static-analyzer-api-path: ${{ secrets.PROD_V6Y_STATIC_ANALYZER_API_PATH }}
38-
prod-v6y-static-analyzer-api-port: ${{ secrets.PROD_V6Y_STATIC_ANALYZER_API_PORT }}
39-
prod-v6y-devops-api-path: ${{ secrets.PROD_V6Y_DEVOPS_API_PATH }}
40-
prod-v6y-devops-api-port: ${{ secrets.PROD_V6Y_DEVOPS_API_PORT }}
41-
prod-v6y-dynamic-analyzer-api-path: ${{ secrets.PROD_V6Y_DYNAMIC_ANALYZER_API_PATH }}
42-
prod-v6y-dynamic-analyzer-api-port: ${{ secrets.PROD_V6Y_DYNAMIC_ANALYZER_API_PORT }}
43-
prod-v6y-main-api-path: ${{ secrets.PROD_V6Y_MAIN_API_PATH }}
44-
prod-v6y-main-api-port: ${{ secrets.PROD_V6Y_MAIN_API_PORT }}
45-
prod-v6y-bff-api-path: ${{ secrets.PROD_V6Y_BFF_API_PATH }}
46-
prod-v6y-bff-api-port: ${{ secrets.PROD_V6Y_BFF_API_PORT }}
47-
prod-next-public-v6y-bff-path: ${{ secrets.PROD_NEXT_PUBLIC_V6Y_BFF_PATH }}
48-
prod-nextauth-url: ${{ secrets.PROD_NEXTAUTH_URL }}
49-
dev-psql-db-host: ${{ secrets.DEV_PSQL_DB_HOST }}
50-
dev-psql-db-name: ${{ secrets.DEV_PSQL_DB_NAME }}
51-
dev-psql-db-user: ${{ secrets.DEV_PSQL_DB_USER }}
52-
dev-psql-db-password: ${{ secrets.DEV_PSQL_DB_PASSWORD }}
53-
dev-psql-db-port: ${{ secrets.DEV_PSQL_DB_PORT }}
54-
dev-gitlab-private-token: ${{ secrets.DEV_GITLAB_PRIVATE_TOKEN }}
55-
dev-github-private-token: ${{ secrets.DEV_GITHUB_PRIVATE_TOKEN }}
56-
dev-jwt-secret: ${{ secrets.DEV_JWT_SECRET }}
57-
dev-v6y-static-analyzer-api-path: ${{ secrets.DEV_V6Y_STATIC_ANALYZER_API_PATH }}
58-
dev-v6y-static-analyzer-api-port: ${{ secrets.DEV_V6Y_STATIC_ANALYZER_API_PORT }}
59-
dev-v6y-devops-api-path: ${{ secrets.DEV_V6Y_DEVOPS_API_PATH }}
60-
dev-v6y-devops-api-port: ${{ secrets.DEV_V6Y_DEVOPS_API_PORT }}
61-
dev-v6y-dynamic-analyzer-api-path: ${{ secrets.DEV_V6Y_DYNAMIC_ANALYZER_API_PATH }}
62-
dev-v6y-dynamic-analyzer-api-port: ${{ secrets.DEV_V6Y_DYNAMIC_ANALYZER_API_PORT }}
63-
dev-v6y-main-api-path: ${{ secrets.DEV_V6Y_MAIN_API_PATH }}
64-
dev-v6y-main-api-port: ${{ secrets.DEV_V6Y_MAIN_API_PORT }}
65-
dev-v6y-bff-api-path: ${{ secrets.DEV_V6Y_BFF_API_PATH }}
66-
dev-v6y-bff-api-port: ${{ secrets.DEV_V6Y_BFF_API_PORT }}
67-
dev-next-public-v6y-bff-path: ${{ secrets.DEV_NEXT_PUBLIC_V6Y_BFF_PATH }}
68-
dev-nextauth-url: ${{ secrets.DEV_NEXTAUTH_URL }}
69-
70-
- name: Install Docker
43+
# NEXT_PUBLIC_* values are inlined into the browser bundle by next build,
44+
# so this is the one value the images need at build time. Everything else
45+
# (database credentials, JWT secret, service ports) is read at runtime and
46+
# must be injected by the deployment target, never baked into a layer.
47+
#
48+
# The production value is used even for main builds: these images exist to
49+
# be deployed, and a NEXT_PUBLIC_ value is public by construction since it
50+
# ships to browsers. Targeting another environment means rebuilding with a
51+
# different NEXT_PUBLIC_V6Y_BFF_PATH.
52+
- name: Resolve the public BFF path baked into the front bundles
7153
run: |
72-
curl -fsSL https://get.docker.com -o get-docker.sh
73-
sudo sh get-docker.sh
74-
docker --version
54+
echo "NEXT_PUBLIC_V6Y_BFF_PATH=${{ secrets.PROD_NEXT_PUBLIC_V6Y_BFF_PATH }}" >> "$GITHUB_ENV"
7555
76-
- name: Install Docker Compose
56+
- name: Compute image tags
57+
id: tags
7758
run: |
78-
DOCKER_COMPOSE_VERSION=$(curl -s "https://api.github.com/repos/docker/compose/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
79-
sudo curl -L "https://github.com/docker/compose/releases/download/$DOCKER_COMPOSE_VERSION/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
80-
sudo chmod +x /usr/local/bin/docker-compose
81-
docker-compose --version
82-
83-
- name: Determine Image Tag
84-
id: set-tag
85-
run: |
86-
if [[ "${{ github.event_name }}" == "push" ]]; then
87-
echo "IMAGE_TAG=${{ github.sha }}" >> $GITHUB_ENV
88-
elif [[ "${{ github.event_name }}" == "release" ]]; then
89-
echo "IMAGE_TAG=${{ github.event.release.tag_name }}" >> $GITHUB_ENV
59+
set -euo pipefail
60+
short_sha="$(git rev-parse --short HEAD)"
61+
if [[ "${{ github.event_name }}" == "release" ]]; then
62+
tags="${{ github.event.release.tag_name }} latest"
63+
else
64+
tags="main sha-${short_sha} latest"
9065
fi
91-
shell: bash
66+
echo "IMAGE_TAGS=${tags}" >> "$GITHUB_ENV"
67+
echo "list=${tags}" >> "$GITHUB_OUTPUT"
68+
echo "Tagging every image with: ${tags}"
69+
70+
- name: Set up Docker Buildx
71+
uses: docker/setup-buildx-action@v3
9272

93-
- name: Log into Docker registry
73+
- name: Log in to the container registry
9474
uses: docker/login-action@v3
9575
with:
9676
registry: ${{ env.REGISTRY }}
97-
username: ${{ github.repository_owner }}
77+
username: ${{ github.actor }}
9878
password: ${{ secrets.GITHUB_TOKEN }}
9979

100-
- name: Validate Docker Compose Configuration
101-
run: docker-compose -f docker-compose.yml config
102-
103-
- name: Build and push images using Docker Compose
104-
run: |
105-
export REGISTRY="ghcr.io/${{ github.repository_owner }}/"
106-
export IMAGE_TAG="${{ env.IMAGE_TAG }}"
107-
docker-compose -f docker-compose.yml build
108-
docker-compose -f docker-compose.yml push
80+
- name: Build and push every service image
81+
uses: docker/bake-action@v5
82+
with:
83+
files: docker-bake.hcl
84+
push: true
85+
# A shared cache scope is intentional: all targets descend from the
86+
# same install and build stages, so they warm each other's layers.
87+
set: |
88+
*.cache-from=type=gha,scope=v6y-images
89+
*.cache-to=type=gha,mode=max,scope=v6y-images
90+
env:
91+
REGISTRY: ${{ env.REGISTRY }}/${{ github.repository_owner }}/
92+
IMAGE_TAGS: ${{ env.IMAGE_TAGS }}
93+
NEXT_PUBLIC_V6Y_BFF_PATH: ${{ env.NEXT_PUBLIC_V6Y_BFF_PATH }}
94+
SOURCE_COMMIT: ${{ github.sha }}
10995

110-
- name: Deploy services using Docker Compose
111-
if: github.event_name == 'push' || github.event_name == 'release'
96+
- name: Summarise what was published
11297
run: |
113-
docker-compose -f docker-compose.yml pull
114-
docker-compose -f docker-compose.yml up -d
98+
{
99+
echo "### Images published to ${REGISTRY}/${{ github.repository_owner }}"
100+
echo
101+
echo "Tags applied to each image: \`${{ steps.tags.outputs.list }}\`"
102+
echo
103+
for image in v6y-migrate v6y-bff v6y-bfb-main-analyzer \
104+
v6y-bfb-static-code-auditor v6y-bfb-url-dynamic-auditor \
105+
v6y-bfb-devops-auditor v6y-frontend v6y-frontend-bo; do
106+
echo "- \`${REGISTRY}/${{ github.repository_owner }}/${image}\`"
107+
done
108+
} >> "$GITHUB_STEP_SUMMARY"

0 commit comments

Comments
 (0)