Skip to content

Commit

Permalink
feat(plugin): add basic support for github actions
Browse files Browse the repository at this point in the history
There have been several requests to gain access or over ride the build
id of the image so that the caller can control that and reference it
later in a build process. Initial attempts to expose this information
from the nextRelease property. Unfortunately, this object seems to be
sandboxed, and additional information is not carried to other plugins.
As an alternative, this adds basic support for github actions be setting
output and environment variable that include the build id and image sha
where possible

fixes: #49
  • Loading branch information
esatterwhite committed Dec 26, 2024
1 parent ad6a6a4 commit 3c96ccb
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 12 deletions.
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,34 @@ the default docker image tags for the 1.0.0 release would be `1.0.0`, `1-latest`
the docker tags for version `1.2.3` will be `1.2.3`, `1.2-latest`, `1-latest` and `latest`
the docker tags for version `2.3.4-beta.6` will be `2.3.4-beta.6`, `2.3-beta`, `2-beta` and `beta`

## GitHub Actions

The plugin has some basic support for github actions by exposing several outputs and environment variables
during the publish stage

> [!WARNING]
>
> When using buildx image shas are different per platform, and as such using the shas directly
> is not supported and may result in unexpected results.
### Outputs

| name | description | example |
|--------------------------|------------------------------------------------------------------------------------|--------------------------------------------------------------------|
| `docker_image` | The full name of the docker image including the registry, sans any tag information | quay.io/codedependant/my-image |
| `docker_image_build_id` | The unique build id used to initial build the image during a release | |
| `docker_image_sha_short` | A shorted version of the image sha value suitable for referencing the image | `b94d27b9934d3e0` |
| `docker_image_sha_long` | The full sha256 value that points the image that was build during a release | `b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9` |

### Environment Variables

| name | description | example |
|-------------------------------------------|------------------------------------------------------------------------------------|--------------------------------------------------------------------|
| `SEMANTIC_RELEASE_DOCKER_IMAGE` | The full name of the docker image including the registry, sans any tag information | quay.io/codedependant/my-image |
| `SEMANTIC_RELEASE_DOCKER_IMAGE_BUILD_ID` | The unique build id used to initial build the image during a release | |
| `SEMANTIC_RELEASE_DOCKER_IMAGE_SHA_SHORT` | A shorted version of the image sha value suitable for referencing the image | `b94d27b9934d3e0` |
| `SEMANTIC_RELEASE_DOCKER_IMAGE_SHA_LONG` | The full sha256 value that points the image that was build during a release | `b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9` |

## Development

### Docker Registry
Expand Down
23 changes: 18 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict'

const crypto = require('crypto')
const docker = require('./lib/docker/index.js')
const dockerPrepare = require('./lib/prepare.js')
const dockerVerify = require('./lib/verify.js')
const dockerPublish = require('./lib/publish.js')
Expand All @@ -9,6 +10,7 @@ const dockerSuccess = require('./lib/success.js')
const dockerFail = require('./lib/fail.js')
const build_id = crypto.randomBytes(10).toString('hex')

let image
module.exports = {
buildConfig
, fail
Expand All @@ -18,22 +20,33 @@ module.exports = {
, verifyConditions
}

/* istanbul ignore next */
async function fail(config, context) {
return dockerFail(await buildConfig(build_id, config, context), context)
const opts = await buildConfig(build_id, config, context)
context.image = image || docker.Image.from(opts, context)
return dockerFail(opts, context)
}

async function prepare(config, context) {
return dockerPrepare(await buildConfig(build_id, config, context), context)
const opts = await buildConfig(build_id, config, context)
image = await dockerPrepare(opts, context)
return image
}

async function publish(config, context) {
return dockerPublish(await buildConfig(build_id, config, context), context)
const opts = await buildConfig(build_id, config, context)
context.image = image || docker.Image.from(opts, context)
return dockerPublish(opts, context)
}

async function success(config, context) {
return dockerSuccess(await buildConfig(build_id, config, context), context)
const opts = await buildConfig(build_id, config, context)
context.image = image || docker.Image.from(opts, context)
return dockerSuccess(opts, context)
}

async function verifyConditions(config, context) {
return dockerVerify(await buildConfig(build_id, config, context), context)
const opts = await buildConfig(build_id, config, context)
context.image = image || docker.Image.from(opts, context)
return dockerVerify(opts, context)
}
9 changes: 5 additions & 4 deletions lib/docker/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const execa = require('execa')
const buildTemplateVars = require('../build-template-vars.js')
const array = require('../lang/array/index.js')
const string = require('../lang/string/index.js')
const SHA_REGEX = /(?:writing image\s)?[^@](?:sha\d{3}):(?<sha>\w+)/i
const SHA_REGEX = /(?:writing image\s)?[^@]?(?:sha\d{3}):(?<sha>\w+)/i

function render(item, vars) {
if (Array.isArray(item)) {
Expand Down Expand Up @@ -43,6 +43,7 @@ class Image {
}

this.sha = sha
this.sha256 = null
this.opts = {
build_id: build_id
, args: new Map()
Expand All @@ -62,7 +63,6 @@ class Image {

if (quiet) this.flag('quiet', null)


for (const tag of this.tags) {
this.flag('tag', tag)
}
Expand Down Expand Up @@ -273,11 +273,12 @@ class Image {
const line = lines[x]
const match = SHA_REGEX.exec(line)
if (match) {
this.sha = match.groups.sha.substring(0, 12)
this.sha256 = match.groups.sha
this.sha = this.sha256.substring(0, 12)
return this.sha
}
}
this.sha = this.build_id
this.sha = this.opts.build_id
return this.sha
}

Expand Down
3 changes: 1 addition & 2 deletions lib/prepare.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ const docker = require('./docker/index.js')
module.exports = dockerPrepare

async function dockerPrepare(opts, context) {
const image = docker.Image.from(opts, context)
const {image = docker.Image.from(opts, context)} = context
context.logger.info('building image', image.name)
context.logger.info('build command: docker %s', image.build_cmd.join(' '))

await image.build()
return image
}
Expand Down
16 changes: 15 additions & 1 deletion lib/publish.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
'use strict'

const actions = require('@actions/core')
const docker = require('./docker/index.js')

module.exports = publish

async function publish(opts, context) {
const image = docker.Image.from(opts, context)
const {image = docker.Image.from(opts, context)} = context

const sha = image.sha || opts.build_id
const sha256 = image.sha256 || opts.build_id

actions.setOutput('docker_image', image.repo)
actions.setOutput('docker_image_build_id', opts.build_id)
actions.setOutput('docker_image_sha_short', sha)
actions.setOutput('docker_image_sha_long', sha256)

actions.exportVariable('SEMANTIC_RELEASE_DOCKER_IMAGE', image.repo)
actions.exportVariable('SEMANTIC_RELEASE_DOCKER_IMAGE_BUILD_ID', opts.build_id)
actions.exportVariable('SEMANTIC_RELEASE_DOCKER_IMAGE_SHA_SHORT', sha)
actions.exportVariable('SEMANTIC_RELEASE_DOCKER_IMAGE_SHA_LONG', sha256)
await image.push()
}
1 change: 1 addition & 0 deletions test/unit/docker/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ test('Image', async (t) => {

tt.notOk(img.sha, 'no show before build')
const sha = await img.build()
tt.ok(sha, 'sha value returned from build function')
tt.equal(sha, img.sha, 'image sha set after build')
const {stdout} = await execa('docker', ['run', '--rm', img.name, 'ls', '-1'])
tt.same(
Expand Down

0 comments on commit 3c96ccb

Please sign in to comment.