Skip to content

Commit

Permalink
fix(image): account for stderr when looking for an image sha
Browse files Browse the repository at this point in the history
in the case the progress output is set to plain, the build output is
written to stderr rather than stdout. This updates the logic to check
each line with a regex starting from the end of the output

Fixes: #46
  • Loading branch information
esatterwhite committed Feb 4, 2024
1 parent 270b413 commit 8f37d45
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 10 deletions.
18 changes: 14 additions & 4 deletions lib/docker/image.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
'use strict'

const os = require('os')
const path = require('path')
const crypto = require('crypto')
const execa = require('execa')
const array = require('../lang/array/index.js')
const SHA_REGEX = /(?:writing image\s)?[^@](?:sha\d{3}):(?<sha>\w+)/i

class Image {
constructor(opts) {
Expand Down Expand Up @@ -160,10 +162,18 @@ class Image {
const stream = execa('docker', this.build_cmd)
stream.stdout.pipe(process.stdout)
stream.stderr.pipe(process.stderr)
const {stdout} = await stream
const [_, sha] = stdout.split(':')
this.sha = sha.substring(0, 12)
return this.sha
const {stdout, stderr} = await stream
const lines = (stdout || stderr).split(os.EOL)
const len = lines.length - 1

for (let x = len; x >= 0; x--) {
const line = lines[x]
const match = SHA_REGEX.exec(line)
if (match) {
this.sha = match.groups.sha.substring(0, 12)
return this.sha
}
}
}

async tag(tag, push = true) {
Expand Down
2 changes: 1 addition & 1 deletion test/fixture/docker/Dockerfile.publish
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM debian:buster-slim
FROM debian:bullseye-slim
COPY . /opt/whizbang
WORKDIR /opt/whizbang
CMD ["echo", "$PWD"]
68 changes: 63 additions & 5 deletions test/integration/prepare.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,6 @@ test('steps::prepare', async (t) => {
tt.equal(image.opts.args.get('MAJOR_TEMPLATE'), '2', 'MAJOR_TEMPLATE value')
tt.equal(image.opts.args.get('GIT_REF'), 'abacadaba', 'GIT_REF value')
tt.match(image.opts.args.get('BUILD_DATE'), DATE_REGEX, 'BUILD_DATE value')
tt.match(
image.opts.flags.get('TAG_TEMPLATE')
, ['v2.1.2']
, 'TAG_TEMPLATE stored as a flag'
)
tt.equal(image.context, path.join(context.cwd, config.context), 'docker context path')

const {stdout} = await execa('docker', [
Expand All @@ -85,4 +80,67 @@ test('steps::prepare', async (t) => {
])
tt.equal(stdout, build_id, 'build image fully built')
})

t.test('build image created - progress plain', async (tt) => {
const build_id = crypto.randomBytes(5).toString('hex')
const context = {
env: {
...process.env
, DOCKER_REGISTRY_USER: 'iamweasel'
, DOCKER_REGISTRY_PASSWORD: 'secretsquirrel'
}
, cwd: fixturedir
, nextRelease: {
version: '2.1.2'
, gitTag: 'v2.1.2'
, gitHead: 'abacadaba'
}
, logger: {
success: sinon.stub()
, info: sinon.stub()
, debug: sinon.stub()
, fatal: sinon.stub()
}
}

const config = await buildConfig(build_id, {
dockerRegistry: DOCKER_REGISTRY_HOST
, dockerProject: 'docker-prepare'
, dockerImage: 'alternate'
, dockerBuildQuiet: false
, dockerBuildFlags: {
progress: 'plain'
, 'no-cache': null
}
, dockerArgs: {
MY_VARIABLE: '1'
, TAG_TEMPLATE: '{{git_tag}}'
, MAJOR_TEMPLATE: '{{major}}'
, GIT_REF: '{{git_sha}}'
, BUILD_DATE: '{{now}}'
}
, dockerFile: 'docker/Dockerfile.prepare'
, dockerContext: 'docker'
}, context)

const image = await prepare(config, context)

tt.on('end', () => {
image.clean()
})

tt.equal(image.opts.args.get('TAG_TEMPLATE'), 'v2.1.2', 'TAG_TEMPLATE value')
tt.equal(image.opts.args.get('MAJOR_TEMPLATE'), '2', 'MAJOR_TEMPLATE value')
tt.equal(image.opts.args.get('GIT_REF'), 'abacadaba', 'GIT_REF value')
tt.match(image.opts.args.get('BUILD_DATE'), DATE_REGEX, 'BUILD_DATE value')
tt.equal(image.context, path.join(context.cwd, config.context), 'docker context path')

const {stdout} = await execa('docker', [
'images', image.name
, '-q', '--format={{ .Tag }}:{{ .ID}}'
])
const [tag, id] = stdout.split(':')
tt.equal(image.id, id, 'captured id matches docker image id')
tt.equal(tag, build_id, 'build image fully built')
})
}).catch(threw)

0 comments on commit 8f37d45

Please sign in to comment.