@@ -102,23 +102,37 @@ jobs:
102102
103103 const builds = process.env.BUILDS ? process.env.BUILDS.split(',') : Object.keys(config.build);
104104 const push_to = process.env.PUSH_TO ? process.env.PUSH_TO.split(',') : Object.keys(config.push || {});
105+ const skip_push = process.env.SKIP_PUSH === 'true';
105106
106107 const flavors = builds.map(id => [id, config.build[id]]).filter(([id, flavor]) => flavor.skip !== true).map(([id, flavor]) => {
108+ const hooksDirectory = path.join('./deploy/build', flavor.directory, 'hooks');
109+ const testImagesHookScript = path.join(hooksDirectory, 'test-images.sh');
110+ const testImagesHookReport = path.join(hooksDirectory, 'test-images-report');
111+ const testImageEnabled = fs.existsSync(testImagesHookScript);
112+
107113 return {
108114 ...flavor,
109115 id,
116+ skip_retag: skip_push,
110117 // Add metadata to the flavor object (will be used as matrix input)
111118 build_time: buildTime,
112119 image_tag: imageTag,
113120 image_tag_branch_name: imageTagBranchName,
114- ecr_respositories: flavor.components.map(component => component.ecr_repository),
121+ ecr_repositories: flavor.components.map(component => component.ecr_repository),
122+ test_images: {
123+ enabled: testImageEnabled,
124+ script_path: testImagesHookScript,
125+ report_path: testImagesHookReport,
126+ },
115127 components: flavor.components.map(component => {
116128 // Format build arguments as build-args string
117129 const formattedBuildArgs = component.build_args ?
118130 Object.entries(component.build_args).map(([key, value]) => `${key}=${value}`).join('\n') : '';
119131
120132 return {
121133 ...component,
134+ // We can skip the push only if we don't want to test the image below
135+ skip_push: skip_push && !testImageEnabled,
122136 // Add metadata to the component object (will be used as matrix input),
123137 flavor,
124138 flavor_id: id,
@@ -133,16 +147,18 @@ jobs:
133147 };
134148 });
135149
136- const flattenedComponents = flavors.flatMap(flavor => flavor.components);
137-
138150 const result = {
139151 flavors,
140- components: flattenedComponents,
152+ flavorsToTest: flavors.filter(flavor => flavor.test_images.enabled),
153+ flavorsToRetag: flavors.filter(flavor => flavor.skip_retag !== true),
154+ componentsToBuild: flavors.flatMap(flavor => flavor.components),
141155 push_to: push_to.join(','),
156+ skip_push,
142157 };
143158 console.log(result);
144159 return result;
145160 env :
161+ SKIP_PUSH : ${{ inputs.skip_push }}
146162 BUILDS : ${{ inputs.builds }}
147163 PUSH_TO : ${{ inputs.push_to }}
148164
@@ -152,7 +168,7 @@ jobs:
152168 strategy :
153169 fail-fast : ${{ inputs.fail_fast }}
154170 matrix :
155- component : ${{ fromJson(needs.get-flavors.outputs.result).components }}
171+ component : ${{ fromJson(needs.get-flavors.outputs.result).componentsToBuild }}
156172 runs-on : ${{ vars.BUILD_DOCKER_RUNS_ON_OVERRIDE || vars.RUNS_ON_OVERRIDE || inputs.runs_on || 'ubuntu-22.04' }}
157173 steps :
158174 - name : View flavor and component
@@ -279,9 +295,12 @@ jobs:
279295 ignore-unfixed : false
280296 vuln-type : " os,library"
281297 severity : ${{ steps.set_severity.outputs.severity }}
298+ # The cache update takes quite long, so let's try to disable it for now: https://github.com/aquasecurity/trivy-action#cache
299+ cache : " false"
282300 continue-on-error : false
283301
284302 - name : Push image
303+ if : ${{ matrix.component.skip_push != true }}
285304 # Instead of the docker/build-push-action@v6 which will rebuild the image, just push it directly
286305 run : docker push ${{ matrix.component.image_ref }}
287306
@@ -292,10 +311,12 @@ jobs:
292311 test-images :
293312 name : Test images of flavor ${{ matrix.flavor.id || 'default' }}
294313 needs : [get-flavors, build-flavors]
314+ # Skip in case we would have an empty matrix. Note that in this case it also skips all downstream jobs...
315+ if : ${{ toJSON(fromJson(needs.get-flavors.outputs.result).flavorsToTest) != '[]' }}
295316 strategy :
296317 fail-fast : false
297318 matrix :
298- flavor : ${{ fromJson(needs.get-flavors.outputs.result).flavors }}
319+ flavor : ${{ fromJson(needs.get-flavors.outputs.result).flavorsToTest }}
299320 runs-on : ${{ inputs.runs_on || 'ubuntu-22.04' }}
300321 steps :
301322 - name : Checkout repository
@@ -304,13 +325,6 @@ jobs:
304325 ref : ${{ inputs.branch || github.sha }}
305326 token : ${{ secrets.CHECKOUT_TOKEN || github.event.repository.private == true && secrets.DATAVISYN_BOT_REPO_TOKEN || github.token }}
306327
307- - name : Checkout github-workflows repository
308- uses : actions/checkout@v5
309- with :
310- repository : datavisyn/github-workflows
311- ref : ${{ env.WORKFLOW_BRANCH }}
312- path : ./tmp/github-workflows
313-
314328 - name : Configure AWS Credentials
315329 uses :
aws-actions/[email protected] 316330 with :
@@ -325,9 +339,8 @@ jobs:
325339 shell : bash
326340 id : test-images
327341 run : |
328- hooks_folder="$(realpath -m "./deploy/build/${{ matrix.flavor.directory }}/hooks")"
329- test_images_hook="$hooks_folder/test-images.sh"
330- test_images_report="$hooks_folder/test-images-report"
342+ test_images_hook=$(jq -r '.test_images.script_path' <<< "$FLAVOR")
343+ test_images_report=$(jq -r '.test_images.report_path' <<< "$FLAVOR")
331344
332345 if [[ -f "$test_images_hook" ]]; then
333346 # Iterate through all components and store their image ref in an environment variable
@@ -340,15 +353,17 @@ jobs:
340353 export "IMAGE_${name_upper}=${image_ref}"
341354 done;
342355
343- # Create report folder to avoid any downstream Docker volume issues
344- # TODO: For some reason this doesn't work yet, i.e. if a docker-compose script mounts a volume here, nothing shows up...
356+ # Create a directory to store the report results
345357 mkdir -p "$test_images_report"
346- chmod 777 "$test_images_report"
347- echo "test_images_report=${test_images_report}" >> "$GITHUB_OUTPUT"
348358
349359 echo "Run $test_images_hook"
350360 chmod +x "$test_images_hook"
351361 bash "$test_images_hook"
362+
363+ # If the report folder is not empty, we store it as output
364+ if [[ -n "$(ls -A "$test_images_report")" ]]; then
365+ echo "test_images_report=${test_images_report}" >> "$GITHUB_OUTPUT"
366+ fi
352367 else
353368 echo "No $test_images_hook found, skipping tests."
354369 fi
@@ -369,11 +384,13 @@ jobs:
369384 retag-images :
370385 name : Retag images of flavor ${{ matrix.flavor.id || 'default' }}
371386 needs : [get-flavors, test-images]
372- if : ${{ inputs.skip_push != true }}
387+ # Skip in case we would have an empty matrix. Note that in this case it also skips all downstream jobs...
388+ # We need the always() && !cancelled() && !failure() because the test-images may have been skipped (which is fine). See https://github.com/actions/runner/issues/491#issuecomment-1507495166
389+ if : ${{ always() && !cancelled() && !failure() && toJSON(fromJson(needs.get-flavors.outputs.result).flavorsToRetag) != '[]' }}
373390 strategy :
374391 fail-fast : false
375392 matrix :
376- flavor : ${{ fromJson(needs.get-flavors.outputs.result).flavors }}
393+ flavor : ${{ fromJson(needs.get-flavors.outputs.result).flavorsToRetag }}
377394 # Do not run this on self-hosted, as it is faster and shouldn't be blocking anything
378395 # runs-on: ${{ inputs.runs_on || 'ubuntu-22.04' }}
379396 runs-on : " ubuntu-22.04"
@@ -410,7 +427,7 @@ jobs:
410427 echo "image_tag=$image_tag"
411428 echo "image_tag_branch_name=$image_tag_branch_name"
412429
413- for repository_name in $(jq -r '.ecr_respositories []' <<< "$FLAVOR"); do
430+ for repository_name in $(jq -r '.ecr_repositories []' <<< "$FLAVOR"); do
414431 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 )')
415432 if [[ -z "${IMAGE_META}" || ${IMAGE_META} == "null" ]]; then
416433 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')
@@ -428,9 +445,9 @@ jobs:
428445
429446 push-to-repositories :
430447 name : Push images to push targets
431- # if? When should we do this? Always? Only for certain branches? If so, how should we define that, in the config.json?
432- if : ${{ inputs.skip_push != true && fromJson(needs.get-flavors.outputs.result).push_to != '' }}
433448 needs : [retag-images, get-flavors]
449+ # if? When should we do this? Always? Only for certain branches? If so, how should we define that, in the config.json?
450+ if : ${{ fromJson(needs.get-flavors.outputs.result).skip_push != true && fromJson(needs.get-flavors.outputs.result).push_to != '' }}
434451 uses : datavisyn/github-workflows/.github/workflows/build-docker-artifacts-trigger-push.yml@main
435452 secrets : inherit
436453 with :
0 commit comments