Skip to content

Commit

Permalink
feat(template)!: replace simple template engine with handlebars
Browse files Browse the repository at this point in the history
replaces the simple template engine with handlebars and a set of default
helpers

BREAKING CHANGE: Use handlebars as template engine. Place holders are
now double curlies `{{ }}`

resolves: #16
  • Loading branch information
esatterwhite committed Dec 31, 2021
1 parent 6807acc commit b20c89c
Show file tree
Hide file tree
Showing 42 changed files with 531 additions and 47 deletions.
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
hoist=true
package-lock=false
lock-file=false
45 changes: 36 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ builds a an image using the specified docker file and context. This image will b
### publish

pushes the tags Images with specified tags and pushes them to the registry.
Tags support simple templating. Values enclosed in braces `{}` will be subsititued with release context information
Tags support simple templating via [handlebars][]. Values enclosed in braces `{{}}` will be substituted with release context information

## Installation

Expand All @@ -31,7 +31,7 @@ Run `npm i --save-dev @codedependant/semantic-release-docker` to install this se
### Docker registry authentication

The `docker registry` authentication set via environment variables. It is not required, and if
omitted, it is assumed the docker daemon is already authenticated with the targe registry.
omitted, it is assumed the docker daemon is already authenticated with the target registry.

### Environment variables

Expand All @@ -44,11 +44,11 @@ omitted, it is assumed the docker daemon is already authenticated with the targe

| Option | Description | Default
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | --------
| `dockerTags` | _Optional_. An array of strings allowing to specify additional tags to apply to the image. Supports templating | [`latest`, `{major}-latest`, `{version}`] |
| `dockerTags` | _Optional_. An array of strings allowing to specify additional tags to apply to the image. Supports templating | [`latest`, `{{major}}-latest`, `{{version}}`] |
| `dockerImage` | _Optional_. The name of the image to release. | Parsed from package.json `name` property |
| `dockerRegistry` | _Optional_. The hostname and port used by the the registry in format `hostname[:port]`. Omit the port if the registry uses the default port | `null` (dockerhub) |
| `dockerProject` | _Optional_. The project or repository name to publish the image to | For scoped packages, the scope will be used, otherwise `null` |
| `dockerFile` | _Optional_. The path, relative to `$PWD` to a Docker file to build the target image with | `Dockerfile` |
| `dockerFile` | _Optional_. The path, relative to `$PWD` to a Docker file to build the target image with | `Dockerfile` |
| `dockerContext` | _Optional_. A path, relative to `$PWD` to use as the build context A | `.` |
| `dockerLogin` | _Optional_. Set to false it by pass docker login if the docker daemon is already authorized | `true` |
| `dockerArgs` | _Optional_. Include additional values for docker's `build-arg`. Supports templating | |
Expand All @@ -58,7 +58,7 @@ omitted, it is assumed the docker daemon is already authenticated with the targe

By default several build arguments will be included when the docker images is being built.
Build arguments can be templated in the same fashion as docker tags. If the value for a
build argument is explictly `true`, the value will be omitted and the value from
build argument is explicitly `true`, the value will be omitted and the value from
a matching environment variable will be utilized instead. This can be useful when trying to include
secrets and other sensitive information

Expand Down Expand Up @@ -93,6 +93,28 @@ String template will be passed these
| `build` | A Random build hash representing the current execution context | `String` |
| `now` | Current timestamp is ISO 8601 format | `String` |

### Template Helpers

The following handlebars template helpers are pre installed

| Helper name | Description | Return Type | Example |
|:------------:|------------------------------------------------------------------------|:-----------:|--------------------------------------------------------------------------------------------|
| `endswith` | returns true if a string ends with another | [Boolean][] | <pre lang="hbs">{{#if (endswith myvar 'ing')}}{{ othervar }}{{/if}}</pre> |
| `eq` | returns true if two values are strictly equal to each other | [Boolean][] | <pre lang="hbs">{{#if (eq var_one var_two)}}{{ var_three }}{{/if}}</pre> |
| `gt` | returns true if the first value is greater than the second | | [Boolean][] | <pre lang="hbs">{{#if (gt var_one var_two)}}{{ var_three }}{{/if}}</pre> |
| `gte` | returns true if the first value is greater than or equal to the second | [Boolean][] | <pre lang="hbs">{{#if (gte var_one var_two)}}{{ var_three }}{{/if}}</pre> |
| `includes` | returns true if the input (string \| array) includes the second value | [Boolean][] | <pre lang="hbs">{{#if (includes some_array 'one')}}{{ var_one }}{{/if}}</pre> |
| `lower` | returns the lower cased varient of the input string | [String][] | <pre lang="hbs">{{ lower my_var }}</pre> |
| `lt` | returns true if the first value is less than the second | [Boolean][] | <pre lang="hbs">{{#if (lt var_one var_two)}}{{ var_three }}{{/if}}</pre> |
| `lte` | returns true if the first value is less than or equal to the second | [Boolean][] | <pre lang="hbs">{{#if (lte var_one var_two)}}{{ var_three }}{{/if}}</pre> |
| `neq` | returns true if two values are not equal to each other | [Boolean][] | <pre lang="hbs">{{#if (neq var_one var_two)}}{{ var_three }}{{/if}}</pre> |
| `pick` | returns the first non null-ish value. Will treat `false` as a value | `any` | <pre lang="hbs">{{#with (pick var_one, var_two) as \| value \|}}{{ value }}{{/with}}</pre> |
| `split` | splits csv values into a javascript array | [Array][] | <pre lang="hbs">{{#each (split csv_value)}}{{ this }}{{/each}} |
| `startswith` | returns true if a string starts with another | [Boolean][] | <pre lang="hbs">{{#if (starts myvar 'foo')}}{{ othervar }}{{/if}}</pre> |
| `upper` | returns the upper cased varient of the input string | [String][] | <pre lang="hbs">{{upper my_var}}</pre> |



## Usage

**full configuration**:
Expand All @@ -104,15 +126,15 @@ module.exports = {
branches: ['main']
plugins: [
['@codedependant/semantic-release-docker', {
dockerTags: ['latest', '{version}', '{major}-latest', '{major}.{minor}'],
dockerTags: ['latest', '{{version}}', '{{major}}-latest', '{{major}}.{{minor}}'],
dockerImage: 'my-image',
dockerFile: 'Dockerfile',
dockerRegistry: 'quay.io',
dockerProject: 'codedependant',
dockerArgs: {
API_TOKEN: true
, RELEASE_DATE: new Date().toISOString()
, RELEASE_VERSION: '{next.version}'
, RELEASE_VERSION: '{{next.version}}'
}
}]
]
Expand All @@ -129,13 +151,13 @@ Alternatively, using global options w/ root configuration
"version": "1.0.0"
"release": {
"extends": "@internal/release-config-docker",
"dockerTags": ["latest", "{version}", "{major}-latest", "{major}.{minor}"],
"dockerTags": ["latest", "{{version}}", "{{major}}-latest", "{{major}}.{{minor}}"],
"dockerImage": "my-image",
"dockerFile": "Dockerfile",
"dockerRegistry": "quay.io",
"dockerArgs": {
"GITHUB_TOKEN": true
, "SOME_VALUE": '{git_sha}'
, "SOME_VALUE": '{{git_sha}}'
}
}
}
Expand Down Expand Up @@ -182,3 +204,8 @@ $ openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout server.key -o

**NOTE**: When prompted for an FQDN it must be `registry:5000`
**NOTE**: The credentials for the local registry are **user:** `iamweasel`, **pass:** `secretsquirrel`

[handlebars]: https://handlebarsjs.com
[Boolean]: https://mdn.io/boolean
[String]: https://mdn.io/string
[Array]: https://mdn.io/array
2 changes: 1 addition & 1 deletion lib/build-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ async function buildConfig(build_id, config, context) {
const {
dockerFile: dockerfile = 'Dockerfile'
, dockerNoCache: nocache = false
, dockerTags: tags = ['latest', '{major}-latest', '{version}']
, dockerTags: tags = ['latest', '{{major}}-latest', '{{version}}']
, dockerArgs: args = {}
, dockerRegistry: registry = null
, dockerLogin: login = true
Expand Down
10 changes: 10 additions & 0 deletions lib/handlebars/helpers/endswith.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict'

module.exports = endsWith

function endsWith(str, ...args) {
if (typeof str !== 'string') return false
return args.some((arg) => {
return str.endsWith(arg)
})
}
7 changes: 7 additions & 0 deletions lib/handlebars/helpers/eq.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict'

module.exports = eq

function eq(lh, rh) {
return lh === rh
}
7 changes: 7 additions & 0 deletions lib/handlebars/helpers/gt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict'

module.exports = gt

function gt(lh, rh) {
return lh > rh
}
7 changes: 7 additions & 0 deletions lib/handlebars/helpers/gte.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict'

module.exports = gte

function gte(lh, rh) {
return lh >= rh
}
9 changes: 9 additions & 0 deletions lib/handlebars/helpers/includes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict'

module.exports = includes

function includes(input, arg, position) {
if (!Array.isArray(input) && typeof input !== 'string') return false
return input.includes(arg, position)
}

17 changes: 17 additions & 0 deletions lib/handlebars/helpers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use strict'

module.exports = {
endswith: require('./endswith')
, eq: require('./eq')
, gt: require('./gt')
, gte: require('./gte')
, includes: require('./includes')
, lower: require('./lower')
, lt: require('./lt')
, lte: require('./lte')
, neq: require('./neq')
, pick: require('./pick')
, startswith: require('./startswith')
, split: require('./split')
, upper: require('./upper')
}
8 changes: 8 additions & 0 deletions lib/handlebars/helpers/lower.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use strict'

module.exports = lower

function lower(str) {
if (typeof str !== 'string') return ''
return str.toLowerCase()
}
7 changes: 7 additions & 0 deletions lib/handlebars/helpers/lt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict'

module.exports = lt

function lt(lh, rh) {
return lh < rh
}
7 changes: 7 additions & 0 deletions lib/handlebars/helpers/lte.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict'

module.exports = lte

function lte(lh, rh) {
return lh < rh
}
9 changes: 9 additions & 0 deletions lib/handlebars/helpers/neq.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict'

module.exports = neq

function neq(lh, rh) {
/* eslint-disable eqeqeq */
return lh != rh
/* eslint-enable eqeqeq */
}
13 changes: 13 additions & 0 deletions lib/handlebars/helpers/pick.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use strict'

module.exports = pick

function pick(...args) {
return args.find((value) => {
/* eslint-disable no-eq-null */
if (value == null) return false
/* eslint-enable no-eq-null */
if (value === '') return false
return true
})
}
5 changes: 5 additions & 0 deletions lib/handlebars/helpers/split.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict'

module.exports = require('../../lang/array/to-array.js')


10 changes: 10 additions & 0 deletions lib/handlebars/helpers/startswith.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict'

module.exports = startsWith

function startsWith(str, ...args) {
if (typeof str !== 'string') return false
return args.some((arg) => {
return str.startsWith(arg)
})
}
9 changes: 9 additions & 0 deletions lib/handlebars/helpers/upper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

'use strict'

module.exports = upper

function upper(str) {
if (typeof str !== 'string') return ''
return str.toUpperCase()
}
10 changes: 10 additions & 0 deletions lib/handlebars/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict'

const Handlebars = require('handlebars')
const helpers = require('./helpers')
const handlebars = Handlebars.noConflict()

handlebars.registerHelper(helpers)

module.exports = handlebars

16 changes: 9 additions & 7 deletions lib/lang/string/template.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
'use strict'
const object = require('../object/index.js')

const handlebars = require('../../handlebars')

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
})
if (typeof str !== 'string') return echo(str)
return handlebars.compile(str)
}

function echo(input) {
return () => {
return input
}
}
11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@
"version": "3.1.2",
"description": "docker package",
"main": "index.js",
"files": [
"lib/",
"README.md",
"CHANGELOG.md",
"LICENSE",
"package.json",
"index.js"
],
"scripts": {
"test": "docker-compose -f compose/base.yml -f compose/test.yml up --exit-code-from semantic-release --force-recreate --remove-orphans",
"test": "docker-compose -f compose/base.yml -f compose/test.yml up --exit-code-from semantic-release --force-recreate --remove-orphans --build",
"start": "docker-compose -f compose/base.yml -f compose/dev.yml up --force-recreate --remove-orphans --build",
"stop": "docker-compose -f compose/base.yml -f compose/dev.yml down",
"tap": "tap",
Expand Down Expand Up @@ -71,6 +79,7 @@
"@semantic-release/error": "^2.2.0",
"debug": "^4.1.1",
"execa": "^4.0.2",
"handlebars": "^4.7.7",
"semver": "^7.3.2"
}
}
8 changes: 2 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion test/fixture/docker/Dockerfile.test
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM debian:buster-slim
COPY . /opt/app
WORKDIR /opt/app
RUN ls -alh
CMD ["echo", "$PWD"]

0 comments on commit b20c89c

Please sign in to comment.