Skip to content

Commit a5680a6

Browse files
committed
attribute to enable/disable images
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
1 parent be6d2cc commit a5680a6

8 files changed

Lines changed: 225 additions & 9 deletions

File tree

.github/workflows/ci.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,21 @@ jobs:
146146
prefix=foo-
147147
suffix=-bar
148148
149+
images:
150+
runs-on: ubuntu-latest
151+
steps:
152+
-
153+
name: Checkout
154+
uses: actions/checkout@v3
155+
-
156+
name: Docker meta
157+
uses: ./
158+
with:
159+
images: |
160+
name=${{ env.DOCKER_IMAGE }}
161+
name=ghcr.io/name/app,enable=${{ github.event_name == 'pull_request' }}
162+
name=ghcr.io/name/release,enable=${{ startsWith(github.ref, 'refs/tags/') }}
163+
149164
labels:
150165
runs-on: ubuntu-latest
151166
steps:

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ ___
1919
* [Customizing](#customizing)
2020
* [inputs](#inputs)
2121
* [outputs](#outputs)
22+
* [`images` input](#images-input)
2223
* [`flavor` input](#flavor-input)
2324
* [`tags` input](#tags-input)
2425
* [`type=schedule`](#typeschedule)
@@ -291,6 +292,29 @@ Following outputs are available
291292
| `json` | String | JSON output of tags and labels |
292293
| `bake-file` | File | [Bake definition file](https://github.com/docker/buildx#file-definition) path |
293294

295+
## `images` input
296+
297+
`images` defines a list of Docker images to use as base name for [`tags`](#tags-input):
298+
299+
```yaml
300+
images: |
301+
name/foo
302+
ghcr.io/name/bar
303+
# or
304+
name=name/foo
305+
name=ghcr.io/name/bar
306+
```
307+
308+
Extended attributes and default values:
309+
310+
```yaml
311+
images: |
312+
name=,enable=true
313+
```
314+
315+
* `name=<string>` image base name
316+
* `enable=<true|false>` enable this entry (default `true`)
317+
294318
## `flavor` input
295319

296320
`flavor` defines a global behavior for [`tags`](#tags-input):

__tests__/image.test.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import {describe, expect, test} from '@jest/globals';
2+
import {Transform, Image} from '../src/image';
3+
4+
describe('transform', () => {
5+
// prettier-ignore
6+
test.each([
7+
[
8+
[
9+
`name/foo`
10+
],
11+
[
12+
{
13+
name: `name/foo`,
14+
enable: true,
15+
}
16+
] as Image[],
17+
false
18+
],
19+
[
20+
[
21+
`name/foo`,
22+
`name/bar`
23+
],
24+
[
25+
{
26+
name: `name/foo`,
27+
enable: true,
28+
},
29+
{
30+
name: `name/bar`,
31+
enable: true,
32+
}
33+
] as Image[],
34+
false
35+
],
36+
[
37+
[
38+
`name=name/bar`,
39+
`name/foo,enable=false`,
40+
`name=ghcr.io/name/foo,enable=true`
41+
],
42+
[
43+
{
44+
name: `name/bar`,
45+
enable: true,
46+
},
47+
{
48+
name: `name/foo`,
49+
enable: false,
50+
},
51+
{
52+
name: `ghcr.io/name/foo`,
53+
enable: true,
54+
},
55+
] as Image[],
56+
false
57+
],
58+
[
59+
[`value=name/foo`], undefined, true
60+
],
61+
[
62+
[`name/foo,enable=bar`], undefined, true
63+
],
64+
[
65+
[`name/foo,bar=baz`], undefined, true
66+
],
67+
[
68+
[`name=,enable=true`], undefined, true
69+
]
70+
])('given %p', async (l: string[], expected: Image[], invalid: boolean) => {
71+
try {
72+
const images = Transform(l);
73+
expect(images).toEqual(expected);
74+
} catch (err) {
75+
if (!invalid) {
76+
console.error(err);
77+
}
78+
// eslint-disable-next-line jest/no-conditional-expect
79+
expect(true).toBe(invalid);
80+
}
81+
});
82+
});

__tests__/meta.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,39 @@ describe('push', () => {
693693
"org.opencontainers.image.revision=860c1904a1ce19322e91ac35af1ab07466440c37",
694694
"org.opencontainers.image.licenses=MIT"
695695
]
696+
],
697+
[
698+
'push20',
699+
'event_push_dev.env',
700+
{
701+
images: [
702+
'org/app',
703+
'ghcr.io/user/app,enable=false'
704+
],
705+
tags: [
706+
`type=edge,branch=master`,
707+
`type=ref,event=branch,enable=false`,
708+
`type=sha,format=long`
709+
],
710+
} as Inputs,
711+
{
712+
main: 'sha-860c1904a1ce19322e91ac35af1ab07466440c37',
713+
partial: [],
714+
latest: false
715+
} as Version,
716+
[
717+
'org/app:sha-860c1904a1ce19322e91ac35af1ab07466440c37'
718+
],
719+
[
720+
"org.opencontainers.image.title=Hello-World",
721+
"org.opencontainers.image.description=This your first repo!",
722+
"org.opencontainers.image.url=https://github.com/octocat/Hello-World",
723+
"org.opencontainers.image.source=https://github.com/octocat/Hello-World",
724+
"org.opencontainers.image.version=sha-860c1904a1ce19322e91ac35af1ab07466440c37",
725+
"org.opencontainers.image.created=2020-01-10T00:30:00.000Z",
726+
"org.opencontainers.image.revision=860c1904a1ce19322e91ac35af1ab07466440c37",
727+
"org.opencontainers.image.licenses=MIT"
728+
]
696729
]
697730
])('given %p with %p event', tagsLabelsTest);
698731
});

dist/index.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/image.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import {parse} from 'csv-parse/sync';
2+
3+
export interface Image {
4+
name: string;
5+
enable: boolean;
6+
}
7+
8+
export function Transform(inputs: string[]): Image[] {
9+
const images: Image[] = [];
10+
for (const input of inputs) {
11+
const image: Image = {name: '', enable: true};
12+
const fields = parse(input, {
13+
relaxColumnCount: true,
14+
skipEmptyLines: true
15+
})[0];
16+
for (const field of fields) {
17+
const parts = field
18+
.toString()
19+
.split('=')
20+
.map(item => item.trim());
21+
if (parts.length == 1) {
22+
image.name = parts[0].toLowerCase();
23+
} else {
24+
const key = parts[0].toLowerCase();
25+
const value = parts[1];
26+
switch (key) {
27+
case 'name': {
28+
image.name = value.toLowerCase();
29+
break;
30+
}
31+
case 'enable': {
32+
if (!['true', 'false'].includes(value)) {
33+
throw new Error(`Invalid enable attribute value: ${input}`);
34+
}
35+
image.enable = /true/i.test(value);
36+
break;
37+
}
38+
default: {
39+
throw new Error(`Unknown image attribute: ${input}`);
40+
}
41+
}
42+
}
43+
}
44+
if (image.name.length == 0) {
45+
throw new Error(`Image name attribute empty: ${input}`);
46+
}
47+
images.push(image);
48+
}
49+
return images;
50+
}

src/meta.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import * as pep440 from '@renovate/pep440';
66
import * as semver from 'semver';
77
import {Inputs, tmpDir} from './context';
88
import {ReposGetResponseData} from './github';
9+
import * as icl from './image';
910
import * as tcl from './tag';
1011
import * as fcl from './flavor';
1112
import * as core from '@actions/core';
@@ -23,6 +24,7 @@ export class Meta {
2324
private readonly inputs: Inputs;
2425
private readonly context: Context;
2526
private readonly repo: ReposGetResponseData;
27+
private readonly images: icl.Image[];
2628
private readonly tags: tcl.Tag[];
2729
private readonly flavor: fcl.Flavor;
2830
private readonly date: Date;
@@ -38,6 +40,7 @@ export class Meta {
3840
this.inputs = inputs;
3941
this.context = context;
4042
this.repo = repo;
43+
this.images = icl.Transform(inputs.images);
4144
this.tags = tcl.Transform(inputs.tags);
4245
this.flavor = fcl.Transform(inputs.flavor);
4346
this.date = new Date();
@@ -404,20 +407,29 @@ export class Meta {
404407
});
405408
}
406409

410+
private getImageNames(): Array<string> {
411+
const images: Array<string> = [];
412+
for (const image of this.images) {
413+
if (!image.enable) {
414+
continue;
415+
}
416+
images.push(image.name);
417+
}
418+
return images;
419+
}
420+
407421
public getTags(): Array<string> {
408422
if (!this.version.main) {
409423
return [];
410424
}
411-
412425
const tags: Array<string> = [];
413-
for (const image of this.inputs.images) {
414-
const imageLc = image.toLowerCase();
415-
tags.push(`${imageLc}:${this.version.main}`);
426+
for (const imageName of this.getImageNames()) {
427+
tags.push(`${imageName}:${this.version.main}`);
416428
for (const partial of this.version.partial) {
417-
tags.push(`${imageLc}:${partial}`);
429+
tags.push(`${imageName}:${partial}`);
418430
}
419431
if (this.version.latest) {
420-
tags.push(`${imageLc}:${this.flavor.prefixLatest ? this.flavor.prefix : ''}latest${this.flavor.suffixLatest ? this.flavor.suffix : ''}`);
432+
tags.push(`${imageName}:${this.flavor.prefixLatest ? this.flavor.prefix : ''}latest${this.flavor.suffixLatest ? this.flavor.suffix : ''}`);
421433
}
422434
}
423435
return tags;
@@ -470,7 +482,7 @@ export class Meta {
470482
return res;
471483
}, {}),
472484
args: {
473-
DOCKER_META_IMAGES: this.inputs.images.join(','),
485+
DOCKER_META_IMAGES: this.getImageNames().join(','),
474486
DOCKER_META_VERSION: this.version.main
475487
}
476488
}

0 commit comments

Comments
 (0)