Compare commits

..

21 Commits

Author SHA1 Message Date
CrazyMax
9ae6899cfa Update CHANGELOG 2020-12-24 16:47:13 +01:00
CrazyMax
db66d4df79 Inject DOCKER_META_IMAGES and DOCKER_META_VERSION args in bake definition (#37)
Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-24 15:45:28 +00:00
CrazyMax
b500d9c7b5 Missing entry in action.yml 2020-12-24 14:06:20 +01:00
CrazyMax
aa3823e012 Update CHANGELOG 2020-12-24 04:19:39 +01:00
CrazyMax
a4739af83c Update README 2020-12-24 04:16:21 +01:00
CrazyMax
10e9d5d585 Add bake-file output (#36)
Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-24 03:13:41 +00:00
CrazyMax
3479bd5aaa Add label-custom input (#35)
Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-23 21:09:38 +00:00
dependabot[bot]
c48ac80f46 Bump node-notifier from 8.0.0 to 8.0.1 (#33)
Bumps [node-notifier](https://github.com/mikaelbr/node-notifier) from 8.0.0 to 8.0.1.
- [Release notes](https://github.com/mikaelbr/node-notifier/releases)
- [Changelog](https://github.com/mikaelbr/node-notifier/blob/v8.0.1/CHANGELOG.md)
- [Commits](https://github.com/mikaelbr/node-notifier/compare/v8.0.0...v8.0.1)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-23 09:00:39 +00:00
CrazyMax
805449f25e Update dev workflow (#32)
Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>
2020-12-19 02:53:36 +00:00
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
21 changed files with 7449 additions and 4078 deletions

View File

@@ -1 +1,5 @@
node_modules /.dev
/coverage
/dist
/lib
/node_modules

View File

@@ -2,33 +2,20 @@
Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great.
Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE). Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license)
to the public under the [project's open source license](LICENSE).
## Submitting a pull request ## Submitting a pull request
1. [Fork](https://github.com/crazy-max/ghaction-docker-meta/fork) and clone the repository 1. [Fork](https://github.com/crazy-max/ghaction-docker-meta/fork) and clone the repository
2. Configure and install the dependencies: `yarn install` 2. Configure and install the dependencies: `yarn install`
3. Make sure the tests pass on your machine: `yarn run test` 3. Create a new branch: `git checkout -b my-branch-name`
4. Create a new branch: `git checkout -b my-branch-name` 4. Make your changes
5. Make your change, add tests, and make sure the tests still pass 5. Make sure the tests pass: `docker buildx bake test`
6. Run pre-checkin: `yarn run pre-checkin` 6. Format code and build javascript artifacts: `docker buildx bake pre-checkin`
7. Push to your fork and [submit a pull request](https://github.com/crazy-max/ghaction-docker-meta/compare) 7. Validate all code has correctly formatted and built: `docker buildx bake validate`
8. Pat your self on the back and wait for your pull request to be reviewed and merged. 8. Push to your fork and [submit a pull request](https://github.com/crazy-max/ghaction-docker-meta/compare)
9. Pat your self on the back and wait for your pull request to be reviewed and merged.
## Container based developer flow
If you don't want to maintain a Node developer environment that fits this project you can use containerized commands instead of invoking yarn directly.
```
# format code and build javascript artifacts
docker buildx bake pre-checkin
# validate all code has correctly formatted and built
docker buildx bake validate
# run tests
docker buildx bake test
```
Here are a few things you can do that will increase the likelihood of your pull request being accepted: Here are a few things you can do that will increase the likelihood of your pull request being accepted:

View File

@@ -82,10 +82,18 @@ jobs:
tag-semver: tag-semver:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
tag-latest:
- 'true'
- 'false'
steps: steps:
- name: Checkout -
name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Docker meta -
name: Docker meta
uses: ./ uses: ./
with: with:
images: | images: |
@@ -95,6 +103,26 @@ jobs:
{{raw}} {{raw}}
{{version}} {{version}}
{{major}}.{{minor}}.{{patch}} {{major}}.{{minor}}.{{patch}}
tag-latest: ${{ matrix.tag-latest }}
label-custom:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Docker meta
uses: ./
with:
images: |
${{ env.DOCKER_IMAGE }}
ghcr.io/name/app
label-custom: |
maintainer=CrazyMax
org.opencontainers.image.title=MyCustomTitle
org.opencontainers.image.description=Another description
org.opencontainers.image.vendor=MyCompany
docker-push: docker-push:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -114,7 +142,10 @@ jobs:
with: with:
images: ${{ env.DOCKER_IMAGE }} images: ${{ env.DOCKER_IMAGE }}
tag-sha: true 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 name: Set up QEMU
uses: docker/setup-qemu-action@v1 uses: docker/setup-qemu-action@v1
@@ -146,3 +177,38 @@ jobs:
name: Dump context name: Dump context
if: always() if: always()
uses: crazy-max/ghaction-dump-context@v1 uses: crazy-max/ghaction-dump-context@v1
bake:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Docker meta
id: docker_meta
uses: ./
with:
images: |
${{ env.DOCKER_IMAGE }}
ghcr.io/name/app
tag-sha: true
tag-semver: |
{{version}}
{{major}}.{{minor}}
{{major}}
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
-
name: Build
uses: crazy-max/ghaction-docker-buildx-bake@v1
with:
files: |
./test/docker-bake.hcl
${{ steps.docker_meta.outputs.bake-file }}
targets: |
release

View File

@@ -8,39 +8,24 @@ on:
paths-ignore: paths-ignore:
- '**.md' - '**.md'
pull_request: pull_request:
branches:
- 'master'
paths-ignore: paths-ignore:
- '**.md' - '**.md'
jobs: jobs:
test-containerized:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Validate
run: docker buildx bake validate
-
name: Test
run: docker buildx bake test
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
-
name: Install
run: yarn install
- -
name: Test name: Test
run: yarn run test run: docker buildx bake test
- -
name: Upload coverage name: Upload coverage
uses: codecov/codecov-action@v1 uses: codecov/codecov-action@v1
if: success()
with: with:
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage/clover.xml file: ./coverage/clover.xml

25
.github/workflows/validate.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: validate
on:
push:
branches:
- 'master'
- 'releases/v*'
paths-ignore:
- '**.md'
pull_request:
branches:
- 'master'
paths-ignore:
- '**.md'
jobs:
validate:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Validate
run: docker buildx bake validate

View File

@@ -1,5 +1,40 @@
# Changelog # Changelog
## 1.11.0 (2020/12/24)
* Inject `DOCKER_META_IMAGES` and `DOCKER_META_VERSION` args in bake definition (#37)
## 1.10.1 (2020/12/24)
* Missing entry in `action.yml`
## 1.10.0 (2020/12/24)
* Add `bake-file` output (#36)
* Add `label-custom` input (#35)
* Bump node-notifier from 8.0.0 to 8.0.1 (#33)
* Update dev workflow (#32)
## 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) ## 1.8.3 (2020/11/20)
* Lowercase image name (#16) * Lowercase image name (#16)

View File

@@ -1,9 +1,9 @@
#syntax=docker/dockerfile:1.1-experimental #syntax=docker/dockerfile:1.2
FROM node:12 AS deps FROM node:12 AS deps
WORKDIR /src WORKDIR /src
COPY package.json yarn.lock ./ COPY package.json yarn.lock ./
RUN --mount=type=cache,target=/usr/local/share/.cache/yarn \ RUN --mount=type=cache,target=/src/node_modules \
yarn install yarn install
FROM scratch AS update-yarn FROM scratch AS update-yarn
@@ -17,20 +17,29 @@ FROM deps AS base
COPY . . COPY . .
FROM base AS build FROM base AS build
RUN yarn build RUN --mount=type=cache,target=/src/node_modules \
yarn build
FROM deps AS test FROM deps AS test
ENV RUNNER_TEMP=/tmp/github_runner
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
COPY . . COPY . .
RUN yarn run test RUN --mount=type=cache,target=/src/node_modules \
yarn run test
FROM scratch AS test-coverage
COPY --from=test /src/coverage /coverage/
FROM base AS run-format FROM base AS run-format
RUN yarn run format RUN --mount=type=cache,target=/src/node_modules \
yarn run format
FROM scratch AS format FROM scratch AS format
COPY --from=run-format /src/src/*.ts /src/ COPY --from=run-format /src/src/*.ts /src/
FROM base AS validate-format FROM base AS validate-format
RUN yarn run format-check RUN --mount=type=cache,target=/src/node_modules \
yarn run format-check
FROM scratch AS dist FROM scratch AS dist
COPY --from=build /src/dist/ /dist/ COPY --from=build /src/dist/ /dist/

181
README.md
View File

@@ -16,30 +16,23 @@ If you are interested, [check out](https://git.io/Je09Y) my other :octocat: GitH
___ ___
* [Features](#features)
* [Usage](#usage) * [Usage](#usage)
* [Basic](#basic) * [Basic](#basic)
* [Semver](#semver) * [Semver](#semver)
* [Complete](#complete) * [Bake definition](#bake-definition)
* [Customizing](#customizing) * [Customizing](#customizing)
* [inputs](#inputs) * [inputs](#inputs)
* [outputs](#outputs) * [outputs](#outputs)
* [Notes](#notes) * [Notes](#notes)
* [Latest tag](#latest-tag) * [Latest tag](#latest-tag)
* [`tag-match` examples](#tag-match-examples)
* [Handle semver tag](#handle-semver-tag) * [Handle semver tag](#handle-semver-tag)
* [`tag-match` examples](#tag-match-examples)
* [Schedule tag](#schedule-tag) * [Schedule tag](#schedule-tag)
* [Overwrite labels](#overwrite-labels) * [Overwrite labels](#overwrite-labels)
* [Keep up-to-date with GitHub Dependabot](#keep-up-to-date-with-github-dependabot) * [Keep up-to-date with GitHub Dependabot](#keep-up-to-date-with-github-dependabot)
* [How can I help?](#how-can-i-help) * [Contributing](#contributing)
* [License](#license) * [License](#license)
## Features
* Docker tags generated from GitHub action event and Git metadata
* [OCI Image Format Specification](https://github.com/opencontainers/image-spec/blob/master/annotations.md) used to generate Docker labels
* [Handlebars template](https://handlebarsjs.com/guide/) to apply to schedule tag
## Usage ## Usage
### Basic ### Basic
@@ -163,23 +156,29 @@ jobs:
labels: ${{ steps.docker_meta.outputs.labels }} labels: ${{ steps.docker_meta.outputs.labels }}
``` ```
### Complete ### Bake definition
| Event | Ref | Commit SHA | Docker Tags | This action also handles a bake definition file that can be used with the
|-----------------|-------------------------------|------------|-----------------------------------------| [Docker Buildx Bake action](https://github.com/crazy-max/ghaction-docker-buildx-bake). You just have to declare an empty
| `schedule` | `refs/heads/master` | `45f132a` | `sha-45f132a`, `nightly` | target named `ghaction-docker-meta` and inherit from it.
| `pull_request` | `refs/pull/2/merge` | `a123b57` | `sha-45f132a`, `pr-2` |
| `push` | `refs/heads/master` | `cf20257` | `sha-45f132a`, `master` | ```hcl
| `push` | `refs/heads/my/branch` | `a5df687` | `sha-45f132a`, `my-branch` | // docker-bake.hcl
| `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` | target "ghaction-docker-meta" {}
target "build" {
inherits = ["ghaction-docker-meta"]
context = "./"
dockerfile = "Dockerfile"
platforms = ["linux/amd64", "linux/arm/v6", "linux/arm/v7", "linux/arm64", "linux/386", "linux/ppc64le"]
}
```
```yaml ```yaml
name: ci name: ci
on: on:
schedule:
- cron: '0 10 * * *' # everyday at 10am
push: push:
branches: branches:
- '**' - '**'
@@ -200,6 +199,7 @@ jobs:
uses: crazy-max/ghaction-docker-meta@v1 uses: crazy-max/ghaction-docker-meta@v1
with: with:
images: name/app images: name/app
tag-sha: true
tag-semver: | tag-semver: |
{{version}} {{version}}
{{major}}.{{minor}} {{major}}.{{minor}}
@@ -210,22 +210,44 @@ jobs:
name: Set up Docker Buildx name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1 uses: docker/setup-buildx-action@v1
- -
name: Login to DockerHub name: Build
if: github.event_name != 'pull_request' uses: crazy-max/ghaction-docker-buildx-bake@v1
uses: docker/login-action@v1
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} files: |
password: ${{ secrets.DOCKERHUB_TOKEN }} ./docker-bake.hcl
- ${{ steps.docker_meta.outputs.bake-file }}
name: Build and push targets: |
uses: docker/build-push-action@v2 build
with: ```
context: .
file: ./Dockerfile Content of `${{ steps.docker_meta.outputs.bake-file }}` file will look like this:
platforms: linux/amd64,linux/arm64,linux/386
push: ${{ github.event_name != 'pull_request' }} ```json
tags: ${{ steps.docker_meta.outputs.tags }} {
labels: ${{ steps.docker_meta.outputs.labels }} "target": {
"ghaction-docker-meta": {
"tags": [
"name/app:1.1.1",
"name/app:1.1",
"name/app:latest"
],
"labels": {
"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"
},
"args": {
"DOCKER_META_IMAGES": "name/app",
"DOCKER_META_VERSION": "1.1.1"
}
}
}
}
``` ```
## Customizing ## Customizing
@@ -234,21 +256,37 @@ jobs:
Following inputs can be used as `step.with` keys Following inputs can be used as `step.with` keys
> `List` type is a newline-delimited string
> ```yaml
> label-custom: |
> org.opencontainers.image.title=MyCustomTitle
> org.opencontainers.image.description=Another description
> org.opencontainers.image.vendor=MyCompany
> ```
> `CSV` type is a comma-delimited string
> ```yaml
> images: name/app,ghcr.io/name/app
> ```
| Name | Type | Description | | Name | Type | Description |
|---------------------|----------|------------------------------------| |---------------------|----------|------------------------------------|
| `images` | List/CSV | List of Docker images to use as base name for tags | | `images` | List/CSV | List of Docker images to use as base name for tags |
| `tag-sha` | Bool | Add git short SHA as Docker tag (default `false`) | | `tag-sha` | Bool | Add git short commit as Docker tag (default `false`) |
| `tag-edge` | Bool | Enable edge branch tagging (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-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` | 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-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-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 |
| `label-custom` | List | List of custom labels |
| `sep-tags` | String | Separator to use for tags output (default `\n`) | | `sep-tags` | String | Separator to use for tags output (default `\n`) |
| `sep-labels` | String | Separator to use for labels 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 ### outputs
@@ -256,9 +294,10 @@ Following outputs are available
| Name | Type | Description | | Name | Type | Description |
|---------------|---------|---------------------------------------| |---------------|---------|---------------------------------------|
| `version` | String | Generated Docker image version | | `version` | String | Docker image version |
| `tags` | String | Generated Docker tags | | `tags` | String | Docker tags |
| `labels` | String | Generated Docker labels | | `labels` | String | Docker labels |
| `bake-file` | File | [Bake definition file](https://github.com/docker/buildx#file-definition) path |
## Notes ## Notes
@@ -266,18 +305,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, 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 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 generated only if `tag-semver` is a valid [semver](https://semver.org/) or if Git tag matches a regular expression
`tag-semver` is valid [semver](https://semver.org/). with the [`tag-match` input](#tag-match-examples). Can be disabled if `tag-latest` is `false`.
### `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` |
### Handle semver tag ### Handle semver tag
@@ -293,14 +322,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` | `{{minor}}` | :white_check_mark: | `2`, `latest` | `2` |
| `v1.2.3` | `{{patch}}` | :white_check_mark: | `3`, `latest` | `3` | | `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`* | | `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` | `{{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` | | `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` | | `release1` | `{{raw}}` | :x: | `release1` | `release1` |
> *First occurrence of `tag-semver` will be taken as `output.version` > *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 ### Schedule tag
@@ -320,16 +360,13 @@ labels generated are not suitable, you can overwrite them like this:
```yaml ```yaml
- -
name: Build and push name: Docker meta
uses: docker/build-push-action@v2 id: docker_meta
uses: crazy-max/ghaction-docker-meta@v1
with: with:
context: . images: name/app
file: ./Dockerfile label-custom: |
platforms: linux/amd64,linux/arm64,linux/386 maintainer=CrazyMax
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.docker_meta.outputs.tags }}
labels: |
${{ steps.docker_meta.outputs.labels }}
org.opencontainers.image.title=MyCustomTitle org.opencontainers.image.title=MyCustomTitle
org.opencontainers.image.description=Another description org.opencontainers.image.description=Another description
org.opencontainers.image.vendor=MyCompany org.opencontainers.image.vendor=MyCompany
@@ -351,12 +388,14 @@ updates:
interval: "daily" interval: "daily"
``` ```
## How can I help? ## Contributing
All kinds of contributions are welcome :raised_hands:! The most basic way to show your support is to star :star2: Want to contribute? Awesome! The most basic way to show your support is to star :star2: the project,
the project, or to raise issues :speech_balloon: You can also support this project by or to raise issues :speech_balloon:. If you want to open a pull request, please read the
[**becoming a sponsor on GitHub**](https://github.com/sponsors/crazy-max) :clap: or by making a [contributing guidelines](.github/CONTRIBUTING.md).
[Paypal donation](https://www.paypal.me/crazyws) to ensure this journey continues indefinitely! :rocket:
You can also support this project by [**becoming a sponsor on GitHub**](https://github.com/sponsors/crazy-max) or by
making a [Paypal donation](https://www.paypal.me/crazyws) to ensure this journey continues indefinitely!
Thanks again for your support, it is much appreciated! :pray: Thanks again for your support, it is much appreciated! :pray:

View File

@@ -1,54 +1,161 @@
import * as fs from 'fs';
import * as path from 'path';
import * as context from '../src/context'; import * as context from '../src/context';
jest.spyOn(context, 'tmpDir').mockImplementation((): string => {
const tmpDir = path.join('/tmp/.ghaction-docker-meta-jest').split(path.sep).join(path.posix.sep);
if (!fs.existsSync(tmpDir)) {
fs.mkdirSync(tmpDir, {recursive: true});
}
return tmpDir;
});
describe('getInputList', () => { describe('getInputList', () => {
it('handles single line correctly', async () => { it('single line correctly', async () => {
await setInput('foo', 'bar'); await setInput('foo', 'bar');
const res = await context.getInputList('foo'); const res = await context.getInputList('foo');
console.log(res); console.log(res);
expect(res).toEqual(['bar']); expect(res).toEqual(['bar']);
}); });
it('handles multiple lines correctly', async () => { it('multiline correctly', async () => {
setInput('foo', 'bar\nbaz'); setInput('foo', 'bar\nbaz');
const res = await context.getInputList('foo'); const res = await context.getInputList('foo');
console.log(res); console.log(res);
expect(res).toEqual(['bar', 'baz']); expect(res).toEqual(['bar', 'baz']);
}); });
it('remove empty lines correctly', async () => { it('empty lines correctly', async () => {
setInput('foo', 'bar\n\nbaz'); setInput('foo', 'bar\n\nbaz');
const res = await context.getInputList('foo'); const res = await context.getInputList('foo');
console.log(res); console.log(res);
expect(res).toEqual(['bar', 'baz']); expect(res).toEqual(['bar', 'baz']);
}); });
it('handles comma correctly', async () => { it('comma correctly', async () => {
setInput('foo', 'bar,baz'); setInput('foo', 'bar,baz');
const res = await context.getInputList('foo'); const res = await context.getInputList('foo');
console.log(res); console.log(res);
expect(res).toEqual(['bar', 'baz']); expect(res).toEqual(['bar', 'baz']);
}); });
it('remove empty result correctly', async () => { it('empty result correctly', async () => {
setInput('foo', 'bar,baz,'); setInput('foo', 'bar,baz,');
const res = await context.getInputList('foo'); const res = await context.getInputList('foo');
console.log(res); console.log(res);
expect(res).toEqual(['bar', 'baz']); expect(res).toEqual(['bar', 'baz']);
}); });
it('handles different new lines correctly', async () => { it('different new lines correctly', async () => {
setInput('foo', 'bar\r\nbaz'); setInput('foo', 'bar\r\nbaz');
const res = await context.getInputList('foo'); const res = await context.getInputList('foo');
console.log(res); console.log(res);
expect(res).toEqual(['bar', 'baz']); expect(res).toEqual(['bar', 'baz']);
}); });
it('handles different new lines and comma correctly', async () => { it('different new lines and comma correctly', async () => {
setInput('foo', 'bar\r\nbaz,bat'); setInput('foo', 'bar\r\nbaz,bat');
const res = await context.getInputList('foo'); const res = await context.getInputList('foo');
console.log(res); console.log(res);
expect(res).toEqual(['bar', 'baz', 'bat']); expect(res).toEqual(['bar', 'baz', 'bat']);
}); });
it('multiline and ignoring comma correctly', async () => {
setInput('cache-from', 'user/app:cache\ntype=local,src=path/to/dir');
const res = await context.getInputList('cache-from', true);
console.log(res);
expect(res).toEqual(['user/app:cache', 'type=local,src=path/to/dir']);
});
it('different new lines and ignoring comma correctly', async () => {
setInput('cache-from', 'user/app:cache\r\ntype=local,src=path/to/dir');
const res = await context.getInputList('cache-from', true);
console.log(res);
expect(res).toEqual(['user/app:cache', 'type=local,src=path/to/dir']);
});
it('multiline values', async () => {
setInput(
'secrets',
`GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789
"MYSECRET=aaaaaaaa
bbbbbbb
ccccccccc"
FOO=bar`
);
const res = await context.getInputList('secrets', true);
console.log(res);
expect(res).toEqual([
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
`MYSECRET=aaaaaaaa
bbbbbbb
ccccccccc`,
'FOO=bar'
]);
});
it('multiline values with empty lines', async () => {
setInput(
'secrets',
`GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789
"MYSECRET=aaaaaaaa
bbbbbbb
ccccccccc"
FOO=bar
"EMPTYLINE=aaaa
bbbb
ccc"`
);
const res = await context.getInputList('secrets', true);
console.log(res);
expect(res).toEqual([
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
`MYSECRET=aaaaaaaa
bbbbbbb
ccccccccc`,
'FOO=bar',
`EMPTYLINE=aaaa
bbbb
ccc`
]);
});
it('multiline values without quotes', async () => {
setInput(
'secrets',
`GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789
MYSECRET=aaaaaaaa
bbbbbbb
ccccccccc
FOO=bar`
);
const res = await context.getInputList('secrets', true);
console.log(res);
expect(res).toEqual(['GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789', 'MYSECRET=aaaaaaaa', 'bbbbbbb', 'ccccccccc', 'FOO=bar']);
});
it('multiline values escape quotes', async () => {
setInput(
'secrets',
`GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789
"MYSECRET=aaaaaaaa
bbbb""bbb
ccccccccc"
FOO=bar`
);
const res = await context.getInputList('secrets', true);
console.log(res);
expect(res).toEqual([
'GIT_AUTH_TOKEN=abcdefgh,ijklmno=0123456789',
`MYSECRET=aaaaaaaa
bbbb\"bbb
ccccccccc`,
'FOO=bar'
]);
});
}); });
describe('asyncForEach', () => { describe('asyncForEach', () => {

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 repo = await github.repo(process.env.GITHUB_TOKEN || '');
const meta = new Meta({...getInputs(), ...inputs}, context, repo); const meta = new Meta({...getInputs(), ...inputs}, context, repo);
const version = meta.version(); const version = meta.version;
console.log('version', version); console.log('version', version);
expect(version).toEqual(exVersion); expect(version).toEqual(exVersion);
@@ -376,6 +376,35 @@ describe('push', () => {
"org.opencontainers.image.licenses=MIT" "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); ])('given %p event ', tagsLabelsTest);
}); });
@@ -437,7 +466,7 @@ describe('push tag', () => {
{ {
images: ['user/app'], images: ['user/app'],
tagMatch: `\\d{8}`, tagMatch: `\\d{8}`,
tagMatchLatest: false, tagLatest: false,
} as Inputs, } as Inputs,
{ {
main: '20200110', main: '20200110',
@@ -464,7 +493,7 @@ describe('push tag', () => {
images: ['user/app'], images: ['user/app'],
tagMatch: `(.*)-RC`, tagMatch: `(.*)-RC`,
tagMatchGroup: 1, tagMatchGroup: 1,
tagMatchLatest: false, tagLatest: false,
} as Inputs, } as Inputs,
{ {
main: '20200110', main: '20200110',
@@ -715,7 +744,7 @@ describe('push tag', () => {
'event_tag_v2.0.8-beta.67.env', 'event_tag_v2.0.8-beta.67.env',
{ {
images: ['org/app', 'ghcr.io/user/app'], images: ['org/app', 'ghcr.io/user/app'],
tagSemver: ['{{version}}', '{{major}}.{{minor}}', '{{major}}'], tagSemver: ['{{major}}.{{minor}}', '{{major}}'],
} as Inputs, } as Inputs,
{ {
main: '2.0.8-beta.67', main: '2.0.8-beta.67',
@@ -737,6 +766,32 @@ describe('push tag', () => {
"org.opencontainers.image.licenses=MIT" "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); ])('given %p event ', tagsLabelsTest);
}); });
@@ -906,7 +961,7 @@ describe('latest', () => {
'event_tag_v1.1.1.env', 'event_tag_v1.1.1.env',
{ {
images: ['org/app', 'ghcr.io/user/app'], images: ['org/app', 'ghcr.io/user/app'],
tagMatchLatest: false, tagLatest: false,
} as Inputs, } as Inputs,
{ {
main: 'v1.1.1', main: 'v1.1.1',
@@ -932,7 +987,7 @@ describe('latest', () => {
'event_tag_v1.1.1.env', 'event_tag_v1.1.1.env',
{ {
images: ['org/app', 'ghcr.io/MyUSER/MyApp'], images: ['org/app', 'ghcr.io/MyUSER/MyApp'],
tagMatchLatest: false, tagLatest: false,
} as Inputs, } as Inputs,
{ {
main: 'v1.1.1', main: 'v1.1.1',
@@ -954,6 +1009,42 @@ describe('latest', () => {
"org.opencontainers.image.licenses=MIT" "org.opencontainers.image.licenses=MIT"
] ]
], ],
[
'event_tag_v1.1.1.env',
{
images: ['org/app', 'ghcr.io/MyUSER/MyApp'],
tagLatest: false,
labelCustom: [
"maintainer=CrazyMax",
"org.opencontainers.image.title=MyCustomTitle",
"org.opencontainers.image.description=Another description",
"org.opencontainers.image.vendor=MyCompany",
],
} as Inputs,
{
main: 'v1.1.1',
partial: [],
latest: false
} as Version,
[
'org/app:v1.1.1',
'ghcr.io/myuser/myapp:v1.1.1',
],
[
"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=v1.1.1",
"org.opencontainers.image.created=2020-01-10T00:30:00.000Z",
"org.opencontainers.image.revision=90dd6032fac8bda1b6c4436a2e65de27961ed071",
"org.opencontainers.image.licenses=MIT",
"maintainer=CrazyMax",
"org.opencontainers.image.title=MyCustomTitle",
"org.opencontainers.image.description=Another description",
"org.opencontainers.image.vendor=MyCompany"
]
],
])('given %p event ', tagsLabelsTest); ])('given %p event ', tagsLabelsTest);
}); });
@@ -1203,3 +1294,462 @@ describe('release', () => {
], ],
])('given %p event ', tagsLabelsTest); ])('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);
});
describe('bake-file', () => {
// prettier-ignore
test.each([
[
'event_push.env',
{
images: ['user/app'],
tagCustom: ['my', 'custom', 'tags']
} as Inputs,
{
"target": {
"ghaction-docker-meta": {
"tags": [
"user/app:dev",
"user/app:my",
"user/app:custom",
"user/app:tags"
],
"labels": {
"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"
},
"args": {
"DOCKER_META_IMAGES": "user/app",
"DOCKER_META_VERSION": "dev",
}
}
}
}
],
[
'event_push.env',
{
images: ['user/app'],
tagCustom: ['my']
} as Inputs,
{
"target": {
"ghaction-docker-meta": {
"tags": [
"user/app:dev",
"user/app:my",
],
"labels": {
"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"
},
"args": {
"DOCKER_META_IMAGES": "user/app",
"DOCKER_META_VERSION": "dev",
}
}
}
}
],
[
'event_tag_release1.env',
{
images: ['user/app'],
tagCustom: ['my', 'custom', 'tags']
} as Inputs,
{
"target": {
"ghaction-docker-meta": {
"tags": [
"user/app:release1",
"user/app:my",
"user/app:custom",
"user/app:tags",
"user/app:latest"
],
"labels": {
"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"
},
"args": {
"DOCKER_META_IMAGES": "user/app",
"DOCKER_META_VERSION": "release1",
}
}
}
}
],
[
'event_tag_20200110-RC2.env',
{
images: ['user/app'],
tagMatch: `\\d{8}`,
tagLatest: false,
tagCustom: ['my', 'custom', 'tags']
} as Inputs,
{
"target": {
"ghaction-docker-meta": {
"tags": [
"user/app:20200110",
"user/app:my",
"user/app:custom",
"user/app:tags"
],
"labels": {
"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"
},
"args": {
"DOCKER_META_IMAGES": "user/app",
"DOCKER_META_VERSION": "20200110",
}
}
}
}
],
[
'event_tag_v1.1.1.env',
{
images: ['org/app', 'ghcr.io/user/app'],
tagSemver: ['{{version}}', '{{major}}.{{minor}}', '{{major}}'],
tagCustom: ['my', 'custom', 'tags']
} as Inputs,
{
"target": {
"ghaction-docker-meta": {
"tags": [
"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"
],
"labels": {
"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"
},
"args": {
"DOCKER_META_IMAGES": "org/app,ghcr.io/user/app",
"DOCKER_META_VERSION": "1.1.1",
}
}
}
}
],
[
'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,
{
"target": {
"ghaction-docker-meta": {
"tags": [
"org/app:my",
"org/app:custom",
"org/app:tags",
"ghcr.io/user/app:my",
"ghcr.io/user/app:custom",
"ghcr.io/user/app:tags"
],
"labels": {
"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"
},
"args": {
"DOCKER_META_IMAGES": "org/app,ghcr.io/user/app",
"DOCKER_META_VERSION": "my",
}
}
}
}
],
[
'event_tag_v1.1.1.env',
{
images: ['org/app'],
labelCustom: [
"maintainer=CrazyMax",
"org.opencontainers.image.title=MyCustom=Title",
"org.opencontainers.image.description=Another description",
"org.opencontainers.image.vendor=MyCompany",
],
} as Inputs,
{
"target": {
"ghaction-docker-meta": {
"tags": [
"org/app:v1.1.1",
"org/app:latest"
],
"labels": {
"maintainer": "CrazyMax",
"org.opencontainers.image.title": "MyCustom=Title",
"org.opencontainers.image.description": "Another description",
"org.opencontainers.image.url": "https://github.com/octocat/Hello-World",
"org.opencontainers.image.source": "https://github.com/octocat/Hello-World",
"org.opencontainers.image.vendor": "MyCompany",
"org.opencontainers.image.version": "v1.1.1",
"org.opencontainers.image.created": "2020-01-10T00:30:00.000Z",
"org.opencontainers.image.revision": "90dd6032fac8bda1b6c4436a2e65de27961ed071",
"org.opencontainers.image.licenses": "MIT"
},
"args": {
"DOCKER_META_IMAGES": "org/app",
"DOCKER_META_VERSION": "v1.1.1",
}
}
}
}
]
])('given %p event ', async (envFile: string, inputs: Inputs, exBakeDefinition: {}) => {
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 bakeFile = meta.bakeFile();
console.log('bakeFile', bakeFile, fs.readFileSync(bakeFile, 'utf8'));
expect(JSON.parse(fs.readFileSync(bakeFile, 'utf8'))).toEqual(exBakeDefinition);
});
});

View File

@@ -31,14 +31,28 @@ inputs:
description: 'Group to get if tag-match matches (default 0)' description: 'Group to get if tag-match matches (default 0)'
default: '0' default: '0'
required: false 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: 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' default: 'true'
required: false required: false
tag-schedule: tag-schedule:
description: 'Template to apply to schedule tag' description: 'Template to apply to schedule tag'
default: 'nightly' default: 'nightly'
required: false required: false
tag-custom:
description: 'List of custom tags'
required: false
tag-custom-only:
description: 'Only use tag-custom as Docker tags'
required: false
label-custom:
description: 'List of custom labels'
required: false
sep-tags: sep-tags:
description: 'Separator to use for tags output (default \n)' description: 'Separator to use for tags output (default \n)'
required: false required: false
@@ -57,6 +71,8 @@ outputs:
description: 'Generated Docker tags' description: 'Generated Docker tags'
labels: labels:
description: 'Generated Docker labels' description: 'Generated Docker labels'
bake-file:
description: 'Bake definiton file'
runs: runs:
using: 'node12' using: 'node12'

2485
dist/index.js generated vendored

File diff suppressed because it is too large Load Diff

View File

@@ -7,36 +7,48 @@ group "pre-checkin" {
} }
group "validate" { group "validate" {
targets = ["validate-format", "validate-build", "validate-yarn"] targets = ["validate-format", "validate-build", "validate-yarn"]
}
target "dockerfile" {
dockerfile = "Dockerfile.dev"
} }
target "update-yarn" { target "update-yarn" {
inherits = ["dockerfile"]
target = "update-yarn" target = "update-yarn"
output = ["."] output = ["."]
} }
target "build" { target "build" {
inherits = ["dockerfile"]
target = "dist" target = "dist"
output = ["."] output = ["."]
} }
target "test" { target "test" {
target = "test" inherits = ["dockerfile"]
target = "test-coverage"
output = ["."]
} }
target "format" { target "format" {
inherits = ["dockerfile"]
target = "format" target = "format"
output = ["."] output = ["."]
} }
target "validate-format" { target "validate-format" {
inherits = ["dockerfile"]
target = "validate-format" target = "validate-format"
} }
target "validate-build" { target "validate-build" {
inherits = ["dockerfile"]
target = "validate-build" target = "validate-build"
} }
target "validate-yarn" { target "validate-yarn" {
target = "validate-yarn" inherits = ["dockerfile"]
target = "validate-yarn"
} }

View File

@@ -25,9 +25,10 @@
"dependencies": { "dependencies": {
"@actions/core": "^1.2.6", "@actions/core": "^1.2.6",
"@actions/github": "^4.0.0", "@actions/github": "^4.0.0",
"csv-parse": "^4.14.2",
"handlebars": "^4.7.6", "handlebars": "^4.7.6",
"moment": "^2.29.1", "moment": "^2.29.1",
"semver": "^7.3.2" "semver": "^7.3.4"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^26.0.0", "@types/jest": "^26.0.0",

View File

@@ -1,4 +1,10 @@
import csvparse from 'csv-parse/lib/sync';
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
let _tmpDir: string;
export interface Inputs { export interface Inputs {
images: string[]; images: string[];
@@ -8,13 +14,23 @@ export interface Inputs {
tagSemver: string[]; tagSemver: string[];
tagMatch: string; tagMatch: string;
tagMatchGroup: number; tagMatchGroup: number;
tagMatchLatest: boolean; tagLatest: boolean;
tagSchedule: string; tagSchedule: string;
tagCustom: string[];
tagCustomOnly: boolean;
labelCustom: string[];
sepTags: string; sepTags: string;
sepLabels: string; sepLabels: string;
githubToken: string; githubToken: string;
} }
export function tmpDir(): string {
if (!_tmpDir) {
_tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ghaction-docker-meta-')).split(path.sep).join(path.posix.sep);
}
return _tmpDir;
}
export function getInputs(): Inputs { export function getInputs(): Inputs {
return { return {
images: getInputList('images'), images: getInputList('images'),
@@ -24,23 +40,41 @@ export function getInputs(): Inputs {
tagSemver: getInputList('tag-semver'), tagSemver: getInputList('tag-semver'),
tagMatch: core.getInput('tag-match'), tagMatch: core.getInput('tag-match'),
tagMatchGroup: Number(core.getInput('tag-match-group')) || 0, 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', tagSchedule: core.getInput('tag-schedule') || 'nightly',
tagCustom: getInputList('tag-custom'),
tagCustomOnly: /true/i.test(core.getInput('tag-custom-only') || 'false'),
labelCustom: getInputList('label-custom'),
sepTags: core.getInput('sep-tags') || `\n`, sepTags: core.getInput('sep-tags') || `\n`,
sepLabels: core.getInput('sep-labels') || `\n`, sepLabels: core.getInput('sep-labels') || `\n`,
githubToken: core.getInput('github-token') githubToken: core.getInput('github-token')
}; };
} }
export function getInputList(name: string): string[] { export function getInputList(name: string, ignoreComma?: boolean): string[] {
let res: Array<string> = [];
const items = core.getInput(name); const items = core.getInput(name);
if (items == '') { if (items == '') {
return []; return res;
} }
return items
.split(/\r?\n/) for (let output of csvparse(items, {
.filter(x => x) columns: false,
.reduce<string[]>((acc, line) => acc.concat(line.split(',').filter(x => x)).map(pat => pat.trim()), []); relaxColumnCount: true,
skipLinesWithEmptyValues: true
}) as Array<string[]>) {
if (output.length == 1) {
res.push(output[0]);
continue;
} else if (!ignoreComma) {
res.push(...output);
continue;
}
res.push(output.join(','));
}
return res.filter(item => item).map(pat => pat.trim());
} }
export const asyncForEach = async (array, callback) => { export const asyncForEach = async (array, callback) => {

View File

@@ -1,3 +1,4 @@
import * as fs from 'fs';
import {getInputs, Inputs} from './context'; import {getInputs, Inputs} from './context';
import * as github from './github'; import * as github from './github';
import {Meta, Version} from './meta'; import {Meta, Version} from './meta';
@@ -27,12 +28,13 @@ async function run() {
const meta: Meta = new Meta(inputs, context, repo); const meta: Meta = new Meta(inputs, context, repo);
const version: Version = meta.version(); const version: Version = meta.version;
core.startGroup(`Docker image version`); core.startGroup(`Docker image version`);
core.info(version.main || ''); core.info(version.main || '');
core.endGroup(); core.endGroup();
core.setOutput('version', version.main || ''); core.setOutput('version', version.main || '');
// Docker tags
const tags: Array<string> = meta.tags(); const tags: Array<string> = meta.tags();
core.startGroup(`Docker tags`); core.startGroup(`Docker tags`);
for (let tag of tags) { for (let tag of tags) {
@@ -41,13 +43,21 @@ async function run() {
core.endGroup(); core.endGroup();
core.setOutput('tags', tags.join(inputs.sepTags)); core.setOutput('tags', tags.join(inputs.sepTags));
// Docker labels
const labels: Array<string> = meta.labels(); const labels: Array<string> = meta.labels();
core.startGroup(`Docker labels`); core.startGroup(`Docker labels`);
for (let label of labels) { for (let label of labels) {
core.info(label); core.info(label);
} }
core.endGroup(); core.endGroup();
core.setOutput('labels', labels.join(inputs.sepTags)); core.setOutput('labels', labels.join(inputs.sepLabels));
// Bake definition file
const bakeFile: string = meta.bakeFile();
core.startGroup(`Bake definition file`);
core.info(fs.readFileSync(bakeFile, 'utf8'));
core.endGroup();
core.setOutput('bake-file', bakeFile);
} catch (error) { } catch (error) {
core.setFailed(error.message); core.setFailed(error.message);
} }

View File

@@ -1,7 +1,10 @@
import * as handlebars from 'handlebars'; import * as handlebars from 'handlebars';
import * as moment from 'moment'; import * as fs from 'fs';
import * as path from 'path';
import moment from 'moment';
import * as semver from 'semver'; import * as semver from 'semver';
import {Inputs} from './context'; import {Inputs, tmpDir} from './context';
import * as core from '@actions/core';
import {Context} from '@actions/github/lib/context'; import {Context} from '@actions/github/lib/context';
import {ReposGetResponseData} from '@octokit/types'; import {ReposGetResponseData} from '@octokit/types';
@@ -12,6 +15,8 @@ export interface Version {
} }
export class Meta { export class Meta {
public readonly version: Version;
private readonly inputs: Inputs; private readonly inputs: Inputs;
private readonly context: Context; private readonly context: Context;
private readonly repo: ReposGetResponseData; private readonly repo: ReposGetResponseData;
@@ -25,11 +30,12 @@ export class Meta {
this.context = context; this.context = context;
this.repo = repo; this.repo = repo;
this.date = new Date(); this.date = new Date();
this.version = this.getVersion();
} }
public version(): Version { private getVersion(): Version {
const currentDate = this.date; const currentDate = this.date;
const version: Version = { let version: Version = {
main: undefined, main: undefined,
partial: [], partial: [],
latest: false latest: false
@@ -43,13 +49,18 @@ export class Meta {
}); });
} else if (/^refs\/tags\//.test(this.context.ref)) { } else if (/^refs\/tags\//.test(this.context.ref)) {
version.main = this.context.ref.replace(/^refs\/tags\//g, '').replace(/\//g, '-'); 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)) { if (this.inputs.tagSemver.length > 0 && semver.valid(version.main)) {
const sver = semver.parse(version.main, { const sver = semver.parse(version.main, {
includePrerelease: true includePrerelease: true
}); });
version.latest = !semver.prerelease(version.main); if (semver.prerelease(version.main)) {
version.main = handlebars.compile(this.inputs.tagSemver[0])(sver); version.main = handlebars.compile('{{version}}')(sver);
if (version.latest) { } else {
version.latest = this.inputs.tagLatest;
version.main = handlebars.compile(this.inputs.tagSemver[0])(sver);
for (const semverTpl of this.inputs.tagSemver) { for (const semverTpl of this.inputs.tagSemver) {
const partial = handlebars.compile(semverTpl)(sver); const partial = handlebars.compile(semverTpl)(sver);
if (partial == version.main) { if (partial == version.main) {
@@ -68,13 +79,13 @@ export class Meta {
} }
if (tagMatch) { if (tagMatch) {
version.main = tagMatch[this.inputs.tagMatchGroup]; version.main = tagMatch[this.inputs.tagMatchGroup];
version.latest = this.inputs.tagMatchLatest; version.latest = this.inputs.tagLatest;
} }
} else { } else {
version.latest = this.inputs.tagMatchLatest; version.latest = this.inputs.tagLatest;
} }
} else if (/^refs\/heads\//.test(this.context.ref)) { } 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) { if (this.inputs.tagEdge && this.inputs.tagEdgeBranch === version.main) {
version.main = 'edge'; version.main = 'edge';
} }
@@ -82,24 +93,35 @@ export class Meta {
version.main = `pr-${this.context.ref.replace(/^refs\/pull\//g, '').replace(/\/merge$/g, '')}`; 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); version.partial = version.partial.filter((item, index) => version.partial.indexOf(item) === index);
return version; return version;
} }
public tags(): Array<string> { public tags(): Array<string> {
const version: Version = this.version(); if (!this.version.main) {
if (!version.main) {
return []; return [];
} }
let tags: Array<string> = []; let tags: Array<string> = [];
for (const image of this.inputs.images) { for (const image of this.inputs.images) {
const imageLc = image.toLowerCase(); const imageLc = image.toLowerCase();
tags.push(`${imageLc}:${version.main}`); tags.push(`${imageLc}:${this.version.main}`);
for (const partial of version.partial) { for (const partial of this.version.partial) {
tags.push(`${imageLc}:${partial}`); tags.push(`${imageLc}:${partial}`);
} }
if (version.latest) { if (this.version.latest) {
tags.push(`${imageLc}:latest`); tags.push(`${imageLc}:latest`);
} }
if (this.context.sha && this.inputs.tagSha) { if (this.context.sha && this.inputs.tagSha) {
@@ -110,15 +132,51 @@ export class Meta {
} }
public labels(): Array<string> { public labels(): Array<string> {
return [ let labels: Array<string> = [
`org.opencontainers.image.title=${this.repo.name || ''}`, `org.opencontainers.image.title=${this.repo.name || ''}`,
`org.opencontainers.image.description=${this.repo.description || ''}`, `org.opencontainers.image.description=${this.repo.description || ''}`,
`org.opencontainers.image.url=${this.repo.html_url || ''}`, `org.opencontainers.image.url=${this.repo.html_url || ''}`,
`org.opencontainers.image.source=${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.created=${this.date.toISOString()}`,
`org.opencontainers.image.revision=${this.context.sha || ''}`, `org.opencontainers.image.revision=${this.context.sha || ''}`,
`org.opencontainers.image.licenses=${this.repo.license?.spdx_id || ''}` `org.opencontainers.image.licenses=${this.repo.license?.spdx_id || ''}`
]; ];
labels.push(...this.inputs.labelCustom);
return labels;
}
public bakeFile(): string {
let jsonLabels = {};
for (let label of this.labels()) {
const matches = label.match(/([^=]*)=(.*)/);
if (!matches) {
continue;
}
jsonLabels[matches[1]] = matches[2];
}
const bakeFile = path.join(tmpDir(), 'ghaction-docker-meta-bake.json').split(path.sep).join(path.posix.sep);
fs.writeFileSync(
bakeFile,
JSON.stringify(
{
target: {
'ghaction-docker-meta': {
tags: this.tags(),
labels: jsonLabels,
args: {
DOCKER_META_IMAGES: this.inputs.images.join(','),
DOCKER_META_VERSION: this.version.main
}
}
}
},
null,
2
)
);
return bakeFile;
} }
} }

38
test/docker-bake.hcl Normal file
View File

@@ -0,0 +1,38 @@
target "ghaction-docker-meta" {}
group "default" {
targets = ["db", "app"]
}
group "release" {
targets = ["db", "app-plus"]
}
target "db" {
context = "./test"
tags = ["docker.io/tonistiigi/db"]
}
target "app" {
inherits = ["ghaction-docker-meta"]
context = "./test"
dockerfile = "Dockerfile"
args = {
name = "foo"
}
}
target "cross" {
platforms = [
"linux/amd64",
"linux/arm64",
"linux/386"
]
}
target "app-plus" {
inherits = ["app", "cross"]
args = {
IAMPLUS = "true"
}
}

View File

@@ -11,9 +11,11 @@
"rootDir": "./src", "rootDir": "./src",
"strict": true, "strict": true,
"noImplicitAny": false, "noImplicitAny": false,
"esModuleInterop": false, "esModuleInterop": true,
"resolveJsonModule": true,
"sourceMap": true "sourceMap": true
}, },
"exclude": ["node_modules", "**/*.test.ts"] "exclude": [
"node_modules",
"**/*.test.ts"
]
} }

View File

@@ -1176,6 +1176,11 @@ cssstyle@^2.2.0:
dependencies: dependencies:
cssom "~0.3.6" cssom "~0.3.6"
csv-parse@^4.14.2:
version "4.14.2"
resolved "https://registry.yarnpkg.com/csv-parse/-/csv-parse-4.14.2.tgz#c1329cff95a99b8773a92c4e62f8bff114b34726"
integrity sha512-YE2xlTKtM035/94llhgsp9qFQxGi47EkQJ1pZ+mLT/98GpIsbjkMGAb7Rmu9hNxVfYFOLf10hP+rPVqnoccLgw==
dashdash@^1.12.0: dashdash@^1.12.0:
version "1.14.1" version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
@@ -2545,6 +2550,13 @@ lodash@^4.17.19:
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== 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: make-dir@^3.0.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
@@ -2713,9 +2725,9 @@ node-modules-regexp@^1.0.0:
integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=
node-notifier@^8.0.0: node-notifier@^8.0.0:
version "8.0.0" version "8.0.1"
resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.0.tgz#a7eee2d51da6d0f7ff5094bc7108c911240c1620" resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.1.tgz#f86e89bbc925f2b068784b31f382afdc6ca56be1"
integrity sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA== integrity sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==
dependencies: dependencies:
growly "^1.3.0" growly "^1.3.0"
is-wsl "^2.2.0" is-wsl "^2.2.0"
@@ -3163,10 +3175,12 @@ saxes@^5.0.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
semver@7.x, semver@^7.3.2: semver@7.x, semver@^7.3.2, semver@^7.3.4:
version "7.3.2" version "7.3.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97"
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==
dependencies:
lru-cache "^6.0.0"
semver@^6.0.0, semver@^6.3.0: semver@^6.0.0, semver@^6.3.0:
version "6.3.0" version "6.3.0"
@@ -3653,9 +3667,9 @@ uuid@^3.3.2:
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
uuid@^8.3.0: uuid@^8.3.0:
version "8.3.1" version "8.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.1.tgz#2ba2e6ca000da60fce5a196954ab241131e05a31" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg== integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
v8-to-istanbul@^6.0.1: v8-to-istanbul@^6.0.1:
version "6.0.1" version "6.0.1"
@@ -3808,6 +3822,11 @@ y18n@^4.0.0:
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== 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: yargs-parser@20.x:
version "20.2.3" version "20.2.3"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.3.tgz#92419ba867b858c868acf8bae9bf74af0dd0ce26" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.3.tgz#92419ba867b858c868acf8bae9bf74af0dd0ce26"