1+ name : Build docker artifacts
2+
3+ on :
4+ workflow_call :
5+ inputs :
6+ branch :
7+ type : string
8+ required : false
9+ # When using github.ref || github.head_ref, it would contain the full path, including /, which breaks the postgres hostname
10+ default : ${{ github.sha }}
11+ runs_on :
12+ type : string
13+ required : false
14+ default : " ubuntu-22.04"
15+ secrets :
16+ DATAVISYN_BOT_REPO_TOKEN :
17+ required : false
18+ CHECKOUT_TOKEN :
19+ required : false
20+ description : " Token to use for the checkout actions to access private repositories"
21+
22+ concurrency :
23+ group : " ${{ github.workflow }}-${{ github.ref || github.head_ref }}"
24+ cancel-in-progress : true
25+
26+ env :
27+ WORKFLOW_BRANCH : " mp/build_docker"
28+ PYTHON_BASE_IMAGE : " python:3.10.8-slim-bullseye"
29+ DATAVISYN_PYTHON_BASE_IMAGE : " 188237246440.dkr.ecr.eu-central-1.amazonaws.com/datavisyn/base/python:main"
30+ NODE_BASE_IMAGE : " node:20.9-bullseye"
31+ DATAVISYN_NGINX_BASE_IMAGE : " 188237246440.dkr.ecr.eu-central-1.amazonaws.com/datavisyn/base/nginx:main"
32+
33+ permissions :
34+ contents : read
35+ id-token : write
36+
37+ jobs :
38+ get-flavors :
39+ name : Get flavors from config.json
40+ outputs :
41+ result : ${{ steps.get-flavors.outputs.result }}
42+ runs-on : ${{ inputs.runs_on || 'ubuntu-22.04' }}
43+ steps :
44+ - name : Checkout repository
45+ uses : actions/checkout@v4
46+ with :
47+ ref : ${{ inputs.branch }}
48+ token : ${{ secrets.CHECKOUT_TOKEN || github.event.repository.private == true && secrets.DATAVISYN_BOT_REPO_TOKEN || github.token }}
49+
50+ - name : Checkout github-workflows repository
51+ uses : actions/checkout@v4
52+ with :
53+ repository : datavisyn/github-workflows
54+ ref : ${{ env.WORKFLOW_BRANCH }}
55+ path : ./tmp/github-workflows
56+
57+ - name : Validate ./deploy/build/config.json
58+ shell : bash
59+ run : |
60+ # Validate the config with the schema
61+ python -m venv .venv
62+ source .venv/bin/activate
63+ pip install jsonschema
64+ jsonschema -i ./deploy/build/config.json ./tmp/github-workflows/.github/workflows/build-docker-artifacts-config.schema.json
65+ deactivate
66+ rm -rf .venv
67+
68+ - name : Get all flavors and components from ./deploy/build/config.json
69+ uses : actions/github-script@v7
70+ id : get-flavors
71+ with :
72+ script : |
73+ const fs = require('fs');
74+ const path = require('path');
75+ const config = require('./deploy/build/config.json');
76+
77+ const buildTime = new Date().toISOString().replace(/:/g, '').replace(/\..+/, 'Z');
78+ const imageTagBranchName = "${{ github.ref }}".replace('refs/heads/', '').replace(/[^a-zA-Z0-9._-]/g, '-');
79+ const imageTag = `tagged-${imageTagBranchName}-${buildTime}`;
80+
81+ const flavors = config.flavors.filter(flavor => flavor.skip !== true).map(flavor => {
82+ return {
83+ ...flavor,
84+ // Add metadata to the flavor object (will be used as matrix input)
85+ build_time: buildTime,
86+ image_tag: imageTag,
87+ image_tag_branch_name: imageTagBranchName,
88+ ecr_respositories: flavor.components.map(component => component.ecr_repository),
89+ components: flavor.components.map(component => {
90+ return {
91+ ...component,
92+ // Add metadata to the component object (will be used as matrix input),
93+ flavor,
94+ flavor_directory: `./deploy/build/${flavor.directory}`,
95+ build_time: buildTime,
96+ image_tag: imageTag,
97+ image_tag_branch_name: imageTagBranchName,
98+ };
99+ }),
100+ };
101+ });
102+
103+ const flattenedComponents = flavors.flatMap(flavor => flavor.components);
104+
105+ const result = {
106+ flavors,
107+ components: flattenedComponents,
108+ };
109+ console.log(result);
110+ return result;
111+
112+ build-flavors :
113+ name : Build ${{ matrix.component.directory }} of ${{ matrix.component.flavor.directory }} (${{ matrix.component.ecr_repository }}:${{ matrix.component.image_tag }})
114+ needs : get-flavors
115+ strategy :
116+ fail-fast : true
117+ matrix :
118+ component : ${{ fromJson(needs.get-flavors.outputs.result).components }}
119+ runs-on : ${{ inputs.runs_on || 'ubuntu-22.04' }}
120+ steps :
121+ - name : View flavor and component
122+ shell : bash
123+ run : |
124+ echo "Component ${{ toJson(matrix.component) }}"
125+ - name : Remove unnecessary files
126+ run : |
127+ sudo rm -rf /usr/share/dotnet
128+ sudo rm -rf /usr/local/lib/android
129+ sudo rm -rf /opt/ghc
130+ # TODO: Support arbitrary repositories, not just the current one?
131+ - name : Checkout repository
132+ uses : actions/checkout@v4
133+ with :
134+ ref : ${{ inputs.branch }}
135+ token : ${{ secrets.CHECKOUT_TOKEN || github.event.repository.private == true && secrets.DATAVISYN_BOT_REPO_TOKEN || github.token }}
136+ # This is required such that yarn install can access private repositories, i.e. visyn_pro
137+ # https://github.com/yarnpkg/yarn/issues/2614#issuecomment-2148174789
138+ persist-credentials : false
139+ - name : Checkout github-workflows repository
140+ uses : actions/checkout@v4
141+ with :
142+ repository : datavisyn/github-workflows
143+ ref : ${{ env.WORKFLOW_BRANCH }}
144+ path : ./tmp/github-workflows
145+ # This is required such that yarn install can access private repositories, i.e. visyn_pro
146+ # https://github.com/yarnpkg/yarn/issues/2614#issuecomment-2148174789
147+ persist-credentials : false
148+ - name : Copy _base folder and .env
149+ shell : bash
150+ run : |
151+ if [[ -d "./deploy/build/_base" ]]; then
152+ echo "copy _base directory into flavor"
153+ cp -r -n "./deploy/build/_base/." "${{ matrix.component.flavor_directory }}"
154+ tree "${{ matrix.component.flavor_directory }}"
155+ fi
156+ if [[ -f "${{ matrix.component.flavor_directory }}/${{ matrix.component.directory }}/.env" ]]; then
157+ echo "copy .env into repo root"
158+ cp "${{ matrix.component.flavor_directory }}/${{ matrix.component.directory }}/.env" "./"
159+ fi
160+
161+ # Required for build secrets to work: https://docs.docker.com/build/ci/github-actions/secrets/#secret-mounts
162+ - name : Set up QEMU
163+ uses : docker/setup-qemu-action@v3
164+ - name : Set up Docker Buildx
165+ uses : docker/setup-buildx-action@v3
166+
167+ - name : Configure AWS Credentials
168+ uses :
aws-actions/[email protected] 169+ with :
170+ role-to-assume : ${{ vars.DV_AWS_ECR_ROLE }}
171+ aws-region : ${{ vars.DV_AWS_REGION }}
172+
173+ - name : Login to Amazon ECR
174+ id : login-ecr
175+ uses :
aws-actions/[email protected] 176+
177+ - name : Build image
178+ uses : docker/build-push-action@v6
179+ with :
180+ context : .
181+ file : ${{ matrix.component.flavor_directory }}/${{ matrix.component.directory }}/Dockerfile
182+ push : true
183+ # Disable provenance as it creates weird multi-arch images: https://github.com/docker/build-push-action/issues/755
184+ provenance : false
185+ build-args : |
186+ DOCKERFILE_DIRECTORY=${{ matrix.component.flavor_directory }}/${{ matrix.component.directory }}
187+ PYTHON_BASE_IMAGE=${{ env.PYTHON_BASE_IMAGE }}
188+ DATAVISYN_PYTHON_BASE_IMAGE=${{ env.DATAVISYN_PYTHON_BASE_IMAGE }}
189+ NODE_BASE_IMAGE=${{ env.NODE_BASE_IMAGE }}
190+ DATAVISYN_NGINX_BASE_IMAGE=${{ env.DATAVISYN_NGINX_BASE_IMAGE }}
191+ secrets :
192+ # Mount the token as secret mount: https://docs.docker.com/build/ci/github-actions/secrets/#secret-mounts
193+ " github_token=${{ secrets.CHECKOUT_TOKEN || github.event.repository.private == true && secrets.DATAVISYN_BOT_REPO_TOKEN || github.token }}"
194+ # TODO: As soon as we only have a single tag, we can push the same image to multiple repositories: https://docs.docker.com/build/ci/github-actions/push-multi-registries/
195+ # This will be useful for the images which don't change between flavors, e.g. the backend images
196+ tags : |
197+ ${{ vars.DV_AWS_ECR_REGISTRY }}/${{ matrix.component.ecr_repository }}:${{ matrix.component.image_tag }}
198+ labels : |
199+ name=${{ matrix.component.ecr_repository }}
200+ version=${{ matrix.component.image_tag_branch_name }}
201+ org.opencontainers.image.description=Image for ${{ matrix.component.ecr_repository }}
202+ org.opencontainers.image.source=${{ github.event.repository.html_url }}
203+ org.opencontainers.image.url=${{ github.event.repository.html_url }}
204+ org.opencontainers.image.title=${{ matrix.component.ecr_repository }}
205+ org.opencontainers.image.version=${{ matrix.component.image_tag_branch_name }}
206+ org.opencontainers.image.created=${{ matrix.component.build_time }}
207+ org.opencontainers.image.revision=${{ github.sha }}
208+ env :
209+ # Disable the build summary for now as it leads to "Failed to export build record: .../export/rec.dockerbuild not found"
210+ # https://github.com/docker/build-push-action/issues/1156#issuecomment-2437227730
211+ DOCKER_BUILD_SUMMARY : false
212+
213+ - name : Log out from Amazon ECR
214+ shell : bash
215+ run : docker logout ${{ steps.login-ecr.outputs.registry }}
216+
217+ - name : Scan image
218+ if : ${{ matrix.component.skip_image_scan != true }}
219+ id : get-ecr-scan-result
220+ uses : ./tmp/github-workflows/.github/actions/get-ecr-scan-result
221+ with :
222+ aws_role : ${{ vars.DV_AWS_ECR_ROLE }}
223+ aws_region : ${{ vars.DV_AWS_REGION }}
224+ ecr_registry : ${{ vars.DV_AWS_ECR_REGISTRY }}
225+ ecr_repository : ${{ matrix.component.ecr_repository }}
226+ image_tag : ${{ matrix.component.image_tag }}
227+ - name : Check scan results
228+ if : ${{ matrix.component.skip_image_scan != true }}
229+ run : |
230+ if [ "${{ steps.get-ecr-scan-result.outputs.critical }}" != "null" ] || [ "${{ steps.get-ecr-scan-result.outputs.high }}" != "null" ]; then
231+ echo "Docker image contains vulnerabilities at critical or high level"
232+ exit 1 #exit execution due to docker image vulnerabilities
233+ fi
234+
235+ post-build :
236+ name : Retag images of flavor ${{ matrix.flavor || 'default' }}
237+ needs : [get-flavors, build-flavors]
238+ strategy :
239+ fail-fast : false
240+ matrix :
241+ flavor : ${{ fromJson(needs.get-flavors.outputs.result).flavors }}
242+ runs-on : ${{ inputs.runs_on || 'ubuntu-22.04' }}
243+ steps :
244+ - name : Checkout repository
245+ uses : actions/checkout@v4
246+ with :
247+ ref : ${{ inputs.branch }}
248+ token : ${{ secrets.CHECKOUT_TOKEN || github.event.repository.private == true && secrets.DATAVISYN_BOT_REPO_TOKEN || github.token }}
249+
250+ - name : Checkout github-workflows repository
251+ uses : actions/checkout@v4
252+ with :
253+ repository : datavisyn/github-workflows
254+ ref : ${{ env.WORKFLOW_BRANCH }}
255+ path : ./tmp/github-workflows
256+
257+ - name : Configure AWS Credentials
258+ uses :
aws-actions/[email protected] 259+ with :
260+ role-to-assume : ${{ vars.DV_AWS_ECR_ROLE }}
261+ aws-region : ${{ vars.DV_AWS_REGION }}
262+
263+ - name : Login to Amazon ECR
264+ id : login-ecr
265+ uses :
aws-actions/[email protected] 266+
267+ - name : Retag images
268+ shell : bash
269+ run : |
270+ image_tag="${{ matrix.flavor.image_tag }}"
271+ image_tag_branch_name="${{ matrix.flavor.image_tag_branch_name }}"
272+
273+ echo image_tag=$image_tag
274+ echo image_tag_branch_name=$image_tag_branch_name
275+
276+ for repository_name in $(jq -r '.ecr_respositories[]' <<< "$FLAVOR"); do
277+ IMAGE_META=$(aws ecr describe-images --repository-name "$repository_name" --image-ids imageTag="$image_tag" --output json | jq --arg var "${image_tag_branch_name}" '.imageDetails[0].imageTags | index( $var )')
278+ if [[ -z "${IMAGE_META}" || ${IMAGE_META} == "null" ]]; then
279+ MANIFEST=$(aws ecr batch-get-image --repository-name $repository_name --image-ids imageTag=$image_tag --output json | jq --raw-output --join-output '.images[0].imageManifest')
280+ aws ecr put-image --repository-name $repository_name --image-tag $image_tag_branch_name --image-manifest "$MANIFEST"
281+ else
282+ echo "image already tagged!"
283+ fi
284+ done;
285+ env :
286+ FLAVOR : ${{ toJSON(matrix.flavor) }}
0 commit comments