@@ -146,205 +146,19 @@ runs:
146146 with :
147147 value : ${{ inputs.platform }}
148148
149- - id : resolve-oci-registries
150- uses : actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
149+ - id : docker-setup
150+ uses : ./self-actions/docker/setup
151151 with :
152- script : |
153- function parseJsonObjectInput(inputName, rawValue) {
154- const value = `${rawValue}`.trim();
155- if (!value.length) {
156- return null;
157- }
158-
159- if (!value.startsWith('{')) {
160- return value;
161- }
162-
163- let parsedValue;
164- try {
165- parsedValue = JSON.parse(value);
166- } catch (error) {
167- throw new Error(`"${inputName}" input is not a valid JSON object: ${error}`);
168- }
169-
170- if (parsedValue === null || Array.isArray(parsedValue) || typeof parsedValue !== 'object') {
171- throw new Error(`"${inputName}" input must be a string or a JSON object`);
172- }
173-
174- return parsedValue;
175- }
176-
177- function normalizeString(value, fieldName) {
178- if (typeof value !== 'string') {
179- throw new Error(`"${fieldName}" must be a string`);
180- }
181-
182- const trimmedValue = value.trim();
183- if (!trimmedValue.length) {
184- throw new Error(`"${fieldName}" must not be empty`);
185- }
186-
187- return trimmedValue;
188- }
189-
190- function isPullRole(role) {
191- return role === 'pull' || role.startsWith('pull:');
192- }
193-
194- function normalizeRoleMapInput(inputName, rawValue) {
195- const parsedValue = parseJsonObjectInput(inputName, rawValue);
196-
197- if (parsedValue === null) {
198- return {};
199- }
200-
201- if (typeof parsedValue === 'string') {
202- return { scalar: normalizeString(parsedValue, inputName) };
203- }
204-
205- return Object.entries(parsedValue).reduce((roleMap, [key, value]) => {
206- if (key !== 'push' && key !== 'cache' && !isPullRole(key)) {
207- throw new Error(`"${inputName}.${key}" is not supported`);
208- }
209-
210- roleMap[key] = normalizeString(value, `${inputName}.${key}`);
211- return roleMap;
212- }, {});
213- }
214-
215- function resolveCredentialByRole(credentialMap, role, registry, pushRegistry) {
216- const defaultCredential = credentialMap.scalar ?? '';
217-
218- if (role === 'push') {
219- return credentialMap.push ?? defaultCredential;
220- }
221-
222- if (role === 'cache') {
223- return credentialMap.cache ?? credentialMap.push ?? defaultCredential;
224- }
225-
226- if (!isPullRole(role)) {
227- return defaultCredential;
228- }
229-
230- if (credentialMap[role] !== undefined) {
231- return credentialMap[role];
232- }
233-
234- if (credentialMap.pull !== undefined) {
235- return credentialMap.pull;
236- }
237-
238- if (registry === pushRegistry && credentialMap.push !== undefined) {
239- return credentialMap.push;
240- }
241-
242- return defaultCredential;
243- }
244-
245- const registryInput = normalizeRoleMapInput('oci-registry', `${{ inputs.oci-registry }}`);
246-
247- let pushRegistry = '';
248- let cacheRegistry = '';
249- let pullRegistryEntries = [];
250- let pullRegistries = [];
251-
252- if (registryInput.scalar) {
253- pushRegistry = registryInput.scalar;
254- cacheRegistry = pushRegistry;
255- pullRegistries = [pushRegistry];
256- } else {
257- pushRegistry = registryInput.push ?? '';
258- cacheRegistry = registryInput.cache ?? pushRegistry;
259- pullRegistryEntries = Object.entries(registryInput)
260- .filter(([key]) => isPullRole(key))
261- .map(([role, registry]) => ({ role, registry }));
262-
263- if (!pushRegistry.length) {
264- throw new Error(`"oci-registry.push" is required when "oci-registry" uses the JSON object format`);
265- }
266-
267- if (!pullRegistryEntries.length) {
268- pullRegistryEntries = [{ role: 'pull', registry: pushRegistry }];
269- }
270-
271- pullRegistries = pullRegistryEntries.map(({ registry }) => registry);
272- }
273-
274- const cacheType = `${{ inputs.cache-type }}`.trim();
275- const registryEntries = [
276- { role: 'push', registry: pushRegistry, required: true },
277- ...pullRegistryEntries.map(pullRegistryEntry => ({ ...pullRegistryEntry, required: false })),
278- ];
279-
280- if (cacheType === 'registry') {
281- registryEntries.push({ role: 'cache', registry: cacheRegistry, required: true });
282- }
283-
284- const usernameByRole = normalizeRoleMapInput('oci-registry-username', `${{ inputs.oci-registry-username }}`);
285- const passwordByRole = normalizeRoleMapInput('oci-registry-password', `${{ inputs.oci-registry-password }}`);
286-
287- const registryLoginsByRegistry = new Map();
288- for (const registryEntry of registryEntries) {
289- const { role, registry, required } = registryEntry;
290- const username = resolveCredentialByRole(usernameByRole, role, registry, pushRegistry);
291- const password = resolveCredentialByRole(passwordByRole, role, registry, pushRegistry);
292-
293- if ((username && !password) || (!username && password)) {
294- throw new Error(`Credentials for "${role}" must define both username and password`);
295- }
296-
297- const existingRegistryLogin = registryLoginsByRegistry.get(registry);
298- if (existingRegistryLogin) {
299- const hasDifferentUsername = existingRegistryLogin.username && username && existingRegistryLogin.username !== username;
300- const hasDifferentPassword = existingRegistryLogin.password && password && existingRegistryLogin.password !== password;
301- if (hasDifferentUsername || hasDifferentPassword) {
302- throw new Error(`Conflicting credentials configured for registry "${registry}"`);
303- }
304-
305- if (!existingRegistryLogin.username && username) {
306- existingRegistryLogin.username = username;
307- }
308-
309- if (!existingRegistryLogin.password && password) {
310- existingRegistryLogin.password = password;
311- }
312- existingRegistryLogin.required ||= required;
313- continue;
314- }
315-
316- registryLoginsByRegistry.set(registry, {
317- registry,
318- username,
319- password,
320- required,
321- });
322- }
323-
324- const registryLogins = [...registryLoginsByRegistry.values()].map(registryLogin => {
325- if (registryLogin.required && (!registryLogin.username || !registryLogin.password)) {
326- throw new Error(`Credentials for registry "${registryLogin.registry}" are required`);
327- }
328-
329- return registryLogin;
330- });
331-
332- const registryOutputNames = {
333- push: ['push', 'registry'].join('-'),
334- cache: ['cache', 'registry'].join('-'),
335- pull: ['pull', 'registries'].join('-'),
336- logins: ['registry', 'logins'].join('-'),
337- };
338-
339- core.setOutput(registryOutputNames.push, pushRegistry);
340- core.setOutput(registryOutputNames.cache, cacheRegistry);
341- core.setOutput(registryOutputNames.pull, JSON.stringify(pullRegistries));
342- core.setOutput(registryOutputNames.logins, JSON.stringify(registryLogins));
152+ oci-registry : ${{ inputs.oci-registry }}
153+ oci-registry-username : ${{ inputs.oci-registry-username }}
154+ oci-registry-password : ${{ inputs.oci-registry-password }}
155+ cache-type : ${{ inputs.cache-type }}
156+ setup-docker : true
343157
344158 - id : metadata
345159 uses : ./self-actions/docker/get-image-metadata
346160 with :
347- oci-registry : ${{ steps.resolve-oci-registries .outputs.push-registry }}
161+ oci-registry : ${{ steps.docker-setup .outputs.push-registry }}
348162 repository : ${{ inputs.repository }}
349163 image : ${{ inputs.image }}
350164 tag : ${{ inputs.tag }}
@@ -382,7 +196,7 @@ runs:
382196
383197 const cacheType = `${{ inputs.cache-type }}`.trim();
384198 const metadataImage = `${{ steps.metadata.outputs.image }}`;
385- const cacheRegistry = `${{ steps.resolve-oci-registries .outputs.cache-registry }}`.trim();
199+ const cacheRegistry = `${{ steps.docker-setup .outputs.cache-registry }}`.trim();
386200 const metadataImageWithoutRegistry = metadataImage.replace(/^[^\/]+\//, '');
387201 const cacheBaseImage = cacheRegistry.length ? `${cacheRegistry}/${metadataImageWithoutRegistry}` : metadataImage;
388202 const cacheImage = cacheType === 'registry' ? `${cacheBaseImage}/cache` : metadataImage;
@@ -443,23 +257,11 @@ runs:
443257 }
444258 }
445259
446- - if : steps.get-docker-config.outputs.docker-exists != 'true'
447- uses : docker/setup-docker-action@1a6edb0ba9ac496f6850236981f15d8f9a82254d # v5.0.0
448-
449260 - if : steps.get-docker-config.outputs.platform-exists != 'true'
450261 uses : docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
451262 with :
452263 platforms : ${{ inputs.platform }}
453264
454- - uses : docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
455- id : setup-buildx
456- with :
457- # FIXME: upgrade version when available (https://github.com/docker/buildx/releases)
458- version : v0.31.1
459- # FIXME: upgrade version when available (https://hub.docker.com/r/moby/buildkit)
460- driver-opts : |
461- image=moby/buildkit:v0.27.0
462-
463265 # Caching setup
464266 - id : cache-arguments
465267 uses : int128/docker-build-cache-config-action@3a4a4fababc091be29633e5a2b3bbf523996802a # v1.47.0
@@ -479,46 +281,10 @@ runs:
479281 - name : Restore Docker cache mounts
480282 uses : reproducible-containers/buildkit-cache-dance@1b8ab18fbda5ad3646e3fcc9ed9dd41ce2f297b4 # v3.3.2
481283 with :
482- builder : ${{ steps.setup-buildx .outputs.name }}
284+ builder : ${{ steps.docker-setup .outputs.buildx- name }}
483285 cache-dir : cache-mount
484286 dockerfile : ${{ steps.get-docker-config.outputs.dockerfile-path }}
485287 skip-extraction : ${{ steps.cache.outputs.cache-hit }}
486-
487- - id : login-oci-registries
488- uses : actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
489- with :
490- script : |
491- const registryLoginsInput = `${{ steps.resolve-oci-registries.outputs.registry-logins }}`;
492- let registryLogins = [];
493- try {
494- registryLogins = JSON.parse(registryLoginsInput);
495- } catch (error) {
496- throw new Error(`Resolved registry logins are not a valid JSON array: ${error}`);
497- }
498-
499- for (const registryLogin of registryLogins) {
500- const { registry, username, password, required } = registryLogin;
501-
502- if (!username && !password) {
503- if (required) {
504- throw new Error(`Credentials for registry "${registry}" are required`);
505- }
506-
507- core.info(`Skipping Docker login for optional registry "${registry}" because no credentials were provided.`);
508- continue;
509- }
510-
511- await exec.exec(
512- 'docker',
513- ['login', registry, '--username', username, '--password-stdin'],
514- {
515- input: `${password}\n`,
516- silent: true,
517- },
518- );
519-
520- core.info(`Logged in to "${registry}".`);
521- }
522288 # jscpd:ignore-end
523289 - id : build
524290 uses : docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
0 commit comments