8888 Accepts either a string (container image name) or a JSON object with container options.
8989
9090 String format (simple):
91- ```
91+ ```yml
9292 container: "node:18"
9393 ```
9494
123123 SECRET_EXAMPLE=$\{{ secrets.SECRET_EXAMPLE }}
124124 ```
125125 required : false
126+ container-password :
127+ description : |
128+ Password for container registry authentication, if required.
129+ Used when the container image is hosted in a private registry.
130+ See https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/run-jobs-in-a-container#defining-credentials-for-a-container-registry.
131+ required : false
126132 outputs :
127133 build-artifact-id :
128134 description : " ID of the build artifact) uploaded during the build step."
@@ -131,56 +137,72 @@ on:
131137permissions : {}
132138
133139jobs :
134- parse-container :
135- name : 📦 Parse Container Configuration
136- if : inputs.container != ''
140+ prepare :
141+ name : 📦 Prepare configuration
137142 runs-on : ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
138143 permissions : {}
139144 outputs :
140- config : ${{ steps.parse.outputs.config }}
145+ container-image : ${{ steps.parse.outputs.container-image }}
146+ container-options : ${{ steps.parse.outputs.container-options }}
147+ container-username : ${{ steps.parse.outputs.container-username }}
141148 steps :
142149 - id : parse
143150 uses : actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
144151 env :
145152 CONTAINER_INPUT : ${{ inputs.container }}
153+ CONTAINER_PASSWORD : ${{ secrets.container-password }}
146154 with :
147155 script : |
148156 const containerInput = process.env.CONTAINER_INPUT.trim();
157+ if (!containerInput) {
158+ return;
159+ }
160+ core.debug(`Container input: ${containerInput}`);
149161
150162 // Check if input is a JSON object or a simple string
151163 const isJson = containerInput.startsWith('{');
152164
153- let config = {
154- image: '',
165+ let container = {
155166 options: '--user root:root'
156167 };
157168
158169 if (isJson) {
159170 try {
160- const container = JSON.parse(containerInput);
161-
162- // Set image
163- config.image = container.image || '';
164-
165- // Add env if provided
166- if (container.env && Object.keys(container.env).length > 0) {
167- config.env = container.env;
168- }
169-
170- // Merge user options with default --user root:root
171- if (container.options) {
172- config.options = `${config.options} ${container.options}`;
173- }
171+ const parsedContainer = JSON.parse(containerInput);
172+ core.debug(`Parsed container input as JSON: ${JSON.stringify(parsedContainer)}`);
173+ container = {
174+ ...container,
175+ ...parsedContainer,
176+ options: `${container.options} ${parsedContainer.options || ''}`.trim()
177+ };
178+
174179 } catch (error) {
175- core.setFailed(`Failed to parse container input as JSON: ${error.message}`);
176- return;
180+ return core.setFailed(`Failed to parse container input as JSON: ${error.message}`,{ cause: error });
177181 }
178182 } else {
179183 // Simple string format - just the image name
180- config .image = containerInput;
184+ container .image = containerInput;
181185 }
182186
183- core.setOutput('config', JSON.stringify(config));
187+ core.debug(`Parsed container configuration: ${JSON.stringify(container)}`);
188+
189+ if (!container.image) {
190+ return core.setFailed('Container image must be specified in the container input.');
191+ }
192+ core.setOutput('container-image', container.image);
193+
194+ if (container.options) {
195+ core.setOutput('container-options', container.options);
196+ }
197+
198+ if (container.credentials?.username) {
199+ core.setOutput('container-username', container.credentials.username);
200+ if (!process.env.CONTAINER_PASSWORD) {
201+ return core.setFailed('Container password must be provided when container credentials username is specified.');
202+ }
203+ } else if (process.env.CONTAINER_PASSWORD) {
204+ return core.setFailed('Container credentials username must be provided when container password is specified.');
205+ }
184206
185207 code-ql :
186208 name : 🛡️ CodeQL Analysis
@@ -208,9 +230,11 @@ jobs:
208230 setup :
209231 name : ⚙️ Setup
210232 runs-on : ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
211- container : ${{ inputs.container != '' && fromJSON(needs.parse-container.outputs.config) || null }}
212- needs : parse-container
213- if : ${{ always() && !cancelled() && !failure() }}
233+ needs : prepare
234+ container : &container-setup
235+ image : ${{ needs.prepare.outputs.container-image || '' }}
236+ options : ${{ needs.prepare.outputs.container-options || ' ' }}
237+ credentials : ${{ fromJSON(needs.prepare.outputs.container-username && format('{{"username":{0},"password":{1}}}',toJSON(needs.prepare.outputs.container-username),toJSON(secrets.container-password)) || '{}') }}
214238 permissions :
215239 contents : read
216240 # FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
@@ -220,7 +244,7 @@ jobs:
220244 build-commands : ${{ steps.build-variables.outputs.commands }}
221245 build-artifact : ${{ steps.build-variables.outputs.artifact }}
222246 steps :
223- - if : inputs. container == ''
247+ - if : needs.prepare.outputs. container-image == null
224248 uses : hoverkraft-tech/ci-github-common/actions/checkout@753288393de1f3d92f687a6761d236ca800f5306 # 0.28.1
225249
226250 - id : build-variables
@@ -324,22 +348,21 @@ jobs:
324348
325349 lint :
326350 name : 👕 Lint
327- if : inputs.checks == true && inputs.lint && always() && !cancelled() && !failure()
328- runs-on : ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
329- container : ${{ inputs.container != '' && fromJSON(needs.parse-container.outputs.config) || null }}
351+ if : inputs.checks == true && inputs.lint
330352 needs :
331- - parse-container
353+ - prepare
332354 - setup
355+ runs-on : ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
356+ container : *container-setup
333357 # jscpd:ignore-start
334358 permissions :
335359 contents : read
336360 # FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
337361 id-token : write
338362 steps :
339363 - uses : hoverkraft-tech/ci-github-common/actions/checkout@753288393de1f3d92f687a6761d236ca800f5306 # 0.28.1
340- if : inputs. container == ''
364+ if : needs.prepare.outputs. container-image == null
341365
342- # FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
343366 - id : oidc
344367 uses : ChristopherHX/oidc@73eee1ff03fdfce10eda179f617131532209edbd # v3
345368 - uses : actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
@@ -375,16 +398,16 @@ jobs:
375398 - uses : ./self-workflow/actions/lint
376399 with :
377400 working-directory : ${{ inputs.working-directory }}
378- container : ${{ inputs. container != ' ' }}
401+ container : ${{ needs.prepare.outputs. container-image && 'true' || 'false ' }}
379402
380403 build :
381404 name : 🏗️ Build
382- if : inputs.checks == true && always() && !cancelled() && !failure()
405+ if : inputs.checks == true
383406 runs-on : ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
407+ container : *container-setup
384408 # jscpd:ignore-start
385- container : ${{ inputs.container != '' && fromJSON(needs.parse-container.outputs.config) || null }}
386409 needs :
387- - parse-container
410+ - prepare
388411 - setup
389412 permissions :
390413 contents : read
@@ -394,7 +417,7 @@ jobs:
394417 artifact-id : ${{ steps.build.outputs.artifact-id }}
395418 steps :
396419 - uses : hoverkraft-tech/ci-github-common/actions/checkout@753288393de1f3d92f687a6761d236ca800f5306 # 0.28.1
397- if : needs.setup.outputs.build-commands && inputs. container == ''
420+ if : needs.setup.outputs.build-commands && needs.prepare.outputs. container-image == null
398421
399422 # FIXME: This is a workaround for having workflow ref. See https://github.com/orgs/community/discussions/38659
400423 - id : oidc
@@ -422,15 +445,15 @@ jobs:
422445 build-env : ${{ needs.setup.outputs.build-env }}
423446 build-secrets : ${{ secrets.build-secrets }}
424447 build-artifact : ${{ needs.setup.outputs.build-artifact }}
425- container : ${{ inputs. container != ' ' }}
448+ container : ${{ needs.prepare.outputs. container-image && 'true' || 'false ' }}
426449
427450 test :
428451 name : 🧪 Test
429- if : inputs.checks == true && inputs.test && always() && !cancelled() && !failure()
452+ if : inputs.checks == true && inputs.test
430453 runs-on : ${{ inputs.runs-on && fromJson(inputs.runs-on) || 'ubuntu-latest' }}
431- container : ${{ inputs. container != '' && fromJSON(needs.parse-container.outputs.config) || null }}
454+ container : * container-setup
432455 needs :
433- - parse-container
456+ - prepare
434457 - setup
435458 - build
436459 permissions :
@@ -440,9 +463,9 @@ jobs:
440463 id-token : write
441464 steps :
442465 - uses : hoverkraft-tech/ci-github-common/actions/checkout@753288393de1f3d92f687a6761d236ca800f5306 # 0.28.1
443- if : inputs. container == ''
466+ if : needs.prepare.outputs. container-image == null
444467
445- - if : needs.build.outputs.artifact-id && inputs. container == ''
468+ - if : needs.build.outputs.artifact-id && needs.prepare.outputs. container-image == null
446469 uses : actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
447470 with :
448471 artifact-ids : ${{ needs.build.outputs.artifact-id }}
@@ -491,7 +514,7 @@ jobs:
491514 - uses : ./self-workflow/actions/test
492515 with :
493516 working-directory : ${{ inputs.working-directory }}
494- container : ${{ inputs. container != ' ' }}
517+ container : ${{ needs.prepare.outputs. container-image && 'true' || 'false ' }}
495518 coverage : ${{ steps.prepare-test-options.outputs.coverage }}
496- coverage-files : ${{ steps.prepare-test-options.outputs[' coverage-files'] }}
519+ coverage-files : ${{ steps.prepare-test-options.outputs. coverage-files }}
497520 github-token : ${{ github.token }}
0 commit comments