Skip to content

Commit

Permalink
feat(config): allow templated build arguments
Browse files Browse the repository at this point in the history
allows docker build arguents to be treated as a string template
  • Loading branch information
esatterwhite committed Apr 8, 2021
1 parent e157d3f commit 7167dcf
Show file tree
Hide file tree
Showing 22 changed files with 343 additions and 18 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,5 @@ dist

# TernJS port file
.tern-port

*.vim
7 changes: 5 additions & 2 deletions lib/build-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ async function buildConfig(build_id, config, context) {
const project = object.has(config.docker, 'project') ? config.docker.project : scope
const root = object.get(context, 'options.root')
const target = path.relative(root || context.cwd, context.cwd) || PWD

const {nextRelease = {}} = context
return {
tags
, registry
Expand All @@ -47,11 +47,14 @@ async function buildConfig(build_id, config, context) {
, NPM_PACKAGE_SCOPE: scope
, CONFIG_NAME: image || name
, CONFIG_PROJECT: project
, ...args
, GIT_SHA: nextRelease.gitHead || ''
, GIT_TAG: nextRelease.gitTag || ''
, ...(args || {})
}
, name: image || name
, build: build_id
, login: login
, env: context.env
, context: config.context || '.'
}
}
26 changes: 26 additions & 0 deletions lib/build-template-vars.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use strict'

const semver = require('semver')

module.exports = buildTemplateVars

function buildTemplateVars(context, opts) {
const {nextRelease = {}, lastRelease = {}} = context

const versions = {
next: semver.parse(nextRelease.version) || {}
, previous: semver.parse(lastRelease.version) || {}
}

const {tags: _, ...rest} = opts
return {
...versions.next
, ...versions
, ...nextRelease
, ...rest
, git_tag: nextRelease.gitTag
, git_sha: nextRelease.gitHead
, release_type: nextRelease.type
, release_notes: nextRelease.notes
}
}
2 changes: 1 addition & 1 deletion lib/docker/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class Image {
get build_cmd() {
const args = []
for (const [name, value] of this.opts.args.entries()) {
if (value === true) {
if (value === true || value == null) { // eslint-disable-line no-eq-null
args.push('--build-arg', name)
} else {
args.push('--build-arg', `${name}=${value}`)
Expand Down
1 change: 1 addition & 0 deletions lib/lang/string/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module.exports = template

function template(str) {
return function interpolate(values) {
if (typeof str !== 'string') return str
return str.replace(/{([^{}]*)}/g, function(original, parsed) {
const result = object.get(values, parsed)
return typeof result === 'string' || typeof result === 'number' ? result : original
Expand Down
4 changes: 4 additions & 0 deletions lib/prepare.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const path = require('path')
const debug = require('debug')('semantic-release:semantic-release-docker:prepare')
const docker = require('./docker/index.js')
const buildTemplateVars = require('./build-template-vars.js')

module.exports = dockerPrepare

Expand All @@ -20,7 +21,10 @@ async function dockerPrepare(opts, context) {
const args = {
...opts.args
}

if (args) {
const vars = buildTemplateVars(context, opts)
debug('template variables', vars)
for (const [key, value] of Object.entries(args)) {
image.arg(key, value)
}
Expand Down
19 changes: 5 additions & 14 deletions lib/publish.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
'use strict'

const semver = require('semver')
const buildTemplateVars = require('./build-template-vars.js')
const docker = require('./docker/index.js')
const string = require('./lang/string/index.js')

module.exports = publish

async function publish(opts, context) {
const {lastRelease, nextRelease, cwd, logger} = context
const versions = {
next: semver.parse(nextRelease.version)
, previous: semver.parse(lastRelease.version)
}

const {cwd, logger} = context
const image = new docker.Image({
registry: opts.registry
, project: opts.project
Expand All @@ -22,18 +17,14 @@ async function publish(opts, context) {
, cwd: cwd
})

const vars = {
...versions.next
, ...versions
}

const vars = buildTemplateVars(context, opts)
const tags = opts.tags.map((template) => {
return string.template(template)(vars)
})
}).filter(Boolean)

logger.info('tagging docker image', image.id)
for (const tag of tags) {
console.log(`pushing image: ${image.repo} tag: ${tag}`)
logger.info(`pushing image: ${image.repo} tag: ${tag}`)
await image.tag(tag)
}

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@
],
"nyc-arg": [
"--exclude=coverage/",
"--exclude=test/"
"--exclude=test/",
"--all"
]
},
"devDependencies": {
Expand Down
1 change: 1 addition & 0 deletions release.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict'

/* istanbul ignore file */
module.exports = {
branches: [
'master'
Expand Down
9 changes: 9 additions & 0 deletions test/common/git/add.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict'

const execa = require('execa')

module.exports = add

async function add(cwd, file = '.') {
await execa('git', ['add', file], {cwd: cwd})
}
11 changes: 11 additions & 0 deletions test/common/git/commit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'use strict'

const execa = require('execa')
const head = require('./head.js')

module.exports = commit

async function commit(cwd, message) {
await execa('git', ['commit', '-m', message], {cwd: cwd})
return head(cwd)
}
10 changes: 10 additions & 0 deletions test/common/git/head.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict'

const execa = require('execa')

module.exports = head

async function head(cwd) {
const {stdout} = await execa('git', ['rev-parse', 'HEAD'], {cwd: cwd})
return stdout
}
13 changes: 13 additions & 0 deletions test/common/git/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use strict'

module.exports = {
add: require('./add.js')
, commit: require('./commit.js')
, head: require('./head.js')
, initOrigin: require('./init-origin.js')
, initRemote: require('./init-remote.js')
, init: require('./init.js')
, push: require('./push.js')
, tag: require('./tag.js')
, tags: require('./tags.js')
}
13 changes: 13 additions & 0 deletions test/common/git/init-origin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use strict'

const execa = require('execa')
const initRemote = require('./init-remote.js')

module.exports = initOrigin

async function initOrigin(cwd) {
const origin = await initRemote()
await execa('git', ['remote', 'add', 'origin', origin], {cwd: cwd})
await execa('git', ['push', '--all', 'origin'], {cwd: cwd})
return origin
}
16 changes: 16 additions & 0 deletions test/common/git/init-remote.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use strict'

const path = require('path')
const os = require('os')
const {promises: fs} = require('fs')
const execa = require('execa')

module.exports = initRemote

async function initRemote(branch = 'main') {
const cwd = await fs.mkdtemp(path.join(os.tmpdir(), path.sep))
await execa('git', [
'init', '--bare', `--initial-branch=${branch}`
], {cwd: cwd})
return `file://${cwd}`
}
18 changes: 18 additions & 0 deletions test/common/git/init.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict'

const path = require('path')
const os = require('os')
const {promises: fs} = require('fs')
const execa = require('execa')

module.exports = init

async function init(dir, branch = 'main') {
const cwd = dir || await fs.mkdtemp(path.join(os.tmpdir(), path.sep))
await execa('git', ['init'], {cwd: cwd})
await execa('git', ['checkout', '-b', branch], {cwd: cwd})
await execa('git', ['config', '--add', 'commit.gpgsign', false])
await execa('git', ['config', '--add', 'pull.default', 'current'])
await execa('git', ['config', '--add', 'push.default', 'current'])
return cwd
}
9 changes: 9 additions & 0 deletions test/common/git/push.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict'

const execa = require('execa')

module.exports = push

async function push(cwd, remote = 'origin', branch = 'main') {
await execa('git', ['push', '--tags', remote, `HEAD:${branch}`], {cwd: cwd})
}
13 changes: 13 additions & 0 deletions test/common/git/tag.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use strict'

const execa = require('execa')

module.exports = tag

async function tag(cwd, name, hash) {
const args = hash
? ['tag', '-f', name, hash]
: ['tag', name]

await execa('git', args, {cwd: cwd})
}
14 changes: 14 additions & 0 deletions test/common/git/tags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'use strict'

const os = require('os')
const execa = require('execa')

module.exports = tags

async function tags(cwd, hash) {
const cmd = hash
? ['describe', '--tags', '--exact-match', hash]
: ['tag', '-l', '--sort', 'v:refname']
const {stdout} = await execa('git', cmd, {cwd: cwd})
return stdout.split(os.EOL).filter(Boolean)
}
100 changes: 100 additions & 0 deletions test/integration/release.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
'use strict'

const execa = require('execa')
const {test, threw} = require('tap')
const git = require('../common/git/index.js')

const stringify = JSON.stringify

test('docker release', async (t) => {
const cwd = t.testdir({
'package.json': stringify({
name: 'service-meta-package'
, version: '0.0.0-development'
, scripts: {
'test-release': 'semantic-release'
}
, release: {
ci: true
, npmPublish: false
, branches: ['main']
, docker: {
registry: 'localhost:5000'
, project: 'docker-release'
, image: 'fake'
, args: {
SAMPLE_THING: '{type}.{version}'
, GIT_REF: '{git_sha}-{git_tag}'
}
}
, plugins: [
'@semantic-release/commit-analyzer'
, '@semantic-release/release-notes-generator'
, '@semantic-release/npm'
, '@codedependant/semantic-release-docker'
]
}
, devDependencies: {
'semantic-release': '*'
, '@semantic-release/commit-analyzer': '*'
, '@semantic-release/release-notes-generator': '*'
, '@semantic-release/npm': '*'
, '@codedependant/semantic-release-docker': 'file:../../../'
}
})
, Dockerfile: 'FROM debian:buster-slim\n\nRUN ls -alh'
, '.gitignore': 'node_modules/'
})

await git.init(cwd)
await git.add(cwd)
await git.commit(cwd, 'feat: initial release')

const origin = await git.initOrigin(cwd)
t.comment(`repository: ${cwd}`)
t.comment(`origin: ${origin}`)

{
const stream = execa('npm', [
'install'
], {
cwd: cwd
, extendEnv: false
, env: {
BRANCH_NAME: 'main'
, CI_BRANCH: 'main'
, CI: 'true'
, GITHUB_REF: 'refs/heads/main'
, PWD: cwd
, DEBUG: process.env.DEBUG
, PATH: process.env.PATH
, HOME: process.env.HOME
, USER: process.env.USER
}
})

stream.stdout.pipe(process.stdout)
await stream
}

const stream = execa('npm', [
'run'
, 'test-release'
, `--repositoryUrl=${origin}`], {
cwd: cwd
, extendEnv: false
, env: {
BRANCH_NAME: 'main'
, CI_BRANCH: 'main'
, CI: 'true'
, GITHUB_REF: 'refs/heads/main'
, PWD: cwd
, DEBUG: process.env.DEBUG
, PATH: process.env.PATH
, HOME: process.env.HOME
, USER: process.env.USER
}
})
await stream

}).catch(threw)

0 comments on commit 7167dcf

Please sign in to comment.