From 6387d358c40ff9edd76692cbbe0ca23743cf4439 Mon Sep 17 00:00:00 2001 From: Sean Smith Date: Wed, 5 Oct 2022 21:48:56 -0700 Subject: [PATCH] Add optional pushImage input (#111) --- .github/workflows/ci.yml | 4 ++++ .github/workflows/pr.yml | 6 +++++- README.md | 1 + action.yml | 6 +++++- dist/index.js | 24 +++++++++++++++++++----- src/docker-build-push.js | 8 +++++--- src/docker.js | 16 ++++++++++++++-- tests/docker-build-push.test.js | 2 +- tests/docker.test.js | 23 ++++++++++++++++++++++- 9 files changed, 76 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2ff7396..7b60682 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,10 @@ jobs: - name: Check out code uses: actions/checkout@v2 + - uses: actions/setup-node@v3 + with: + node-version: 16 + - name: Build run: npm ci diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index b04d519..d44129e 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -10,8 +10,12 @@ jobs: - name: Check out code uses: actions/checkout@v2 + - uses: actions/setup-node@v3 + with: + node-version: 16 + - name: Build run: npm ci - - name: Run unit tests + - name: Run unit tests run: npm run test diff --git a/README.md b/README.md index be33266..575a5c6 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ steps: | password | Docker registry password or token | No | String | | githubOrg | GitHub organization to push image to (if not current) | No | String | | enableBuildKit | Enables Docker BuildKit support | No | Boolean | +| pushImage | Flag for disabling the login & push steps, set to `true` by default | No | Boolean | ## Outputs diff --git a/action.yml b/action.yml index 2cb8fab..f9104e6 100644 --- a/action.yml +++ b/action.yml @@ -51,6 +51,10 @@ inputs: description: "Enables Docker BuildKit support" required: false default: "false" + pushImage: + description: "Flag for disabling the login & push steps, set to true by default" + required: false + default: "true" outputs: imageFullName: description: "Full name of the Docker image with registry prefix and tag suffix" @@ -59,7 +63,7 @@ outputs: tags: description: "Tags for the Docker image" runs: - using: "node12" + using: "node16" main: "dist/index.js" branding: icon: "anchor" diff --git a/dist/index.js b/dist/index.js index 60e749a..b2054df 100644 --- a/dist/index.js +++ b/dist/index.js @@ -10050,7 +10050,8 @@ const buildOpts = { target: undefined, buildDir: undefined, enableBuildKit: false, - platform: undefined + platform: undefined, + skipPush: false }; const run = () => { @@ -10071,15 +10072,16 @@ const run = () => { buildOpts.buildDir = core.getInput('directory') || '.'; buildOpts.enableBuildKit = core.getInput('enableBuildKit') === 'true'; buildOpts.platform = core.getInput('platform'); + buildOpts.skipPush = core.getInput('pushImage') === 'false'; // Create the Docker image name const imageFullName = docker.createFullImageName(registry, image, githubOwner); core.info(`Docker image name used for this build: ${imageFullName}`); // Log in, build & push the Docker image - docker.login(username, password, registry); + docker.login(username, password, registry, buildOpts.skipPush); docker.build(imageFullName, dockerfile, buildOpts); - docker.push(imageFullName, buildOpts.tags); + docker.push(imageFullName, buildOpts.tags, buildOpts.skipPush); // Capture outputs core.setOutput('imageFullName', imageFullName); @@ -10197,7 +10199,12 @@ const isEcr = registry => registry && registry.includes('amazonaws'); const getRegion = registry => registry.substring(registry.indexOf('ecr.') + 4, registry.indexOf('.amazonaws')); // Log in to provided Docker registry -const login = (username, password, registry) => { +const login = (username, password, registry, skipPush) => { + if (skipPush) { + core.info('Input skipPush is set to true, skipping Docker log in step...'); + return; + } + // If using ECR, use the AWS CLI login command in favor of docker login if (isEcr(registry)) { const region = getRegion(registry); @@ -10210,11 +10217,18 @@ const login = (username, password, registry) => { cp.execSync(`docker login -u ${username} --password-stdin ${registry}`, { input: password }); + } else { + core.setFailed('Must supply Docker registry credentials to push image!'); } }; // Push Docker image & all tags -const push = (imageName, tags) => { +const push = (imageName, tags, skipPush) => { + if (skipPush) { + core.info('Input skipPush is set to true, skipping Docker push step...'); + return; + } + core.info(`Pushing tags ${tags} for Docker image ${imageName}...`); cp.execSync(`docker push ${imageName} --all-tags`, cpOptions); }; diff --git a/src/docker-build-push.js b/src/docker-build-push.js index 189b6ca..23f0fc5 100644 --- a/src/docker-build-push.js +++ b/src/docker-build-push.js @@ -10,7 +10,8 @@ const buildOpts = { target: undefined, buildDir: undefined, enableBuildKit: false, - platform: undefined + platform: undefined, + skipPush: false }; const run = () => { @@ -31,15 +32,16 @@ const run = () => { buildOpts.buildDir = core.getInput('directory') || '.'; buildOpts.enableBuildKit = core.getInput('enableBuildKit') === 'true'; buildOpts.platform = core.getInput('platform'); + buildOpts.skipPush = core.getInput('pushImage') === 'false'; // Create the Docker image name const imageFullName = docker.createFullImageName(registry, image, githubOwner); core.info(`Docker image name used for this build: ${imageFullName}`); // Log in, build & push the Docker image - docker.login(username, password, registry); + docker.login(username, password, registry, buildOpts.skipPush); docker.build(imageFullName, dockerfile, buildOpts); - docker.push(imageFullName, buildOpts.tags); + docker.push(imageFullName, buildOpts.tags, buildOpts.skipPush); // Capture outputs core.setOutput('imageFullName', imageFullName); diff --git a/src/docker.js b/src/docker.js index 51811b9..dd62684 100644 --- a/src/docker.js +++ b/src/docker.js @@ -97,7 +97,12 @@ const isEcr = registry => registry && registry.includes('amazonaws'); const getRegion = registry => registry.substring(registry.indexOf('ecr.') + 4, registry.indexOf('.amazonaws')); // Log in to provided Docker registry -const login = (username, password, registry) => { +const login = (username, password, registry, skipPush) => { + if (skipPush) { + core.info('Input skipPush is set to true, skipping Docker log in step...'); + return; + } + // If using ECR, use the AWS CLI login command in favor of docker login if (isEcr(registry)) { const region = getRegion(registry); @@ -110,11 +115,18 @@ const login = (username, password, registry) => { cp.execSync(`docker login -u ${username} --password-stdin ${registry}`, { input: password }); + } else { + core.setFailed('Must supply Docker registry credentials to push image!'); } }; // Push Docker image & all tags -const push = (imageName, tags) => { +const push = (imageName, tags, skipPush) => { + if (skipPush) { + core.info('Input skipPush is set to true, skipping Docker push step...'); + return; + } + core.info(`Pushing tags ${tags} for Docker image ${imageName}...`); cp.execSync(`docker push ${imageName} --all-tags`, cpOptions); }; diff --git a/tests/docker-build-push.test.js b/tests/docker-build-push.test.js index e175b86..a2238a1 100644 --- a/tests/docker-build-push.test.js +++ b/tests/docker-build-push.test.js @@ -24,7 +24,7 @@ const mockRepoName = 'some-repo'; const runAssertions = (imageFullName, inputs, tagOverrides) => { // Inputs - expect(core.getInput).toHaveBeenCalledTimes(15); + expect(core.getInput).toHaveBeenCalledTimes(16); // Outputs const tags = tagOverrides || parseArray(inputs.tags); diff --git a/tests/docker.test.js b/tests/docker.test.js index e288e72..e904c72 100644 --- a/tests/docker.test.js +++ b/tests/docker.test.js @@ -296,7 +296,21 @@ describe('Docker build, login & push commands', () => { ); }); - test("returns undefined if empty login and doesn't execute command", () => { + test('Skip login command if skipPush is set to true', () => { + const skipPush = true; + docker.login(username, password, registry, skipPush); + + expect(cp.execSync.mock.calls.length).toEqual(0); + }); + + test('Missing username or password should throw an error', () => { + docker.login(undefined, undefined, registry); + + expect(cp.execSync.mock.calls.length).toEqual(0); + expect(core.setFailed).toHaveBeenCalled(); + }); + + test('returns undefined if empty login and does not execute command', () => { docker.login(username, password, registry); expect(cp.execSync.mock.calls.length).toEqual(0); @@ -312,5 +326,12 @@ describe('Docker build, login & push commands', () => { expect(cp.execSync).toHaveBeenCalledWith(`docker push ${imageName} --all-tags`, cpOptions); }); + + test('Skip push command if skipPush is set to true', () => { + const skipPush = true; + docker.push('my-org/my-image', 'latest', skipPush); + + expect(cp.execSync.mock.calls.length).toEqual(0); + }); }); });