Compare commits

..

No commits in common. "master" and "v5.1.0" have entirely different histories.

49 changed files with 7594 additions and 7215 deletions

View file

@ -1,12 +1,2 @@
/coverage /coverage
/node_modules
# Dependency directories
node_modules/
jspm_packages/
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

3
.eslintignore Normal file
View file

@ -0,0 +1,3 @@
/dist/**
/coverage/**
/node_modules/**

24
.eslintrc.json Normal file
View file

@ -0,0 +1,24 @@
{
"env": {
"node": true,
"es6": true,
"jest": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:jest/recommended",
"plugin:prettier/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint",
"jest",
"prettier"
]
}

2
.gitattributes vendored
View file

@ -1,5 +1,3 @@
/.yarn/releases/** binary
/.yarn/plugins/** binary
/__tests__/fixtures/** -linguist-detectable /__tests__/fixtures/** -linguist-detectable
/dist/** linguist-generated=true /dist/** linguist-generated=true
/lib/** linguist-generated=true /lib/** linguist-generated=true

View file

@ -4,12 +4,6 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"
cooldown:
default-days: 2
groups:
crazy-max-dot-github:
patterns:
- "crazy-max/.github/*"
labels: labels:
- "dependencies" - "dependencies"
- "bot" - "bot"
@ -17,8 +11,6 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"
cooldown:
default-days: 2
versioning-strategy: "increase" versioning-strategy: "increase"
allow: allow:
- dependency-type: "production" - dependency-type: "production"

View file

@ -1,8 +1,5 @@
name: ci name: ci
permissions:
contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
@ -20,39 +17,14 @@ on:
env: env:
DOCKER_IMAGE: localhost:5000/name/app DOCKER_IMAGE: localhost:5000/name/app
BUILDX_VERSION: latest
jobs: jobs:
context:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
context:
- workflow
- git
steps:
-
name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
-
name: Docker meta
uses: ./
with:
context: ${{ matrix.context }}
multi-images: multi-images:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: ${{ env.BUILDX_VERSION }}
driver: docker
- -
name: Docker meta name: Docker meta
uses: ./ uses: ./
@ -83,13 +55,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: ${{ env.BUILDX_VERSION }}
driver: docker
- -
name: Docker meta name: Docker meta
uses: ./ uses: ./
@ -119,13 +85,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: ${{ env.BUILDX_VERSION }}
driver: docker
- -
name: Docker meta name: Docker meta
uses: ./ uses: ./
@ -153,13 +113,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: ${{ env.BUILDX_VERSION }}
driver: docker
- -
name: Docker meta name: Docker meta
uses: ./ uses: ./
@ -184,13 +138,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: ${{ env.BUILDX_VERSION }}
driver: docker
- -
name: Docker meta name: Docker meta
uses: ./ uses: ./
@ -207,13 +155,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: ${{ env.BUILDX_VERSION }}
driver: docker
- -
name: Docker meta name: Docker meta
uses: ./ uses: ./
@ -223,18 +165,12 @@ jobs:
name=ghcr.io/name/app,enable=${{ github.event_name == 'pull_request' }} name=ghcr.io/name/app,enable=${{ github.event_name == 'pull_request' }}
name=ghcr.io/name/release,enable=${{ startsWith(github.ref, 'refs/tags/') }} name=ghcr.io/name/release,enable=${{ startsWith(github.ref, 'refs/tags/') }}
custom-labels-annotations: labels:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: ${{ env.BUILDX_VERSION }}
driver: docker
- -
name: Docker meta name: Docker meta
uses: ./ uses: ./
@ -247,24 +183,13 @@ jobs:
org.opencontainers.image.title=MyCustomTitle org.opencontainers.image.title=MyCustomTitle
org.opencontainers.image.description=this is a "good" example org.opencontainers.image.description=this is a "good" example
org.opencontainers.image.vendor=MyCompany org.opencontainers.image.vendor=MyCompany
annotations: |
maintainer=Foo
org.opencontainers.image.title=MyFooTitle
org.opencontainers.image.description=this is a "foo" example
org.opencontainers.image.vendor=MyFooCompany
global-exps: global-exps:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: ${{ env.BUILDX_VERSION }}
driver: docker
- -
name: Docker meta name: Docker meta
uses: ./ uses: ./
@ -272,8 +197,6 @@ jobs:
images: | images: |
${{ env.DOCKER_IMAGE }} ${{ env.DOCKER_IMAGE }}
ghcr.io/name/app ghcr.io/name/app
labels: |
org.opencontainers.image.created={{commit_date 'YYYY-MM-DDTHH:mm:ss.SSS[Z]'}}
tags: | tags: |
type=sha type=sha
type=raw,value=gexp-branch-{{branch}} type=raw,value=gexp-branch-{{branch}}
@ -281,20 +204,13 @@ jobs:
type=raw,value=gexp-tag-{{tag}} type=raw,value=gexp-tag-{{tag}}
type=raw,value=gexp-baseref-{{base_ref}} type=raw,value=gexp-baseref-{{base_ref}}
type=raw,value=gexp-defbranch,enable={{is_default_branch}} type=raw,value=gexp-defbranch,enable={{is_default_branch}}
type=raw,value=gexp-notdefbranch,enable={{is_not_default_branch}}
json: json:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: ${{ env.BUILDX_VERSION }}
driver: docker
- -
name: Docker meta name: Docker meta
id: meta id: meta
@ -317,19 +233,13 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
services: services:
registry: registry:
image: registry:2.8.3@sha256:a3d8aaa63ed8681a604f1dea0aa03f100d5895b6a58ace528858a7b332415373 image: registry:2
ports: ports:
- 5000:5000 - 5000:5000
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: ${{ env.BUILDX_VERSION }}
driver-opts: network=host
- -
name: Docker meta name: Docker meta
id: docker_meta id: docker_meta
@ -346,9 +256,17 @@ jobs:
type=semver,pattern=v{{major}}.{{minor}} type=semver,pattern=v{{major}}.{{minor}}
type=semver,pattern=v{{major}} type=semver,pattern=v{{major}}
type=sha type=sha
-
name: Set up QEMU
uses: docker/setup-qemu-action@v3
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver-opts: network=host
- -
name: Build and push to local registry name: Build and push to local registry
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 uses: docker/build-push-action@v5
with: with:
context: ./test context: ./test
file: ./test/Dockerfile file: ./test/Dockerfile
@ -365,18 +283,17 @@ jobs:
name: Check manifest name: Check manifest
run: | run: |
docker buildx imagetools inspect ${{ env.DOCKER_IMAGE }}:${{ steps.docker_meta.outputs.version }} docker buildx imagetools inspect ${{ env.DOCKER_IMAGE }}:${{ steps.docker_meta.outputs.version }}
-
name: Dump context
if: always()
uses: crazy-max/ghaction-dump-context@v2
bake: bake:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: ${{ env.BUILDX_VERSION }}
- -
name: Docker meta name: Docker meta
id: docker_meta id: docker_meta
@ -394,14 +311,20 @@ jobs:
type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}} type=semver,pattern={{major}}
type=sha type=sha
-
name: Set up QEMU
uses: docker/setup-qemu-action@v3
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- -
name: Build name: Build
uses: docker/bake-action@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7.0.0 uses: docker/bake-action@v4
with: with:
files: | files: |
./test/docker-bake.hcl ./test/docker-bake.hcl
cwd://${{ steps.docker_meta.outputs.bake-file-tags }} ${{ steps.docker_meta.outputs.bake-file-tags }}
cwd://${{ steps.docker_meta.outputs.bake-file-labels }} ${{ steps.docker_meta.outputs.bake-file-labels }}
targets: | targets: |
release release
@ -416,13 +339,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: ${{ env.BUILDX_VERSION }}
driver: docker
- -
name: Docker meta name: Docker meta
id: meta id: meta
@ -434,7 +351,7 @@ jobs:
sep-tags: ${{ matrix.sep }} sep-tags: ${{ matrix.sep }}
- -
name: Tags name: Tags
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 uses: actions/github-script@v7
with: with:
script: | script: |
console.log(`${{ steps.meta.outputs.tags }}`); console.log(`${{ steps.meta.outputs.tags }}`);
@ -444,13 +361,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: ${{ env.BUILDX_VERSION }}
driver: docker
- -
name: Docker meta name: Docker meta
id: meta id: meta
@ -461,11 +372,9 @@ jobs:
ghcr.io/name/app ghcr.io/name/app
labels: | labels: |
maintainer=CrazyMax maintainer=CrazyMax
annotations: |
maintainer=Foo
- -
name: Build name: Build
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0 uses: docker/build-push-action@v5
with: with:
context: ./test context: ./test
file: ./test/output.Dockerfile file: ./test/output.Dockerfile
@ -473,46 +382,14 @@ jobs:
DOCKER_METADATA_OUTPUT_VERSION DOCKER_METADATA_OUTPUT_VERSION
DOCKER_METADATA_OUTPUT_TAGS DOCKER_METADATA_OUTPUT_TAGS
DOCKER_METADATA_OUTPUT_LABELS DOCKER_METADATA_OUTPUT_LABELS
DOCKER_METADATA_OUTPUT_ANNOTATIONS
DOCKER_METADATA_OUTPUT_JSON DOCKER_METADATA_OUTPUT_JSON
no-output-env:
runs-on: ubuntu-latest
env:
DOCKER_METADATA_SET_OUTPUT_ENV: false
steps:
-
name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
-
name: Docker meta
id: meta
uses: ./
with:
images: |
${{ env.DOCKER_IMAGE }}
ghcr.io/name/app
labels: |
maintainer=CrazyMax
annotations: |
maintainer=Foo
-
name: No output environment variables set
shell: bash
run: |
[[ "$(printenv | grep "^DOCKER_METADATA_OUTPUT_" | wc -l)" -eq 0 ]] || exit 1
bake-annotations: bake-annotations:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: ${{ env.BUILDX_VERSION }}
- -
name: Docker meta name: Docker meta
id: docker_meta id: docker_meta
@ -532,14 +409,22 @@ jobs:
type=sha type=sha
env: env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index
-
name: Set up QEMU
uses: docker/setup-qemu-action@v3
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
version: v0.12.0-rc1
- -
name: Build name: Build
uses: docker/bake-action@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7.0.0 uses: docker/bake-action@v4
with: with:
files: | files: |
./test/docker-bake.hcl ./test/docker-bake.hcl
cwd://${{ steps.docker_meta.outputs.bake-file-tags }} ${{ steps.docker_meta.outputs.bake-file-tags }}
cwd://${{ steps.docker_meta.outputs.bake-file-annotations }} ${{ steps.docker_meta.outputs.bake-file-annotations }}
targets: | targets: |
release release
@ -548,13 +433,7 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: ${{ env.BUILDX_VERSION }}
driver: docker
- -
name: Docker meta name: Docker meta
uses: ./ uses: ./
@ -568,70 +447,3 @@ jobs:
- -
name: Print envs name: Print envs
run: env|sort run: env|sort
bake-path-context:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: latest
-
name: Docker meta
id: docker_meta
uses: ./
-
name: Build
uses: docker/bake-action@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7.0.0
with:
source: .
files: |
./test/docker-bake.hcl
${{ steps.docker_meta.outputs.bake-file-tags }}
${{ steps.docker_meta.outputs.bake-file-labels }}
targets: |
release
sha-short:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
short-length:
- ''
- 16
steps:
-
name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
version: ${{ env.BUILDX_VERSION }}
driver: docker
-
name: Docker meta
uses: ./
with:
images: |
${{ env.DOCKER_IMAGE }}
ghcr.io/name/app
tags: |
type=sha
env:
DOCKER_METADATA_SHORT_SHA_LENGTH: ${{ matrix.short-length }}
dump:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
-
name: Dump context
uses: crazy-max/ghaction-dump-context@5d2753e7076f4568c7729971e25231f32147e2d8 # v3.0.0

View file

@ -1,46 +0,0 @@
name: codeql
permissions:
contents: read
on:
push:
branches:
- 'master'
- 'releases/v*'
pull_request:
env:
NODE_VERSION: "24"
jobs:
analyze:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
-
name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
-
name: Enable corepack
run: |
corepack enable
yarn --version
-
name: Set up Node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: ${{ env.NODE_VERSION }}
-
name: Initialize CodeQL
uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
with:
languages: javascript-typescript
build-mode: none
-
name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
with:
category: "/language:javascript-typescript"

View file

@ -1,17 +0,0 @@
name: pr-assign-author
permissions:
contents: read
on:
pull_request_target: # zizmor: ignore[dangerous-triggers] safe to use without checkout
types:
- opened
- reopened
jobs:
run:
uses: crazy-max/.github/.github/workflows/pr-assign-author.yml@d89fe92d808a15e2b2ed5cdb62db7c172c31410d # v1.6.0
permissions:
contents: read
pull-requests: write

View file

@ -1,28 +0,0 @@
name: publish
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
release:
types:
- published
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
packages: write
steps:
-
name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
-
name: Publish
uses: actions/publish-immutable-action@4bc8754ffc40f27910afb20287dbbbb675a4e978 # v0.0.4

View file

@ -1,8 +1,5 @@
name: test name: test
permissions:
contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
@ -20,16 +17,14 @@ jobs:
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Test name: Test
uses: docker/bake-action@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7.0.0 uses: docker/bake-action@v4
with: with:
source: .
targets: test targets: test
- -
name: Upload coverage name: Upload coverage
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 uses: codecov/codecov-action@v3
with: with:
files: ./coverage/clover.xml file: ./coverage/clover.xml
token: ${{ secrets.CODECOV_TOKEN }}

View file

@ -1,56 +0,0 @@
name: update-dist
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
pull_request:
types:
- opened
- synchronize
jobs:
update-dist:
if: github.actor == 'dependabot[bot]' && github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == github.event.pull_request.head.repo.full_name
runs-on: ubuntu-latest
steps:
-
name: GitHub auth token from GitHub App
id: docker-read-app
uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3.0.0
with:
app-id: ${{ secrets.GHACTIONS_REPO_WRITE_APP_ID }}
private-key: ${{ secrets.GHACTIONS_REPO_WRITE_APP_PRIVATE_KEY }}
owner: docker
-
name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0
token: ${{ steps.docker-read-app.outputs.token }}
-
name: Build
uses: docker/bake-action@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7.0.0
with:
source: .
targets: build
-
name: Commit and push dist
run: |
if [ -n "$(git status --porcelain -- dist)" ]; then
(
set -x
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add dist
git commit -m "chore: update generated content"
git push
)
else
echo "No changes in dist"
fi

View file

@ -1,8 +1,5 @@
name: validate name: validate
permissions:
contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
@ -18,17 +15,16 @@ jobs:
prepare: prepare:
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
matrix: ${{ steps.generate.outputs.matrix }} targets: ${{ steps.targets.outputs.matrix }}
steps: steps:
- -
name: Checkout name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@v4
- -
name: Generate matrix name: Targets matrix
id: generate id: targets
uses: docker/bake-action/subaction/matrix@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7.0.0 run: |
with: echo "matrix=$(docker buildx bake validate --print | jq -cr '.group.validate.targets')" >> $GITHUB_OUTPUT
target: validate
validate: validate:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -37,10 +33,13 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
include: ${{ fromJson(needs.prepare.outputs.matrix) }} target: ${{ fromJson(needs.prepare.outputs.targets) }}
steps: steps:
-
name: Checkout
uses: actions/checkout@v4
- -
name: Validate name: Validate
uses: docker/bake-action@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7.0.0 uses: docker/bake-action@v4
with: with:
targets: ${{ matrix.target }} targets: ${{ matrix.target }}

View file

@ -1,29 +0,0 @@
name: zizmor
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
workflow_dispatch:
push:
branches:
- 'master'
- 'releases/v*'
tags:
- 'v*'
pull_request:
jobs:
zizmor:
uses: crazy-max/.github/.github/workflows/zizmor.yml@d89fe92d808a15e2b2ed5cdb62db7c172c31410d # v1.6.0
permissions:
contents: read
security-events: write
with:
min-severity: medium
min-confidence: medium
persona: pedantic

3
.github/zizmor.yml vendored
View file

@ -1,3 +0,0 @@
rules:
secrets-outside-env: # FIXME: remove this rule when zizmor 1.24.0 is released, fixing the right persona attached to this rule: https://github.com/zizmorcore/zizmor/pull/1783
disable: true

71
.gitignore vendored
View file

@ -1,5 +1,12 @@
# https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore /.dev
node_modules/
lib
# Jetbrains
/.idea
/*.iml
# Rest of the file pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
# Logs # Logs
logs logs
*.log *.log
@ -7,7 +14,6 @@ npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
lerna-debug.log* lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html) # Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
@ -18,14 +24,34 @@ pids
*.seed *.seed
*.pid.lock *.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul # Coverage directory used by tools like istanbul
coverage coverage
*.lcov *.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories # Dependency directories
node_modules/
jspm_packages/ jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache # TypeScript cache
*.tsbuildinfo *.tsbuildinfo
@ -35,19 +61,36 @@ jspm_packages/
# Optional eslint cache # Optional eslint cache
.eslintcache .eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file # Yarn Integrity file
.yarn-integrity .yarn-integrity
# dotenv environment variable files # dotenv environment variables file
.env .env
.env.development.local .env.test
.env.test.local
.env.production.local
.env.local
# yarn v2 # parcel-bundler cache (https://parceljs.org/)
.yarn/cache .cache
.yarn/unplugged
.yarn/build-state.yml # next.js build output
.yarn/install-state.gz .next
.pnp.*
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/

View file

@ -1,6 +0,0 @@
# Dependency directories
node_modules/
jspm_packages/
# yarn v2
.yarn/

View file

@ -6,5 +6,6 @@
"singleQuote": true, "singleQuote": true,
"trailingComma": "none", "trailingComma": "none",
"bracketSpacing": false, "bracketSpacing": false,
"arrowParens": "avoid" "arrowParens": "avoid",
"parser": "typescript"
} }

View file

@ -1,17 +0,0 @@
# https://yarnpkg.com/configuration/yarnrc
compressionLevel: mixed
enableGlobalCache: false
enableHardenedMode: true
logFilters:
- code: YN0013
level: discard
- code: YN0019
level: discard
- code: YN0076
level: discard
- code: YN0086
level: discard
nodeLinker: node-modules

229
README.md
View file

@ -44,12 +44,10 @@ ___
* [`{{sha}}`](#sha) * [`{{sha}}`](#sha)
* [`{{base_ref}}`](#base_ref) * [`{{base_ref}}`](#base_ref)
* [`{{is_default_branch}}`](#is_default_branch) * [`{{is_default_branch}}`](#is_default_branch)
* [`{{is_not_default_branch}}`](#is_not_default_branch)
* [`{{date '<format>' tz='<timezone>'}}`](#date-format-tztimezone) * [`{{date '<format>' tz='<timezone>'}}`](#date-format-tztimezone)
* [`{{commit_date '<format>' tz='<timezone>'}}`](#commit_date-format-tztimezone)
* [Major version zero](#major-version-zero) * [Major version zero](#major-version-zero)
* [JSON output object](#json-output-object) * [JSON output object](#json-output-object)
* [Overwrite labels and annotations](#overwrite-labels-and-annotations) * [Overwrite labels](#overwrite-labels)
* [Annotations](#annotations) * [Annotations](#annotations)
* [Contributing](#contributing) * [Contributing](#contributing)
@ -75,23 +73,27 @@ jobs:
docker: docker:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
-
name: Checkout
uses: actions/checkout@v4
- -
name: Docker meta name: Docker meta
id: meta id: meta
uses: docker/metadata-action@v6 uses: docker/metadata-action@v5
with: with:
images: name/app images: name/app
- -
name: Login to DockerHub name: Login to DockerHub
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'
uses: docker/login-action@v4 uses: docker/login-action@v3
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- -
name: Build and push name: Build and push
uses: docker/build-push-action@v7 uses: docker/build-push-action@v5
with: with:
context: .
push: ${{ github.event_name != 'pull_request' }} push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
@ -125,10 +127,13 @@ jobs:
docker: docker:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
-
name: Checkout
uses: actions/checkout@v4
- -
name: Docker meta name: Docker meta
id: meta id: meta
uses: docker/metadata-action@v6 uses: docker/metadata-action@v5
with: with:
images: | images: |
name/app name/app
@ -140,14 +145,15 @@ jobs:
- -
name: Login to DockerHub name: Login to DockerHub
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'
uses: docker/login-action@v4 uses: docker/login-action@v3
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- -
name: Build and push name: Build and push
uses: docker/build-push-action@v7 uses: docker/build-push-action@v5
with: with:
context: .
push: ${{ github.event_name != 'pull_request' }} push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
@ -199,10 +205,13 @@ jobs:
docker: docker:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
-
name: Checkout
uses: actions/checkout@v4
- -
name: Docker meta name: Docker meta
id: meta id: meta
uses: docker/metadata-action@v6 uses: docker/metadata-action@v5
with: with:
images: | images: |
name/app name/app
@ -214,11 +223,11 @@ jobs:
type=sha type=sha
- -
name: Build name: Build
uses: docker/bake-action@v7 uses: docker/bake-action@v3
with: with:
files: | files: |
./docker-bake.hcl ./docker-bake.hcl
cwd://${{ steps.meta.outputs.bake-file }} ${{ steps.meta.outputs.bake-file }}
targets: build targets: build
``` ```
@ -261,12 +270,12 @@ similar to the previous one:
```yaml ```yaml
- -
name: Build name: Build
uses: docker/bake-action@v7 uses: docker/bake-action@v3
with: with:
files: | files: |
./docker-bake.hcl ./docker-bake.hcl
cwd://${{ steps.meta.outputs.bake-file-tags }} ${{ steps.meta.outputs.bake-file-tags }}
cwd://${{ steps.meta.outputs.bake-file-labels }} ${{ steps.meta.outputs.bake-file-labels }}
targets: build targets: build
``` ```
@ -276,7 +285,6 @@ similar to the previous one:
The following inputs can be used as `step.with` keys: The following inputs can be used as `step.with` keys:
> [!NOTE]
> `List` type is a newline-delimited string > `List` type is a newline-delimited string
> ```yaml > ```yaml
> labels: | > labels: |
@ -285,18 +293,16 @@ The following inputs can be used as `step.with` keys:
> org.opencontainers.image.vendor=MyCompany > org.opencontainers.image.vendor=MyCompany
> ``` > ```
| Name | Type | Description | | Name | Type | Description |
|-------------------|--------|------------------------------------------------------------------------------| |---------------|--------|-------------------------------------------------------------------------------|
| `context` | String | Where to get context data. Allowed options are: `workflow` (default), `git`. | | `context` | String | Where to get context data. Allowed options are: `workflow` (default), `git`. |
| `images` | List | List of Docker images to use as base name for tags | | `images` | List | List of Docker images to use as base name for tags |
| `tags` | List | List of [tags](#tags-input) as key-value pair attributes | | `tags` | List | List of [tags](#tags-input) as key-value pair attributes |
| `flavor` | List | [Flavor](#flavor-input) to apply | | `flavor` | List | [Flavor](#flavor-input) to apply |
| `labels` | List | List of custom labels | | `labels` | List | List of custom labels |
| `annotations` | List | List of custom annotations | | `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`) | | `bake-target` | String | Bake target name (default `docker-metadata-action`) |
| `sep-annotations` | String | Separator to use for annotations output (default `\n`) |
| `bake-target` | String | Bake target name (default `docker-metadata-action`) |
### outputs ### outputs
@ -306,7 +312,6 @@ The following outputs are available:
|-------------------------|--------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------| |-------------------------|--------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `version` | String | Docker image version | | `version` | String | Docker image version |
| `tags` | String | Docker tags | | `tags` | String | Docker tags |
| `tag-names` | String | Docker tag names without image base name |
| `labels` | String | Docker labels | | `labels` | String | Docker labels |
| `annotations` | String | [Annotations](https://github.com/moby/buildkit/blob/master/docs/annotations.md) | | `annotations` | String | [Annotations](https://github.com/moby/buildkit/blob/master/docs/annotations.md) |
| `json` | String | JSON output of tags and labels | | `json` | String | JSON output of tags and labels |
@ -314,7 +319,7 @@ The following outputs are available:
| `bake-file-labels` | File | [Bake file definition](https://docs.docker.com/build/bake/reference/) path with labels | | `bake-file-labels` | File | [Bake file definition](https://docs.docker.com/build/bake/reference/) path with labels |
| `bake-file-annotations` | File | [Bake file definition](https://docs.docker.com/build/bake/reference/) path with [annotations](https://github.com/moby/buildkit/blob/master/docs/annotations.md) | | `bake-file-annotations` | File | [Bake file definition](https://docs.docker.com/build/bake/reference/) path with [annotations](https://github.com/moby/buildkit/blob/master/docs/annotations.md) |
Alternatively, each output is also exported as an environment variable when `DOCKER_METADATA_SET_OUTPUT_ENV` is `true`: Alternatively, each output is also exported as an environment variable:
* `DOCKER_METADATA_OUTPUT_VERSION` * `DOCKER_METADATA_OUTPUT_VERSION`
* `DOCKER_METADATA_OUTPUT_TAGS` * `DOCKER_METADATA_OUTPUT_TAGS`
@ -328,7 +333,7 @@ Alternatively, each output is also exported as an environment variable when `DOC
So it can be used with our [Docker Build Push action](https://github.com/docker/build-push-action/): So it can be used with our [Docker Build Push action](https://github.com/docker/build-push-action/):
```yaml ```yaml
- uses: docker/build-push-action@v7 - uses: docker/build-push-action@v5
with: with:
build-args: | build-args: |
DOCKER_METADATA_OUTPUT_JSON DOCKER_METADATA_OUTPUT_JSON
@ -336,12 +341,10 @@ So it can be used with our [Docker Build Push action](https://github.com/docker/
### environment variables ### environment variables
| Name | Type | Description | | Name | Type | Description |
|--------------------------------------|--------|----------------------------------------------------------------------------------------------------------------------------------------------| |--------------------------------------|--------|------------------------------------------------------------------------------------------------------------|
| `DOCKER_METADATA_PR_HEAD_SHA` | Bool | If `true`, set associated head SHA instead of commit SHA that triggered the workflow on pull request event | | `DOCKER_METADATA_PR_HEAD_SHA` | Bool | If `true`, set associated head SHA instead of commit SHA that triggered the workflow on pull request event |
| `DOCKER_METADATA_SHORT_SHA_LENGTH` | Number | Specifies the length of the [short commit SHA](#typesha) to ensure uniqueness. Default is `7`, but can be increased for larger repositories. | | `DOCKER_METADATA_ANNOTATIONS_LEVELS` | String | Comma separated list of annotations levels to set for annotations output separated (default `manifest`) |
| `DOCKER_METADATA_ANNOTATIONS_LEVELS` | String | Comma separated list of annotations levels to set for annotations output separated (default `manifest`) |
| `DOCKER_METADATA_SET_OUTPUT_ENV` | Bool | If `true`, sets each output as an environment variable (default `true`) |
## `context` input ## `context` input
@ -456,7 +459,7 @@ tags: |
# handlebars # handlebars
type=schedule,pattern={{date 'YYYYMMDD'}} type=schedule,pattern={{date 'YYYYMMDD'}}
# handlebars with timezone # handlebars with timezone
type=schedule,pattern={{date 'YYYYMMDD-HHmmss' tz='Asia/Tokyo'}} type=schedule,pattern={{date 'YYYYMMDD-hhmmss' tz='Asia/Tokyo'}}
``` ```
Will be used on [schedule event](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule). Will be used on [schedule event](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule).
@ -488,8 +491,6 @@ tags: |
type=semver,pattern={{version}} type=semver,pattern={{version}}
# use custom value instead of git tag # use custom value instead of git tag
type=semver,pattern={{version}},value=v1.0.0 type=semver,pattern={{version}},value=v1.0.0
# use custom value and match part of it
type=semver,pattern={{version}},value=p1/v1.0.0,match=v(\d.\d.\d)$
``` ```
Will be used on a [push tag event](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#push) Will be used on a [push tag event](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#push)
@ -505,21 +506,18 @@ with the following expressions:
* `minor` ; minor version identifier * `minor` ; minor version identifier
* `patch` ; patch version identifier * `patch` ; patch version identifier
| Git tag | Pattern | Match | Output | | Git tag | Pattern | Output |
|------------------|-----------------------|----------------|------------------| |--------------------|----------------------------------------------------------|----------------------|
| `v1.2.3` | `{{raw}}` | | `v1.2.3` | | `v1.2.3` | `{{raw}}` | `v1.2.3` |
| `v1.2.3` | `{{version}}` | | `1.2.3` | | `v1.2.3` | `{{version}}` | `1.2.3` |
| `v1.2.3` | `{{major}}.{{minor}}` | | `1.2` | | `v1.2.3` | `{{major}}.{{minor}}` | `1.2` |
| `v1.2.3` | `v{{major}}` | | `v1` | | `v1.2.3` | `v{{major}}` | `v1` |
| `v1.2.3` | `{{minor}}` | | `2` | | `v1.2.3` | `{{minor}}` | `2` |
| `v1.2.3` | `{{patch}}` | | `3` | | `v1.2.3` | `{{patch}}` | `3` |
| `p1/v1.2.3` | `{{version}}` | `v(\d.\d.\d)$` | `1.2.3` | | `v2.0.8-beta.67` | `{{raw}}` | `v2.0.8-beta.67` |
| `v2.0.8-beta.67` | `{{raw}}` | | `v2.0.8-beta.67` | | `v2.0.8-beta.67` | `{{version}}` | `2.0.8-beta.67` |
| `v2.0.8-beta.67` | `{{version}}` | | `2.0.8-beta.67` | | `v2.0.8-beta.67` | `{{major}}.{{minor}}` | `2.0.8-beta.67`* |
| `v2.0.8-beta.67` | `{{major}}` | | `2.0.8-beta.67`* |
| `v2.0.8-beta.67` | `{{major}}.{{minor}}` | | `2.0.8-beta.67`* |
> [!IMPORTANT]
> *Pre-release (rc, beta, alpha) will only extend `{{version}}` (or `{{raw}}` > *Pre-release (rc, beta, alpha) will only extend `{{version}}` (or `{{raw}}`
> if specified) as tag because they are updated frequently, and contain many > if specified) as tag because they are updated frequently, and contain many
> breaking changes that are (by the author's design) not yet fit for public > breaking changes that are (by the author's design) not yet fit for public
@ -529,7 +527,7 @@ Extended attributes and default values:
```yaml ```yaml
tags: | tags: |
type=semver,enable=true,priority=900,prefix=,suffix=,pattern=,value=,match= type=semver,enable=true,priority=900,prefix=,suffix=,pattern=,value=
``` ```
### `type=pep440` ### `type=pep440`
@ -540,8 +538,6 @@ tags: |
type=pep440,pattern={{version}} type=pep440,pattern={{version}}
# use custom value instead of git tag # use custom value instead of git tag
type=pep440,pattern={{version}},value=1.0.0 type=pep440,pattern={{version}},value=1.0.0
# use custom value and match part of it
type=pep440,pattern={{version}},value=p1/v1.0.0,match=v(\d.\d.\d)$
``` ```
Will be used on a [push tag event](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#push) Will be used on a [push tag event](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#push)
@ -557,22 +553,20 @@ with the following expressions:
* `minor` ; minor version identifier * `minor` ; minor version identifier
* `patch` ; patch version identifier * `patch` ; patch version identifier
| Git tag | Pattern | Match | Output | | Git tag | Pattern | Output |
|--------------|-----------------------|----------------|----------------| |--------------------|----------------------------------------------------------|----------------------|
| `1.2.3` | `{{raw}}` | | `1.2.3` | | `1.2.3` | `{{raw}}` | `1.2.3` |
| `1.2.3` | `{{version}}` | | `1.2.3` | | `1.2.3` | `{{version}}` | `1.2.3` |
| `v1.2.3` | `{{version}}` | | `1.2.3` | | `v1.2.3` | `{{version}}` | `1.2.3` |
| `1.2.3` | `{{major}}.{{minor}}` | | `1.2` | | `1.2.3` | `{{major}}.{{minor}}` | `1.2` |
| `1.2.3` | `v{{major}}` | | `v1` | | `1.2.3` | `v{{major}}` | `v1` |
| `v1.2.3rc2` | `{{raw}}` | | `v1.2.3rc2` | | `v1.2.3rc2` | `{{raw}}` | `v1.2.3rc2` |
| `1.2.3rc2` | `{{version}}` | | `1.2.3rc2` | | `1.2.3rc2` | `{{version}}` | `1.2.3rc2` |
| `p1/v1.2.3` | `{{version}}` | `v(\d.\d.\d)$` | `1.2.3` | | `1.2.3rc2` | `{{major}}.{{minor}}` | `1.2.3rc2`* |
| `1.2.3rc2` | `{{major}}.{{minor}}` | | `1.2.3rc2`* | | `1.2.3post1` | `{{major}}.{{minor}}` | `1.2.3.post1`* |
| `1.2.3post1` | `{{major}}.{{minor}}` | | `1.2.3.post1`* | | `1.2.3beta2` | `{{major}}.{{minor}}` | `1.2.3b2`* |
| `1.2.3beta2` | `{{major}}.{{minor}}` | | `1.2.3b2`* | | `1.0dev4` | `{{major}}.{{minor}}` | `1.0.dev4`* |
| `1.0dev4` | `{{major}}.{{minor}}` | | `1.0.dev4`* |
> [!IMPORTANT]
> *dev/pre/post release will only extend `{{version}}` (or `{{raw}}` if > *dev/pre/post release will only extend `{{version}}` (or `{{raw}}` if
> specified) as tag because they are updated frequently, and contain many > specified) as tag because they are updated frequently, and contain many
> breaking changes that are (by the author's design) not yet fit for public > breaking changes that are (by the author's design) not yet fit for public
@ -709,26 +703,7 @@ tags: |
type=sha,format=long type=sha,format=long
``` ```
Output Git short commit (or long if specified) as Docker tag like Output Git short commit (or long if specified) as Docker tag like `sha-ad132f5`.
`sha-860c190`.
By default, the length of the short commit SHA is `7` characters. You can
increase this length for larger repositories by setting the
[`DOCKER_METADATA_SHORT_SHA_LENGTH` environment variable](#environment-variables):
```yaml
-
name: Docker meta
id: meta
uses: docker/metadata-action@v6
with:
images: |
name/app
tags: |
type=sha
env:
DOCKER_METADATA_SHORT_SHA_LENGTH: 12
```
Extended attributes and default values: Extended attributes and default values:
@ -762,7 +737,6 @@ generated by default (`auto` mode) for:
* [`type=ref,event=tag`](#typeref) * [`type=ref,event=tag`](#typeref)
* [`type=semver,pattern=...`](#typesemver) * [`type=semver,pattern=...`](#typesemver)
* [`type=pep440,pattern=...`](#typepep440)
* [`type=match,pattern=...`](#typematch) * [`type=match,pattern=...`](#typematch)
For conditionally tagging with latest for a specific branch name, e.g. if your For conditionally tagging with latest for a specific branch name, e.g. if your
@ -804,8 +778,7 @@ Each tags `type` attribute has a default priority:
### Global expressions ### Global expressions
The following [Handlebars' template](https://handlebarsjs.com/guide/) expressions The following [Handlebars' template](https://handlebarsjs.com/guide/) expressions
for `prefix`, `suffix`, `value` and `enable` attributes of `tags` input are for `prefix`, `suffix`, `value` and `enable` attributes are available:
available:
```yaml ```yaml
tags: | tags: |
@ -815,13 +788,6 @@ tags: |
type=raw,value=mytag-{{branch}}-{{sha}} type=raw,value=mytag-{{branch}}-{{sha}}
``` ```
They can also be applied to `labels` and `annotations` inputs:
```yaml
labels: |
org.opencontainers.image.created={{commit_date 'YYYY-MM-DDTHH:mm:ss.SSS[Z]'}}
```
#### `{{branch}}` #### `{{branch}}`
Returns the branch name that triggered the workflow run. Will be empty if not Returns the branch name that triggered the workflow run. Will be empty if not
@ -862,7 +828,6 @@ workflow run. Will be empty for a branch reference:
| `push` | `refs/heads/my/branch` | | | `push` | `refs/heads/my/branch` | |
| `push tag`* | `refs/tags/v1.2.3` | `master` | | `push tag`* | `refs/tags/v1.2.3` | `master` |
> [!IMPORTANT]
> *`base_ref` is available in the push payload but doesn't always seem to > *`base_ref` is available in the push payload but doesn't always seem to
> return the expected branch when the push tag event occurs. It's also > return the expected branch when the push tag event occurs. It's also
> [not documented in GitHub docs](https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#push). > [not documented in GitHub docs](https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#push).
@ -874,11 +839,6 @@ workflow run. Will be empty for a branch reference:
Returns `true` if the branch that triggered the workflow run is the default Returns `true` if the branch that triggered the workflow run is the default
one, otherwise `false`. one, otherwise `false`.
#### `{{is_not_default_branch}}`
Returns `true` if the branch that triggered the workflow run is not the default
one, otherwise `false`.
#### `{{date '<format>' tz='<timezone>'}}` #### `{{date '<format>' tz='<timezone>'}}`
Returns the current date rendered by its [moment format](https://momentjs.com/docs/#/displaying/format/). Returns the current date rendered by its [moment format](https://momentjs.com/docs/#/displaying/format/).
@ -890,20 +850,6 @@ Default `tz` is UTC.
| `{{date 'dddd, MMMM Do YYYY, h:mm:ss a'}}` | `Friday, January 10th 2020, 3:25:50 pm` | | `{{date 'dddd, MMMM Do YYYY, h:mm:ss a'}}` | `Friday, January 10th 2020, 3:25:50 pm` |
| `{{date 'YYYYMMDD-HHmmss' tz='Asia/Tokyo'}}` | `20200110-093000` | | `{{date 'YYYYMMDD-HHmmss' tz='Asia/Tokyo'}}` | `20200110-093000` |
#### `{{commit_date '<format>' tz='<timezone>'}}`
Returns the date when the current git commit is committed, rendered by its
[moment format](https://momentjs.com/docs/#/displaying/format/). It falls back
to the current date if the commit date is not available.
Default `tz` is UTC.
| Expression | Output example |
|-----------------------------------------------------|-----------------------------------------|
| `{{commit_date 'YYYYMMDD'}}` | `20200110` |
| `{{commit_date 'dddd, MMMM Do YYYY, h:mm:ss a'}}` | `Friday, January 10th 2020, 3:25:50 pm` |
| `{{commit_date 'YYYYMMDD-HHmmss' tz='Asia/Tokyo'}}` | `20200110-093000` |
### Major version zero ### Major version zero
Major version zero (`0.y.z`) is for initial development and **may** change at Major version zero (`0.y.z`) is for initial development and **may** change at
@ -931,13 +877,13 @@ that you can reuse them further in your workflow using the [`fromJSON` function]
```yaml ```yaml
- -
name: Docker meta name: Docker meta
uses: docker/metadata-action@v6 uses: docker/metadata-action@v5
id: meta id: meta
with: with:
images: name/app images: name/app
- -
name: Build and push name: Build and push
uses: docker/build-push-action@v7 uses: docker/build-push-action@v5
with: with:
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
@ -947,17 +893,16 @@ that you can reuse them further in your workflow using the [`fromJSON` function]
REVISION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }} REVISION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }}
``` ```
### Overwrite labels and annotations ### Overwrite labels
If some [OCI Image Format Specification](https://github.com/opencontainers/image-spec/blob/master/annotations.md) If some [OCI Image Format Specification](https://github.com/opencontainers/image-spec/blob/master/annotations.md)
generated are not suitable as labels/annotations, you can overwrite them like labels generated are not suitable, you can overwrite them like this:
this:
```yaml ```yaml
- -
name: Docker meta name: Docker meta
id: meta id: meta
uses: docker/metadata-action@v6 uses: docker/metadata-action@v5
with: with:
images: name/app images: name/app
labels: | labels: |
@ -979,12 +924,12 @@ of the `metadata-action`:
```yaml ```yaml
- -
name: Docker meta name: Docker meta
uses: docker/metadata-action@v6 uses: docker/metadata-action@v5
with: with:
images: name/app images: name/app
- -
name: Build and push name: Build and push
uses: docker/build-push-action@v7 uses: docker/build-push-action@v5
with: with:
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
annotations: ${{ steps.meta.outputs.annotations }} annotations: ${{ steps.meta.outputs.annotations }}
@ -995,43 +940,35 @@ The same can be done with the [`bake-action`](https://github.com/docker/bake-act
```yaml ```yaml
- -
name: Docker meta name: Docker meta
uses: docker/metadata-action@v6 uses: docker/metadata-action@v5
with: with:
images: name/app images: name/app
- -
name: Build name: Build
uses: docker/bake-action@v7 uses: docker/bake-action@v3
with: with:
files: | files: |
./docker-bake.hcl ./docker-bake.hcl
cwd://${{ steps.meta.outputs.bake-file-tags }} ${{ steps.meta.outputs.bake-file-tags }}
cwd://${{ steps.meta.outputs.bake-file-annotations }} ${{ steps.meta.outputs.bake-file-annotations }}
targets: build targets: build
``` ```
Note that annotations can be attached at many different levels within a manifest. If you want to set specific level(s) for your annotations, you can use the
By default, the generated annotations will be attached to image manifests,
but different registries may expect annotations at different places;
a common practice is to read annotations at _image indexes_ if present,
which are often used by multi-arch builds to index platform-specific images.
If you want to specify level(s) for your annotations, you can use the
[`DOCKER_METADATA_ANNOTATIONS_LEVELS` environment variable](#environment-variables) [`DOCKER_METADATA_ANNOTATIONS_LEVELS` environment variable](#environment-variables)
with a comma separated list of all levels the annotations should be attached to (defaults to `manifest`). with a comma separated list of levels (defaults to `manifest`):
The following configuration demonstrates the ability to attach annotations to both image manifests and image indexes,
though your registry may only need annotations at the index level. (That is, `index` alone may be enough.)
Please consult the documentation of your registry.
```yaml ```yaml
- -
name: Docker meta name: Docker meta
uses: docker/metadata-action@v6 uses: docker/metadata-action@v5
with: with:
images: name/app images: name/app
env: env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index
- -
name: Build and push name: Build and push
uses: docker/build-push-action@v7 uses: docker/build-push-action@v5
with: with:
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
annotations: ${{ steps.meta.outputs.annotations }} annotations: ${{ steps.meta.outputs.annotations }}

300
UPGRADE.md Normal file
View file

@ -0,0 +1,300 @@
# Upgrade notes
## v2 to v3
* Repository has been moved to docker org. Replace `crazy-max/ghaction-docker-meta@v2`
with `docker/metadata-action@v5`
* The default bake target has been changed: `ghaction-docker-meta` > `docker-metadata-action`
## v1 to v2
* [inputs](#inputs)
* [`tag-sha`](#tag-sha)
* [`tag-edge` / `tag-edge-branch`](#tag-edge--tag-edge-branch)
* [`tag-semver`](#tag-semver)
* [`tag-match` / `tag-match-group`](#tag-match--tag-match-group)
* [`tag-latest`](#tag-latest)
* [`tag-schedule`](#tag-schedule)
* [`tag-custom` / `tag-custom-only`](#tag-custom--tag-custom-only)
* [`label-custom`](#label-custom)
* [Basic workflow](#basic-workflow)
* [Semver workflow](#semver-workflow)
### inputs
| New | Unchanged | Removed |
|------------|-----------------|--------------------|
| `tags` | `images` | `tag-sha` |
| `flavor` | `sep-tags` | `tag-edge` |
| `labels` | `sep-labels` | `tag-edge-branch` |
| | | `tag-semver` |
| | | `tag-match` |
| | | `tag-match-group` |
| | | `tag-latest` |
| | | `tag-schedule` |
| | | `tag-custom` |
| | | `tag-custom-only` |
| | | `label-custom` |
#### `tag-sha`
```yaml
tags: |
type=sha
```
#### `tag-edge` / `tag-edge-branch`
```yaml
tags: |
# default branch
type=edge
# specify branch
type=edge,branch=main
```
#### `tag-semver`
```yaml
tags: |
type=semver,pattern={{version}}
```
#### `tag-match` / `tag-match-group`
```yaml
tags: |
type=match,pattern=v(.*),group=1
```
#### `tag-latest`
`tag-latest` is now handled through the [`flavor` input](README.md#flavor-input):
```yaml
flavor: |
latest=auto
```
See also the notes about ["latest tag" behavior](README.md#latest-tag)
#### `tag-schedule`
```yaml
tags: |
# default tag (nightly)
type=schedule
# specific pattern
type=schedule,pattern={{date 'YYYYMMDD'}}
```
#### `tag-custom` / `tag-custom-only`
```yaml
tags: |
type=raw,value=foo
type=raw,value=bar
# or
type=raw,foo
type=raw,bar
# or
foo
bar
```
#### `label-custom`
Same behavior for `labels`:
```yaml
labels: |
maintainer=CrazyMax
```
### Basic workflow
```yaml
# v1
name: ci
on:
push:
branches:
- 'master'
tags:
- 'v*'
pull_request:
branches:
- 'master'
jobs:
docker:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Docker meta
id: meta
uses: docker/metadata-action@v1
with:
images: name/app
-
name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
```
```yaml
# v2
name: ci
on:
push:
branches:
- 'master'
tags:
- 'v*'
pull_request:
branches:
- 'master'
jobs:
docker:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: name/app
-
name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
```
### Semver workflow
```yaml
# v1
name: ci
on:
push:
branches:
- 'master'
tags:
- 'v*'
pull_request:
branches:
- 'master'
jobs:
docker:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Docker meta
id: meta
uses: docker/metadata-action@v1
with:
images: name/app
tag-semver: |
{{version}}
{{major}}.{{minor}}
-
name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
```
```yaml
# v2
name: ci
on:
push:
branches:
- 'master'
tags:
- 'v*'
pull_request:
branches:
- 'master'
jobs:
docker:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: name/app
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
-
name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
```

View file

@ -0,0 +1,207 @@
import {jest} from '@jest/globals';
export const context = {
repo: {
owner: 'docker',
repo: 'actions-toolkit'
},
ref: 'refs/heads/master',
runId: 123,
payload: {
after: '860c1904a1ce19322e91ac35af1ab07466440c37',
base_ref: null,
before: '5f3331d7f7044c18ca9f12c77d961c4d7cf3276a',
commits: [
{
author: {
email: 'crazy-max@users.noreply.github.com',
name: 'CrazyMax',
username: 'crazy-max'
},
committer: {
email: 'crazy-max@users.noreply.github.com',
name: 'CrazyMax',
username: 'crazy-max'
},
distinct: true,
id: '860c1904a1ce19322e91ac35af1ab07466440c37',
message: 'hello dev',
timestamp: '2022-04-19T11:27:24+02:00',
tree_id: 'd2c60af597e863787d2d27f569e30495b0b92820',
url: 'https://github.com/docker/test-docker-action/commit/860c1904a1ce19322e91ac35af1ab07466440c37'
}
],
compare: 'https://github.com/docker/test-docker-action/compare/5f3331d7f704...860c1904a1ce',
created: false,
deleted: false,
forced: false,
head_commit: {
author: {
email: 'crazy-max@users.noreply.github.com',
name: 'CrazyMax',
username: 'crazy-max'
},
committer: {
email: 'crazy-max@users.noreply.github.com',
name: 'CrazyMax',
username: 'crazy-max'
},
distinct: true,
id: '860c1904a1ce19322e91ac35af1ab07466440c37',
message: 'hello dev',
timestamp: '2022-04-19T11:27:24+02:00',
tree_id: 'd2c60af597e863787d2d27f569e30495b0b92820',
url: 'https://github.com/docker/test-docker-action/commit/860c1904a1ce19322e91ac35af1ab07466440c37'
},
organization: {
avatar_url: 'https://avatars.githubusercontent.com/u/5429470?v=4',
description: 'Docker helps developers bring their ideas to life by conquering the complexity of app development.',
events_url: 'https://api.github.com/orgs/docker/events',
hooks_url: 'https://api.github.com/orgs/docker/hooks',
id: 5429470,
issues_url: 'https://api.github.com/orgs/docker/issues',
login: 'docker',
members_url: 'https://api.github.com/orgs/docker/members{/member}',
node_id: 'MDEyOk9yZ2FuaXphdGlvbjU0Mjk0NzA=',
public_members_url: 'https://api.github.com/orgs/docker/public_members{/member}',
repos_url: 'https://api.github.com/orgs/docker/repos',
url: 'https://api.github.com/orgs/docker'
},
pusher: {
email: 'github@crazymax.dev',
name: 'crazy-max'
},
ref: 'refs/heads/dev',
repository: {
allow_forking: true,
archive_url: 'https://api.github.com/repos/docker/test-docker-action/{archive_format}{/ref}',
archived: false,
assignees_url: 'https://api.github.com/repos/docker/test-docker-action/assignees{/user}',
blobs_url: 'https://api.github.com/repos/docker/test-docker-action/git/blobs{/sha}',
branches_url: 'https://api.github.com/repos/docker/test-docker-action/branches{/branch}',
clone_url: 'https://github.com/docker/test-docker-action.git',
collaborators_url: 'https://api.github.com/repos/docker/test-docker-action/collaborators{/collaborator}',
comments_url: 'https://api.github.com/repos/docker/test-docker-action/comments{/number}',
commits_url: 'https://api.github.com/repos/docker/test-docker-action/commits{/sha}',
compare_url: 'https://api.github.com/repos/docker/test-docker-action/compare/{base}...{head}',
contents_url: 'https://api.github.com/repos/docker/test-docker-action/contents/{+path}',
contributors_url: 'https://api.github.com/repos/docker/test-docker-action/contributors',
created_at: 1596792180,
default_branch: 'master',
deployments_url: 'https://api.github.com/repos/docker/test-docker-action/deployments',
description: 'Test "Docker" Actions',
disabled: false,
downloads_url: 'https://api.github.com/repos/docker/test-docker-action/downloads',
events_url: 'https://api.github.com/repos/docker/test-docker-action/events',
fork: false,
forks: 1,
forks_count: 1,
forks_url: 'https://api.github.com/repos/docker/test-docker-action/forks',
full_name: 'docker/test-docker-action',
git_commits_url: 'https://api.github.com/repos/docker/test-docker-action/git/commits{/sha}',
git_refs_url: 'https://api.github.com/repos/docker/test-docker-action/git/refs{/sha}',
git_tags_url: 'https://api.github.com/repos/docker/test-docker-action/git/tags{/sha}',
git_url: 'git://github.com/docker/test-docker-action.git',
has_downloads: true,
has_issues: true,
has_pages: false,
has_projects: true,
has_wiki: true,
homepage: '',
hooks_url: 'https://api.github.com/repos/docker/test-docker-action/hooks',
html_url: 'https://github.com/docker/test-docker-action',
id: 285789493,
is_template: false,
issue_comment_url: 'https://api.github.com/repos/docker/test-docker-action/issues/comments{/number}',
issue_events_url: 'https://api.github.com/repos/docker/test-docker-action/issues/events{/number}',
issues_url: 'https://api.github.com/repos/docker/test-docker-action/issues{/number}',
keys_url: 'https://api.github.com/repos/docker/test-docker-action/keys{/key_id}',
labels_url: 'https://api.github.com/repos/docker/test-docker-action/labels{/name}',
language: 'JavaScript',
languages_url: 'https://api.github.com/repos/docker/test-docker-action/languages',
license: {
key: 'mit',
name: 'MIT License',
node_id: 'MDc6TGljZW5zZTEz',
spdx_id: 'MIT',
url: 'https://api.github.com/licenses/mit'
},
master_branch: 'master',
merges_url: 'https://api.github.com/repos/docker/test-docker-action/merges',
milestones_url: 'https://api.github.com/repos/docker/test-docker-action/milestones{/number}',
mirror_url: null,
name: 'test-docker-action',
node_id: 'MDEwOlJlcG9zaXRvcnkyODU3ODk0OTM=',
notifications_url: 'https://api.github.com/repos/docker/test-docker-action/notifications{?since,all,participating}',
open_issues: 6,
open_issues_count: 6,
organization: 'docker',
owner: {
avatar_url: 'https://avatars.githubusercontent.com/u/5429470?v=4',
email: 'info@docker.com',
events_url: 'https://api.github.com/users/docker/events{/privacy}',
followers_url: 'https://api.github.com/users/docker/followers',
following_url: 'https://api.github.com/users/docker/following{/other_user}',
gists_url: 'https://api.github.com/users/docker/gists{/gist_id}',
gravatar_id: '',
html_url: 'https://github.com/docker',
id: 5429470,
login: 'docker',
name: 'docker',
node_id: 'MDEyOk9yZ2FuaXphdGlvbjU0Mjk0NzA=',
organizations_url: 'https://api.github.com/users/docker/orgs',
received_events_url: 'https://api.github.com/users/docker/received_events',
repos_url: 'https://api.github.com/users/docker/repos',
site_admin: false,
starred_url: 'https://api.github.com/users/docker/starred{/owner}{/repo}',
subscriptions_url: 'https://api.github.com/users/docker/subscriptions',
type: 'Organization',
url: 'https://api.github.com/users/docker'
},
private: true,
pulls_url: 'https://api.github.com/repos/docker/test-docker-action/pulls{/number}',
pushed_at: 1650360446,
releases_url: 'https://api.github.com/repos/docker/test-docker-action/releases{/id}',
size: 796,
ssh_url: 'git@github.com:docker/test-docker-action.git',
stargazers: 0,
stargazers_count: 0,
stargazers_url: 'https://api.github.com/repos/docker/test-docker-action/stargazers',
statuses_url: 'https://api.github.com/repos/docker/test-docker-action/statuses/{sha}',
subscribers_url: 'https://api.github.com/repos/docker/test-docker-action/subscribers',
subscription_url: 'https://api.github.com/repos/docker/test-docker-action/subscription',
svn_url: 'https://github.com/docker/test-docker-action',
tags_url: 'https://api.github.com/repos/docker/test-docker-action/tags',
teams_url: 'https://api.github.com/repos/docker/test-docker-action/teams',
topics: [],
trees_url: 'https://api.github.com/repos/docker/test-docker-action/git/trees{/sha}',
updated_at: '2022-04-19T09:05:09Z',
url: 'https://github.com/docker/test-docker-action',
visibility: 'private',
watchers: 0,
watchers_count: 0
},
sender: {
avatar_url: 'https://avatars.githubusercontent.com/u/1951866?v=4',
events_url: 'https://api.github.com/users/crazy-max/events{/privacy}',
followers_url: 'https://api.github.com/users/crazy-max/followers',
following_url: 'https://api.github.com/users/crazy-max/following{/other_user}',
gists_url: 'https://api.github.com/users/crazy-max/gists{/gist_id}',
gravatar_id: '',
html_url: 'https://github.com/crazy-max',
id: 1951866,
login: 'crazy-max',
node_id: 'MDQ6VXNlcjE5NTE4NjY=',
organizations_url: 'https://api.github.com/users/crazy-max/orgs',
received_events_url: 'https://api.github.com/users/crazy-max/received_events',
repos_url: 'https://api.github.com/users/crazy-max/repos',
site_admin: false,
starred_url: 'https://api.github.com/users/crazy-max/starred{/owner}{/repo}',
subscriptions_url: 'https://api.github.com/users/crazy-max/subscriptions',
type: 'User',
url: 'https://api.github.com/users/crazy-max'
}
}
};
export const getOctokit = jest.fn();

View file

@ -1,10 +1,19 @@
import {beforeEach, describe, expect, test, it, vi} from 'vitest'; import {afterEach, beforeEach, describe, expect, test, it, jest} from '@jest/globals';
import {Git} from '@docker/actions-toolkit/lib/git.js'; import * as dotenv from 'dotenv';
import {Toolkit} from '@docker/actions-toolkit/lib/toolkit.js'; import * as fs from 'fs';
import * as path from 'path';
import {Context} from '@actions/github/lib/context';
import {Git} from '@docker/actions-toolkit/lib/git';
import {GitHub} from '@docker/actions-toolkit/lib/github';
import * as context from '../src/context.js'; import {ContextSource, getContext, getInputs, Inputs} from '../src/context';
const toolkit = new Toolkit({githubToken: 'fake-github-token'}); beforeEach(() => {
jest.clearAllMocks();
jest.spyOn(GitHub, 'context', 'get').mockImplementation((): Context => {
return new Context();
});
});
describe('getInputs', () => { describe('getInputs', () => {
beforeEach(() => { beforeEach(() => {
@ -17,25 +26,23 @@ describe('getInputs', () => {
}); });
// prettier-ignore // prettier-ignore
const cases: [number, Map<string, string>, context.Inputs][] = [ test.each([
[ [
0, 0,
new Map<string, string>([ new Map<string, string>([
['images', 'moby/buildkit\nghcr.io/moby/mbuildkit'], ['images', 'moby/buildkit\nghcr.io/moby/mbuildkit'],
]), ]),
{ {
context: context.ContextSource.workflow, context: ContextSource.workflow,
bakeTarget: 'docker-metadata-action', bakeTarget: 'docker-metadata-action',
flavor: [], flavor: [],
githubToken: '', githubToken: '',
images: ['moby/buildkit', 'ghcr.io/moby/mbuildkit'], images: ['moby/buildkit', 'ghcr.io/moby/mbuildkit'],
labels: [], labels: [],
annotations: [],
sepLabels: '\n', sepLabels: '\n',
sepTags: '\n', sepTags: '\n',
sepAnnotations: '\n',
tags: [], tags: [],
} } as Inputs
], ],
[ [
1, 1,
@ -44,21 +51,18 @@ describe('getInputs', () => {
['images', 'moby/buildkit'], ['images', 'moby/buildkit'],
['sep-labels', ','], ['sep-labels', ','],
['sep-tags', ','], ['sep-tags', ','],
['sep-annotations', ',']
]), ]),
{ {
context: context.ContextSource.workflow, context: ContextSource.workflow,
bakeTarget: 'metadata', bakeTarget: 'metadata',
flavor: [], flavor: [],
githubToken: '', githubToken: '',
images: ['moby/buildkit'], images: ['moby/buildkit'],
labels: [], labels: [],
annotations: [],
sepLabels: ',', sepLabels: ',',
sepTags: ',', sepTags: ',',
sepAnnotations: ',',
tags: [], tags: [],
} } as Inputs
], ],
[ [
2, 2,
@ -66,111 +70,57 @@ describe('getInputs', () => {
['images', 'moby/buildkit\n#comment\nghcr.io/moby/mbuildkit'], ['images', 'moby/buildkit\n#comment\nghcr.io/moby/mbuildkit'],
]), ]),
{ {
context: context.ContextSource.workflow, context: ContextSource.workflow,
bakeTarget: 'docker-metadata-action', bakeTarget: 'docker-metadata-action',
flavor: [], flavor: [],
githubToken: '', githubToken: '',
images: ['moby/buildkit', 'ghcr.io/moby/mbuildkit'], images: ['moby/buildkit', 'ghcr.io/moby/mbuildkit'],
labels: [], labels: [],
annotations: [],
sepLabels: '\n', sepLabels: '\n',
sepTags: '\n', sepTags: '\n',
sepAnnotations: '\n',
tags: [], tags: [],
} } as Inputs
], ],
[ ])(
3, '[%d] given %p as inputs, returns %p',
new Map<string, string>([ async (num: number, inputs: Map<string, string>, expected: Inputs) => {
['labels', 'mylabel=foo#bar\n#comment\nanother=bar'], inputs.forEach((value: string, name: string) => {
]), setInput(name, value);
{ });
context: context.ContextSource.workflow, expect(await getInputs()).toEqual(expected);
bakeTarget: 'docker-metadata-action', }
flavor: [], );
githubToken: '',
images: [],
labels: ['mylabel=foo#bar', 'another=bar'],
annotations: [],
sepLabels: '\n',
sepTags: '\n',
sepAnnotations: '\n',
tags: [],
}
],
[
4,
new Map<string, string>([
['annotations', 'org.opencontainers.image.url=https://example.com/path#readme\n#comment\norg.opencontainers.image.source=https://github.com/docker/metadata-action'],
]),
{
context: context.ContextSource.workflow,
bakeTarget: 'docker-metadata-action',
flavor: [],
githubToken: '',
images: [],
labels: [],
annotations: [
'org.opencontainers.image.url=https://example.com/path#readme',
'org.opencontainers.image.source=https://github.com/docker/metadata-action'
],
sepLabels: '\n',
sepTags: '\n',
sepAnnotations: '\n',
tags: [],
}
],
[
5,
new Map<string, string>([
['tags', 'type=raw,value=foo#bar\n#comment'],
['flavor', 'prefix=v#1\n#comment'],
]),
{
context: context.ContextSource.workflow,
bakeTarget: 'docker-metadata-action',
flavor: ['prefix=v#1'],
githubToken: '',
images: [],
labels: [],
annotations: [],
sepLabels: '\n',
sepTags: '\n',
sepAnnotations: '\n',
tags: ['type=raw,value=foo#bar'],
}
],
];
test.each(cases)('[%d] given %o as inputs, returns %o', async (num: number, inputs: Map<string, string>, expected: context.Inputs) => {
inputs.forEach((value: string, name: string) => {
setInput(name, value);
});
const res = await context.getInputs();
expect(res).toEqual(expected);
});
}); });
describe('getContext', () => { describe('getContext', () => {
it('workflow', async () => { const originalEnv = process.env;
const ctx = await context.getContext(context.ContextSource.workflow, toolkit); beforeEach(() => {
expect(ctx.ref).toEqual('refs/heads/dev'); jest.resetModules();
expect(ctx.sha).toEqual('5f3331d7f7044c18ca9f12c77d961c4d7cf3276a'); process.env = {
expect(ctx.commitDate).toEqual(new Date('2024-11-13T13:42:28.000Z')); ...originalEnv,
...dotenv.parse(fs.readFileSync(path.join(__dirname, 'fixtures/event_create_branch.env')))
};
}); });
afterEach(() => {
process.env = originalEnv;
});
it('workflow', async () => {
const context = await getContext(ContextSource.workflow);
expect(context.ref).toEqual('refs/heads/dev');
expect(context.sha).toEqual('5f3331d7f7044c18ca9f12c77d961c4d7cf3276a');
});
it('git', async () => { it('git', async () => {
vi.spyOn(Git, 'context').mockImplementation((): Promise<context.Context> => { jest.spyOn(Git, 'context').mockImplementation((): Promise<Context> => {
return Promise.resolve({ return Promise.resolve({
ref: 'refs/heads/git-test', ref: 'refs/heads/git-test',
sha: 'git-test-sha' sha: 'git-test-sha'
} as context.Context); } as Context);
}); });
vi.spyOn(Git, 'commitDate').mockImplementation(async (): Promise<Date> => { const context = await getContext(ContextSource.git);
return new Date('2023-01-01T13:42:28.000Z'); expect(context.ref).toEqual('refs/heads/git-test');
}); expect(context.sha).toEqual('git-test-sha');
const ctx = await context.getContext(context.ContextSource.git, toolkit);
expect(ctx.ref).toEqual('refs/heads/git-test');
expect(ctx.sha).toEqual('git-test-sha');
expect(ctx.commitDate).toEqual(new Date('2023-01-01T13:42:28.000Z'));
}); });
}); });

View file

@ -1,6 +1,6 @@
import {describe, expect, test} from 'vitest'; import {describe, expect, test} from '@jest/globals';
import {Flavor, Transform} from '../src/flavor.js'; import {Flavor, Transform} from '../src/flavor';
describe('transform', () => { describe('transform', () => {
// prettier-ignore // prettier-ignore
@ -175,7 +175,7 @@ describe('transform', () => {
if (!invalid) { if (!invalid) {
console.error(err); console.error(err);
} }
// eslint-disable-next-line vitest/no-conditional-expect // eslint-disable-next-line jest/no-conditional-expect
expect(true).toBe(invalid); expect(true).toBe(invalid);
} }
}); });

View file

@ -1,6 +1,6 @@
import {describe, expect, test} from 'vitest'; import {describe, expect, test} from '@jest/globals';
import {Transform, Image} from '../src/image.js'; import {Transform, Image} from '../src/image';
describe('transform', () => { describe('transform', () => {
// prettier-ignore // prettier-ignore
@ -95,7 +95,7 @@ describe('transform', () => {
if (!invalid) { if (!invalid) {
console.error(err); console.error(err);
} }
// eslint-disable-next-line vitest/no-conditional-expect // eslint-disable-next-line jest/no-conditional-expect
expect(true).toBe(invalid); expect(true).toBe(invalid);
} }
}); });

File diff suppressed because it is too large Load diff

View file

@ -1,252 +0,0 @@
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import {vi} from 'vitest';
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-metadata-action-'));
const githubPayload = {
after: '860c1904a1ce19322e91ac35af1ab07466440c37',
base_ref: null,
before: '5f3331d7f7044c18ca9f12c77d961c4d7cf3276a',
commits: [
{
author: {
email: 'crazy-max@users.noreply.github.com',
name: 'CrazyMax',
username: 'crazy-max'
},
committer: {
email: 'crazy-max@users.noreply.github.com',
name: 'CrazyMax',
username: 'crazy-max'
},
distinct: true,
id: '5f3331d7f7044c18ca9f12c77d961c4d7cf3276a',
message: 'hello dev',
timestamp: '2024-11-13T13:42:28Z',
tree_id: 'd2c60af597e863787d2d27f569e30495b0b92820',
url: 'https://github.com/docker/test-docker-action/commit/5f3331d7f7044c18ca9f12c77d961c4d7cf3276a'
}
],
compare: 'https://github.com/docker/test-docker-action/compare/5f3331d7f704...860c1904a1ce',
created: false,
deleted: false,
forced: false,
head_commit: {
author: {
email: 'crazy-max@users.noreply.github.com',
name: 'CrazyMax',
username: 'crazy-max'
},
committer: {
email: 'crazy-max@users.noreply.github.com',
name: 'CrazyMax',
username: 'crazy-max'
},
distinct: true,
id: '5f3331d7f7044c18ca9f12c77d961c4d7cf3276a',
message: 'hello dev',
timestamp: '2024-11-13T13:42:28Z',
tree_id: 'd2c60af597e863787d2d27f569e30495b0b92820',
url: 'https://github.com/docker/test-docker-action/commit/5f3331d7f7044c18ca9f12c77d961c4d7cf3276a'
},
organization: {
avatar_url: 'https://avatars.githubusercontent.com/u/5429470?v=4',
description: 'Docker helps developers bring their ideas to life by conquering the complexity of app development.',
events_url: 'https://api.github.com/orgs/docker/events',
hooks_url: 'https://api.github.com/orgs/docker/hooks',
id: 5429470,
issues_url: 'https://api.github.com/orgs/docker/issues',
login: 'docker',
members_url: 'https://api.github.com/orgs/docker/members{/member}',
node_id: 'MDEyOk9yZ2FuaXphdGlvbjU0Mjk0NzA=',
public_members_url: 'https://api.github.com/orgs/docker/public_members{/member}',
repos_url: 'https://api.github.com/orgs/docker/repos',
url: 'https://api.github.com/orgs/docker'
},
pusher: {
email: 'github@crazymax.dev',
name: 'crazy-max'
},
ref: 'refs/heads/dev',
repository: {
allow_forking: true,
archive_url: 'https://api.github.com/repos/docker/test-docker-action/{archive_format}{/ref}',
archived: false,
assignees_url: 'https://api.github.com/repos/docker/test-docker-action/assignees{/user}',
blobs_url: 'https://api.github.com/repos/docker/test-docker-action/git/blobs{/sha}',
branches_url: 'https://api.github.com/repos/docker/test-docker-action/branches{/branch}',
clone_url: 'https://github.com/docker/test-docker-action.git',
collaborators_url: 'https://api.github.com/repos/docker/test-docker-action/collaborators{/collaborator}',
comments_url: 'https://api.github.com/repos/docker/test-docker-action/comments{/number}',
commits_url: 'https://api.github.com/repos/docker/test-docker-action/commits{/sha}',
compare_url: 'https://api.github.com/repos/docker/test-docker-action/compare/{base}...{head}',
contents_url: 'https://api.github.com/repos/docker/test-docker-action/contents/{+path}',
contributors_url: 'https://api.github.com/repos/docker/test-docker-action/contributors',
created_at: 1596792180,
default_branch: 'master',
deployments_url: 'https://api.github.com/repos/docker/test-docker-action/deployments',
description: 'Test "Docker" Actions',
disabled: false,
downloads_url: 'https://api.github.com/repos/docker/test-docker-action/downloads',
events_url: 'https://api.github.com/repos/docker/test-docker-action/events',
fork: false,
forks: 1,
forks_count: 1,
forks_url: 'https://api.github.com/repos/docker/test-docker-action/forks',
full_name: 'docker/test-docker-action',
git_commits_url: 'https://api.github.com/repos/docker/test-docker-action/git/commits{/sha}',
git_refs_url: 'https://api.github.com/repos/docker/test-docker-action/git/refs{/sha}',
git_tags_url: 'https://api.github.com/repos/docker/test-docker-action/git/tags{/sha}',
git_url: 'git://github.com/docker/test-docker-action.git',
has_downloads: true,
has_issues: true,
has_pages: false,
has_projects: true,
has_wiki: true,
homepage: '',
hooks_url: 'https://api.github.com/repos/docker/test-docker-action/hooks',
html_url: 'https://github.com/docker/test-docker-action',
id: 285789493,
is_template: false,
issue_comment_url: 'https://api.github.com/repos/docker/test-docker-action/issues/comments{/number}',
issue_events_url: 'https://api.github.com/repos/docker/test-docker-action/issues/events{/number}',
issues_url: 'https://api.github.com/repos/docker/test-docker-action/issues{/number}',
keys_url: 'https://api.github.com/repos/docker/test-docker-action/keys{/key_id}',
labels_url: 'https://api.github.com/repos/docker/test-docker-action/labels{/name}',
language: 'JavaScript',
languages_url: 'https://api.github.com/repos/docker/test-docker-action/languages',
license: {
key: 'mit',
name: 'MIT License',
node_id: 'MDc6TGljZW5zZTEz',
spdx_id: 'MIT',
url: 'https://api.github.com/licenses/mit'
},
master_branch: 'master',
merges_url: 'https://api.github.com/repos/docker/test-docker-action/merges',
milestones_url: 'https://api.github.com/repos/docker/test-docker-action/milestones{/number}',
mirror_url: null,
name: 'test-docker-action',
node_id: 'MDEwOlJlcG9zaXRvcnkyODU3ODk0OTM=',
notifications_url: 'https://api.github.com/repos/docker/test-docker-action/notifications{?since,all,participating}',
open_issues: 6,
open_issues_count: 6,
organization: 'docker',
owner: {
avatar_url: 'https://avatars.githubusercontent.com/u/5429470?v=4',
email: 'info@docker.com',
events_url: 'https://api.github.com/users/docker/events{/privacy}',
followers_url: 'https://api.github.com/users/docker/followers',
following_url: 'https://api.github.com/users/docker/following{/other_user}',
gists_url: 'https://api.github.com/users/docker/gists{/gist_id}',
gravatar_id: '',
html_url: 'https://github.com/docker',
id: 5429470,
login: 'docker',
name: 'docker',
node_id: 'MDEyOk9yZ2FuaXphdGlvbjU0Mjk0NzA=',
organizations_url: 'https://api.github.com/users/docker/orgs',
received_events_url: 'https://api.github.com/users/docker/received_events',
repos_url: 'https://api.github.com/users/docker/repos',
site_admin: false,
starred_url: 'https://api.github.com/users/docker/starred{/owner}{/repo}',
subscriptions_url: 'https://api.github.com/users/docker/subscriptions',
type: 'Organization',
url: 'https://api.github.com/users/docker'
},
private: true,
pulls_url: 'https://api.github.com/repos/docker/test-docker-action/pulls{/number}',
pushed_at: 1650360446,
releases_url: 'https://api.github.com/repos/docker/test-docker-action/releases{/id}',
size: 796,
ssh_url: 'git@github.com:docker/test-docker-action.git',
stargazers: 0,
stargazers_count: 0,
stargazers_url: 'https://api.github.com/repos/docker/test-docker-action/stargazers',
statuses_url: 'https://api.github.com/repos/docker/test-docker-action/statuses/{sha}',
subscribers_url: 'https://api.github.com/repos/docker/test-docker-action/subscribers',
subscription_url: 'https://api.github.com/repos/docker/test-docker-action/subscription',
svn_url: 'https://github.com/docker/test-docker-action',
tags_url: 'https://api.github.com/repos/docker/test-docker-action/tags',
teams_url: 'https://api.github.com/repos/docker/test-docker-action/teams',
topics: [],
trees_url: 'https://api.github.com/repos/docker/test-docker-action/git/trees{/sha}',
updated_at: '2022-04-19T09:05:09Z',
url: 'https://github.com/docker/test-docker-action',
visibility: 'private',
watchers: 0,
watchers_count: 0
},
sender: {
avatar_url: 'https://avatars.githubusercontent.com/u/1951866?v=4',
events_url: 'https://api.github.com/users/crazy-max/events{/privacy}',
followers_url: 'https://api.github.com/users/crazy-max/followers',
following_url: 'https://api.github.com/users/crazy-max/following{/other_user}',
gists_url: 'https://api.github.com/users/crazy-max/gists{/gist_id}',
gravatar_id: '',
html_url: 'https://github.com/crazy-max',
id: 1951866,
login: 'crazy-max',
node_id: 'MDQ6VXNlcjE5NTE4NjY=',
organizations_url: 'https://api.github.com/users/crazy-max/orgs',
received_events_url: 'https://api.github.com/users/crazy-max/received_events',
repos_url: 'https://api.github.com/users/crazy-max/repos',
site_admin: false,
starred_url: 'https://api.github.com/users/crazy-max/starred{/owner}{/repo}',
subscriptions_url: 'https://api.github.com/users/crazy-max/subscriptions',
type: 'User',
url: 'https://api.github.com/users/crazy-max'
}
};
const githubEventPath = path.join(tmpDir, 'github-event.json');
fs.writeFileSync(githubEventPath, JSON.stringify(githubPayload));
process.env = Object.assign({}, process.env, {
TEMP: tmpDir,
GITHUB_REPOSITORY: 'docker/metadata-action',
GITHUB_REF: 'refs/heads/dev',
GITHUB_RUN_ID: '2188748038',
GITHUB_RUN_ATTEMPT: '1',
GITHUB_RUN_NUMBER: '15',
GITHUB_SHA: '5f3331d7f7044c18ca9f12c77d961c4d7cf3276a',
GITHUB_EVENT_PATH: githubEventPath,
RUNNER_TEMP: path.join(tmpDir, 'runner-temp'),
RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache')
});
const getCommitMock = vi.hoisted(() =>
vi.fn(async () => ({
data: {
commit: {
committer: {
date: '2024-11-13T13:42:28Z'
}
}
}
}))
);
const getOctokitMock = vi.hoisted(() =>
vi.fn(() => ({
rest: {
repos: {
getCommit: getCommitMock
}
}
}))
);
vi.mock('@actions/github', async importOriginal => {
const actual = await importOriginal<typeof import('@actions/github')>();
return {
...actual,
context: {
...actual.context,
payload: githubPayload
},
getOctokit: getOctokitMock
};
});

View file

@ -1,6 +1,6 @@
import {describe, expect, test} from 'vitest'; import {describe, expect, test} from '@jest/globals';
import {Transform, Parse, Tag, Type, RefEvent, ShaFormat, DefaultPriorities} from '../src/tag.js'; import {Transform, Parse, Tag, Type, RefEvent, ShaFormat, DefaultPriorities} from '../src/tag';
describe('transform', () => { describe('transform', () => {
// prettier-ignore // prettier-ignore
@ -32,8 +32,7 @@ describe('transform', () => {
"priority": DefaultPriorities[Type.Semver], "priority": DefaultPriorities[Type.Semver],
"enable": "true", "enable": "true",
"pattern": "{{version}}", "pattern": "{{version}}",
"value": "", "value": ""
"match": ""
} }
}, },
{ {
@ -107,7 +106,7 @@ describe('transform', () => {
if (!invalid) { if (!invalid) {
console.error(err); console.error(err);
} }
// eslint-disable-next-line vitest/no-conditional-expect // eslint-disable-next-line jest/no-conditional-expect
expect(true).toBe(invalid); expect(true).toBe(invalid);
} }
}); });
@ -148,8 +147,7 @@ describe('parse', () => {
"priority": DefaultPriorities[Type.Semver], "priority": DefaultPriorities[Type.Semver],
"enable": "true", "enable": "true",
"pattern": "{{version}}", "pattern": "{{version}}",
"value": "", "value": ""
"match": ""
} }
} as Tag, } as Tag,
false false
@ -162,8 +160,7 @@ describe('parse', () => {
"priority": "1", "priority": "1",
"enable": "true", "enable": "true",
"pattern": "{{version}}", "pattern": "{{version}}",
"value": "", "value": ""
"match": ""
} }
} as Tag, } as Tag,
false false
@ -176,22 +173,7 @@ describe('parse', () => {
"priority": "1", "priority": "1",
"enable": "true", "enable": "true",
"pattern": "{{version}}", "pattern": "{{version}}",
"value": "v1.0.0", "value": "v1.0.0"
"match": ""
}
} as Tag,
false
],
[
`type=semver,priority=1,enable=true,pattern={{version}},value=p1/v1.0.0,"match=v(\\d.\\d.\\d)$"`,
{
type: Type.Semver,
attrs: {
"priority": "1",
"enable": "true",
"pattern": "{{version}}",
"value": "p1/v1.0.0",
"match": "v(\\d.\\d.\\d)$"
} }
} as Tag, } as Tag,
false false
@ -461,7 +443,7 @@ describe('parse', () => {
if (!invalid) { if (!invalid) {
console.error(err); console.error(err);
} }
// eslint-disable-next-line vitest/no-conditional-expect // eslint-disable-next-line jest/no-conditional-expect
expect(true).toBe(invalid); expect(true).toBe(invalid);
} }
}); });

View file

@ -23,18 +23,12 @@ inputs:
labels: labels:
description: 'List of custom labels' description: 'List of custom labels'
required: false required: false
annotations:
description: 'List of custom annotations'
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
sep-labels: sep-labels:
description: 'Separator to use for labels output (default \n)' description: 'Separator to use for labels output (default \n)'
required: false required: false
sep-annotations:
description: 'Separator to use for annotations output (default \n)'
required: false
bake-target: bake-target:
description: 'Bake target name (default docker-metadata-action)' description: 'Bake target name (default docker-metadata-action)'
required: false required: false
@ -48,8 +42,6 @@ outputs:
description: 'Generated Docker image version' description: 'Generated Docker image version'
tags: tags:
description: 'Generated Docker tags' description: 'Generated Docker tags'
tag-names:
description: 'Generated Docker tag names without image base name'
labels: labels:
description: 'Generated Docker labels' description: 'Generated Docker labels'
annotations: annotations:
@ -61,10 +53,10 @@ outputs:
bake-file-labels: bake-file-labels:
description: 'Bake definition file with labels' description: 'Bake definition file with labels'
bake-file-annotations: bake-file-annotations:
description: 'Bake definition file with annotations' description: 'Bake definiton file with annotations'
bake-file: bake-file:
description: 'Bake definition file with tags and labels' description: 'Bake definition file with tags and labels'
runs: runs:
using: 'node24' using: 'node20'
main: 'dist/index.js' main: 'dist/index.js'

View file

@ -1,21 +1,13 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
ARG NODE_VERSION=24 ARG NODE_VERSION=20
FROM node:${NODE_VERSION}-alpine AS base FROM node:${NODE_VERSION}-alpine AS base
RUN apk add --no-cache cpio findutils git rsync RUN apk add --no-cache cpio findutils git
WORKDIR /src WORKDIR /src
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/.yarn/cache <<EOT
set -e
corepack enable
yarn --version
yarn config set --home enableTelemetry 0
EOT
FROM base AS deps FROM base AS deps
RUN --mount=type=bind,target=.,rw \ RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/.yarn/cache \
--mount=type=cache,target=/src/node_modules \ --mount=type=cache,target=/src/node_modules \
yarn install && mkdir /vendor && cp yarn.lock /vendor yarn install && mkdir /vendor && cp yarn.lock /vendor
@ -28,34 +20,24 @@ RUN --mount=type=bind,target=.,rw <<EOT
git add -A git add -A
cp -rf /vendor/* . cp -rf /vendor/* .
if [ -n "$(git status --porcelain -- yarn.lock)" ]; then if [ -n "$(git status --porcelain -- yarn.lock)" ]; then
echo >&2 'ERROR: Vendor result differs. Please vendor your package with "docker buildx bake vendor"' echo >&2 'ERROR: Vendor result differs. Please vendor your package with "docker buildx bake vendor-update"'
git status --porcelain -- yarn.lock git status --porcelain -- yarn.lock
exit 1 exit 1
fi fi
EOT EOT
FROM deps AS build FROM deps AS build
RUN --mount=target=/context \ RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/.yarn/cache \ --mount=type=cache,target=/src/node_modules \
--mount=type=cache,target=/src/node_modules <<EOT yarn run build && mkdir /out && cp -Rf dist /out/
set -e
rsync -a /context/. .
rm -rf dist
yarn run build
mkdir /out
cp -r dist /out
EOT
FROM scratch AS build-update FROM scratch AS build-update
COPY --from=build /out / COPY --from=build /out /
FROM build AS build-validate FROM build AS build-validate
RUN --mount=target=/context \ RUN --mount=type=bind,target=.,rw <<EOT
--mount=target=.,type=tmpfs <<EOT
set -e set -e
rsync -a /context/. .
git add -A git add -A
rm -rf dist
cp -rf /out/* . cp -rf /out/* .
if [ -n "$(git status --porcelain -- dist)" ]; then if [ -n "$(git status --porcelain -- dist)" ]; then
echo >&2 'ERROR: Build result differs. Please build first with "docker buildx bake build"' echo >&2 'ERROR: Build result differs. Please build first with "docker buildx bake build"'
@ -66,24 +48,24 @@ EOT
FROM deps AS format FROM deps AS format
RUN --mount=type=bind,target=.,rw \ RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/.yarn/cache \
--mount=type=cache,target=/src/node_modules \ --mount=type=cache,target=/src/node_modules \
yarn run format && mkdir /out && find . -name '*.ts' -not -path './node_modules/*' -not -path './.yarn/*' | cpio -pdm /out yarn run format \
&& mkdir /out && find . -name '*.ts' -not -path './node_modules/*' | cpio -pdm /out
FROM scratch AS format-update FROM scratch AS format-update
COPY --from=format /out / COPY --from=format /out /
FROM deps AS lint FROM deps AS lint
RUN --mount=type=bind,target=.,rw \ RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/.yarn/cache \
--mount=type=cache,target=/src/node_modules \ --mount=type=cache,target=/src/node_modules \
yarn run lint yarn run lint
FROM deps AS test FROM deps AS test
ENV RUNNER_TEMP=/tmp/github_runner
ENV RUNNER_TOOL_CACHE=/tmp/github_tool_cache
RUN --mount=type=bind,target=.,rw \ RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/src/.yarn/cache \
--mount=type=cache,target=/src/node_modules \ --mount=type=cache,target=/src/node_modules \
yarn run test --coverage --coverage.reportsDirectory=/tmp/coverage yarn run test --coverage --coverageDirectory=/tmp/coverage
FROM scratch AS test-coverage FROM scratch AS test-coverage
COPY --from=test /tmp/coverage / COPY --from=test /tmp/coverage /

299
dist/606.index.js generated vendored
View file

@ -1,299 +0,0 @@
export const id = 606;
export const ids = [606];
export const modules = {
/***/ 606:
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ pMap)
/* harmony export */ });
/* unused harmony exports pMapIterable, pMapSkip */
async function pMap(
iterable,
mapper,
{
concurrency = Number.POSITIVE_INFINITY,
stopOnError = true,
signal,
} = {},
) {
return new Promise((resolve_, reject_) => {
if (iterable[Symbol.iterator] === undefined && iterable[Symbol.asyncIterator] === undefined) {
throw new TypeError(`Expected \`input\` to be either an \`Iterable\` or \`AsyncIterable\`, got (${typeof iterable})`);
}
if (typeof mapper !== 'function') {
throw new TypeError('Mapper function is required');
}
if (!((Number.isSafeInteger(concurrency) && concurrency >= 1) || concurrency === Number.POSITIVE_INFINITY)) {
throw new TypeError(`Expected \`concurrency\` to be an integer from 1 and up or \`Infinity\`, got \`${concurrency}\` (${typeof concurrency})`);
}
const result = [];
const errors = [];
const skippedIndexesMap = new Map();
let isRejected = false;
let isResolved = false;
let isIterableDone = false;
let resolvingCount = 0;
let currentIndex = 0;
const iterator = iterable[Symbol.iterator] === undefined ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator]();
const signalListener = () => {
reject(signal.reason);
};
const cleanup = () => {
signal?.removeEventListener('abort', signalListener);
};
const resolve = value => {
resolve_(value);
cleanup();
};
const reject = reason => {
isRejected = true;
isResolved = true;
reject_(reason);
cleanup();
};
if (signal) {
if (signal.aborted) {
reject(signal.reason);
}
signal.addEventListener('abort', signalListener, {once: true});
}
const next = async () => {
if (isResolved) {
return;
}
const nextItem = await iterator.next();
const index = currentIndex;
currentIndex++;
// Note: `iterator.next()` can be called many times in parallel.
// This can cause multiple calls to this `next()` function to
// receive a `nextItem` with `done === true`.
// The shutdown logic that rejects/resolves must be protected
// so it runs only one time as the `skippedIndex` logic is
// non-idempotent.
if (nextItem.done) {
isIterableDone = true;
if (resolvingCount === 0 && !isResolved) {
if (!stopOnError && errors.length > 0) {
reject(new AggregateError(errors)); // eslint-disable-line unicorn/error-message
return;
}
isResolved = true;
if (skippedIndexesMap.size === 0) {
resolve(result);
return;
}
const pureResult = [];
// Support multiple `pMapSkip`'s.
for (const [index, value] of result.entries()) {
if (skippedIndexesMap.get(index) === pMapSkip) {
continue;
}
pureResult.push(value);
}
resolve(pureResult);
}
return;
}
resolvingCount++;
// Intentionally detached
(async () => {
try {
const element = await nextItem.value;
if (isResolved) {
return;
}
const value = await mapper(element, index);
// Use Map to stage the index of the element.
if (value === pMapSkip) {
skippedIndexesMap.set(index, value);
}
result[index] = value;
resolvingCount--;
await next();
} catch (error) {
if (stopOnError) {
reject(error);
} else {
errors.push(error);
resolvingCount--;
// In that case we can't really continue regardless of `stopOnError` state
// since an iterable is likely to continue throwing after it throws once.
// If we continue calling `next()` indefinitely we will likely end up
// in an infinite loop of failed iteration.
try {
await next();
} catch (error) {
reject(error);
}
}
}
})();
};
// Create the concurrent runners in a detached (non-awaited)
// promise. We need this so we can await the `next()` calls
// to stop creating runners before hitting the concurrency limit
// if the iterable has already been marked as done.
// NOTE: We *must* do this for async iterators otherwise we'll spin up
// infinite `next()` calls by default and never start the event loop.
(async () => {
for (let index = 0; index < concurrency; index++) {
try {
// eslint-disable-next-line no-await-in-loop
await next();
} catch (error) {
reject(error);
break;
}
if (isIterableDone || isRejected) {
break;
}
}
})();
});
}
function pMapIterable(
iterable,
mapper,
{
concurrency = Number.POSITIVE_INFINITY,
backpressure = concurrency,
} = {},
) {
if (iterable[Symbol.iterator] === undefined && iterable[Symbol.asyncIterator] === undefined) {
throw new TypeError(`Expected \`input\` to be either an \`Iterable\` or \`AsyncIterable\`, got (${typeof iterable})`);
}
if (typeof mapper !== 'function') {
throw new TypeError('Mapper function is required');
}
if (!((Number.isSafeInteger(concurrency) && concurrency >= 1) || concurrency === Number.POSITIVE_INFINITY)) {
throw new TypeError(`Expected \`concurrency\` to be an integer from 1 and up or \`Infinity\`, got \`${concurrency}\` (${typeof concurrency})`);
}
if (!((Number.isSafeInteger(backpressure) && backpressure >= concurrency) || backpressure === Number.POSITIVE_INFINITY)) {
throw new TypeError(`Expected \`backpressure\` to be an integer from \`concurrency\` (${concurrency}) and up or \`Infinity\`, got \`${backpressure}\` (${typeof backpressure})`);
}
return {
async * [Symbol.asyncIterator]() {
const iterator = iterable[Symbol.asyncIterator] === undefined ? iterable[Symbol.iterator]() : iterable[Symbol.asyncIterator]();
const promises = [];
let runningMappersCount = 0;
let isDone = false;
let index = 0;
function trySpawn() {
if (isDone || !(runningMappersCount < concurrency && promises.length < backpressure)) {
return;
}
const promise = (async () => {
const {done, value} = await iterator.next();
if (done) {
return {done: true};
}
runningMappersCount++;
// Spawn if still below concurrency and backpressure limit
trySpawn();
try {
const returnValue = await mapper(await value, index++);
runningMappersCount--;
if (returnValue === pMapSkip) {
const index = promises.indexOf(promise);
if (index > 0) {
promises.splice(index, 1);
}
}
// Spawn if still below backpressure limit and just dropped below concurrency limit
trySpawn();
return {done: false, value: returnValue};
} catch (error) {
isDone = true;
return {error};
}
})();
promises.push(promise);
}
trySpawn();
while (promises.length > 0) {
const {error, done, value} = await promises[0]; // eslint-disable-line no-await-in-loop
promises.shift();
if (error) {
throw error;
}
if (done) {
return;
}
// Spawn if just dropped below backpressure limit and below the concurrency limit
trySpawn();
if (value === pMapSkip) {
continue;
}
yield value;
}
},
};
}
const pMapSkip = Symbol('skip');
/***/ })
};
//# sourceMappingURL=606.index.js.map

1
dist/606.index.js.map generated vendored

File diff suppressed because one or more lines are too long

89
dist/index.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

2181
dist/licenses.txt generated vendored

File diff suppressed because it is too large Load diff

3
dist/package.json generated vendored
View file

@ -1,3 +0,0 @@
{
"type": "module"
}

1
dist/sourcemap-register.cjs generated vendored

File diff suppressed because one or more lines are too long

1
dist/sourcemap-register.js generated vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,15 +1,9 @@
target "_common" {
args = {
BUILDKIT_CONTEXT_KEEP_GIT_DIR = 1
}
}
group "default" { group "default" {
targets = ["build"] targets = ["build"]
} }
group "pre-checkin" { group "pre-checkin" {
targets = ["vendor", "format", "build"] targets = ["vendor-update", "format", "build"]
} }
group "validate" { group "validate" {
@ -17,49 +11,42 @@ group "validate" {
} }
target "build" { target "build" {
inherits = ["_common"]
dockerfile = "dev.Dockerfile" dockerfile = "dev.Dockerfile"
target = "build-update" target = "build-update"
output = ["."] output = ["."]
} }
target "build-validate" { target "build-validate" {
inherits = ["_common"]
dockerfile = "dev.Dockerfile" dockerfile = "dev.Dockerfile"
target = "build-validate" target = "build-validate"
output = ["type=cacheonly"] output = ["type=cacheonly"]
} }
target "format" { target "format" {
inherits = ["_common"]
dockerfile = "dev.Dockerfile" dockerfile = "dev.Dockerfile"
target = "format-update" target = "format-update"
output = ["."] output = ["."]
} }
target "lint" { target "lint" {
inherits = ["_common"]
dockerfile = "dev.Dockerfile" dockerfile = "dev.Dockerfile"
target = "lint" target = "lint"
output = ["type=cacheonly"] output = ["type=cacheonly"]
} }
target "vendor" { target "vendor-update" {
inherits = ["_common"]
dockerfile = "dev.Dockerfile" dockerfile = "dev.Dockerfile"
target = "vendor-update" target = "vendor-update"
output = ["."] output = ["."]
} }
target "vendor-validate" { target "vendor-validate" {
inherits = ["_common"]
dockerfile = "dev.Dockerfile" dockerfile = "dev.Dockerfile"
target = "vendor-validate" target = "vendor-validate"
output = ["type=cacheonly"] output = ["type=cacheonly"]
} }
target "test" { target "test" {
inherits = ["_common"]
dockerfile = "dev.Dockerfile" dockerfile = "dev.Dockerfile"
target = "test-coverage" target = "test-coverage"
output = ["./coverage"] output = ["./coverage"]

View file

@ -1,52 +0,0 @@
import {defineConfig} from 'eslint/config';
import js from '@eslint/js';
import tseslint from '@typescript-eslint/eslint-plugin';
import vitest from '@vitest/eslint-plugin';
import globals from 'globals';
import eslintConfigPrettier from 'eslint-config-prettier/flat';
import eslintPluginPrettier from 'eslint-plugin-prettier';
export default defineConfig([
{
ignores: ['.yarn/**/*', 'coverage/**/*', 'dist/**/*']
},
js.configs.recommended,
...tseslint.configs['flat/recommended'],
eslintConfigPrettier,
{
languageOptions: {
globals: {
...globals.node
}
}
},
{
files: ['__tests__/**'],
...vitest.configs.recommended,
languageOptions: {
globals: {
...globals.node,
...vitest.environments.env.globals
}
},
rules: {
...vitest.configs.recommended.rules,
'vitest/no-conditional-expect': 'error',
'vitest/no-disabled-tests': 0
}
},
{
plugins: {
prettier: eslintPluginPrettier
},
rules: {
'prettier/prettier': 'error',
'@typescript-eslint/no-require-imports': [
'error',
{
allowAsImport: true
}
]
}
}
]);

31
jest.config.ts Normal file
View file

@ -0,0 +1,31 @@
import fs from 'fs';
import os from 'os';
import path from 'path';
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'docker-metadata-action-'));
process.env = Object.assign({}, process.env, {
TEMP: tmpDir,
GITHUB_REPOSITORY: 'docker/metadata-action',
RUNNER_TEMP: path.join(tmpDir, 'runner-temp'),
RUNNER_TOOL_CACHE: path.join(tmpDir, 'runner-tool-cache')
}) as {
[key: string]: string;
};
module.exports = {
clearMocks: true,
testEnvironment: 'node',
moduleFileExtensions: ['js', 'ts'],
setupFiles: ['dotenv/config'],
testMatch: ['**/*.test.ts'],
transform: {
'^.+\\.ts$': 'ts-jest'
},
moduleNameMapper: {
'^csv-parse/sync': '<rootDir>/node_modules/csv-parse/dist/cjs/sync.cjs'
},
collectCoverageFrom: ['src/**/{!(main.ts),}.ts'],
coveragePathIgnorePatterns: ['lib/', 'node_modules/', '__mocks__/', '__tests__/'],
verbose: true
};

View file

@ -1,13 +1,17 @@
{ {
"name": "docker-metadata-action", "name": "docker-metadata-action",
"description": "GitHub Action to extract metadata (tags, labels) for Docker", "description": "GitHub Action to extract metadata (tags, labels) for Docker",
"type": "module", "main": "lib/main.js",
"main": "src/main.ts",
"scripts": { "scripts": {
"build": "ncc build --source-map --minify --license licenses.txt", "build": "ncc build src/main.ts --source-map --minify --license licenses.txt",
"lint": "eslint --max-warnings=0 .", "lint": "yarn run prettier && yarn run eslint",
"format": "eslint --fix .", "format": "yarn run prettier:fix && yarn run eslint:fix",
"test": "vitest run" "eslint": "eslint --max-warnings=0 .",
"eslint:fix": "eslint --fix .",
"prettier": "prettier --check \"./**/*.ts\"",
"prettier:fix": "prettier --write \"./**/*.ts\"",
"test": "jest",
"all": "yarn run build && yarn run format && yarn test"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -22,34 +26,33 @@
], ],
"author": "Docker Inc.", "author": "Docker Inc.",
"license": "Apache-2.0", "license": "Apache-2.0",
"packageManager": "yarn@4.9.2",
"dependencies": { "dependencies": {
"@actions/core": "^3.0.0", "@actions/core": "^1.10.1",
"@actions/github": "^9.0.0", "@actions/github": "^6.0.0",
"@docker/actions-toolkit": "^0.79.0", "@docker/actions-toolkit": "^0.14.0",
"@renovate/pep440": "^1.0.0", "@renovate/pep440": "^1.0.0",
"csv-parse": "^6.1.0", "csv-parse": "^5.5.2",
"handlebars": "^4.7.8", "handlebars": "^4.7.8",
"moment": "^2.30.1", "moment": "^2.29.4",
"moment-timezone": "^0.6.1", "moment-timezone": "^0.5.43",
"semver": "^7.7.4" "semver": "^7.5.4"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.39.3", "@types/csv-parse": "^1.2.2",
"@types/node": "^24.11.0", "@types/node": "^20.5.9",
"@types/semver": "^7.7.1", "@types/semver": "^7.5.1",
"@typescript-eslint/eslint-plugin": "^8.56.1", "@typescript-eslint/eslint-plugin": "^6.6.0",
"@typescript-eslint/parser": "^8.56.1", "@typescript-eslint/parser": "^6.6.0",
"@vercel/ncc": "^0.38.4", "@vercel/ncc": "^0.38.0",
"@vitest/coverage-v8": "^4.0.18", "dotenv": "^16.3.1",
"@vitest/eslint-plugin": "^1.6.9", "eslint": "^8.48.0",
"dotenv": "^17.3.1", "eslint-config-prettier": "^9.0.0",
"eslint": "^9.39.3", "eslint-plugin-jest": "^27.2.3",
"eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-prettier": "^5.5.5", "jest": "^29.6.4",
"globals": "^17.3.0", "prettier": "^3.0.3",
"prettier": "^3.8.1", "ts-jest": "^29.1.1",
"typescript": "^5.9.3", "ts-node": "^10.9.1",
"vitest": "^4.0.18" "typescript": "^5.2.2"
} }
} }

View file

@ -1,15 +1,8 @@
import * as core from '@actions/core'; import * as core from '@actions/core';
import {Context} from '@actions/github/lib/context';
import {Util} from '@docker/actions-toolkit/lib/util.js'; import {Util} from '@docker/actions-toolkit/lib/util';
import {Git} from '@docker/actions-toolkit/lib/git.js'; import {Git} from '@docker/actions-toolkit/lib/git';
import {GitHub} from '@docker/actions-toolkit/lib/github/github.js'; import {GitHub} from '@docker/actions-toolkit/lib/github';
import {Toolkit} from '@docker/actions-toolkit/lib/toolkit.js';
type GithubContext = typeof GitHub.context;
export interface Context extends GithubContext {
commitDate: Date;
}
export interface Inputs { export interface Inputs {
context: ContextSource; context: ContextSource;
@ -17,10 +10,8 @@ export interface Inputs {
tags: string[]; tags: string[];
flavor: string[]; flavor: string[];
labels: string[]; labels: string[];
annotations: string[];
sepTags: string; sepTags: string;
sepLabels: string; sepLabels: string;
sepAnnotations: string;
bakeTarget: string; bakeTarget: string;
githubToken: string; githubToken: string;
} }
@ -28,14 +19,12 @@ export interface Inputs {
export function getInputs(): Inputs { export function getInputs(): Inputs {
return { return {
context: (core.getInput('context') || ContextSource.workflow) as ContextSource, context: (core.getInput('context') || ContextSource.workflow) as ContextSource,
images: Util.getInputList('images', {ignoreComma: true, comment: '#', commentNoInfix: true}), images: Util.getInputList('images', {ignoreComma: true, comment: '#'}),
tags: Util.getInputList('tags', {ignoreComma: true, comment: '#', commentNoInfix: true}), tags: Util.getInputList('tags', {ignoreComma: true, comment: '#'}),
flavor: Util.getInputList('flavor', {ignoreComma: true, comment: '#', commentNoInfix: true}), flavor: Util.getInputList('flavor', {ignoreComma: true, comment: '#'}),
labels: Util.getInputList('labels', {ignoreComma: true, comment: '#', commentNoInfix: true}), labels: Util.getInputList('labels', {ignoreComma: true, comment: '#'}),
annotations: Util.getInputList('annotations', {ignoreComma: true, comment: '#', commentNoInfix: true}),
sepTags: core.getInput('sep-tags', {trimWhitespace: false}) || `\n`, sepTags: core.getInput('sep-tags', {trimWhitespace: false}) || `\n`,
sepLabels: core.getInput('sep-labels', {trimWhitespace: false}) || `\n`, sepLabels: core.getInput('sep-labels', {trimWhitespace: false}) || `\n`,
sepAnnotations: core.getInput('sep-annotations', {trimWhitespace: false}) || `\n`,
bakeTarget: core.getInput('bake-target') || `docker-metadata-action`, bakeTarget: core.getInput('bake-target') || `docker-metadata-action`,
githubToken: core.getInput('github-token') githubToken: core.getInput('github-token')
}; };
@ -46,10 +35,10 @@ export enum ContextSource {
git = 'git' git = 'git'
} }
export async function getContext(source: ContextSource, toolkit: Toolkit): Promise<Context> { export async function getContext(source: ContextSource): Promise<Context> {
switch (source) { switch (source) {
case ContextSource.workflow: case ContextSource.workflow:
return await getContextFromWorkflow(toolkit); return getContextFromWorkflow();
case ContextSource.git: case ContextSource.git:
return await getContextFromGit(); return await getContextFromGit();
default: default:
@ -57,7 +46,7 @@ export async function getContext(source: ContextSource, toolkit: Toolkit): Promi
} }
} }
async function getContextFromWorkflow(toolkit: Toolkit): Promise<Context> { function getContextFromWorkflow(): Context {
const context = GitHub.context; const context = GitHub.context;
// Needs to override Git reference with pr ref instead of upstream branch ref // Needs to override Git reference with pr ref instead of upstream branch ref
@ -76,63 +65,9 @@ async function getContextFromWorkflow(toolkit: Toolkit): Promise<Context> {
} }
} }
return { return context;
commitDate: await getCommitDateFromWorkflow(context.sha, toolkit),
...context
} as Context;
} }
async function getContextFromGit(): Promise<Context> { async function getContextFromGit(): Promise<Context> {
const ctx = await Git.context(); return await Git.context();
return {
commitDate: await Git.commitDate(ctx.sha),
...ctx
} as Context;
}
async function getCommitDateFromWorkflow(sha: string, toolkit: Toolkit): Promise<Date> {
const event = GitHub.context.payload as unknown as {
// branch push
commits?: Array<{
timestamp: string;
// commit sha
id: string;
}>;
// tags
head_commit?: {
timestamp: string;
// commit sha
id: string;
};
};
if (event.commits) {
const commitDate = event.commits.find(x => x.id === sha)?.timestamp;
if (commitDate) {
return new Date(commitDate);
}
}
if (event.head_commit) {
if (event.head_commit.id === sha) {
return new Date(event.head_commit.timestamp);
}
}
// fallback to github api for commit date
try {
const commit = await toolkit.github.octokit.rest.repos.getCommit({
owner: GitHub.context.repo.owner,
repo: GitHub.context.repo.repo,
ref: sha
});
if (commit.data.commit.committer?.date) {
return new Date(commit.data.commit.committer.date);
}
throw new Error('Committer date not found');
} catch (error) {
core.debug(`Failed to get commit date from GitHub API: ${error.message}`);
return new Date();
}
} }

View file

@ -1,20 +1,23 @@
import * as fs from 'fs'; import * as fs from 'fs';
import * as core from '@actions/core'; import * as core from '@actions/core';
import * as actionsToolkit from '@docker/actions-toolkit'; import * as actionsToolkit from '@docker/actions-toolkit';
import {Toolkit} from '@docker/actions-toolkit/lib/toolkit.js'; import {Toolkit} from '@docker/actions-toolkit/lib/toolkit';
import {Util} from '@docker/actions-toolkit/lib/util.js';
import {getContext, getInputs, Inputs} from './context.js'; import {getContext, getInputs, Inputs} from './context';
import {Meta, Version} from './meta.js'; import {Meta, Version} from './meta';
function setOutput(name: string, value: string) {
core.setOutput(name, value);
core.exportVariable(`DOCKER_METADATA_OUTPUT_${name.replace(/\W/g, '_').toUpperCase()}`, value);
}
actionsToolkit.run( actionsToolkit.run(
// main // main
async () => { async () => {
const inputs: Inputs = getInputs(); const inputs: Inputs = getInputs();
const toolkit = new Toolkit({githubToken: inputs.githubToken}); const toolkit = new Toolkit({githubToken: inputs.githubToken});
const context = await getContext(inputs.context, toolkit); const context = await getContext(inputs.context);
const repo = await toolkit.github.repoData(); const repo = await toolkit.github.repoData();
const setOutput = outputEnvEnabled() ? setOutputAndEnv : core.setOutput;
await core.group(`Context info`, async () => { await core.group(`Context info`, async () => {
core.info(`eventName: ${context.eventName}`); core.info(`eventName: ${context.eventName}`);
@ -25,7 +28,6 @@ actionsToolkit.run(
core.info(`actor: ${context.actor}`); core.info(`actor: ${context.actor}`);
core.info(`runNumber: ${context.runNumber}`); core.info(`runNumber: ${context.runNumber}`);
core.info(`runId: ${context.runId}`); core.info(`runId: ${context.runId}`);
core.info(`commitDate: ${context.commitDate}`);
}); });
if (core.isDebug()) { if (core.isDebug()) {
@ -47,7 +49,7 @@ actionsToolkit.run(
setOutput('version', version.main || ''); setOutput('version', version.main || '');
// Docker tags // Docker tags
const tags = meta.getTags(); const tags: Array<string> = meta.getTags();
if (tags.length == 0) { if (tags.length == 0) {
core.warning('No Docker tag has been generated. Check tags input.'); core.warning('No Docker tag has been generated. Check tags input.');
} else { } else {
@ -58,7 +60,6 @@ actionsToolkit.run(
}); });
} }
setOutput('tags', tags.join(inputs.sepTags)); setOutput('tags', tags.join(inputs.sepTags));
setOutput('tag-names', meta.getTags(true).join(inputs.sepTags));
// Docker labels // Docker labels
const labels: Array<string> = meta.getLabels(); const labels: Array<string> = meta.getLabels();
@ -70,31 +71,32 @@ actionsToolkit.run(
}); });
// Annotations // Annotations
const annotationsRaw: Array<string> = meta.getAnnotations(); const alevels = process.env.DOCKER_METADATA_ANNOTATIONS_LEVELS || 'manifest';
const annotationsLevels = process.env.DOCKER_METADATA_ANNOTATIONS_LEVELS || 'manifest'; if (labels.length > 0) {
await core.group(`Annotations`, async () => { await core.group(`Annotations`, async () => {
const annotations: Array<string> = []; const annotations: Array<string> = [];
for (const level of annotationsLevels.split(',')) { for (const level of alevels.split(',')) {
annotations.push( annotations.push(
...annotationsRaw.map(label => { ...labels.map(label => {
const v = `${level}:${label}`; const v = `${level}:${label}`;
core.info(v); core.info(v);
return v; return v;
}) })
); );
} }
setOutput(`annotations`, annotations.join(inputs.sepAnnotations)); setOutput(`annotations`, annotations.join(inputs.sepLabels));
}); });
}
// JSON // JSON
const jsonOutput = meta.getJSON(annotationsLevels.split(',')); const jsonOutput = meta.getJSON(alevels.split(','));
await core.group(`JSON output`, async () => { await core.group(`JSON output`, async () => {
core.info(JSON.stringify(jsonOutput, null, 2)); core.info(JSON.stringify(jsonOutput, null, 2));
setOutput('json', JSON.stringify(jsonOutput)); setOutput('json', JSON.stringify(jsonOutput));
}); });
// Bake files // Bake files
for (const kind of ['tags', 'labels', 'annotations:' + annotationsLevels]) { for (const kind of ['tags', 'labels', 'annotations:' + alevels]) {
const outputName = kind.split(':')[0]; const outputName = kind.split(':')[0];
const bakeFile: string = meta.getBakeFile(kind); const bakeFile: string = meta.getBakeFile(kind);
await core.group(`Bake file definition (${outputName})`, async () => { await core.group(`Bake file definition (${outputName})`, async () => {
@ -104,18 +106,6 @@ actionsToolkit.run(
} }
// Bake file with tags and labels // Bake file with tags and labels
setOutput(`bake-file`, `${meta.getBakeFileTagsLabels()}`); setOutput(`bake-file`, meta.getBakeFileTagsLabels());
} }
); );
function setOutputAndEnv(name: string, value: string) {
core.setOutput(name, value);
core.exportVariable(`DOCKER_METADATA_OUTPUT_${name.replace(/\W/g, '_').toUpperCase()}`, value);
}
function outputEnvEnabled(): boolean {
if (process.env.DOCKER_METADATA_SET_OUTPUT_ENV) {
return Util.parseBool(process.env.DOCKER_METADATA_SET_OUTPUT_ENV);
}
return true;
}

View file

@ -5,15 +5,14 @@ import moment from 'moment-timezone';
import * as pep440 from '@renovate/pep440'; import * as pep440 from '@renovate/pep440';
import * as semver from 'semver'; import * as semver from 'semver';
import * as core from '@actions/core'; import * as core from '@actions/core';
import {Context as ToolkitContext} from '@docker/actions-toolkit/lib/context.js'; import {Context} from '@actions/github/lib/context';
import {GitHubRepo} from '@docker/actions-toolkit/lib/types/github/github.js'; import {Context as ToolkitContext} from '@docker/actions-toolkit/lib/context';
import {GitHubRepo} from '@docker/actions-toolkit/lib/types/github';
import {Inputs, Context} from './context.js'; import {Inputs} from './context';
import * as icl from './image.js'; import * as icl from './image';
import * as tcl from './tag.js'; import * as tcl from './tag';
import * as fcl from './flavor.js'; import * as fcl from './flavor';
const defaultShortShaLength = 7;
export interface Version { export interface Version {
main: string | undefined; main: string | undefined;
@ -114,7 +113,6 @@ export class Meta {
} }
const currentDate = this.date; const currentDate = this.date;
const commitDate = this.context.commitDate;
const vraw = this.setValue( const vraw = this.setValue(
handlebars.compile(tag.attrs['pattern'])({ handlebars.compile(tag.attrs['pattern'])({
date: function (format, options) { date: function (format, options) {
@ -130,20 +128,6 @@ export class Meta {
} }
}); });
return m.tz(tz).format(format); return m.tz(tz).format(format);
},
commit_date: function (format, options) {
const m = moment(commitDate);
let tz = 'UTC';
Object.keys(options.hash).forEach(key => {
switch (key) {
case 'tz':
tz = options.hash[key];
break;
default:
throw new Error(`Unknown ${key} attribute`);
}
});
return m.tz(tz).format(format);
} }
}), }),
tag tag
@ -161,20 +145,8 @@ export class Meta {
if (tag.attrs['value'].length > 0) { if (tag.attrs['value'].length > 0) {
vraw = this.setGlobalExp(tag.attrs['value']); vraw = this.setGlobalExp(tag.attrs['value']);
} else { } else {
vraw = this.context.ref.replace(/^refs\/tags\//g, ''); vraw = this.context.ref.replace(/^refs\/tags\//g, '').replace(/\//g, '-');
} }
if (tag.attrs['match'].length > 0) {
const tmatch = vraw.match(tag.attrs['match']);
if (!tmatch) {
core.warning(`${tag.attrs['match']} does not match ${vraw}.`);
} else {
vraw = tmatch[1];
}
}
vraw = vraw.replace(/\//g, '-');
if (!semver.valid(vraw)) { if (!semver.valid(vraw)) {
core.warning(`${vraw} is not a valid semver. More info: https://semver.org/`); core.warning(`${vraw} is not a valid semver. More info: https://semver.org/`);
return version; return version;
@ -207,20 +179,8 @@ export class Meta {
if (tag.attrs['value'].length > 0) { if (tag.attrs['value'].length > 0) {
vraw = this.setGlobalExp(tag.attrs['value']); vraw = this.setGlobalExp(tag.attrs['value']);
} else { } else {
vraw = this.context.ref.replace(/^refs\/tags\//g, ''); vraw = this.context.ref.replace(/^refs\/tags\//g, '').replace(/\//g, '-');
} }
if (tag.attrs['match'].length > 0) {
const tmatch = vraw.match(tag.attrs['match']);
if (!tmatch) {
core.warning(`${tag.attrs['match']} does not match ${vraw}.`);
} else {
vraw = tmatch[1];
}
}
vraw = vraw.replace(/\//g, '-');
if (!pep440.valid(vraw)) { if (!pep440.valid(vraw)) {
core.warning(`${vraw} does not conform to PEP 440. More info: https://www.python.org/dev/peps/pep-0440`); core.warning(`${vraw} does not conform to PEP 440. More info: https://www.python.org/dev/peps/pep-0440`);
return version; return version;
@ -347,7 +307,7 @@ export class Meta {
let val = this.context.sha; let val = this.context.sha;
if (tag.attrs['format'] === tcl.ShaFormat.Short) { if (tag.attrs['format'] === tcl.ShaFormat.Short) {
val = Meta.shortSha(this.context.sha); val = this.context.sha.substring(0, 7);
} }
const vraw = this.setValue(val, tag); const vraw = this.setValue(val, tag);
@ -376,7 +336,7 @@ export class Meta {
if (hp.body.length == 1 && hp.body[0].type == 'MustacheStatement') { if (hp.body.length == 1 && hp.body[0].type == 'MustacheStatement') {
return hp.body[0]['path']['parts'].length == 1 && hp.body[0]['path']['parts'][0] == 'raw'; return hp.body[0]['path']['parts'].length == 1 && hp.body[0]['path']['parts'][0] == 'raw';
} }
} catch { } catch (err) {
return false; return false;
} }
return false; return false;
@ -396,10 +356,9 @@ export class Meta {
return val; return val;
} }
private setGlobalExp(val: string): string { private setGlobalExp(val): string {
const context = this.context; const context = this.context;
const currentDate = this.date; const currentDate = this.date;
const commitDate = this.context.commitDate;
return handlebars.compile(val)({ return handlebars.compile(val)({
branch: function () { branch: function () {
if (!/^refs\/heads\//.test(context.ref)) { if (!/^refs\/heads\//.test(context.ref)) {
@ -414,7 +373,7 @@ export class Meta {
return context.ref.replace(/^refs\/tags\//g, ''); return context.ref.replace(/^refs\/tags\//g, '');
}, },
sha: function () { sha: function () {
return Meta.shortSha(context.sha); return context.sha.substring(0, 7);
}, },
base_ref: function () { base_ref: function () {
if (/^refs\/tags\//.test(context.ref) && context.payload?.base_ref != undefined) { if (/^refs\/tags\//.test(context.ref) && context.payload?.base_ref != undefined) {
@ -427,20 +386,6 @@ export class Meta {
} }
return ''; return '';
}, },
commit_date: function (format, options) {
const m = moment(commitDate);
let tz = 'UTC';
Object.keys(options.hash).forEach(key => {
switch (key) {
case 'tz':
tz = options.hash[key];
break;
default:
throw new Error(`Unknown ${key} attribute`);
}
});
return m.tz(tz).format(format);
},
is_default_branch: function () { is_default_branch: function () {
const branch = context.ref.replace(/^refs\/heads\//g, ''); const branch = context.ref.replace(/^refs\/heads\//g, '');
// TODO: "base_ref" is available in the push payload but doesn't always seem to // TODO: "base_ref" is available in the push payload but doesn't always seem to
@ -463,9 +408,6 @@ export class Meta {
} }
return 'false'; return 'false';
}, },
is_not_default_branch: function () {
return this.is_default_branch() === 'false' ? 'true' : 'false';
},
date: function (format, options) { date: function (format, options) {
const m = moment(currentDate); const m = moment(currentDate);
let tz = 'UTC'; let tz = 'UTC';
@ -494,51 +436,39 @@ export class Meta {
return images; return images;
} }
public getTags(namesOnly?: boolean): Array<string> { public getTags(): Array<string> {
if (!this.version.main) { if (!this.version.main) {
return []; return [];
} }
if (namesOnly) {
return this.generateTags(this.version.main); const generateTags = (imageName: string, version: string): Array<string> => {
} const tags: Array<string> = [];
const prefix = imageName !== '' ? `${imageName}:` : '';
tags.push(`${prefix}${version}`);
for (const partial of this.version.partial) {
tags.push(`${prefix}${partial}`);
}
if (this.version.latest) {
const latestTag = `${this.flavor.prefixLatest ? this.flavor.prefix : ''}latest${this.flavor.suffixLatest ? this.flavor.suffix : ''}`;
tags.push(`${prefix}${Meta.sanitizeTag(latestTag)}`);
}
return tags;
};
const tags: Array<string> = []; const tags: Array<string> = [];
const images = this.getImageNames(); const images = this.getImageNames();
if (images.length > 0) { if (images.length > 0) {
for (const imageName of images) { for (const imageName of images) {
tags.push(...this.generateTags(this.version.main, imageName)); tags.push(...generateTags(imageName, this.version.main));
} }
} else { } else {
tags.push(...this.generateTags(this.version.main)); tags.push(...generateTags('', this.version.main));
}
return tags;
}
private generateTags(version: string, imageName?: string): Array<string> {
const tags: Array<string> = [];
const prefix = imageName ? `${imageName}:` : '';
tags.push(`${prefix}${version}`);
for (const partial of this.version.partial) {
tags.push(`${prefix}${partial}`);
}
if (this.version.latest) {
const latestTag = `${this.flavor.prefixLatest ? this.flavor.prefix : ''}latest${this.flavor.suffixLatest ? this.flavor.suffix : ''}`;
tags.push(`${prefix}${Meta.sanitizeTag(latestTag)}`);
} }
return tags; return tags;
} }
public getLabels(): Array<string> { public getLabels(): Array<string> {
return this.getOCIAnnotationsWithCustoms(this.inputs.labels); const labels: Array<string> = [
}
public getAnnotations(): Array<string> {
return this.getOCIAnnotationsWithCustoms(this.inputs.annotations);
}
private getOCIAnnotationsWithCustoms(extra: string[]): Array<string> {
const res: 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 || ''}`,
@ -548,13 +478,11 @@ export class Meta {
`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 || ''}`
]; ];
extra.forEach(label => { labels.push(...this.inputs.labels);
res.push(this.setGlobalExp(label));
});
return Array.from( return Array.from(
new Map<string, string>( new Map<string, string>(
res labels
.map(label => label.split('=')) .map(label => label.split('='))
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
.filter(([_key, ...values]) => values.length > 0) .filter(([_key, ...values]) => values.length > 0)
@ -568,11 +496,10 @@ export class Meta {
public getJSON(alevels: string[]): unknown { public getJSON(alevels: string[]): unknown {
const annotations: Array<string> = []; const annotations: Array<string> = [];
for (const level of alevels) { for (const level of alevels) {
annotations.push(...this.getAnnotations().map(label => `${level}:${label}`)); annotations.push(...this.getLabels().map(label => `${level}:${label}`));
} }
return { return {
tags: this.getTags(), tags: this.getTags(),
'tag-names': this.getTags(true),
labels: this.getLabels().reduce((res, label) => { labels: this.getLabels().reduce((res, label) => {
const matches = label.match(/([^=]*)=(.*)/); const matches = label.match(/([^=]*)=(.*)/);
if (!matches) { if (!matches) {
@ -587,66 +514,70 @@ export class Meta {
public getBakeFile(kind: string): string { public getBakeFile(kind: string): string {
if (kind == 'tags') { if (kind == 'tags') {
return this.generateBakeFile( return this.generateBakeFile(kind, {
{ tags: this.getTags(),
tags: this.getTags(), args: {
args: { DOCKER_META_IMAGES: this.getImageNames().join(','),
DOCKER_META_IMAGES: this.getImageNames().join(','), DOCKER_META_VERSION: this.version.main
DOCKER_META_VERSION: this.version.main }
} });
},
kind
);
} else if (kind == 'labels') { } else if (kind == 'labels') {
return this.generateBakeFile( return this.generateBakeFile(kind, {
{ labels: this.getLabels().reduce((res, label) => {
labels: this.getLabels().reduce((res, label) => { const matches = label.match(/([^=]*)=(.*)/);
const matches = label.match(/([^=]*)=(.*)/); if (!matches) {
if (!matches) {
return res;
}
res[matches[1]] = matches[2];
return res; return res;
}, {}) }
}, res[matches[1]] = matches[2];
kind return res;
); }, {})
});
} else if (kind.startsWith('annotations:')) { } else if (kind.startsWith('annotations:')) {
const name = kind.split(':')[0]; const name = kind.split(':')[0];
const annotations: Array<string> = []; const annotations: Array<string> = [];
for (const level of kind.split(':')[1].split(',')) { for (const level of kind.split(':')[1].split(',')) {
annotations.push(...this.getAnnotations().map(label => `${level}:${label}`)); annotations.push(...this.getLabels().map(label => `${level}:${label}`));
} }
return this.generateBakeFile( return this.generateBakeFile(name, {
{ annotations: annotations
annotations: annotations });
},
name
);
} }
throw new Error(`Unknown bake file type: ${kind}`); throw new Error(`Unknown bake file type: ${kind}`);
} }
public getBakeFileTagsLabels(): string { public getBakeFileTagsLabels(): string {
return this.generateBakeFile({ const bakeFile = path.join(ToolkitContext.tmpDir(), 'docker-metadata-action-bake.json');
tags: this.getTags(), fs.writeFileSync(
labels: this.getLabels().reduce((res, label) => { bakeFile,
const matches = label.match(/([^=]*)=(.*)/); JSON.stringify(
if (!matches) { {
return res; target: {
} [this.inputs.bakeTarget]: {
res[matches[1]] = matches[2]; tags: this.getTags(),
return res; labels: this.getLabels().reduce((res, label) => {
}, {}), const matches = label.match(/([^=]*)=(.*)/);
args: { if (!matches) {
DOCKER_META_IMAGES: this.getImageNames().join(','), return res;
DOCKER_META_VERSION: this.version.main }
} res[matches[1]] = matches[2];
}); return res;
}, {}),
args: {
DOCKER_META_IMAGES: this.getImageNames().join(','),
DOCKER_META_VERSION: this.version.main
}
}
}
},
null,
2
)
);
return bakeFile;
} }
private generateBakeFile(dt, suffix?: string): string { private generateBakeFile(name: string, dt): string {
const bakeFile = path.join(ToolkitContext.tmpDir(), `docker-metadata-action-bake${suffix ? `-${suffix}` : ''}.json`); const bakeFile = path.join(ToolkitContext.tmpDir(), `docker-metadata-action-bake-${name}.json`);
fs.writeFileSync(bakeFile, JSON.stringify({target: {[this.inputs.bakeTarget]: dt}}, null, 2)); fs.writeFileSync(bakeFile, JSON.stringify({target: {[this.inputs.bakeTarget]: dt}}, null, 2));
return bakeFile; return bakeFile;
} }
@ -658,18 +589,4 @@ export class Meta {
private static sanitizeTag(tag: string): string { private static sanitizeTag(tag: string): string {
return tag.replace(/[^a-zA-Z0-9._-]+/g, '-'); return tag.replace(/[^a-zA-Z0-9._-]+/g, '-');
} }
private static shortSha(sha: string): string {
let shortShaLength = defaultShortShaLength;
if (process.env.DOCKER_METADATA_SHORT_SHA_LENGTH) {
if (isNaN(Number(process.env.DOCKER_METADATA_SHORT_SHA_LENGTH))) {
throw new Error(`DOCKER_METADATA_SHORT_SHA_LENGTH is not a valid number: ${process.env.DOCKER_METADATA_SHORT_SHA_LENGTH}`);
}
shortShaLength = Number(process.env.DOCKER_METADATA_SHORT_SHA_LENGTH);
}
if (shortShaLength >= sha.length) {
return sha;
}
return sha.substring(0, shortShaLength);
}
} }

View file

@ -104,10 +104,10 @@ export function Parse(s: string): Tag {
const value = parts[1]; const value = parts[1];
switch (key) { switch (key) {
case 'type': { case 'type': {
if (!Object.values(Type).includes(value as Type)) { if (!Object.values(Type).includes(value)) {
throw new Error(`Unknown tag type attribute: ${value}`); throw new Error(`Unknown tag type attribute: ${value}`);
} }
tag.type = value as Type; tag.type = value;
break; break;
} }
default: { default: {
@ -137,9 +137,6 @@ export function Parse(s: string): Tag {
if (!Object.prototype.hasOwnProperty.call(tag.attrs, 'value')) { if (!Object.prototype.hasOwnProperty.call(tag.attrs, 'value')) {
tag.attrs['value'] = ''; tag.attrs['value'] = '';
} }
if (!Object.prototype.hasOwnProperty.call(tag.attrs, 'match')) {
tag.attrs['match'] = '';
}
break; break;
} }
case Type.Match: { case Type.Match: {

View file

@ -4,11 +4,9 @@ RUN apk add --no-cache coreutils jq
ARG DOCKER_METADATA_OUTPUT_VERSION ARG DOCKER_METADATA_OUTPUT_VERSION
ARG DOCKER_METADATA_OUTPUT_TAGS ARG DOCKER_METADATA_OUTPUT_TAGS
ARG DOCKER_METADATA_OUTPUT_LABELS ARG DOCKER_METADATA_OUTPUT_LABELS
ARG DOCKER_METADATA_OUTPUT_ANNOTATIONS
ARG DOCKER_METADATA_OUTPUT_JSON ARG DOCKER_METADATA_OUTPUT_JSON
RUN printenv DOCKER_METADATA_OUTPUT_VERSION RUN printenv DOCKER_METADATA_OUTPUT_VERSION
RUN printenv DOCKER_METADATA_OUTPUT_TAGS RUN printenv DOCKER_METADATA_OUTPUT_TAGS
RUN printenv DOCKER_METADATA_OUTPUT_LABELS RUN printenv DOCKER_METADATA_OUTPUT_LABELS
RUN printenv DOCKER_METADATA_OUTPUT_ANNOTATIONS
RUN printenv DOCKER_METADATA_OUTPUT_JSON RUN printenv DOCKER_METADATA_OUTPUT_JSON
RUN echo $DOCKER_METADATA_OUTPUT_JSON | jq RUN echo $DOCKER_METADATA_OUTPUT_JSON | jq

View file

@ -1,8 +1,9 @@
{ {
"compilerOptions": { "compilerOptions": {
"module": "nodenext",
"moduleResolution": "nodenext",
"esModuleInterop": true, "esModuleInterop": true,
"target": "es6",
"module": "commonjs",
"strict": true,
"newLine": "lf", "newLine": "lf",
"outDir": "./lib", "outDir": "./lib",
"rootDir": "./src", "rootDir": "./src",
@ -11,7 +12,11 @@
"resolveJsonModule": true, "resolveJsonModule": true,
"useUnknownInCatchVariables": false, "useUnknownInCatchVariables": false,
}, },
"include": [ "exclude": [
"src/**/*.ts" "./__mocks__/**/*",
"./__tests__/**/*",
"./lib/**/*",
"node_modules",
"jest.config.ts"
] ]
} }

View file

@ -1,16 +0,0 @@
import {defineConfig} from 'vitest/config';
export default defineConfig({
test: {
clearMocks: true,
environment: 'node',
setupFiles: ['./__tests__/setup.unit.ts'],
include: ['**/*.test.ts'],
coverage: {
provider: 'v8',
reporter: ['clover'],
include: ['src/**/*.ts'],
exclude: ['src/**/main.ts']
}
}
});

9015
yarn.lock

File diff suppressed because it is too large Load diff