Compare commits

..

12 Commits

Author SHA1 Message Date
CrazyMax
55d3462f05 Update CHANGELOG 2020-12-08 00:02:30 +01:00
CrazyMax
7040b59aa5 Replace forbidden chars derived from branch name (#29)
Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-07 23:01:39 +00:00
dependabot[bot]
3ae5afe041 Bump semver from 7.3.2 to 7.3.4 (#26)
* Bump semver from 7.3.2 to 7.3.4

Bumps [semver](https://github.com/npm/node-semver) from 7.3.2 to 7.3.4.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/master/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v7.3.2...v7.3.4)

Signed-off-by: dependabot[bot] <support@github.com>

* Update generated content

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-04 19:15:40 +00:00
CrazyMax
b747b8aaa7 Update CHANGELOG 2020-12-04 18:15:25 +01:00
CrazyMax
585ab8356c Allow to add custom tags (#24)
Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-04 17:12:39 +00:00
CrazyMax
9de4428611 Allow to disable latest tag (#23)
Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-01 05:29:34 +00:00
CrazyMax
4c2760ba7a Warn on invalid semver (#22)
Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-01 04:50:39 +00:00
CrazyMax
ef12c77b87 Avoid unnecessary calls to version (#21)
Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-01 04:38:08 +00:00
CrazyMax
c53f88523a Fix README 2020-11-24 14:12:22 +01:00
CrazyMax
6b4bf4724e Update CHANGELOG 2020-11-24 14:09:55 +01:00
Jeremy Gustie
d48c7d2917 Use sepLabels when joining labels for output (#17) 2020-11-24 13:08:49 +00:00
CrazyMax
7cb65aaacb Pre-release (rc, beta, alpha) will only extend {{version}} as tag for tag-semver 2020-11-20 23:12:14 +01:00
12 changed files with 5172 additions and 3940 deletions

View File

@@ -82,10 +82,18 @@ jobs:
tag-semver:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
tag-latest:
- 'true'
- 'false'
steps:
- name: Checkout
-
name: Checkout
uses: actions/checkout@v2
- name: Docker meta
-
name: Docker meta
uses: ./
with:
images: |
@@ -95,6 +103,7 @@ jobs:
{{raw}}
{{version}}
{{major}}.{{minor}}.{{patch}}
tag-latest: ${{ matrix.tag-latest }}
docker-push:
runs-on: ubuntu-latest
@@ -114,7 +123,10 @@ jobs:
with:
images: ${{ env.DOCKER_IMAGE }}
tag-sha: true
tag-match: '\d{1,3}.\d{1,3}.\d{1,3}'
tag-semver: |
v{{version}}
v{{major}}.{{minor}}
v{{major}}
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1

View File

@@ -1,5 +1,25 @@
# Changelog
## 1.9.1 (2020/12/07)
* Replace forbidden chars derived from branch name (#31)
* Bump semver from 7.3.2 to 7.3.4 (#26)
## 1.9.0 (2020/12/04)
* Allow to add custom tags (#24)
* Allow to disable latest tag (#23)
* Warn on invalid semver (#22)
* Avoid unnecessary calls to version (#21)
## 1.8.5 (2020/11/24)
* Use sepLabels when joining labels for output (#17)
## 1.8.4 (2020/11/20)
* Pre-release (rc, beta, alpha) will only extend `{{version}}` as tag for `tag-semver`
## 1.8.3 (2020/11/20)
* Lowercase image name (#16)

View File

@@ -26,8 +26,8 @@ ___
* [outputs](#outputs)
* [Notes](#notes)
* [Latest tag](#latest-tag)
* [`tag-match` examples](#tag-match-examples)
* [Handle semver tag](#handle-semver-tag)
* [`tag-match` examples](#tag-match-examples)
* [Schedule tag](#schedule-tag)
* [Overwrite labels](#overwrite-labels)
* [Keep up-to-date with GitHub Dependabot](#keep-up-to-date-with-github-dependabot)
@@ -168,11 +168,11 @@ jobs:
| Event | Ref | Commit SHA | Docker Tags |
|-----------------|-------------------------------|------------|-----------------------------------------|
| `schedule` | `refs/heads/master` | `45f132a` | `sha-45f132a`, `nightly` |
| `pull_request` | `refs/pull/2/merge` | `a123b57` | `sha-45f132a`, `pr-2` |
| `push` | `refs/heads/master` | `cf20257` | `sha-45f132a`, `master` |
| `push` | `refs/heads/my/branch` | `a5df687` | `sha-45f132a`, `my-branch` |
| `push tag` | `refs/tags/v1.2.3` | `ad132f5` | `sha-45f132a`, `1.2.3`, `1.2`, `latest` |
| `push tag` | `refs/tags/v2.0.8-beta.67` | `fc89efd` | `sha-45f132a`, `2.0.8-beta.67` |
| `pull_request` | `refs/pull/2/merge` | `a123b57` | `sha-a123b57`, `pr-2` |
| `push` | `refs/heads/master` | `cf20257` | `sha-cf20257`, `master` |
| `push` | `refs/heads/my/branch` | `a5df687` | `sha-a5df687`, `my-branch` |
| `push tag` | `refs/tags/v1.2.3` | `ad132f5` | `sha-ad132f5`, `1.2.3`, `1.2`, `latest` |
| `push tag` | `refs/tags/v2.0.8-beta.67` | `fc89efd` | `sha-fc89efd`, `2.0.8-beta.67` |
```yaml
name: ci
@@ -200,6 +200,7 @@ jobs:
uses: crazy-max/ghaction-docker-meta@v1
with:
images: name/app
tag-sha: true
tag-semver: |
{{version}}
{{major}}.{{minor}}
@@ -240,16 +241,20 @@ 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-semver` | List | Handle Git tag as semver [template](#handle-semver-tag) if possible |
| `tag-semver` | List/CSV | Handle Git tag as semver [template](#handle-semver-tag) if possible |
| `tag-match` | String | RegExp to match against a Git tag and use first match as Docker tag |
| `tag-match-group` | Number | Group to get if `tag-match` matches (default `0`) |
| `tag-match-latest` | Bool | Set `latest` Docker tag if `tag-match` matches or on Git tag event (default `true`) |
| `tag-latest` | Bool | Set `latest` Docker tag if `tag-semver`, `tag-match` or Git tag event occurs (default `true`) |
| `tag-schedule` | String | [Template](#schedule-tag) to apply to schedule tag (default `nightly`) |
| `tag-custom` | List/CSV | List of custom tags |
| `tag-custom-only` | Bool | Only use `tag-custom` as Docker tags |
| `sep-tags` | String | Separator to use for tags output (default `\n`) |
| `sep-labels` | String | Separator to use for labels output (default `\n`) |
> List/CSV type can be a newline or comma delimited string
> `tag-semver` and `tag-match` are mutually exclusive
### outputs
Following outputs are available
@@ -266,18 +271,8 @@ Following outputs are available
Latest Docker tag will be generated by default on `push tag` event. If for example you push the `v1.2.3` Git tag,
you will have at the output of this action the Docker tags `v1.2.3` and `latest`. But you can allow the latest tag to be
generated only if the Git tag matches a regular expression with the [`tag-match` input](#tag-match-examples) or if
`tag-semver` is valid [semver](https://semver.org/).
### `tag-match` examples
| Git tag | `tag-match` | `tag-match-group` | Match | Output tags | Output version |
|-------------------------|------------------------------------|-------------------|----------------------|---------------------------|------------------------------|
| `v1.2.3` | `\d{1,3}.\d{1,3}.\d{1,3}` | `0` | :white_check_mark: | `1.2.3`, `latest` | `1.2.3` |
| `v2.0.8-beta.67` | `v(.*)` | `1` | :white_check_mark: | `2.0.8-beta.67`, `latest` | `2.0.8-beta.67` |
| `v2.0.8-beta.67` | `v(\d.\d)` | `1` | :white_check_mark: | `2.0`, `latest` | `2.0` |
| `release1` | `\d{1,3}.\d{1,3}` | `0` | :x: | `release1` | `release1` |
| `20200110-RC2` | `\d+` | `0` | :white_check_mark: | `20200110`, `latest` | `20200110` |
generated only if `tag-semver` is a valid [semver](https://semver.org/) or if Git tag matches a regular expression
with the [`tag-match` input](#tag-match-examples). Can be disabled if `tag-latest` is `false`.
### Handle semver tag
@@ -293,14 +288,25 @@ If Git tag is a valid [semver](https://semver.org/) you can handle it to output
| `v1.2.3` | `{{minor}}` | :white_check_mark: | `2`, `latest` | `2` |
| `v1.2.3` | `{{patch}}` | :white_check_mark: | `3`, `latest` | `3` |
| `v1.2.3` | `{{major}}.{{minor}}`<br>`{{major}}.{{minor}}.{{patch}}` | :white_check_mark: | `1.2`, `1.2.3`, `latest` | `1.2`* |
| `v2.0.8-beta.67` | `{{raw}}` | :white_check_mark: | `2.0.8-beta.67` | `2.0.8-beta.67` |
| `v2.0.8-beta.67` | `{{raw}}` | :white_check_mark: | `2.0.8-beta.67`** | `2.0.8-beta.67` |
| `v2.0.8-beta.67` | `{{version}}` | :white_check_mark: | `2.0.8-beta.67` | `2.0.8-beta.67` |
| `v2.0.8-beta.67` | `{{major}}.{{minor}}` | :white_check_mark: | `2.0.8-beta.67`** | `2.0.8-beta.67` |
| `release1` | `{{raw}}` | :x: | `release1` | `release1` |
> *First occurrence of `tag-semver` will be taken as `output.version`
> **Pre-release (rc, beta, alpha) will only extend `{{version}}` as tag
> **Pre-release (rc, beta, alpha) will only extend `{{version}}` as tag because they are updated frequently,
> and contain many breaking changes that are (by the author's design) not yet fit for public consumption.
### `tag-match` examples
| Git tag | `tag-match` | `tag-match-group` | Match | Output tags | Output version |
|-------------------------|------------------------------------|-------------------|----------------------|---------------------------|------------------------------|
| `v1.2.3` | `\d{1,3}.\d{1,3}.\d{1,3}` | `0` | :white_check_mark: | `1.2.3`, `latest` | `1.2.3` |
| `v2.0.8-beta.67` | `v(.*)` | `1` | :white_check_mark: | `2.0.8-beta.67`, `latest` | `2.0.8-beta.67` |
| `v2.0.8-beta.67` | `v(\d.\d)` | `1` | :white_check_mark: | `2.0`, `latest` | `2.0` |
| `release1` | `\d{1,3}.\d{1,3}` | `0` | :x: | `release1` | `release1` |
| `20200110-RC2` | `\d+` | `0` | :white_check_mark: | `20200110`, `latest` | `20200110` |
### Schedule tag

View File

@@ -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_89a016e8-e5b7-4039-a67e-c8da08f87a0c
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_89a016e8-e5b7-4039-a67e-c8da08f87a0c
GITHUB_REF="refs/heads/my/feature#1245"
GITHUB_REPOSITORY=crazy-max/test-docker-action
GITHUB_REPOSITORY_OWNER=crazy-max
GITHUB_RETENTION_DAYS=90
GITHUB_RUN_ID=325957516
GITHUB_RUN_NUMBER=1
GITHUB_SERVER_URL=https://github.com
GITHUB_SHA=90dd6032fac8bda1b6c4436a2e65de27961ed071
GITHUB_WORKFLOW=event
GITHUB_WORKSPACE=/home/runner/work/test-docker-action/test-docker-action

View File

@@ -44,7 +44,7 @@ const tagsLabelsTest = async (envFile: string, inputs: Inputs, exVersion: Versio
const repo = await github.repo(process.env.GITHUB_TOKEN || '');
const meta = new Meta({...getInputs(), ...inputs}, context, repo);
const version = meta.version();
const version = meta.version;
console.log('version', version);
expect(version).toEqual(exVersion);
@@ -376,6 +376,35 @@ describe('push', () => {
"org.opencontainers.image.licenses=MIT"
]
],
[
'event_push_invalidchars.env',
{
images: ['org/app', 'ghcr.io/user/app'],
tagSha: true,
tagEdge: true,
} as Inputs,
{
main: 'my-feature-1245',
partial: [],
latest: false
} as Version,
[
'org/app:my-feature-1245',
'org/app:sha-90dd603',
'ghcr.io/user/app:my-feature-1245',
'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",
"org.opencontainers.image.version=my-feature-1245",
"org.opencontainers.image.created=2020-01-10T00:30:00.000Z",
"org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071",
"org.opencontainers.image.licenses=MIT"
]
],
])('given %p event ', tagsLabelsTest);
});
@@ -437,7 +466,7 @@ describe('push tag', () => {
{
images: ['user/app'],
tagMatch: `\\d{8}`,
tagMatchLatest: false,
tagLatest: false,
} as Inputs,
{
main: '20200110',
@@ -464,7 +493,7 @@ describe('push tag', () => {
images: ['user/app'],
tagMatch: `(.*)-RC`,
tagMatchGroup: 1,
tagMatchLatest: false,
tagLatest: false,
} as Inputs,
{
main: '20200110',
@@ -715,7 +744,7 @@ describe('push tag', () => {
'event_tag_v2.0.8-beta.67.env',
{
images: ['org/app', 'ghcr.io/user/app'],
tagSemver: ['{{version}}', '{{major}}.{{minor}}', '{{major}}'],
tagSemver: ['{{major}}.{{minor}}', '{{major}}'],
} as Inputs,
{
main: '2.0.8-beta.67',
@@ -737,6 +766,32 @@ describe('push tag', () => {
"org.opencontainers.image.licenses=MIT"
]
],
[
'event_tag_sometag.env',
{
images: ['ghcr.io/user/app'],
tagSemver: ['{{version}}', '{{major}}.{{minor}}', '{{major}}'],
tagLatest: false,
} as Inputs,
{
main: 'sometag',
partial: [],
latest: false
} as Version,
[
'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",
"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);
});
@@ -906,7 +961,7 @@ describe('latest', () => {
'event_tag_v1.1.1.env',
{
images: ['org/app', 'ghcr.io/user/app'],
tagMatchLatest: false,
tagLatest: false,
} as Inputs,
{
main: 'v1.1.1',
@@ -932,7 +987,7 @@ describe('latest', () => {
'event_tag_v1.1.1.env',
{
images: ['org/app', 'ghcr.io/MyUSER/MyApp'],
tagMatchLatest: false,
tagLatest: false,
} as Inputs,
{
main: 'v1.1.1',
@@ -1203,3 +1258,193 @@ describe('release', () => {
],
])('given %p event ', tagsLabelsTest);
});
describe('custom', () => {
// prettier-ignore
test.each([
[
'event_push.env',
{
images: ['user/app'],
tagCustom: ['my', 'custom', 'tags']
} as Inputs,
{
main: 'dev',
partial: ['my', 'custom', 'tags'],
latest: false
} as Version,
[
'user/app:dev',
'user/app:my',
'user/app:custom',
'user/app:tags'
],
[
"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",
"org.opencontainers.image.version=dev",
"org.opencontainers.image.created=2020-01-10T00:30:00.000Z",
"org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071",
"org.opencontainers.image.licenses=MIT"
]
],
[
'event_push.env',
{
images: ['user/app'],
tagCustom: ['my']
} as Inputs,
{
main: 'dev',
partial: ['my'],
latest: false
} as Version,
[
'user/app:dev',
'user/app:my'
],
[
"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",
"org.opencontainers.image.version=dev",
"org.opencontainers.image.created=2020-01-10T00:30:00.000Z",
"org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071",
"org.opencontainers.image.licenses=MIT"
]
],
[
'event_tag_release1.env',
{
images: ['user/app'],
tagCustom: ['my', 'custom', 'tags']
} as Inputs,
{
main: 'release1',
partial: ['my', 'custom', 'tags'],
latest: true
} as Version,
[
'user/app:release1',
'user/app:my',
'user/app:custom',
'user/app:tags',
'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",
"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'],
tagMatch: `\\d{8}`,
tagLatest: false,
tagCustom: ['my', 'custom', 'tags']
} as Inputs,
{
main: '20200110',
partial: ['my', 'custom', 'tags'],
latest: false
} as Version,
[
'user/app:20200110',
'user/app:my',
'user/app:custom',
'user/app:tags'
],
[
"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",
"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: ['org/app', 'ghcr.io/user/app'],
tagSemver: ['{{version}}', '{{major}}.{{minor}}', '{{major}}'],
tagCustom: ['my', 'custom', 'tags']
} as Inputs,
{
main: '1.1.1',
partial: ['1.1', '1', 'my', 'custom', 'tags'],
latest: true
} as Version,
[
'org/app:1.1.1',
'org/app:1.1',
'org/app:1',
'org/app:my',
'org/app:custom',
'org/app:tags',
'org/app:latest',
'ghcr.io/user/app:1.1.1',
'ghcr.io/user/app:1.1',
'ghcr.io/user/app:1',
'ghcr.io/user/app:my',
'ghcr.io/user/app:custom',
'ghcr.io/user/app:tags',
'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",
"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'],
tagSemver: ['{{version}}', '{{major}}.{{minor}}.{{patch}}'],
tagCustom: ['my', 'custom', 'tags'],
tagCustomOnly: true,
} as Inputs,
{
main: 'my',
partial: ['custom', 'tags'],
latest: false
} as Version,
[
'org/app:my',
'org/app:custom',
'org/app:tags',
'ghcr.io/user/app:my',
'ghcr.io/user/app:custom',
'ghcr.io/user/app:tags'
],
[
"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",
"org.opencontainers.image.version=my",
"org.opencontainers.image.created=2020-01-10T00:30:00.000Z",
"org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071",
"org.opencontainers.image.licenses=MIT"
]
],
])('given %p event ', tagsLabelsTest);
});

View File

@@ -31,14 +31,25 @@ inputs:
description: 'Group to get if tag-match matches (default 0)'
default: '0'
required: false
tag-latest:
description: 'Set latest Docker tag if tag-semver, tag-match or Git tag event occurs'
default: 'true'
required: false
tag-match-latest:
description: 'Set latest Docker tag if tag-match matches or on Git tag event'
deprecationMessage: 'tag-match-latest is deprecated. Use tag-latest instead'
description: '(DEPRECATED) Set latest Docker tag if tag-match matches or on Git tag event'
default: 'true'
required: false
tag-schedule:
description: 'Template to apply to schedule tag'
default: 'nightly'
required: false
tag-custom:
description: 'List of custom tags'
required: false
tag-custom-only:
description: 'Only use tag-custom as Docker tags'
required: false
sep-tags:
description: 'Separator to use for tags output (default \n)'
required: false

977
dist/index.js generated vendored
View File

@@ -28,8 +28,10 @@ function getInputs() {
tagSemver: getInputList('tag-semver'),
tagMatch: core.getInput('tag-match'),
tagMatchGroup: Number(core.getInput('tag-match-group')) || 0,
tagMatchLatest: /true/i.test(core.getInput('tag-match-latest') || 'true'),
tagLatest: /true/i.test(core.getInput('tag-latest') || core.getInput('tag-match-latest') || 'true'),
tagSchedule: core.getInput('tag-schedule') || 'nightly',
tagCustom: getInputList('tag-custom'),
tagCustomOnly: /true/i.test(core.getInput('tag-custom-only') || 'false'),
sepTags: core.getInput('sep-tags') || `\n`,
sepLabels: core.getInput('sep-labels') || `\n`,
githubToken: core.getInput('github-token')
@@ -131,7 +133,7 @@ function run() {
core.info(`runId: ${context.runId}`);
core.endGroup();
const meta = new meta_1.Meta(inputs, context, repo);
const version = meta.version();
const version = meta.version;
core.startGroup(`Docker image version`);
core.info(version.main || '');
core.endGroup();
@@ -149,7 +151,7 @@ function run() {
core.info(label);
}
core.endGroup();
core.setOutput('labels', labels.join(inputs.sepTags));
core.setOutput('labels', labels.join(inputs.sepLabels));
}
catch (error) {
core.setFailed(error.message);
@@ -171,6 +173,7 @@ 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;
@@ -180,10 +183,11 @@ class Meta {
this.context = context;
this.repo = repo;
this.date = new Date();
this.version = this.getVersion();
}
version() {
getVersion() {
const currentDate = this.date;
const version = {
let version = {
main: undefined,
partial: [],
latest: false
@@ -197,13 +201,19 @@ class Meta {
}
else if (/^refs\/tags\//.test(this.context.ref)) {
version.main = this.context.ref.replace(/^refs\/tags\//g, '').replace(/\//g, '-');
if (this.inputs.tagSemver.length > 0 && !semver.valid(version.main)) {
core.warning(`${version.main} is not a valid semver. More info: https://semver.org/`);
}
if (this.inputs.tagSemver.length > 0 && semver.valid(version.main)) {
const sver = semver.parse(version.main, {
includePrerelease: true
});
version.latest = !semver.prerelease(version.main);
version.main = handlebars.compile(this.inputs.tagSemver[0])(sver);
if (version.latest) {
if (semver.prerelease(version.main)) {
version.main = handlebars.compile('{{version}}')(sver);
}
else {
version.latest = this.inputs.tagLatest;
version.main = handlebars.compile(this.inputs.tagSemver[0])(sver);
for (const semverTpl of this.inputs.tagSemver) {
const partial = handlebars.compile(semverTpl)(sver);
if (partial == version.main) {
@@ -224,15 +234,15 @@ class Meta {
}
if (tagMatch) {
version.main = tagMatch[this.inputs.tagMatchGroup];
version.latest = this.inputs.tagMatchLatest;
version.latest = this.inputs.tagLatest;
}
}
else {
version.latest = this.inputs.tagMatchLatest;
version.latest = this.inputs.tagLatest;
}
}
else if (/^refs\/heads\//.test(this.context.ref)) {
version.main = this.context.ref.replace(/^refs\/heads\//g, '').replace(/\//g, '-');
version.main = this.context.ref.replace(/^refs\/heads\//g, '').replace(/[^a-zA-Z0-9._-]+/g, '-');
if (this.inputs.tagEdge && this.inputs.tagEdgeBranch === version.main) {
version.main = 'edge';
}
@@ -240,22 +250,33 @@ class Meta {
else if (/^refs\/pull\//.test(this.context.ref)) {
version.main = `pr-${this.context.ref.replace(/^refs\/pull\//g, '').replace(/\/merge$/g, '')}`;
}
if (this.inputs.tagCustom.length > 0) {
if (this.inputs.tagCustomOnly) {
version = {
main: this.inputs.tagCustom.shift(),
partial: this.inputs.tagCustom,
latest: false
};
}
else {
version.partial.push(...this.inputs.tagCustom);
}
}
version.partial = version.partial.filter((item, index) => version.partial.indexOf(item) === index);
return version;
}
tags() {
const version = this.version();
if (!version.main) {
if (!this.version.main) {
return [];
}
let tags = [];
for (const image of this.inputs.images) {
const imageLc = image.toLowerCase();
tags.push(`${imageLc}:${version.main}`);
for (const partial of version.partial) {
tags.push(`${imageLc}:${this.version.main}`);
for (const partial of this.version.partial) {
tags.push(`${imageLc}:${partial}`);
}
if (version.latest) {
if (this.version.latest) {
tags.push(`${imageLc}:latest`);
}
if (this.context.sha && this.inputs.tagSha) {
@@ -271,7 +292,7 @@ class Meta {
`org.opencontainers.image.description=${this.repo.description || ''}`,
`org.opencontainers.image.url=${this.repo.html_url || ''}`,
`org.opencontainers.image.source=${this.repo.html_url || ''}`,
`org.opencontainers.image.version=${this.version().main || ''}`,
`org.opencontainers.image.version=${this.version.main || ''}`,
`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) || ''}`
@@ -9197,6 +9218,348 @@ if ( true && require.extensions) {
}
/***/ }),
/***/ 7129:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
// A linked list to keep track of recently-used-ness
const Yallist = __webpack_require__(665)
const MAX = Symbol('max')
const LENGTH = Symbol('length')
const LENGTH_CALCULATOR = Symbol('lengthCalculator')
const ALLOW_STALE = Symbol('allowStale')
const MAX_AGE = Symbol('maxAge')
const DISPOSE = Symbol('dispose')
const NO_DISPOSE_ON_SET = Symbol('noDisposeOnSet')
const LRU_LIST = Symbol('lruList')
const CACHE = Symbol('cache')
const UPDATE_AGE_ON_GET = Symbol('updateAgeOnGet')
const naiveLength = () => 1
// lruList is a yallist where the head is the youngest
// item, and the tail is the oldest. the list contains the Hit
// objects as the entries.
// Each Hit object has a reference to its Yallist.Node. This
// never changes.
//
// cache is a Map (or PseudoMap) that matches the keys to
// the Yallist.Node object.
class LRUCache {
constructor (options) {
if (typeof options === 'number')
options = { max: options }
if (!options)
options = {}
if (options.max && (typeof options.max !== 'number' || options.max < 0))
throw new TypeError('max must be a non-negative number')
// Kind of weird to have a default max of Infinity, but oh well.
const max = this[MAX] = options.max || Infinity
const lc = options.length || naiveLength
this[LENGTH_CALCULATOR] = (typeof lc !== 'function') ? naiveLength : lc
this[ALLOW_STALE] = options.stale || false
if (options.maxAge && typeof options.maxAge !== 'number')
throw new TypeError('maxAge must be a number')
this[MAX_AGE] = options.maxAge || 0
this[DISPOSE] = options.dispose
this[NO_DISPOSE_ON_SET] = options.noDisposeOnSet || false
this[UPDATE_AGE_ON_GET] = options.updateAgeOnGet || false
this.reset()
}
// resize the cache when the max changes.
set max (mL) {
if (typeof mL !== 'number' || mL < 0)
throw new TypeError('max must be a non-negative number')
this[MAX] = mL || Infinity
trim(this)
}
get max () {
return this[MAX]
}
set allowStale (allowStale) {
this[ALLOW_STALE] = !!allowStale
}
get allowStale () {
return this[ALLOW_STALE]
}
set maxAge (mA) {
if (typeof mA !== 'number')
throw new TypeError('maxAge must be a non-negative number')
this[MAX_AGE] = mA
trim(this)
}
get maxAge () {
return this[MAX_AGE]
}
// resize the cache when the lengthCalculator changes.
set lengthCalculator (lC) {
if (typeof lC !== 'function')
lC = naiveLength
if (lC !== this[LENGTH_CALCULATOR]) {
this[LENGTH_CALCULATOR] = lC
this[LENGTH] = 0
this[LRU_LIST].forEach(hit => {
hit.length = this[LENGTH_CALCULATOR](hit.value, hit.key)
this[LENGTH] += hit.length
})
}
trim(this)
}
get lengthCalculator () { return this[LENGTH_CALCULATOR] }
get length () { return this[LENGTH] }
get itemCount () { return this[LRU_LIST].length }
rforEach (fn, thisp) {
thisp = thisp || this
for (let walker = this[LRU_LIST].tail; walker !== null;) {
const prev = walker.prev
forEachStep(this, fn, walker, thisp)
walker = prev
}
}
forEach (fn, thisp) {
thisp = thisp || this
for (let walker = this[LRU_LIST].head; walker !== null;) {
const next = walker.next
forEachStep(this, fn, walker, thisp)
walker = next
}
}
keys () {
return this[LRU_LIST].toArray().map(k => k.key)
}
values () {
return this[LRU_LIST].toArray().map(k => k.value)
}
reset () {
if (this[DISPOSE] &&
this[LRU_LIST] &&
this[LRU_LIST].length) {
this[LRU_LIST].forEach(hit => this[DISPOSE](hit.key, hit.value))
}
this[CACHE] = new Map() // hash of items by key
this[LRU_LIST] = new Yallist() // list of items in order of use recency
this[LENGTH] = 0 // length of items in the list
}
dump () {
return this[LRU_LIST].map(hit =>
isStale(this, hit) ? false : {
k: hit.key,
v: hit.value,
e: hit.now + (hit.maxAge || 0)
}).toArray().filter(h => h)
}
dumpLru () {
return this[LRU_LIST]
}
set (key, value, maxAge) {
maxAge = maxAge || this[MAX_AGE]
if (maxAge && typeof maxAge !== 'number')
throw new TypeError('maxAge must be a number')
const now = maxAge ? Date.now() : 0
const len = this[LENGTH_CALCULATOR](value, key)
if (this[CACHE].has(key)) {
if (len > this[MAX]) {
del(this, this[CACHE].get(key))
return false
}
const node = this[CACHE].get(key)
const item = node.value
// dispose of the old one before overwriting
// split out into 2 ifs for better coverage tracking
if (this[DISPOSE]) {
if (!this[NO_DISPOSE_ON_SET])
this[DISPOSE](key, item.value)
}
item.now = now
item.maxAge = maxAge
item.value = value
this[LENGTH] += len - item.length
item.length = len
this.get(key)
trim(this)
return true
}
const hit = new Entry(key, value, len, now, maxAge)
// oversized objects fall out of cache automatically.
if (hit.length > this[MAX]) {
if (this[DISPOSE])
this[DISPOSE](key, value)
return false
}
this[LENGTH] += hit.length
this[LRU_LIST].unshift(hit)
this[CACHE].set(key, this[LRU_LIST].head)
trim(this)
return true
}
has (key) {
if (!this[CACHE].has(key)) return false
const hit = this[CACHE].get(key).value
return !isStale(this, hit)
}
get (key) {
return get(this, key, true)
}
peek (key) {
return get(this, key, false)
}
pop () {
const node = this[LRU_LIST].tail
if (!node)
return null
del(this, node)
return node.value
}
del (key) {
del(this, this[CACHE].get(key))
}
load (arr) {
// reset the cache
this.reset()
const now = Date.now()
// A previous serialized cache has the most recent items first
for (let l = arr.length - 1; l >= 0; l--) {
const hit = arr[l]
const expiresAt = hit.e || 0
if (expiresAt === 0)
// the item was created without expiration in a non aged cache
this.set(hit.k, hit.v)
else {
const maxAge = expiresAt - now
// dont add already expired items
if (maxAge > 0) {
this.set(hit.k, hit.v, maxAge)
}
}
}
}
prune () {
this[CACHE].forEach((value, key) => get(this, key, false))
}
}
const get = (self, key, doUse) => {
const node = self[CACHE].get(key)
if (node) {
const hit = node.value
if (isStale(self, hit)) {
del(self, node)
if (!self[ALLOW_STALE])
return undefined
} else {
if (doUse) {
if (self[UPDATE_AGE_ON_GET])
node.value.now = Date.now()
self[LRU_LIST].unshiftNode(node)
}
}
return hit.value
}
}
const isStale = (self, hit) => {
if (!hit || (!hit.maxAge && !self[MAX_AGE]))
return false
const diff = Date.now() - hit.now
return hit.maxAge ? diff > hit.maxAge
: self[MAX_AGE] && (diff > self[MAX_AGE])
}
const trim = self => {
if (self[LENGTH] > self[MAX]) {
for (let walker = self[LRU_LIST].tail;
self[LENGTH] > self[MAX] && walker !== null;) {
// We know that we're about to delete this one, and also
// what the next least recently used key will be, so just
// go ahead and set it now.
const prev = walker.prev
del(self, walker)
walker = prev
}
}
}
const del = (self, node) => {
if (node) {
const hit = node.value
if (self[DISPOSE])
self[DISPOSE](hit.key, hit.value)
self[LENGTH] -= hit.length
self[CACHE].delete(hit.key)
self[LRU_LIST].removeNode(node)
}
}
class Entry {
constructor (key, value, length, now, maxAge) {
this.key = key
this.value = value
this.length = length
this.now = now
this.maxAge = maxAge || 0
}
}
const forEachStep = (self, fn, node, thisp) => {
let hit = node.value
if (isStale(self, hit)) {
del(self, node)
if (!self[ALLOW_STALE])
hit = undefined
}
if (hit)
fn.call(thisp, hit.value, hit.key, self)
}
module.exports = LRUCache
/***/ }),
/***/ 9623:
@@ -16592,12 +16955,7 @@ class Comparator {
return ANY
}
constructor (comp, options) {
if (!options || typeof options !== 'object') {
options = {
loose: !!options,
includePrerelease: false
}
}
options = parseOptions(options)
if (comp instanceof Comparator) {
if (comp.loose === !!options.loose) {
@@ -16719,6 +17077,7 @@ class Comparator {
module.exports = Comparator
const parseOptions = __webpack_require__(785)
const {re, t} = __webpack_require__(9523)
const cmp = __webpack_require__(5098)
const debug = __webpack_require__(427)
@@ -16734,12 +17093,7 @@ const Range = __webpack_require__(9828)
// hoisted class for cyclic dependency
class Range {
constructor (range, options) {
if (!options || typeof options !== 'object') {
options = {
loose: !!options,
includePrerelease: false
}
}
options = parseOptions(options)
if (range instanceof Range) {
if (
@@ -16779,6 +17133,24 @@ class Range {
throw new TypeError(`Invalid SemVer Range: ${range}`)
}
// if we have any that are not the null set, throw out null sets.
if (this.set.length > 1) {
// keep the first one, in case they're all null sets
const first = this.set[0]
this.set = this.set.filter(c => !isNullSet(c[0]))
if (this.set.length === 0)
this.set = [first]
else if (this.set.length > 1) {
// if we have any that are *, then the range is just *
for (const c of this.set) {
if (c.length === 1 && isAny(c[0])) {
this.set = [c]
break
}
}
}
}
this.format()
}
@@ -16797,8 +17169,17 @@ class Range {
}
parseRange (range) {
const loose = this.options.loose
range = range.trim()
// memoize range parsing for performance.
// this is a very hot path, and fully deterministic.
const memoOpts = Object.keys(this.options).join(',')
const memoKey = `parseRange:${memoOpts}:${range}`
const cached = cache.get(memoKey)
if (cached)
return cached
const loose = this.options.loose
// `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`
const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE]
range = range.replace(hr, hyphenReplace(this.options.includePrerelease))
@@ -16820,15 +17201,33 @@ class Range {
// ready to be split into comparators.
const compRe = loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR]
return range
const rangeList = range
.split(' ')
.map(comp => parseComparator(comp, this.options))
.join(' ')
.split(/\s+/)
// >=0.0.0 is equivalent to *
.map(comp => replaceGTE0(comp, this.options))
// in loose mode, throw out any that are not valid comparators
.filter(this.options.loose ? comp => !!comp.match(compRe) : () => true)
.map(comp => new Comparator(comp, this.options))
// if any comparators are the null set, then replace with JUST null set
// if more than one comparator, remove any * comparators
// also, don't include the same comparator more than once
const l = rangeList.length
const rangeMap = new Map()
for (const comp of rangeList) {
if (isNullSet(comp))
return [comp]
rangeMap.set(comp.value, comp)
}
if (rangeMap.size > 1 && rangeMap.has(''))
rangeMap.delete('')
const result = [...rangeMap.values()]
cache.set(memoKey, result)
return result
}
intersects (range, options) {
@@ -16877,6 +17276,10 @@ class Range {
}
module.exports = Range
const LRU = __webpack_require__(7129)
const cache = new LRU({ max: 1000 })
const parseOptions = __webpack_require__(785)
const Comparator = __webpack_require__(1532)
const debug = __webpack_require__(427)
const SemVer = __webpack_require__(8088)
@@ -16888,6 +17291,9 @@ const {
caretTrimReplace
} = __webpack_require__(9523)
const isNullSet = c => c.value === '<0.0.0-0'
const isAny = c => c.value === ''
// take a set of comparators and determine whether there
// exists a version which can satisfy it
const isSatisfiable = (comparators, options) => {
@@ -17205,15 +17611,12 @@ const debug = __webpack_require__(427)
const { MAX_LENGTH, MAX_SAFE_INTEGER } = __webpack_require__(2293)
const { re, t } = __webpack_require__(9523)
const parseOptions = __webpack_require__(785)
const { compareIdentifiers } = __webpack_require__(2463)
class SemVer {
constructor (version, options) {
if (!options || typeof options !== 'object') {
options = {
loose: !!options,
includePrerelease: false
}
}
options = parseOptions(options)
if (version instanceof SemVer) {
if (version.loose === !!options.loose &&
version.includePrerelease === !!options.includePrerelease) {
@@ -17796,13 +18199,9 @@ const {MAX_LENGTH} = __webpack_require__(2293)
const { re, t } = __webpack_require__(9523)
const SemVer = __webpack_require__(8088)
const parseOptions = __webpack_require__(785)
const parse = (version, options) => {
if (!options || typeof options !== 'object') {
options = {
loose: !!options,
includePrerelease: false
}
}
options = parseOptions(options)
if (version instanceof SemVer) {
return version
@@ -18039,6 +18438,24 @@ module.exports = {
}
/***/ }),
/***/ 785:
/***/ ((module) => {
// parse out just the options we care about so we always get a consistent
// obj with keys in a consistent order.
const opts = ['includePrerelease', 'loose', 'rtl']
const parseOptions = options =>
!options ? {}
: typeof options !== 'object' ? { loose: true }
: opts.filter(k => options[k]).reduce((options, k) => {
options[k] = true
return options
}, {})
module.exports = parseOptions
/***/ }),
/***/ 9523:
@@ -18353,6 +18770,7 @@ const minVersion = (range, loose) => {
for (let i = 0; i < range.set.length; ++i) {
const comparators = range.set[i]
let setMin = null
comparators.forEach((comparator) => {
// Clone to avoid manipulating the comparator's semver object.
const compver = new SemVer(comparator.semver.version)
@@ -18367,8 +18785,8 @@ const minVersion = (range, loose) => {
/* fallthrough */
case '':
case '>=':
if (!minver || gt(minver, compver)) {
minver = compver
if (!setMin || gt(compver, setMin)) {
setMin = compver
}
break
case '<':
@@ -18380,6 +18798,8 @@ const minVersion = (range, loose) => {
throw new Error(`Unexpected operation: ${comparator.operator}`)
}
})
if (setMin && (!minver || gt(minver, setMin)))
minver = setMin
}
if (minver && range.test(minver)) {
@@ -18430,7 +18850,7 @@ const outside = (version, range, hilo, options) => {
throw new TypeError('Must provide a hilo val of "<" or ">"')
}
// If it satisifes the range it is not outside
// If it satisfies the range it is not outside
if (satisfies(version, range, options)) {
return false
}
@@ -18557,15 +18977,18 @@ const compare = __webpack_require__(4309)
// - If EQ satisfies every C, return true
// - Else return false
// - If GT
// - If GT is lower than any > or >= comp in C, return false
// - If GT.semver is lower than any > or >= comp in C, return false
// - If GT is >=, and GT.semver does not satisfy every C, return false
// - If LT
// - If LT.semver is greater than that of any > comp in C, return false
// - If LT.semver is greater than any < or <= comp in C, return false
// - If LT is <=, and LT.semver does not satisfy every C, return false
// - If any C is a = range, and GT or LT are set, return false
// - Else return true
const subset = (sub, dom, options) => {
if (sub === dom)
return true
sub = new Range(sub, options)
dom = new Range(dom, options)
let sawNonNull = false
@@ -18588,6 +19011,9 @@ const subset = (sub, dom, options) => {
}
const simpleSubset = (sub, dom, options) => {
if (sub === dom)
return true
if (sub.length === 1 && sub[0].semver === ANY)
return dom.length === 1 && dom[0].semver === ANY
@@ -18626,6 +19052,7 @@ const simpleSubset = (sub, dom, options) => {
if (!satisfies(eq, String(c), options))
return false
}
return true
}
@@ -18637,7 +19064,7 @@ const simpleSubset = (sub, dom, options) => {
if (gt) {
if (c.operator === '>' || c.operator === '>=') {
higher = higherGT(gt, c, options)
if (higher === c)
if (higher === c && higher !== gt)
return false
} else if (gt.operator === '>=' && !satisfies(gt.semver, String(c), options))
return false
@@ -18645,7 +19072,7 @@ const simpleSubset = (sub, dom, options) => {
if (lt) {
if (c.operator === '<' || c.operator === '<=') {
lower = lowerLT(lt, c, options)
if (lower === c)
if (lower === c && lower !== lt)
return false
} else if (lt.operator === '<=' && !satisfies(lt.semver, String(c), options))
return false
@@ -22259,6 +22686,456 @@ function wrappy (fn, cb) {
}
/***/ }),
/***/ 4091:
/***/ ((module) => {
"use strict";
module.exports = function (Yallist) {
Yallist.prototype[Symbol.iterator] = function* () {
for (let walker = this.head; walker; walker = walker.next) {
yield walker.value
}
}
}
/***/ }),
/***/ 665:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
module.exports = Yallist
Yallist.Node = Node
Yallist.create = Yallist
function Yallist (list) {
var self = this
if (!(self instanceof Yallist)) {
self = new Yallist()
}
self.tail = null
self.head = null
self.length = 0
if (list && typeof list.forEach === 'function') {
list.forEach(function (item) {
self.push(item)
})
} else if (arguments.length > 0) {
for (var i = 0, l = arguments.length; i < l; i++) {
self.push(arguments[i])
}
}
return self
}
Yallist.prototype.removeNode = function (node) {
if (node.list !== this) {
throw new Error('removing node which does not belong to this list')
}
var next = node.next
var prev = node.prev
if (next) {
next.prev = prev
}
if (prev) {
prev.next = next
}
if (node === this.head) {
this.head = next
}
if (node === this.tail) {
this.tail = prev
}
node.list.length--
node.next = null
node.prev = null
node.list = null
return next
}
Yallist.prototype.unshiftNode = function (node) {
if (node === this.head) {
return
}
if (node.list) {
node.list.removeNode(node)
}
var head = this.head
node.list = this
node.next = head
if (head) {
head.prev = node
}
this.head = node
if (!this.tail) {
this.tail = node
}
this.length++
}
Yallist.prototype.pushNode = function (node) {
if (node === this.tail) {
return
}
if (node.list) {
node.list.removeNode(node)
}
var tail = this.tail
node.list = this
node.prev = tail
if (tail) {
tail.next = node
}
this.tail = node
if (!this.head) {
this.head = node
}
this.length++
}
Yallist.prototype.push = function () {
for (var i = 0, l = arguments.length; i < l; i++) {
push(this, arguments[i])
}
return this.length
}
Yallist.prototype.unshift = function () {
for (var i = 0, l = arguments.length; i < l; i++) {
unshift(this, arguments[i])
}
return this.length
}
Yallist.prototype.pop = function () {
if (!this.tail) {
return undefined
}
var res = this.tail.value
this.tail = this.tail.prev
if (this.tail) {
this.tail.next = null
} else {
this.head = null
}
this.length--
return res
}
Yallist.prototype.shift = function () {
if (!this.head) {
return undefined
}
var res = this.head.value
this.head = this.head.next
if (this.head) {
this.head.prev = null
} else {
this.tail = null
}
this.length--
return res
}
Yallist.prototype.forEach = function (fn, thisp) {
thisp = thisp || this
for (var walker = this.head, i = 0; walker !== null; i++) {
fn.call(thisp, walker.value, i, this)
walker = walker.next
}
}
Yallist.prototype.forEachReverse = function (fn, thisp) {
thisp = thisp || this
for (var walker = this.tail, i = this.length - 1; walker !== null; i--) {
fn.call(thisp, walker.value, i, this)
walker = walker.prev
}
}
Yallist.prototype.get = function (n) {
for (var i = 0, walker = this.head; walker !== null && i < n; i++) {
// abort out of the list early if we hit a cycle
walker = walker.next
}
if (i === n && walker !== null) {
return walker.value
}
}
Yallist.prototype.getReverse = function (n) {
for (var i = 0, walker = this.tail; walker !== null && i < n; i++) {
// abort out of the list early if we hit a cycle
walker = walker.prev
}
if (i === n && walker !== null) {
return walker.value
}
}
Yallist.prototype.map = function (fn, thisp) {
thisp = thisp || this
var res = new Yallist()
for (var walker = this.head; walker !== null;) {
res.push(fn.call(thisp, walker.value, this))
walker = walker.next
}
return res
}
Yallist.prototype.mapReverse = function (fn, thisp) {
thisp = thisp || this
var res = new Yallist()
for (var walker = this.tail; walker !== null;) {
res.push(fn.call(thisp, walker.value, this))
walker = walker.prev
}
return res
}
Yallist.prototype.reduce = function (fn, initial) {
var acc
var walker = this.head
if (arguments.length > 1) {
acc = initial
} else if (this.head) {
walker = this.head.next
acc = this.head.value
} else {
throw new TypeError('Reduce of empty list with no initial value')
}
for (var i = 0; walker !== null; i++) {
acc = fn(acc, walker.value, i)
walker = walker.next
}
return acc
}
Yallist.prototype.reduceReverse = function (fn, initial) {
var acc
var walker = this.tail
if (arguments.length > 1) {
acc = initial
} else if (this.tail) {
walker = this.tail.prev
acc = this.tail.value
} else {
throw new TypeError('Reduce of empty list with no initial value')
}
for (var i = this.length - 1; walker !== null; i--) {
acc = fn(acc, walker.value, i)
walker = walker.prev
}
return acc
}
Yallist.prototype.toArray = function () {
var arr = new Array(this.length)
for (var i = 0, walker = this.head; walker !== null; i++) {
arr[i] = walker.value
walker = walker.next
}
return arr
}
Yallist.prototype.toArrayReverse = function () {
var arr = new Array(this.length)
for (var i = 0, walker = this.tail; walker !== null; i++) {
arr[i] = walker.value
walker = walker.prev
}
return arr
}
Yallist.prototype.slice = function (from, to) {
to = to || this.length
if (to < 0) {
to += this.length
}
from = from || 0
if (from < 0) {
from += this.length
}
var ret = new Yallist()
if (to < from || to < 0) {
return ret
}
if (from < 0) {
from = 0
}
if (to > this.length) {
to = this.length
}
for (var i = 0, walker = this.head; walker !== null && i < from; i++) {
walker = walker.next
}
for (; walker !== null && i < to; i++, walker = walker.next) {
ret.push(walker.value)
}
return ret
}
Yallist.prototype.sliceReverse = function (from, to) {
to = to || this.length
if (to < 0) {
to += this.length
}
from = from || 0
if (from < 0) {
from += this.length
}
var ret = new Yallist()
if (to < from || to < 0) {
return ret
}
if (from < 0) {
from = 0
}
if (to > this.length) {
to = this.length
}
for (var i = this.length, walker = this.tail; walker !== null && i > to; i--) {
walker = walker.prev
}
for (; walker !== null && i > from; i--, walker = walker.prev) {
ret.push(walker.value)
}
return ret
}
Yallist.prototype.splice = function (start, deleteCount, ...nodes) {
if (start > this.length) {
start = this.length - 1
}
if (start < 0) {
start = this.length + start;
}
for (var i = 0, walker = this.head; walker !== null && i < start; i++) {
walker = walker.next
}
var ret = []
for (var i = 0; walker && i < deleteCount; i++) {
ret.push(walker.value)
walker = this.removeNode(walker)
}
if (walker === null) {
walker = this.tail
}
if (walker !== this.head && walker !== this.tail) {
walker = walker.prev
}
for (var i = 0; i < nodes.length; i++) {
walker = insert(this, walker, nodes[i])
}
return ret;
}
Yallist.prototype.reverse = function () {
var head = this.head
var tail = this.tail
for (var walker = head; walker !== null; walker = walker.prev) {
var p = walker.prev
walker.prev = walker.next
walker.next = p
}
this.head = tail
this.tail = head
return this
}
function insert (self, node, value) {
var inserted = node === self.head ?
new Node(value, null, node, self) :
new Node(value, node, node.next, self)
if (inserted.next === null) {
self.tail = inserted
}
if (inserted.prev === null) {
self.head = inserted
}
self.length++
return inserted
}
function push (self, item) {
self.tail = new Node(item, self.tail, null, self)
if (!self.head) {
self.head = self.tail
}
self.length++
}
function unshift (self, item) {
self.head = new Node(item, null, self.head, self)
if (!self.tail) {
self.tail = self.head
}
self.length++
}
function Node (value, prev, next, list) {
if (!(this instanceof Node)) {
return new Node(value, prev, next, list)
}
this.list = list
this.value = value
if (prev) {
prev.next = this
this.prev = prev
} else {
this.prev = null
}
if (next) {
next.prev = this
this.next = next
} else {
this.next = null
}
}
try {
// add if support for Symbol.iterator is present
__webpack_require__(4091)(Yallist)
} catch (er) {}
/***/ }),
/***/ 2877:

View File

@@ -27,7 +27,7 @@
"@actions/github": "^4.0.0",
"handlebars": "^4.7.6",
"moment": "^2.29.1",
"semver": "^7.3.2"
"semver": "^7.3.4"
},
"devDependencies": {
"@types/jest": "^26.0.0",

View File

@@ -8,8 +8,10 @@ export interface Inputs {
tagSemver: string[];
tagMatch: string;
tagMatchGroup: number;
tagMatchLatest: boolean;
tagLatest: boolean;
tagSchedule: string;
tagCustom: string[];
tagCustomOnly: boolean;
sepTags: string;
sepLabels: string;
githubToken: string;
@@ -24,8 +26,10 @@ export function getInputs(): Inputs {
tagSemver: getInputList('tag-semver'),
tagMatch: core.getInput('tag-match'),
tagMatchGroup: Number(core.getInput('tag-match-group')) || 0,
tagMatchLatest: /true/i.test(core.getInput('tag-match-latest') || 'true'),
tagLatest: /true/i.test(core.getInput('tag-latest') || core.getInput('tag-match-latest') || 'true'),
tagSchedule: core.getInput('tag-schedule') || 'nightly',
tagCustom: getInputList('tag-custom'),
tagCustomOnly: /true/i.test(core.getInput('tag-custom-only') || 'false'),
sepTags: core.getInput('sep-tags') || `\n`,
sepLabels: core.getInput('sep-labels') || `\n`,
githubToken: core.getInput('github-token')

View File

@@ -27,7 +27,7 @@ async function run() {
const meta: Meta = new Meta(inputs, context, repo);
const version: Version = meta.version();
const version: Version = meta.version;
core.startGroup(`Docker image version`);
core.info(version.main || '');
core.endGroup();
@@ -47,7 +47,7 @@ async function run() {
core.info(label);
}
core.endGroup();
core.setOutput('labels', labels.join(inputs.sepTags));
core.setOutput('labels', labels.join(inputs.sepLabels));
} catch (error) {
core.setFailed(error.message);
}

View File

@@ -2,6 +2,7 @@ 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';
@@ -12,6 +13,8 @@ export interface Version {
}
export class Meta {
public readonly version: Version;
private readonly inputs: Inputs;
private readonly context: Context;
private readonly repo: ReposGetResponseData;
@@ -25,11 +28,12 @@ export class Meta {
this.context = context;
this.repo = repo;
this.date = new Date();
this.version = this.getVersion();
}
public version(): Version {
private getVersion(): Version {
const currentDate = this.date;
const version: Version = {
let version: Version = {
main: undefined,
partial: [],
latest: false
@@ -43,13 +47,18 @@ export class Meta {
});
} else if (/^refs\/tags\//.test(this.context.ref)) {
version.main = this.context.ref.replace(/^refs\/tags\//g, '').replace(/\//g, '-');
if (this.inputs.tagSemver.length > 0 && !semver.valid(version.main)) {
core.warning(`${version.main} is not a valid semver. More info: https://semver.org/`);
}
if (this.inputs.tagSemver.length > 0 && semver.valid(version.main)) {
const sver = semver.parse(version.main, {
includePrerelease: true
});
version.latest = !semver.prerelease(version.main);
version.main = handlebars.compile(this.inputs.tagSemver[0])(sver);
if (version.latest) {
if (semver.prerelease(version.main)) {
version.main = handlebars.compile('{{version}}')(sver);
} else {
version.latest = this.inputs.tagLatest;
version.main = handlebars.compile(this.inputs.tagSemver[0])(sver);
for (const semverTpl of this.inputs.tagSemver) {
const partial = handlebars.compile(semverTpl)(sver);
if (partial == version.main) {
@@ -68,13 +77,13 @@ export class Meta {
}
if (tagMatch) {
version.main = tagMatch[this.inputs.tagMatchGroup];
version.latest = this.inputs.tagMatchLatest;
version.latest = this.inputs.tagLatest;
}
} else {
version.latest = this.inputs.tagMatchLatest;
version.latest = this.inputs.tagLatest;
}
} else if (/^refs\/heads\//.test(this.context.ref)) {
version.main = this.context.ref.replace(/^refs\/heads\//g, '').replace(/\//g, '-');
version.main = this.context.ref.replace(/^refs\/heads\//g, '').replace(/[^a-zA-Z0-9._-]+/g, '-');
if (this.inputs.tagEdge && this.inputs.tagEdgeBranch === version.main) {
version.main = 'edge';
}
@@ -82,24 +91,35 @@ export class Meta {
version.main = `pr-${this.context.ref.replace(/^refs\/pull\//g, '').replace(/\/merge$/g, '')}`;
}
if (this.inputs.tagCustom.length > 0) {
if (this.inputs.tagCustomOnly) {
version = {
main: this.inputs.tagCustom.shift(),
partial: this.inputs.tagCustom,
latest: false
};
} else {
version.partial.push(...this.inputs.tagCustom);
}
}
version.partial = version.partial.filter((item, index) => version.partial.indexOf(item) === index);
return version;
}
public tags(): Array<string> {
const version: Version = this.version();
if (!version.main) {
if (!this.version.main) {
return [];
}
let tags: Array<string> = [];
for (const image of this.inputs.images) {
const imageLc = image.toLowerCase();
tags.push(`${imageLc}:${version.main}`);
for (const partial of version.partial) {
tags.push(`${imageLc}:${this.version.main}`);
for (const partial of this.version.partial) {
tags.push(`${imageLc}:${partial}`);
}
if (version.latest) {
if (this.version.latest) {
tags.push(`${imageLc}:latest`);
}
if (this.context.sha && this.inputs.tagSha) {
@@ -115,7 +135,7 @@ export class Meta {
`org.opencontainers.image.description=${this.repo.description || ''}`,
`org.opencontainers.image.url=${this.repo.html_url || ''}`,
`org.opencontainers.image.source=${this.repo.html_url || ''}`,
`org.opencontainers.image.version=${this.version().main || ''}`,
`org.opencontainers.image.version=${this.version.main || ''}`,
`org.opencontainers.image.created=${this.date.toISOString()}`,
`org.opencontainers.image.revision=${this.context.sha || ''}`,
`org.opencontainers.image.licenses=${this.repo.license?.spdx_id || ''}`

View File

@@ -2545,6 +2545,13 @@ lodash@^4.17.19:
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"
make-dir@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
@@ -3163,10 +3170,12 @@ saxes@^5.0.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
semver@7.x, semver@^7.3.2:
version "7.3.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
semver@7.x, semver@^7.3.2, semver@^7.3.4:
version "7.3.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97"
integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==
dependencies:
lru-cache "^6.0.0"
semver@^6.0.0, semver@^6.3.0:
version "6.3.0"
@@ -3808,6 +3817,11 @@ y18n@^4.0.0:
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yargs-parser@20.x:
version "20.2.3"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.3.tgz#92419ba867b858c868acf8bae9bf74af0dd0ce26"