From 5bc3bf6dce6b37e3520283db883f438ef3b8dc2f Mon Sep 17 00:00:00 2001 From: CrazyMax <1951866+crazy-max@users.noreply.github.com> Date: Mon, 26 Oct 2020 01:39:21 +0100 Subject: [PATCH] Coerces Git tag to semver (#3) Co-authored-by: CrazyMax --- .github/workflows/ci.yml | 23 + README.md | 24 + __tests__/fixtures/event_tag_20200110-RC2.env | 23 + .../{event_tag.env => event_tag_release1.env} | 0 __tests__/fixtures/event_tag_sometag.env | 23 + ...nt_tag_semver.env => event_tag_v1.1.1.env} | 0 .../fixtures/event_tag_v2.0.8-beta.67.env | 23 + __tests__/meta.test.ts | 879 +++++++++++------- action.yml | 3 + dist/index.js | 115 ++- src/context.ts | 2 + src/main.ts | 8 +- src/meta.ts | 105 +-- 13 files changed, 785 insertions(+), 443 deletions(-) create mode 100644 __tests__/fixtures/event_tag_20200110-RC2.env rename __tests__/fixtures/{event_tag.env => event_tag_release1.env} (100%) create mode 100644 __tests__/fixtures/event_tag_sometag.env rename __tests__/fixtures/{event_tag_semver.env => event_tag_v1.1.1.env} (100%) create mode 100644 __tests__/fixtures/event_tag_v2.0.8-beta.67.env diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7cc55c3..17f9174 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,6 +53,29 @@ jobs: tag-sha: true tag-schedule: ${{ matrix.tag-schedule }} + coerce: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + tag-coerce-tag: + - "{{raw}}" + - "{{major}}.{{minor}}" + - "{{patch}}" + steps: + - + name: Checkout + uses: actions/checkout@v2.3.3 + - + name: Docker meta + uses: ./ + with: + images: | + ${{ env.DOCKER_IMAGE }} + ghcr.io/name/app + tag-coerce-tag: ${{ matrix.tag-coerce-tag }} + tag-sha: true + docker-push: runs-on: ubuntu-latest services: diff --git a/README.md b/README.md index 0df9c92..e5d8747 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,8 @@ ___ * [inputs](#inputs) * [outputs](#outputs) * [Notes](#notes) + * [Latest tag](#latest-tag) + * [Coerces Git tag](#coerces-git-tag) * [Templates available for schedule tag](#templates-available-for-schedule-tag) * [Keep up-to-date with GitHub Dependabot](#keep-up-to-date-with-github-dependabot) * [How can I help?](#how-can-i-help) @@ -114,6 +116,7 @@ Following inputs can be used as `step.with` keys | `tag-sha` | Bool | Add git short SHA as Docker tag (default `false`) | | `tag-edge` | Bool | Enable edge branch tagging (default `false`) | | `tag-edge-branch` | String | Branch that will be tagged as edge (default `repo.default_branch`) | +| `tag-coerce-tag` | String | Coerces Git tag to semver if possible using [Handlebars template](https://handlebarsjs.com/guide/) | | `tag-schedule` | String | [Handlebars template](https://handlebarsjs.com/guide/) to apply to schedule tag (default `nightly`) | | `sep-tags` | String | Separator to use for tags output (default `\n`) | | `sep-labels` | String | Separator to use for labels output (default `\n`) | @@ -132,6 +135,27 @@ Following outputs are available ## Notes +### Latest tag + +`latest` tag is created only on `push tag` event and resolves one of the following conditions: + +* Git tag is a valid [semver](https://semver.org/) +* Provided `tag-coerce-tag` is valid + +### Coerces Git tag + +Provides a very forgiving translation of a non-semver tag to semver. For more information see +[Coercion section](https://www.npmjs.com/package/semver#coercion). `tag-coerce-tag` supports +[Handlebars template](https://handlebarsjs.com/guide/) with the following inputs: + +| `tag-coerce-tag` | Git tag | Version | +|-------------------------|----------|---------| +| `{{raw}}` | `v1.2.3` | `1.2.3` | +| `{{major}}.{{minor}}` | `v1.2.3` | `1.2` | +| `{{major}}` | `v1.2.3` | `1` | +| `{{minor}}` | `v1.2.3` | `2` | +| `{{patch}}` | `v1.2.3` | `3` | + ### Templates available for schedule tag `tag-schedule` is specially crafted input to support [Handlebars template](https://handlebarsjs.com/guide/) with diff --git a/__tests__/fixtures/event_tag_20200110-RC2.env b/__tests__/fixtures/event_tag_20200110-RC2.env new file mode 100644 index 0000000..3e2a425 --- /dev/null +++ b/__tests__/fixtures/event_tag_20200110-RC2.env @@ -0,0 +1,23 @@ +GITHUB_ACTION=crazy-maxghaction-dump-context +GITHUB_ACTIONS=true +GITHUB_ACTION_PATH=/home/runner/work/_actions/crazy-max/ghaction-dump-context/v1 +GITHUB_ACTOR=crazy-max +GITHUB_API_URL=https://api.github.com +GITHUB_BASE_REF= +GITHUB_ENV=/home/runner/work/_temp/_runner_file_commands/set_env_6ee180c2-b331-434a-a867-89534cbefd83 +GITHUB_EVENT_NAME=push +#GITHUB_EVENT_PATH=/home/runner/work/_temp/_github_workflow/event.json +GITHUB_GRAPHQL_URL=https://api.github.com/graphql +GITHUB_HEAD_REF= +GITHUB_JOB=event +GITHUB_PATH=/home/runner/work/_temp/_runner_file_commands/add_path_6ee180c2-b331-434a-a867-89534cbefd83 +GITHUB_REF=refs/tags/20200110-RC2 +GITHUB_REPOSITORY=crazy-max/test-docker-action +GITHUB_REPOSITORY_OWNER=crazy-max +GITHUB_RETENTION_DAYS=90 +GITHUB_RUN_ID=325968230 +GITHUB_RUN_NUMBER=4 +GITHUB_SERVER_URL=https://github.com +GITHUB_SHA=90dd6032fac8bda1b6c4436a2e65de27961ed071 +GITHUB_WORKFLOW=event +GITHUB_WORKSPACE=/home/runner/work/test-docker-action/test-docker-action diff --git a/__tests__/fixtures/event_tag.env b/__tests__/fixtures/event_tag_release1.env similarity index 100% rename from __tests__/fixtures/event_tag.env rename to __tests__/fixtures/event_tag_release1.env diff --git a/__tests__/fixtures/event_tag_sometag.env b/__tests__/fixtures/event_tag_sometag.env new file mode 100644 index 0000000..2001bce --- /dev/null +++ b/__tests__/fixtures/event_tag_sometag.env @@ -0,0 +1,23 @@ +GITHUB_ACTION=crazy-maxghaction-dump-context +GITHUB_ACTIONS=true +GITHUB_ACTION_PATH=/home/runner/work/_actions/crazy-max/ghaction-dump-context/v1 +GITHUB_ACTOR=crazy-max +GITHUB_API_URL=https://api.github.com +GITHUB_BASE_REF= +GITHUB_ENV=/home/runner/work/_temp/_runner_file_commands/set_env_6ee180c2-b331-434a-a867-89534cbefd83 +GITHUB_EVENT_NAME=push +#GITHUB_EVENT_PATH=/home/runner/work/_temp/_github_workflow/event.json +GITHUB_GRAPHQL_URL=https://api.github.com/graphql +GITHUB_HEAD_REF= +GITHUB_JOB=event +GITHUB_PATH=/home/runner/work/_temp/_runner_file_commands/add_path_6ee180c2-b331-434a-a867-89534cbefd83 +GITHUB_REF=refs/tags/sometag +GITHUB_REPOSITORY=crazy-max/test-docker-action +GITHUB_REPOSITORY_OWNER=crazy-max +GITHUB_RETENTION_DAYS=90 +GITHUB_RUN_ID=325968230 +GITHUB_RUN_NUMBER=4 +GITHUB_SERVER_URL=https://github.com +GITHUB_SHA=90dd6032fac8bda1b6c4436a2e65de27961ed071 +GITHUB_WORKFLOW=event +GITHUB_WORKSPACE=/home/runner/work/test-docker-action/test-docker-action diff --git a/__tests__/fixtures/event_tag_semver.env b/__tests__/fixtures/event_tag_v1.1.1.env similarity index 100% rename from __tests__/fixtures/event_tag_semver.env rename to __tests__/fixtures/event_tag_v1.1.1.env diff --git a/__tests__/fixtures/event_tag_v2.0.8-beta.67.env b/__tests__/fixtures/event_tag_v2.0.8-beta.67.env new file mode 100644 index 0000000..2bd31bb --- /dev/null +++ b/__tests__/fixtures/event_tag_v2.0.8-beta.67.env @@ -0,0 +1,23 @@ +GITHUB_ACTION=crazy-maxghaction-dump-context +GITHUB_ACTIONS=true +GITHUB_ACTION_PATH=/home/runner/work/_actions/crazy-max/ghaction-dump-context/v1 +GITHUB_ACTOR=crazy-max +GITHUB_API_URL=https://api.github.com +GITHUB_BASE_REF= +GITHUB_ENV=/home/runner/work/_temp/_runner_file_commands/set_env_6ee180c2-b331-434a-a867-89534cbefd83 +GITHUB_EVENT_NAME=push +#GITHUB_EVENT_PATH=/home/runner/work/_temp/_github_workflow/event.json +GITHUB_GRAPHQL_URL=https://api.github.com/graphql +GITHUB_HEAD_REF= +GITHUB_JOB=event +GITHUB_PATH=/home/runner/work/_temp/_runner_file_commands/add_path_6ee180c2-b331-434a-a867-89534cbefd83 +GITHUB_REF=refs/tags/v2.0.8-beta.67 +GITHUB_REPOSITORY=crazy-max/test-docker-action +GITHUB_REPOSITORY_OWNER=crazy-max +GITHUB_RETENTION_DAYS=90 +GITHUB_RUN_ID=325968230 +GITHUB_RUN_NUMBER=4 +GITHUB_SERVER_URL=https://github.com +GITHUB_SHA=90dd6032fac8bda1b6c4436a2e65de27961ed071 +GITHUB_WORKFLOW=event +GITHUB_WORKSPACE=/home/runner/work/test-docker-action/test-docker-action diff --git a/__tests__/meta.test.ts b/__tests__/meta.test.ts index 6411922..6ea0f5b 100644 --- a/__tests__/meta.test.ts +++ b/__tests__/meta.test.ts @@ -4,7 +4,7 @@ import * as dotenv from 'dotenv'; import * as moment from 'moment'; import {getInputs, Inputs} from '../src/context'; import * as github from '../src/github'; -import {Meta} from '../src/meta'; +import {Meta, Version} from '../src/meta'; import {Context} from '@actions/github/lib/context'; import {ReposGetResponseData} from '@octokit/types'; @@ -28,15 +28,36 @@ jest.mock('moment', () => { return () => jest.requireActual('moment')('2020-01-10T00:30:00.000Z'); }); -describe('tags and labels', () => { - beforeEach(() => { - Object.keys(process.env).forEach(function (key) { - if (key !== 'GITHUB_TOKEN' && key.startsWith('GITHUB_')) { - delete process.env[key]; - } - }); +beforeEach(() => { + Object.keys(process.env).forEach(function (key) { + if (key !== 'GITHUB_TOKEN' && key.startsWith('GITHUB_')) { + delete process.env[key]; + } }); +}); +const tagsLabelsTest = async (envFile: string, inputs: Inputs, exVersion: Version, exTags: Array, exLabels: Array) => { + process.env = dotenv.parse(fs.readFileSync(path.join(__dirname, 'fixtures', envFile))); + const context = github.context(); + console.log(process.env, context); + + const repo = await github.repo(process.env.GITHUB_TOKEN || ''); + const meta = new Meta({...getInputs(), ...inputs}, context, repo); + + const version = meta.version(); + console.log('version', version); + expect(version).toEqual(exVersion); + + const tags = meta.tags(); + console.log('tags', tags); + expect(tags).toEqual(exTags); + + const labels = meta.labels(); + console.log('labels', labels); + expect(labels).toEqual(exLabels); +}; + +describe('null', () => { // prettier-ignore test.each([ [ @@ -44,7 +65,10 @@ describe('tags and labels', () => { { images: ['user/app'], } as Inputs, - undefined, + { + version: undefined, + latest: false + } as Version, [], [ "org.opencontainers.image.title=Hello-World", @@ -62,7 +86,10 @@ describe('tags and labels', () => { { images: ['user/app'], } as Inputs, - undefined, + { + version: undefined, + latest: false + } as Version, [], [ "org.opencontainers.image.title=Hello-World", @@ -75,32 +102,21 @@ describe('tags and labels', () => { "org.opencontainers.image.licenses=MIT" ] ], - [ - 'event_pull_request.env', - { - images: ['user/app'], - } as Inputs, - 'pr-2', - [ - 'user/app:pr-2' - ], - [ - "org.opencontainers.image.title=Hello-World", - "org.opencontainers.image.description=This your first repo!", - "org.opencontainers.image.url=https://github.com/octocat/Hello-World", - "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", - "org.opencontainers.image.version=pr-2", - "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", - "org.opencontainers.image.revision=1e9249f05bfc090e0688b8fb9c1b347586add504", - "org.opencontainers.image.licenses=MIT" - ] - ], + ])('given %p event ', tagsLabelsTest); +}); + +describe('push', () => { + // prettier-ignore + test.each([ [ 'event_push.env', { images: ['user/app'], } as Inputs, - 'dev', + { + version: 'dev', + latest: false + } as Version, [ 'user/app:dev' ], @@ -121,7 +137,10 @@ describe('tags and labels', () => { images: ['user/app'], tagEdge: true, } as Inputs, - 'edge', + { + version: 'edge', + latest: false + } as Version, [ 'user/app:edge' ], @@ -141,7 +160,10 @@ describe('tags and labels', () => { { images: ['user/app'], } as Inputs, - 'master', + { + version: 'master', + latest: false + } as Version, [ 'user/app:master' ], @@ -156,137 +178,16 @@ describe('tags and labels', () => { "org.opencontainers.image.licenses=MIT" ] ], - [ - 'event_release.env', - { - images: ['user/app'], - } as Inputs, - '1.1.1', - [ - 'user/app:1.1.1', - 'user/app:latest' - ], - [ - "org.opencontainers.image.title=Hello-World", - "org.opencontainers.image.description=This your first repo!", - "org.opencontainers.image.url=https://github.com/octocat/Hello-World", - "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", - "org.opencontainers.image.version=1.1.1", - "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", - "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", - "org.opencontainers.image.licenses=MIT" - ] - ], - [ - 'event_schedule.env', - { - images: ['user/app'], - } as Inputs, - 'nightly', - [ - 'user/app:nightly' - ], - [ - "org.opencontainers.image.title=Hello-World", - "org.opencontainers.image.description=This your first repo!", - "org.opencontainers.image.url=https://github.com/octocat/Hello-World", - "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", - "org.opencontainers.image.version=nightly", - "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", - "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", - "org.opencontainers.image.licenses=MIT" - ] - ], - [ - 'event_schedule.env', - { - images: ['user/app'], - tagSchedule: `{{date 'YYYYMMDD'}}` - } as Inputs, - '20200110', - [ - 'user/app:20200110' - ], - [ - "org.opencontainers.image.title=Hello-World", - "org.opencontainers.image.description=This your first repo!", - "org.opencontainers.image.url=https://github.com/octocat/Hello-World", - "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", - "org.opencontainers.image.version=20200110", - "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", - "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", - "org.opencontainers.image.licenses=MIT" - ] - ], - [ - 'event_schedule.env', - { - images: ['user/app'], - tagSchedule: `{{date 'YYYYMMDD-HHmmss'}}` - } as Inputs, - '20200110-003000', - [ - 'user/app:20200110-003000' - ], - [ - "org.opencontainers.image.title=Hello-World", - "org.opencontainers.image.description=This your first repo!", - "org.opencontainers.image.url=https://github.com/octocat/Hello-World", - "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", - "org.opencontainers.image.version=20200110-003000", - "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", - "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", - "org.opencontainers.image.licenses=MIT" - ] - ], - [ - 'event_tag.env', - { - images: ['user/app'], - } as Inputs, - 'release1', - [ - 'user/app:release1' - ], - [ - "org.opencontainers.image.title=Hello-World", - "org.opencontainers.image.description=This your first repo!", - "org.opencontainers.image.url=https://github.com/octocat/Hello-World", - "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", - "org.opencontainers.image.version=release1", - "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", - "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", - "org.opencontainers.image.licenses=MIT" - ] - ], - [ - 'event_tag_semver.env', - { - images: ['user/app'], - } as Inputs, - '1.1.1', - [ - 'user/app:1.1.1', - 'user/app:latest' - ], - [ - "org.opencontainers.image.title=Hello-World", - "org.opencontainers.image.description=This your first repo!", - "org.opencontainers.image.url=https://github.com/octocat/Hello-World", - "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", - "org.opencontainers.image.version=1.1.1", - "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", - "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", - "org.opencontainers.image.licenses=MIT" - ] - ], [ 'event_workflow_dispatch.env', { images: ['user/app'], tagEdge: true, } as Inputs, - 'edge', + { + version: 'edge', + latest: false + } as Version, [ 'user/app:edge' ], @@ -301,33 +202,15 @@ describe('tags and labels', () => { "org.opencontainers.image.licenses=MIT" ] ], - [ - 'event_pull_request.env', - { - images: ['org/app', 'ghcr.io/user/app'], - } as Inputs, - 'pr-2', - [ - 'org/app:pr-2', - 'ghcr.io/user/app:pr-2' - ], - [ - "org.opencontainers.image.title=Hello-World", - "org.opencontainers.image.description=This your first repo!", - "org.opencontainers.image.url=https://github.com/octocat/Hello-World", - "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", - "org.opencontainers.image.version=pr-2", - "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", - "org.opencontainers.image.revision=1e9249f05bfc090e0688b8fb9c1b347586add504", - "org.opencontainers.image.licenses=MIT" - ] - ], [ 'event_push.env', { images: ['org/app', 'ghcr.io/user/app'], } as Inputs, - 'dev', + { + version: 'dev', + latest: false + } as Version, [ 'org/app:dev', 'ghcr.io/user/app:dev' @@ -349,7 +232,10 @@ describe('tags and labels', () => { images: ['org/app', 'ghcr.io/user/app'], tagEdge: true, } as Inputs, - 'edge', + { + version: 'edge', + latest: false + } as Version, [ 'org/app:edge', 'ghcr.io/user/app:edge' @@ -365,81 +251,16 @@ describe('tags and labels', () => { "org.opencontainers.image.licenses=MIT" ] ], - [ - 'event_schedule.env', - { - images: ['org/app', 'ghcr.io/user/app'], - } as Inputs, - 'nightly', - [ - 'org/app:nightly', - 'ghcr.io/user/app:nightly' - ], - [ - "org.opencontainers.image.title=Hello-World", - "org.opencontainers.image.description=This your first repo!", - "org.opencontainers.image.url=https://github.com/octocat/Hello-World", - "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", - "org.opencontainers.image.version=nightly", - "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", - "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", - "org.opencontainers.image.licenses=MIT" - ] - ], - [ - 'event_tag_semver.env', - { - images: ['org/app', 'ghcr.io/user/app'], - } as Inputs, - '1.1.1', - [ - 'org/app:1.1.1', - 'org/app:latest', - 'ghcr.io/user/app:1.1.1', - 'ghcr.io/user/app:latest' - ], - [ - "org.opencontainers.image.title=Hello-World", - "org.opencontainers.image.description=This your first repo!", - "org.opencontainers.image.url=https://github.com/octocat/Hello-World", - "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", - "org.opencontainers.image.version=1.1.1", - "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", - "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", - "org.opencontainers.image.licenses=MIT" - ] - ], - [ - 'event_pull_request.env', - { - images: ['org/app', 'ghcr.io/user/app'], - tagSha: true, - } as Inputs, - 'pr-2', - [ - 'org/app:pr-2', - 'org/app:sha-1e9249f', - 'ghcr.io/user/app:pr-2', - 'ghcr.io/user/app:sha-1e9249f' - ], - [ - "org.opencontainers.image.title=Hello-World", - "org.opencontainers.image.description=This your first repo!", - "org.opencontainers.image.url=https://github.com/octocat/Hello-World", - "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", - "org.opencontainers.image.version=pr-2", - "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", - "org.opencontainers.image.revision=1e9249f05bfc090e0688b8fb9c1b347586add504", - "org.opencontainers.image.licenses=MIT" - ] - ], [ 'event_push.env', { images: ['org/app', 'ghcr.io/user/app'], tagSha: true, } as Inputs, - 'dev', + { + version: 'dev', + latest: false + } as Version, [ 'org/app:dev', 'org/app:sha-90dd603', @@ -464,7 +285,10 @@ describe('tags and labels', () => { tagSha: true, tagEdge: true, } as Inputs, - 'edge', + { + version: 'edge', + latest: false + } as Version, [ 'org/app:edge', 'org/app:sha-90dd603', @@ -482,56 +306,6 @@ describe('tags and labels', () => { "org.opencontainers.image.licenses=MIT" ] ], - [ - 'event_schedule.env', - { - images: ['org/app', 'ghcr.io/user/app'], - tagSha: true, - } as Inputs, - 'nightly', - [ - 'org/app:nightly', - 'org/app:sha-90dd603', - 'ghcr.io/user/app:nightly', - 'ghcr.io/user/app:sha-90dd603' - ], - [ - "org.opencontainers.image.title=Hello-World", - "org.opencontainers.image.description=This your first repo!", - "org.opencontainers.image.url=https://github.com/octocat/Hello-World", - "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", - "org.opencontainers.image.version=nightly", - "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", - "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", - "org.opencontainers.image.licenses=MIT" - ] - ], - [ - 'event_tag_semver.env', - { - images: ['org/app', 'ghcr.io/user/app'], - tagSha: true, - } as Inputs, - '1.1.1', - [ - 'org/app:1.1.1', - 'org/app:latest', - 'org/app:sha-90dd603', - 'ghcr.io/user/app:1.1.1', - 'ghcr.io/user/app:latest', - 'ghcr.io/user/app:sha-90dd603' - ], - [ - "org.opencontainers.image.title=Hello-World", - "org.opencontainers.image.description=This your first repo!", - "org.opencontainers.image.url=https://github.com/octocat/Hello-World", - "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", - "org.opencontainers.image.version=1.1.1", - "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", - "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", - "org.opencontainers.image.licenses=MIT" - ] - ], [ 'event_push.env', { @@ -540,7 +314,10 @@ describe('tags and labels', () => { tagEdge: true, tagEdgeBranch: 'dev' } as Inputs, - 'edge', + { + version: 'edge', + latest: false + } as Version, [ 'org/app:edge', 'org/app:sha-90dd603', @@ -566,7 +343,10 @@ describe('tags and labels', () => { tagEdge: true, tagEdgeBranch: 'dev' } as Inputs, - 'master', + { + version: 'master', + latest: false + } as Version, [ 'org/app:master', 'org/app:sha-90dd603', @@ -584,24 +364,477 @@ describe('tags and labels', () => { "org.opencontainers.image.licenses=MIT" ] ], - ])('given %p event ', async (envFile, inputs, exVersion, exTags, exLabels) => { - process.env = dotenv.parse(fs.readFileSync(path.join(__dirname, 'fixtures', envFile))); - const context = github.context(); - console.log(process.env, context); - - const repo = await github.repo(process.env.GITHUB_TOKEN || ''); - const meta = new Meta({...getInputs(), ...inputs}, context, repo); - - const version = meta.version(); - console.log('version', version); - expect(version).toEqual(exVersion); - - const tags = meta.tags(); - console.log('tags', tags); - expect(tags).toEqual(exTags); - - const labels = meta.labels(); - console.log('labels', labels); - expect(labels).toEqual(exLabels); - }); + ])('given %p event ', tagsLabelsTest); +}); + +describe('push tag', () => { + // prettier-ignore + test.each([ + [ + 'event_tag_release1.env', + { + images: ['user/app'], + } as Inputs, + { + version: 'release1', + latest: false + } as Version, + [ + 'user/app:release1' + ], + [ + "org.opencontainers.image.title=Hello-World", + "org.opencontainers.image.description=This your first repo!", + "org.opencontainers.image.url=https://github.com/octocat/Hello-World", + "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", + "org.opencontainers.image.version=release1", + "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", + "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", + "org.opencontainers.image.licenses=MIT" + ] + ], + [ + 'event_tag_20200110-RC2.env', + { + images: ['user/app'], + } as Inputs, + { + version: '20200110-RC2', + latest: false + } as Version, + [ + 'user/app:20200110-RC2' + ], + [ + "org.opencontainers.image.title=Hello-World", + "org.opencontainers.image.description=This your first repo!", + "org.opencontainers.image.url=https://github.com/octocat/Hello-World", + "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", + "org.opencontainers.image.version=20200110-RC2", + "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", + "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", + "org.opencontainers.image.licenses=MIT" + ] + ], + [ + 'event_tag_20200110-RC2.env', + { + images: ['user/app'], + tagCoerceTag: '{{major}}', + } as Inputs, + { + version: '20200110', + latest: true + } as Version, + [ + 'user/app:20200110', + 'user/app:latest' + ], + [ + "org.opencontainers.image.title=Hello-World", + "org.opencontainers.image.description=This your first repo!", + "org.opencontainers.image.url=https://github.com/octocat/Hello-World", + "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", + "org.opencontainers.image.version=20200110", + "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", + "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", + "org.opencontainers.image.licenses=MIT" + ] + ], + [ + 'event_tag_v1.1.1.env', + { + images: ['user/app'], + } as Inputs, + { + version: '1.1.1', + latest: true + } as Version, + [ + 'user/app:1.1.1', + 'user/app:latest' + ], + [ + "org.opencontainers.image.title=Hello-World", + "org.opencontainers.image.description=This your first repo!", + "org.opencontainers.image.url=https://github.com/octocat/Hello-World", + "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", + "org.opencontainers.image.version=1.1.1", + "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", + "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", + "org.opencontainers.image.licenses=MIT" + ] + ], + [ + 'event_tag_v1.1.1.env', + { + images: ['org/app', 'ghcr.io/user/app'], + } as Inputs, + { + version: '1.1.1', + latest: true + } as Version, + [ + 'org/app:1.1.1', + 'org/app:latest', + 'ghcr.io/user/app:1.1.1', + 'ghcr.io/user/app:latest' + ], + [ + "org.opencontainers.image.title=Hello-World", + "org.opencontainers.image.description=This your first repo!", + "org.opencontainers.image.url=https://github.com/octocat/Hello-World", + "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", + "org.opencontainers.image.version=1.1.1", + "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", + "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", + "org.opencontainers.image.licenses=MIT" + ] + ], + [ + 'event_tag_v1.1.1.env', + { + images: ['org/app', 'ghcr.io/user/app'], + tagSha: true, + } as Inputs, + { + version: '1.1.1', + latest: true + } as Version, + [ + 'org/app:1.1.1', + 'org/app:latest', + 'org/app:sha-90dd603', + 'ghcr.io/user/app:1.1.1', + 'ghcr.io/user/app:latest', + 'ghcr.io/user/app:sha-90dd603' + ], + [ + "org.opencontainers.image.title=Hello-World", + "org.opencontainers.image.description=This your first repo!", + "org.opencontainers.image.url=https://github.com/octocat/Hello-World", + "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", + "org.opencontainers.image.version=1.1.1", + "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", + "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", + "org.opencontainers.image.licenses=MIT" + ] + ], + [ + 'event_tag_v2.0.8-beta.67.env', + { + images: ['org/app', 'ghcr.io/user/app'], + } as Inputs, + { + version: '2.0.8-beta.67', + latest: true + } as Version, + [ + 'org/app:2.0.8-beta.67', + 'org/app:latest', + 'ghcr.io/user/app:2.0.8-beta.67', + 'ghcr.io/user/app:latest' + ], + [ + "org.opencontainers.image.title=Hello-World", + "org.opencontainers.image.description=This your first repo!", + "org.opencontainers.image.url=https://github.com/octocat/Hello-World", + "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", + "org.opencontainers.image.version=2.0.8-beta.67", + "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", + "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", + "org.opencontainers.image.licenses=MIT" + ] + ], + [ + 'event_tag_v2.0.8-beta.67.env', + { + images: ['org/app', 'ghcr.io/user/app'], + tagCoerceTag: '{{major}}.{{minor}}', + } as Inputs, + { + version: '2.0', + latest: true + } as Version, + [ + 'org/app:2.0', + 'org/app:latest', + 'ghcr.io/user/app:2.0', + 'ghcr.io/user/app:latest' + ], + [ + "org.opencontainers.image.title=Hello-World", + "org.opencontainers.image.description=This your first repo!", + "org.opencontainers.image.url=https://github.com/octocat/Hello-World", + "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", + "org.opencontainers.image.version=2.0", + "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", + "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", + "org.opencontainers.image.licenses=MIT" + ] + ], + [ + 'event_tag_sometag.env', + { + images: ['org/app', 'ghcr.io/user/app'], + tagCoerceTag: '{{major}}.{{minor}}', + } as Inputs, + { + version: 'sometag', + latest: false + } as Version, + [ + 'org/app:sometag', + 'ghcr.io/user/app:sometag' + ], + [ + "org.opencontainers.image.title=Hello-World", + "org.opencontainers.image.description=This your first repo!", + "org.opencontainers.image.url=https://github.com/octocat/Hello-World", + "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", + "org.opencontainers.image.version=sometag", + "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", + "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", + "org.opencontainers.image.licenses=MIT" + ] + ], + ])('given %p event ', tagsLabelsTest); +}); + +describe('pull_request', () => { + // prettier-ignore + test.each([ + [ + 'event_pull_request.env', + { + images: ['user/app'], + } as Inputs, + { + version: 'pr-2', + latest: false + } as Version, + [ + 'user/app:pr-2' + ], + [ + "org.opencontainers.image.title=Hello-World", + "org.opencontainers.image.description=This your first repo!", + "org.opencontainers.image.url=https://github.com/octocat/Hello-World", + "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", + "org.opencontainers.image.version=pr-2", + "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", + "org.opencontainers.image.revision=1e9249f05bfc090e0688b8fb9c1b347586add504", + "org.opencontainers.image.licenses=MIT" + ] + ], + [ + 'event_pull_request.env', + { + images: ['org/app', 'ghcr.io/user/app'], + } as Inputs, + { + version: 'pr-2', + latest: false + } as Version, + [ + 'org/app:pr-2', + 'ghcr.io/user/app:pr-2' + ], + [ + "org.opencontainers.image.title=Hello-World", + "org.opencontainers.image.description=This your first repo!", + "org.opencontainers.image.url=https://github.com/octocat/Hello-World", + "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", + "org.opencontainers.image.version=pr-2", + "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", + "org.opencontainers.image.revision=1e9249f05bfc090e0688b8fb9c1b347586add504", + "org.opencontainers.image.licenses=MIT" + ] + ], + [ + 'event_pull_request.env', + { + images: ['org/app', 'ghcr.io/user/app'], + tagSha: true, + } as Inputs, + { + version: 'pr-2', + latest: false + } as Version, + [ + 'org/app:pr-2', + 'org/app:sha-1e9249f', + 'ghcr.io/user/app:pr-2', + 'ghcr.io/user/app:sha-1e9249f' + ], + [ + "org.opencontainers.image.title=Hello-World", + "org.opencontainers.image.description=This your first repo!", + "org.opencontainers.image.url=https://github.com/octocat/Hello-World", + "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", + "org.opencontainers.image.version=pr-2", + "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", + "org.opencontainers.image.revision=1e9249f05bfc090e0688b8fb9c1b347586add504", + "org.opencontainers.image.licenses=MIT" + ] + ], + ])('given %p event ', tagsLabelsTest); +}); + +describe('schedule', () => { + // prettier-ignore + test.each([ + [ + 'event_schedule.env', + { + images: ['user/app'], + } as Inputs, + { + version: 'nightly', + latest: false + } as Version, + [ + 'user/app:nightly' + ], + [ + "org.opencontainers.image.title=Hello-World", + "org.opencontainers.image.description=This your first repo!", + "org.opencontainers.image.url=https://github.com/octocat/Hello-World", + "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", + "org.opencontainers.image.version=nightly", + "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", + "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", + "org.opencontainers.image.licenses=MIT" + ] + ], + [ + 'event_schedule.env', + { + images: ['user/app'], + tagSchedule: `{{date 'YYYYMMDD'}}` + } as Inputs, + { + version: '20200110', + latest: false + } as Version, + [ + 'user/app:20200110' + ], + [ + "org.opencontainers.image.title=Hello-World", + "org.opencontainers.image.description=This your first repo!", + "org.opencontainers.image.url=https://github.com/octocat/Hello-World", + "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", + "org.opencontainers.image.version=20200110", + "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", + "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", + "org.opencontainers.image.licenses=MIT" + ] + ], + [ + 'event_schedule.env', + { + images: ['user/app'], + tagSchedule: `{{date 'YYYYMMDD-HHmmss'}}` + } as Inputs, + { + version: '20200110-003000', + latest: false + } as Version, + [ + 'user/app:20200110-003000' + ], + [ + "org.opencontainers.image.title=Hello-World", + "org.opencontainers.image.description=This your first repo!", + "org.opencontainers.image.url=https://github.com/octocat/Hello-World", + "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", + "org.opencontainers.image.version=20200110-003000", + "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", + "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", + "org.opencontainers.image.licenses=MIT" + ] + ], + [ + 'event_schedule.env', + { + images: ['org/app', 'ghcr.io/user/app'], + } as Inputs, + { + version: 'nightly', + latest: false + } as Version, + [ + 'org/app:nightly', + 'ghcr.io/user/app:nightly' + ], + [ + "org.opencontainers.image.title=Hello-World", + "org.opencontainers.image.description=This your first repo!", + "org.opencontainers.image.url=https://github.com/octocat/Hello-World", + "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", + "org.opencontainers.image.version=nightly", + "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", + "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", + "org.opencontainers.image.licenses=MIT" + ] + ], + [ + 'event_schedule.env', + { + images: ['org/app', 'ghcr.io/user/app'], + tagSha: true, + } as Inputs, + { + version: 'nightly', + latest: false + } as Version, + [ + 'org/app:nightly', + 'org/app:sha-90dd603', + 'ghcr.io/user/app:nightly', + 'ghcr.io/user/app:sha-90dd603' + ], + [ + "org.opencontainers.image.title=Hello-World", + "org.opencontainers.image.description=This your first repo!", + "org.opencontainers.image.url=https://github.com/octocat/Hello-World", + "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", + "org.opencontainers.image.version=nightly", + "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", + "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", + "org.opencontainers.image.licenses=MIT" + ] + ], + ])('given %p event ', tagsLabelsTest); +}); + +describe('release', () => { + // prettier-ignore + test.each([ + [ + 'event_release.env', + { + images: ['user/app'], + } as Inputs, + { + version: '1.1.1', + latest: true + } as Version, + [ + 'user/app:1.1.1', + 'user/app:latest' + ], + [ + "org.opencontainers.image.title=Hello-World", + "org.opencontainers.image.description=This your first repo!", + "org.opencontainers.image.url=https://github.com/octocat/Hello-World", + "org.opencontainers.image.source=https://github.com/octocat/Hello-World.git", + "org.opencontainers.image.version=1.1.1", + "org.opencontainers.image.created=2020-01-10T00:30:00.000Z", + "org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071", + "org.opencontainers.image.licenses=MIT" + ] + ], + ])('given %p event ', tagsLabelsTest); }); diff --git a/action.yml b/action.yml index 1b3d523..973f8ba 100644 --- a/action.yml +++ b/action.yml @@ -21,6 +21,9 @@ inputs: tag-edge-branch: description: 'Branch that will be tagged as edge (default repo.default_branch)' required: false + tag-coerce-tag: + description: 'Coerces Git tag to semver if possible using Handlebars template' + required: false tag-schedule: description: 'Handlebars template to apply to schedule tag' default: 'nightly' diff --git a/dist/index.js b/dist/index.js index de6f95d..2b34e4a 100644 --- a/dist/index.js +++ b/dist/index.js @@ -25,6 +25,7 @@ function getInputs() { tagSha: /true/i.test(core.getInput('tag-sha') || 'false'), tagEdge: /true/i.test(core.getInput('tag-edge') || 'false'), tagEdgeBranch: core.getInput('tag-edge-branch'), + tagCoerceTag: core.getInput('tag-coerce-tag'), tagSchedule: core.getInput('tag-schedule') || 'nightly', sepTags: core.getInput('sep-tags') || `\n`, sepLabels: core.getInput('sep-labels') || `\n`, @@ -129,9 +130,9 @@ function run() { const meta = new meta_1.Meta(inputs, context, repo); const version = meta.version(); core.startGroup(`Docker image version`); - core.info(`${version}`); + core.info(version.version || ''); core.endGroup(); - core.setOutput('version', version || ''); + core.setOutput('version', version.version || ''); const tags = meta.tags(); core.startGroup(`Docker tags`); for (let tag of tags) { @@ -167,7 +168,6 @@ exports.Meta = void 0; const handlebars = __webpack_require__(7492); const moment = __webpack_require__(9623); const semver = __webpack_require__(1383); -const core = __webpack_require__(2186); class Meta { constructor(inputs, context, repo) { this.inputs = inputs; @@ -179,40 +179,64 @@ class Meta { this.date = new Date(); } version() { + const currentDate = this.date; + const version = { + version: undefined, + latest: false + }; if (/schedule/.test(this.context.eventName)) { - return handlebars.compile(this.inputs.tagSchedule)(this.scheduleTplContext()); + version.version = handlebars.compile(this.inputs.tagSchedule)({ + date: function (format) { + return moment(currentDate).utc().format(format); + } + }); } else if (/^refs\/tags\//.test(this.context.ref)) { const tag = this.context.ref.replace(/^refs\/tags\//g, '').replace(/\//g, '-'); const sver = semver.clean(tag); - return sver ? sver : tag; - } - else if (/^refs\/heads\//.test(this.context.ref)) { - const branch = this.context.ref.replace(/^refs\/heads\//g, '').replace(/\//g, '-'); - return this.inputs.tagEdge && this.inputs.tagEdgeBranch === branch ? 'edge' : branch; - } - else if (/^refs\/pull\//.test(this.context.ref)) { - const pr = this.context.ref.replace(/^refs\/pull\//g, '').replace(/\/merge$/g, ''); - return `pr-${pr}`; - } - } - tags() { - let tags = []; - for (const image of this.inputs.images) { - if (/schedule/.test(this.context.eventName)) { - tags.push.apply(tags, this.eventSchedule(image)); + if (this.inputs.tagCoerceTag) { + const coerce = semver.coerce(tag); + if (coerce) { + version.version = handlebars.compile(this.inputs.tagCoerceTag)(coerce); + version.latest = true; + } + else if (sver) { + version.version = sver; + version.latest = true; + } + else { + version.version = tag; + } } - else if (/^refs\/tags\//.test(this.context.ref)) { - tags.push.apply(tags, this.eventTag(image)); - } - else if (/^refs\/heads\//.test(this.context.ref)) { - tags.push.apply(tags, this.eventBranch(image)); - } - else if (/^refs\/pull\//.test(this.context.ref)) { - tags.push.apply(tags, this.eventPullRequest(image)); + else if (sver) { + version.version = sver; + version.latest = true; } else { - core.warning(`Unknown event "${this.context.eventName}" with ref "${this.context.ref}"`); + version.version = tag; + } + } + else if (/^refs\/heads\//.test(this.context.ref)) { + version.version = this.context.ref.replace(/^refs\/heads\//g, '').replace(/\//g, '-'); + if (this.inputs.tagEdge && this.inputs.tagEdgeBranch === version.version) { + version.version = 'edge'; + } + } + else if (/^refs\/pull\//.test(this.context.ref)) { + version.version = `pr-${this.context.ref.replace(/^refs\/pull\//g, '').replace(/\/merge$/g, '')}`; + } + return version; + } + tags() { + const version = this.version(); + if (!version.version) { + return []; + } + let tags = []; + for (const image of this.inputs.images) { + tags.push(`${image}:${version.version}`); + if (version.latest) { + tags.push(`${image}:latest`); } if (this.context.sha && this.inputs.tagSha) { tags.push(`${image}:sha-${this.context.sha.substr(0, 7)}`); @@ -227,43 +251,12 @@ class Meta { `org.opencontainers.image.description=${this.repo.description || ''}`, `org.opencontainers.image.url=${this.repo.html_url || ''}`, `org.opencontainers.image.source=${this.repo.clone_url || ''}`, - `org.opencontainers.image.version=${this.version() || ''}`, + `org.opencontainers.image.version=${this.version().version || ''}`, `org.opencontainers.image.created=${this.date.toISOString()}`, `org.opencontainers.image.revision=${this.context.sha || ''}`, `org.opencontainers.image.licenses=${((_a = this.repo.license) === null || _a === void 0 ? void 0 : _a.spdx_id) || ''}` ]; } - eventSchedule(image) { - const schedule = handlebars.compile(this.inputs.tagSchedule)(this.scheduleTplContext()); - return [`${image}:${schedule}`]; - } - eventTag(image) { - const tag = this.context.ref.replace(/^refs\/tags\//g, '').replace(/\//g, '-'); - const version = semver.clean(tag); - if (version) { - return [`${image}:${version}`, `${image}:latest`]; - } - return [`${image}:${tag}`]; - } - eventBranch(image) { - const branch = this.context.ref.replace(/^refs\/heads\//g, '').replace(/\//g, '-'); - if (this.inputs.tagEdge && this.inputs.tagEdgeBranch === branch) { - return [`${image}:edge`]; - } - return [`${image}:${branch}`]; - } - eventPullRequest(image) { - const pr = this.context.ref.replace(/^refs\/pull\//g, '').replace(/\/merge$/g, ''); - return [`${image}:pr-${pr}`]; - } - scheduleTplContext() { - const currentDate = this.date; - return { - date: function (format) { - return moment(currentDate).utc().format(format); - } - }; - } } exports.Meta = Meta; //# sourceMappingURL=meta.js.map diff --git a/src/context.ts b/src/context.ts index 805e840..fcc39f4 100644 --- a/src/context.ts +++ b/src/context.ts @@ -5,6 +5,7 @@ export interface Inputs { tagSha: boolean; tagEdge: boolean; tagEdgeBranch: string; + tagCoerceTag: string; tagSchedule: string; sepTags: string; sepLabels: string; @@ -17,6 +18,7 @@ export function getInputs(): Inputs { tagSha: /true/i.test(core.getInput('tag-sha') || 'false'), tagEdge: /true/i.test(core.getInput('tag-edge') || 'false'), tagEdgeBranch: core.getInput('tag-edge-branch'), + tagCoerceTag: core.getInput('tag-coerce-tag'), tagSchedule: core.getInput('tag-schedule') || 'nightly', sepTags: core.getInput('sep-tags') || `\n`, sepLabels: core.getInput('sep-labels') || `\n`, diff --git a/src/main.ts b/src/main.ts index b03187c..692ef21 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,6 +1,6 @@ import {getInputs, Inputs} from './context'; import * as github from './github'; -import {Meta} from './meta'; +import {Meta, Version} from './meta'; import * as core from '@actions/core'; import {Context} from '@actions/github/lib/context'; import {ReposGetResponseData} from '@octokit/types'; @@ -27,11 +27,11 @@ async function run() { const meta: Meta = new Meta(inputs, context, repo); - const version: string | undefined = meta.version(); + const version: Version = meta.version(); core.startGroup(`Docker image version`); - core.info(`${version}`); + core.info(version.version || ''); core.endGroup(); - core.setOutput('version', version || ''); + core.setOutput('version', version.version || ''); const tags: Array = meta.tags(); core.startGroup(`Docker tags`); diff --git a/src/meta.ts b/src/meta.ts index 4904394..c8bb127 100644 --- a/src/meta.ts +++ b/src/meta.ts @@ -2,10 +2,14 @@ import * as handlebars from 'handlebars'; import * as moment from 'moment'; import * as semver from 'semver'; import {Inputs} from './context'; -import * as core from '@actions/core'; import {Context} from '@actions/github/lib/context'; import {ReposGetResponseData} from '@octokit/types'; +export interface Version { + version: string | undefined; + latest: boolean; +} + export class Meta { private readonly inputs: Inputs; private readonly context: Context; @@ -22,35 +26,62 @@ export class Meta { this.date = new Date(); } - public version(): string | undefined { + public version(): Version { + const currentDate = this.date; + const version: Version = { + version: undefined, + latest: false + }; + if (/schedule/.test(this.context.eventName)) { - return handlebars.compile(this.inputs.tagSchedule)(this.scheduleTplContext()); + version.version = handlebars.compile(this.inputs.tagSchedule)({ + date: function (format) { + return moment(currentDate).utc().format(format); + } + }); } else if (/^refs\/tags\//.test(this.context.ref)) { const tag = this.context.ref.replace(/^refs\/tags\//g, '').replace(/\//g, '-'); const sver = semver.clean(tag); - return sver ? sver : tag; + if (this.inputs.tagCoerceTag) { + const coerce = semver.coerce(tag); + if (coerce) { + version.version = handlebars.compile(this.inputs.tagCoerceTag)(coerce); + version.latest = true; + } else if (sver) { + version.version = sver; + version.latest = true; + } else { + version.version = tag; + } + } else if (sver) { + version.version = sver; + version.latest = true; + } else { + version.version = tag; + } } else if (/^refs\/heads\//.test(this.context.ref)) { - const branch = this.context.ref.replace(/^refs\/heads\//g, '').replace(/\//g, '-'); - return this.inputs.tagEdge && this.inputs.tagEdgeBranch === branch ? 'edge' : branch; + version.version = this.context.ref.replace(/^refs\/heads\//g, '').replace(/\//g, '-'); + if (this.inputs.tagEdge && this.inputs.tagEdgeBranch === version.version) { + version.version = 'edge'; + } } else if (/^refs\/pull\//.test(this.context.ref)) { - const pr = this.context.ref.replace(/^refs\/pull\//g, '').replace(/\/merge$/g, ''); - return `pr-${pr}`; + version.version = `pr-${this.context.ref.replace(/^refs\/pull\//g, '').replace(/\/merge$/g, '')}`; } + + return version; } public tags(): Array { + const version: Version = this.version(); + if (!version.version) { + return []; + } + let tags: Array = []; for (const image of this.inputs.images) { - if (/schedule/.test(this.context.eventName)) { - tags.push.apply(tags, this.eventSchedule(image)); - } else if (/^refs\/tags\//.test(this.context.ref)) { - tags.push.apply(tags, this.eventTag(image)); - } else if (/^refs\/heads\//.test(this.context.ref)) { - tags.push.apply(tags, this.eventBranch(image)); - } else if (/^refs\/pull\//.test(this.context.ref)) { - tags.push.apply(tags, this.eventPullRequest(image)); - } else { - core.warning(`Unknown event "${this.context.eventName}" with ref "${this.context.ref}"`); + tags.push(`${image}:${version.version}`); + if (version.latest) { + tags.push(`${image}:latest`); } if (this.context.sha && this.inputs.tagSha) { tags.push(`${image}:sha-${this.context.sha.substr(0, 7)}`); @@ -65,46 +96,10 @@ export class Meta { `org.opencontainers.image.description=${this.repo.description || ''}`, `org.opencontainers.image.url=${this.repo.html_url || ''}`, `org.opencontainers.image.source=${this.repo.clone_url || ''}`, - `org.opencontainers.image.version=${this.version() || ''}`, + `org.opencontainers.image.version=${this.version().version || ''}`, `org.opencontainers.image.created=${this.date.toISOString()}`, `org.opencontainers.image.revision=${this.context.sha || ''}`, `org.opencontainers.image.licenses=${this.repo.license?.spdx_id || ''}` ]; } - - private eventSchedule(image: string): Array { - const schedule = handlebars.compile(this.inputs.tagSchedule)(this.scheduleTplContext()); - return [`${image}:${schedule}`]; - } - - private eventTag(image: string): Array { - const tag = this.context.ref.replace(/^refs\/tags\//g, '').replace(/\//g, '-'); - const version = semver.clean(tag); - if (version) { - return [`${image}:${version}`, `${image}:latest`]; - } - return [`${image}:${tag}`]; - } - - private eventBranch(image: string): Array { - const branch = this.context.ref.replace(/^refs\/heads\//g, '').replace(/\//g, '-'); - if (this.inputs.tagEdge && this.inputs.tagEdgeBranch === branch) { - return [`${image}:edge`]; - } - return [`${image}:${branch}`]; - } - - private eventPullRequest(image: string): Array { - const pr = this.context.ref.replace(/^refs\/pull\//g, '').replace(/\/merge$/g, ''); - return [`${image}:pr-${pr}`]; - } - - private scheduleTplContext(): any { - const currentDate = this.date; - return { - date: function (format) { - return moment(currentDate).utc().format(format); - } - }; - } }