mirror of
https://github.com/docker/metadata-action.git
synced 2024-12-22 09:05:32 +00:00
Merge pull request #107 from crazy-max/onlatest
Allow global prefix/suffix on latest
This commit is contained in:
commit
8a0bc9fddd
|
@ -296,8 +296,8 @@ flavor: |
|
||||||
```
|
```
|
||||||
|
|
||||||
* `latest=<auto|true|false>`: Handle [latest tag](#latest-tag) (default `auto`)
|
* `latest=<auto|true|false>`: Handle [latest tag](#latest-tag) (default `auto`)
|
||||||
* `prefix=<string>`: A global prefix for each generated tag
|
* `prefix=<string>,onlatest=<true|false>`: A global prefix for each generated tag and optionnally for `latest`
|
||||||
* `suffix=<string>`: A global suffix for each generated tag
|
* `suffix=<string>,onlatest=<true|false>`: A global suffix for each generated tag and optionnally for `latest`
|
||||||
|
|
||||||
## `tags` input
|
## `tags` input
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,9 @@ describe('transform', () => {
|
||||||
{
|
{
|
||||||
latest: "true",
|
latest: "true",
|
||||||
prefix: "",
|
prefix: "",
|
||||||
suffix: ""
|
prefixLatest: false,
|
||||||
|
suffix: "",
|
||||||
|
suffixLatest: false,
|
||||||
} as Flavor,
|
} as Flavor,
|
||||||
false
|
false
|
||||||
],
|
],
|
||||||
|
@ -43,7 +45,9 @@ describe('transform', () => {
|
||||||
{
|
{
|
||||||
latest: "false",
|
latest: "false",
|
||||||
prefix: "",
|
prefix: "",
|
||||||
suffix: ""
|
prefixLatest: false,
|
||||||
|
suffix: "",
|
||||||
|
suffixLatest: false,
|
||||||
} as Flavor,
|
} as Flavor,
|
||||||
false
|
false
|
||||||
],
|
],
|
||||||
|
@ -54,7 +58,9 @@ describe('transform', () => {
|
||||||
{
|
{
|
||||||
latest: "auto",
|
latest: "auto",
|
||||||
prefix: "",
|
prefix: "",
|
||||||
suffix: ""
|
prefixLatest: false,
|
||||||
|
suffix: "",
|
||||||
|
suffixLatest: false,
|
||||||
} as Flavor,
|
} as Flavor,
|
||||||
false
|
false
|
||||||
],
|
],
|
||||||
|
@ -72,7 +78,9 @@ describe('transform', () => {
|
||||||
{
|
{
|
||||||
latest: "auto",
|
latest: "auto",
|
||||||
prefix: "sha-",
|
prefix: "sha-",
|
||||||
suffix: ""
|
prefixLatest: false,
|
||||||
|
suffix: "",
|
||||||
|
suffixLatest: false,
|
||||||
} as Flavor,
|
} as Flavor,
|
||||||
false
|
false
|
||||||
],
|
],
|
||||||
|
@ -83,7 +91,9 @@ describe('transform', () => {
|
||||||
{
|
{
|
||||||
latest: "auto",
|
latest: "auto",
|
||||||
prefix: "",
|
prefix: "",
|
||||||
suffix: "-alpine"
|
prefixLatest: false,
|
||||||
|
suffix: "-alpine",
|
||||||
|
suffixLatest: false,
|
||||||
} as Flavor,
|
} as Flavor,
|
||||||
false
|
false
|
||||||
],
|
],
|
||||||
|
@ -96,7 +106,49 @@ describe('transform', () => {
|
||||||
{
|
{
|
||||||
latest: "false",
|
latest: "false",
|
||||||
prefix: "dev-",
|
prefix: "dev-",
|
||||||
suffix: "-alpine"
|
prefixLatest: false,
|
||||||
|
suffix: "-alpine",
|
||||||
|
suffixLatest: false,
|
||||||
|
} as Flavor,
|
||||||
|
false
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
`prefix=dev-,onlatest=true`,
|
||||||
|
],
|
||||||
|
{
|
||||||
|
latest: "auto",
|
||||||
|
prefix: "dev-",
|
||||||
|
prefixLatest: true,
|
||||||
|
suffix: "",
|
||||||
|
suffixLatest: false,
|
||||||
|
} as Flavor,
|
||||||
|
false
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
`suffix=-alpine,onlatest=true`,
|
||||||
|
],
|
||||||
|
{
|
||||||
|
latest: "auto",
|
||||||
|
prefix: "",
|
||||||
|
prefixLatest: false,
|
||||||
|
suffix: "-alpine",
|
||||||
|
suffixLatest: true,
|
||||||
|
} as Flavor,
|
||||||
|
false
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
`prefix=dev-,onlatest=true`,
|
||||||
|
`suffix=-alpine,onlatest=true`,
|
||||||
|
],
|
||||||
|
{
|
||||||
|
latest: "auto",
|
||||||
|
prefix: "dev-",
|
||||||
|
prefixLatest: true,
|
||||||
|
suffix: "-alpine",
|
||||||
|
suffixLatest: true,
|
||||||
} as Flavor,
|
} as Flavor,
|
||||||
false
|
false
|
||||||
],
|
],
|
||||||
|
|
|
@ -1301,7 +1301,78 @@ describe('tag', () => {
|
||||||
"org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071",
|
"org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071",
|
||||||
"org.opencontainers.image.licenses=MIT"
|
"org.opencontainers.image.licenses=MIT"
|
||||||
]
|
]
|
||||||
]
|
],
|
||||||
|
[
|
||||||
|
'tag21',
|
||||||
|
'event_tag_v1.1.1.env',
|
||||||
|
{
|
||||||
|
images: ['org/app', 'ghcr.io/user/app'],
|
||||||
|
tags: [
|
||||||
|
`type=semver,pattern={{version}}`,
|
||||||
|
`type=semver,pattern={{major}}.{{minor}}.{{patch}}`
|
||||||
|
],
|
||||||
|
flavor: [
|
||||||
|
`suffix=-dev,onlatest=true`
|
||||||
|
]
|
||||||
|
} as Inputs,
|
||||||
|
{
|
||||||
|
main: '1.1.1-dev',
|
||||||
|
partial: [],
|
||||||
|
latest: true
|
||||||
|
} as Version,
|
||||||
|
[
|
||||||
|
'org/app:1.1.1-dev',
|
||||||
|
'org/app:latest-dev',
|
||||||
|
'ghcr.io/user/app:1.1.1-dev',
|
||||||
|
'ghcr.io/user/app:latest-dev'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"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-dev",
|
||||||
|
"org.opencontainers.image.created=2020-01-10T00:30:00.000Z",
|
||||||
|
"org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071",
|
||||||
|
"org.opencontainers.image.licenses=MIT"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'tag22',
|
||||||
|
'event_tag_v1.1.1.env',
|
||||||
|
{
|
||||||
|
images: ['org/app', 'ghcr.io/user/app'],
|
||||||
|
tags: [
|
||||||
|
`type=semver,pattern={{version}}`,
|
||||||
|
`type=semver,pattern={{major}}.{{minor}}.{{patch}}`
|
||||||
|
],
|
||||||
|
flavor: [
|
||||||
|
`prefix=foo-,onlatest=true`,
|
||||||
|
`suffix=-dev,onlatest=true`
|
||||||
|
]
|
||||||
|
} as Inputs,
|
||||||
|
{
|
||||||
|
main: 'foo-1.1.1-dev',
|
||||||
|
partial: [],
|
||||||
|
latest: true
|
||||||
|
} as Version,
|
||||||
|
[
|
||||||
|
'org/app:foo-1.1.1-dev',
|
||||||
|
'org/app:foo-latest-dev',
|
||||||
|
'ghcr.io/user/app:foo-1.1.1-dev',
|
||||||
|
'ghcr.io/user/app:foo-latest-dev'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"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=foo-1.1.1-dev",
|
||||||
|
"org.opencontainers.image.created=2020-01-10T00:30:00.000Z",
|
||||||
|
"org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071",
|
||||||
|
"org.opencontainers.image.licenses=MIT"
|
||||||
|
]
|
||||||
|
],
|
||||||
])('given %p with %p event', tagsLabelsTest);
|
])('given %p with %p event', tagsLabelsTest);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
82
dist/index.js
generated
vendored
82
dist/index.js
generated
vendored
|
@ -129,45 +129,78 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
__setModuleDefault(result, mod);
|
__setModuleDefault(result, mod);
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.Transform = void 0;
|
exports.Transform = void 0;
|
||||||
const core = __importStar(__webpack_require__(2186));
|
const core = __importStar(__webpack_require__(2186));
|
||||||
|
const sync_1 = __importDefault(__webpack_require__(8750));
|
||||||
function Transform(inputs) {
|
function Transform(inputs) {
|
||||||
const flavor = {
|
const flavor = {
|
||||||
latest: 'auto',
|
latest: 'auto',
|
||||||
prefix: '',
|
prefix: '',
|
||||||
suffix: ''
|
prefixLatest: false,
|
||||||
|
suffix: '',
|
||||||
|
suffixLatest: false
|
||||||
};
|
};
|
||||||
for (const input of inputs) {
|
for (const input of inputs) {
|
||||||
const parts = input.split('=', 2);
|
const fields = sync_1.default(input, {
|
||||||
if (parts.length == 1) {
|
relaxColumnCount: true,
|
||||||
throw new Error(`Invalid entry: ${input}`);
|
skipLinesWithEmptyValues: true
|
||||||
}
|
})[0];
|
||||||
switch (parts[0]) {
|
let onlatestfor = '';
|
||||||
case 'latest': {
|
for (const field of fields) {
|
||||||
flavor.latest = parts[1];
|
const parts = field.toString().split('=', 2);
|
||||||
if (!['auto', 'true', 'false'].includes(flavor.latest)) {
|
if (parts.length == 1) {
|
||||||
throw new Error(`Invalid latest flavor entry: ${input}`);
|
throw new Error(`Invalid flavor entry: ${input}`);
|
||||||
|
}
|
||||||
|
switch (parts[0]) {
|
||||||
|
case 'latest': {
|
||||||
|
flavor.latest = parts[1];
|
||||||
|
if (!['auto', 'true', 'false'].includes(flavor.latest)) {
|
||||||
|
throw new Error(`Invalid latest flavor entry: ${input}`);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'prefix': {
|
||||||
|
flavor.prefix = parts[1];
|
||||||
|
onlatestfor = 'prefix';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'suffix': {
|
||||||
|
flavor.suffix = parts[1];
|
||||||
|
onlatestfor = 'suffix';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'onlatest': {
|
||||||
|
if (!['true', 'false'].includes(parts[1])) {
|
||||||
|
throw new Error(`Invalid value for onlatest attribute: ${parts[1]}`);
|
||||||
|
}
|
||||||
|
switch (onlatestfor) {
|
||||||
|
case 'prefix': {
|
||||||
|
flavor.prefixLatest = /true/i.test(parts[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'suffix': {
|
||||||
|
flavor.suffixLatest = /true/i.test(parts[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw new Error(`Unknown flavor entry: ${input}`);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'prefix': {
|
|
||||||
flavor.prefix = parts[1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'suffix': {
|
|
||||||
flavor.suffix = parts[1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
throw new Error(`Unknown entry: ${input}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
core.startGroup(`Processing flavor input`);
|
core.startGroup(`Processing flavor input`);
|
||||||
core.info(`latest=${flavor.latest}`);
|
core.info(`latest=${flavor.latest}`);
|
||||||
core.info(`prefix=${flavor.prefix}`);
|
core.info(`prefix=${flavor.prefix}`);
|
||||||
|
core.info(`prefixLatest=${flavor.prefixLatest}`);
|
||||||
core.info(`suffix=${flavor.suffix}`);
|
core.info(`suffix=${flavor.suffix}`);
|
||||||
|
core.info(`suffixLatest=${flavor.suffixLatest}`);
|
||||||
core.endGroup();
|
core.endGroup();
|
||||||
return flavor;
|
return flavor;
|
||||||
}
|
}
|
||||||
|
@ -501,7 +534,6 @@ class Meta {
|
||||||
else {
|
else {
|
||||||
vraw = this.context.ref.replace(/^refs\/tags\//g, '').replace(/\//g, '-');
|
vraw = this.context.ref.replace(/^refs\/tags\//g, '').replace(/\//g, '-');
|
||||||
}
|
}
|
||||||
let latest = false;
|
|
||||||
let tmatch;
|
let tmatch;
|
||||||
const isRegEx = tag.attrs['pattern'].match(/^\/(.+)\/(.*)$/);
|
const isRegEx = tag.attrs['pattern'].match(/^\/(.+)\/(.*)$/);
|
||||||
if (isRegEx) {
|
if (isRegEx) {
|
||||||
|
@ -633,7 +665,7 @@ class Meta {
|
||||||
tags.push(`${imageLc}:${partial}`);
|
tags.push(`${imageLc}:${partial}`);
|
||||||
}
|
}
|
||||||
if (this.version.latest) {
|
if (this.version.latest) {
|
||||||
tags.push(`${imageLc}:latest`);
|
tags.push(`${imageLc}:${this.flavor.prefixLatest ? this.flavor.prefix : ''}latest${this.flavor.suffixLatest ? this.flavor.suffix : ''}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tags;
|
return tags;
|
||||||
|
@ -817,7 +849,7 @@ function Parse(s) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'type': {
|
case 'type': {
|
||||||
if (!Object.values(Type).includes(value)) {
|
if (!Object.values(Type).includes(value)) {
|
||||||
throw new Error(`Unknown type attribute: ${value}`);
|
throw new Error(`Unknown tag type attribute: ${value}`);
|
||||||
}
|
}
|
||||||
tag.type = value;
|
tag.type = value;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,41 +1,71 @@
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
|
import csvparse from 'csv-parse/lib/sync';
|
||||||
|
|
||||||
export interface Flavor {
|
export interface Flavor {
|
||||||
latest: string;
|
latest: string;
|
||||||
prefix: string;
|
prefix: string;
|
||||||
|
prefixLatest: boolean;
|
||||||
suffix: string;
|
suffix: string;
|
||||||
|
suffixLatest: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Transform(inputs: string[]): Flavor {
|
export function Transform(inputs: string[]): Flavor {
|
||||||
const flavor: Flavor = {
|
const flavor: Flavor = {
|
||||||
latest: 'auto',
|
latest: 'auto',
|
||||||
prefix: '',
|
prefix: '',
|
||||||
suffix: ''
|
prefixLatest: false,
|
||||||
|
suffix: '',
|
||||||
|
suffixLatest: false
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const input of inputs) {
|
for (const input of inputs) {
|
||||||
const parts = input.split('=', 2);
|
const fields = csvparse(input, {
|
||||||
if (parts.length == 1) {
|
relaxColumnCount: true,
|
||||||
throw new Error(`Invalid entry: ${input}`);
|
skipLinesWithEmptyValues: true
|
||||||
}
|
})[0];
|
||||||
switch (parts[0]) {
|
let onlatestfor = '';
|
||||||
case 'latest': {
|
for (const field of fields) {
|
||||||
flavor.latest = parts[1];
|
const parts = field.toString().split('=', 2);
|
||||||
if (!['auto', 'true', 'false'].includes(flavor.latest)) {
|
if (parts.length == 1) {
|
||||||
throw new Error(`Invalid latest flavor entry: ${input}`);
|
throw new Error(`Invalid flavor entry: ${input}`);
|
||||||
|
}
|
||||||
|
switch (parts[0]) {
|
||||||
|
case 'latest': {
|
||||||
|
flavor.latest = parts[1];
|
||||||
|
if (!['auto', 'true', 'false'].includes(flavor.latest)) {
|
||||||
|
throw new Error(`Invalid latest flavor entry: ${input}`);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'prefix': {
|
||||||
|
flavor.prefix = parts[1];
|
||||||
|
onlatestfor = 'prefix';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'suffix': {
|
||||||
|
flavor.suffix = parts[1];
|
||||||
|
onlatestfor = 'suffix';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'onlatest': {
|
||||||
|
if (!['true', 'false'].includes(parts[1])) {
|
||||||
|
throw new Error(`Invalid value for onlatest attribute: ${parts[1]}`);
|
||||||
|
}
|
||||||
|
switch (onlatestfor) {
|
||||||
|
case 'prefix': {
|
||||||
|
flavor.prefixLatest = /true/i.test(parts[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'suffix': {
|
||||||
|
flavor.suffixLatest = /true/i.test(parts[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw new Error(`Unknown flavor entry: ${input}`);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'prefix': {
|
|
||||||
flavor.prefix = parts[1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'suffix': {
|
|
||||||
flavor.suffix = parts[1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
throw new Error(`Unknown entry: ${input}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +73,9 @@ export function Transform(inputs: string[]): Flavor {
|
||||||
core.startGroup(`Processing flavor input`);
|
core.startGroup(`Processing flavor input`);
|
||||||
core.info(`latest=${flavor.latest}`);
|
core.info(`latest=${flavor.latest}`);
|
||||||
core.info(`prefix=${flavor.prefix}`);
|
core.info(`prefix=${flavor.prefix}`);
|
||||||
|
core.info(`prefixLatest=${flavor.prefixLatest}`);
|
||||||
core.info(`suffix=${flavor.suffix}`);
|
core.info(`suffix=${flavor.suffix}`);
|
||||||
|
core.info(`suffixLatest=${flavor.suffixLatest}`);
|
||||||
core.endGroup();
|
core.endGroup();
|
||||||
|
|
||||||
return flavor;
|
return flavor;
|
||||||
|
|
|
@ -159,7 +159,6 @@ export class Meta {
|
||||||
vraw = this.context.ref.replace(/^refs\/tags\//g, '').replace(/\//g, '-');
|
vraw = this.context.ref.replace(/^refs\/tags\//g, '').replace(/\//g, '-');
|
||||||
}
|
}
|
||||||
|
|
||||||
let latest: boolean = false;
|
|
||||||
let tmatch;
|
let tmatch;
|
||||||
const isRegEx = tag.attrs['pattern'].match(/^\/(.+)\/(.*)$/);
|
const isRegEx = tag.attrs['pattern'].match(/^\/(.+)\/(.*)$/);
|
||||||
if (isRegEx) {
|
if (isRegEx) {
|
||||||
|
@ -304,7 +303,7 @@ export class Meta {
|
||||||
tags.push(`${imageLc}:${partial}`);
|
tags.push(`${imageLc}:${partial}`);
|
||||||
}
|
}
|
||||||
if (this.version.latest) {
|
if (this.version.latest) {
|
||||||
tags.push(`${imageLc}:latest`);
|
tags.push(`${imageLc}:${this.flavor.prefixLatest ? this.flavor.prefix : ''}latest${this.flavor.suffixLatest ? this.flavor.suffix : ''}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tags;
|
return tags;
|
||||||
|
|
|
@ -100,7 +100,7 @@ export function Parse(s: string): Tag {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'type': {
|
case 'type': {
|
||||||
if (!Object.values(Type).includes(value)) {
|
if (!Object.values(Type).includes(value)) {
|
||||||
throw new Error(`Unknown type attribute: ${value}`);
|
throw new Error(`Unknown tag type attribute: ${value}`);
|
||||||
}
|
}
|
||||||
tag.type = value;
|
tag.type = value;
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue