diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82ee44c..88a3a28 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -398,3 +398,47 @@ jobs: with: files: | ./test/config.hcl + + git-context: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v4 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} + driver-opts: | + image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} + - + name: Build + uses: ./ + with: + source: "{{defaultContext}}" + + git-context-and-local: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v4 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + version: ${{ inputs.buildx-version || env.BUILDX_VERSION }} + driver-opts: | + image=${{ inputs.buildkit-image || env.BUILDKIT_IMAGE }} + - + name: Docker meta + id: meta + uses: docker/metadata-action@v5 + - + name: Build + uses: ./ + with: + source: "{{defaultContext}}" + files: | + cwd://${{ steps.meta.outputs.bake-file }} diff --git a/README.md b/README.md index 979ac84..87205ff 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ as a high-level build command. ___ * [Usage](#usage) + * [Path context](#path-context) + * [Git context](#git-context) * [Customizing](#customizing) * [inputs](#inputs) * [outputs](#outputs) @@ -23,6 +25,12 @@ ___ ## Usage +### Path context + +By default, this action will use the local bake definition (`source: .`), so +you need to use the [`actions/checkout`](https://github.com/actions/checkout/) +action to check out the repository. + ```yaml name: ci @@ -54,11 +62,66 @@ jobs: push: true ``` +### Git context + +Git context can be provided using the [`source` input](#inputs). This means +that you don't need to use the [`actions/checkout`](https://github.com/actions/checkout/) +action to check out the repository as [BuildKit](https://docs.docker.com/build/buildkit/) +will do this directly. + +```yaml +name: ci + +on: + push: + branches: + - 'master' + +jobs: + bake: + runs-on: ubuntu-latest + steps: + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - + name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push + uses: docker/bake-action@v4 + with: + source: "${{ github.server_url }}/${{ github.repository }}.git#${{ github.ref }}" + push: true +``` + +Be careful because **any file mutation in the steps that precede the build step +will be ignored, including processing of the `.dockerignore` file** since +the context is based on the Git reference. However, you can use the +[Path context](#path-context) alongside the [`actions/checkout`](https://github.com/actions/checkout/) +action to remove this restriction. + +Default Git context can also be provided using the [Handlebars template](https://handlebarsjs.com/guide/) +expression `{{defaultContext}}`. Here we can use it to provide a subdirectory +to the default Git context: + +```yaml + - + name: Build and push + uses: docker/bake-action@v4 + with: + source: "{{defaultContext}}:mysubdir" + push: true +``` + ## Customizing ### inputs -Following inputs can be used as `step.with` keys +The following inputs can be used as `step.with` keys > `List` type is a newline-delimited string > ```yaml @@ -75,20 +138,20 @@ Following inputs can be used as `step.with` keys > targets: default,release > ``` -| Name | Type | Description | -|--------------|-------------|---------------------------------------------------------------------------------------------------------------------------------------------| -| `builder` | String | Builder instance (see [setup-buildx](https://github.com/docker/setup-buildx-action) action) | -| `files` | List/CSV | List of [bake definition files](https://docs.docker.com/build/customize/bake/file-definition/) | -| `workdir` | String | Working directory of execution | -| `targets` | List/CSV | List of bake targets (`default` target used if empty) | -| `no-cache` | Bool | Do not use cache when building the image (default `false`) | -| `pull` | Bool | Always attempt to pull a newer version of the image (default `false`) | -| `load` | Bool | Load is a shorthand for `--set=*.output=type=docker` (default `false`) | -| `provenance` | Bool/String | [Provenance](https://docs.docker.com/build/attestations/slsa-provenance/) is a shorthand for `--set=*.attest=type=provenance` | -| `push` | Bool | Push is a shorthand for `--set=*.output=type=registry` (default `false`) | -| `sbom` | Bool/String | [SBOM](https://docs.docker.com/build/attestations/sbom/) is a shorthand for `--set=*.attest=type=sbom` | -| `set` | List | List of [targets values to override](https://docs.docker.com/engine/reference/commandline/buildx_bake/#set) (eg: `targetpattern.key=value`) | -| `source` | String | [Remote bake definition](https://docs.docker.com/build/customize/bake/file-definition/#remote-definition) to build from | +| Name | Type | Description | +|--------------|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `builder` | String | Builder instance (see [setup-buildx](https://github.com/docker/setup-buildx-action) action) | +| `source` | String | Context to build from. Can be either local (`.`) or a [remote bake definition](https://docs.docker.com/build/customize/bake/file-definition/#remote-definition) | +| `files` | List/CSV | List of [bake definition files](https://docs.docker.com/build/customize/bake/file-definition/) | +| `workdir` | String | Working directory of execution | +| `targets` | List/CSV | List of bake targets (`default` target used if empty) | +| `no-cache` | Bool | Do not use cache when building the image (default `false`) | +| `pull` | Bool | Always attempt to pull a newer version of the image (default `false`) | +| `load` | Bool | Load is a shorthand for `--set=*.output=type=docker` (default `false`) | +| `provenance` | Bool/String | [Provenance](https://docs.docker.com/build/attestations/slsa-provenance/) is a shorthand for `--set=*.attest=type=provenance` | +| `push` | Bool | Push is a shorthand for `--set=*.output=type=registry` (default `false`) | +| `sbom` | Bool/String | [SBOM](https://docs.docker.com/build/attestations/sbom/) is a shorthand for `--set=*.attest=type=sbom` | +| `set` | List | List of [targets values to override](https://docs.docker.com/engine/reference/commandline/buildx_bake/#set) (eg: `targetpattern.key=value`) | ### outputs diff --git a/__tests__/context.test.ts b/__tests__/context.test.ts index 19623b8..119a802 100644 --- a/__tests__/context.test.ts +++ b/__tests__/context.test.ts @@ -304,6 +304,25 @@ describe('getArgs', () => { 'image-all' ] ], + [ + 11, + '0.10.0', + new Map([ + ['source', '{{defaultContext}}'], + ['load', 'false'], + ['no-cache', 'false'], + ['push', 'false'], + ['pull', 'false'], + ['files', './foo.hcl'], + ]), + [ + 'bake', + 'https://github.com/docker/build-push-action.git#refs/heads/master', + '--file', './foo.hcl', + '--metadata-file', path.join(tmpDir, 'metadata-file'), + '--provenance', `mode=min,inline-only=true,builder-id=https://github.com/docker/build-push-action/actions/runs/123456789`, + ] + ], ])( '[%d] given %p with %p as inputs, returns %p', async (num: number, buildxVersion: string, inputs: Map, expected: Array) => { diff --git a/action.yml b/action.yml index a0796d2..b3c29e4 100644 --- a/action.yml +++ b/action.yml @@ -10,6 +10,9 @@ inputs: builder: description: "Builder instance" required: false + source: + description: "Context to build from. Can be either local or a remote bake definition" + required: false files: description: "List of bake definition files" required: false @@ -45,9 +48,6 @@ inputs: set: description: "List of targets values to override (eg. targetpattern.key=value)" required: false - source: - description: "Remote bake definition to build from" - required: false outputs: metadata: diff --git a/package.json b/package.json index 50c1325..0da9bb7 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,8 @@ "license": "Apache-2.0", "dependencies": { "@actions/core": "^1.10.1", - "@docker/actions-toolkit": "^0.18.0" + "@docker/actions-toolkit": "^0.18.0", + "handlebars": "^4.7.8" }, "devDependencies": { "@types/node": "^20.5.9", diff --git a/src/context.ts b/src/context.ts index a55e3e5..12b3166 100644 --- a/src/context.ts +++ b/src/context.ts @@ -1,5 +1,7 @@ import * as core from '@actions/core'; +import * as handlebars from 'handlebars'; import {Bake} from '@docker/actions-toolkit/lib/buildx/bake'; +import {Context} from '@docker/actions-toolkit/lib/context'; import {Inputs as BuildxInputs} from '@docker/actions-toolkit/lib/buildx/inputs'; import {GitHub} from '@docker/actions-toolkit/lib/github'; import {Toolkit} from '@docker/actions-toolkit/lib/toolkit'; @@ -48,8 +50,14 @@ export async function getArgs(inputs: Inputs, toolkit: Toolkit): Promise> { const args: Array = ['bake']; - if (inputs.source) { - args.push(inputs.source); + let source = handlebars.compile(inputs.source)({ + defaultContext: Context.gitContext() + }); + if (source === '.') { + source = ''; + } + if (source) { + args.push(source); } await Util.asyncForEach(inputs.files, async file => { args.push('--file', file); @@ -61,7 +69,7 @@ async function getBakeArgs(inputs: Inputs, toolkit: Toolkit): Promise=0.10.0')) { - const bakedef = await toolkit.bake.parseDefinitions([...inputs.files, inputs.source], inputs.targets, inputs.set, inputs.load, inputs.push, inputs.workdir); + const bakedef = await toolkit.bake.parseDefinitions([...inputs.files, source], inputs.targets, inputs.set, inputs.load, inputs.push, inputs.workdir); if (inputs.provenance) { args.push('--provenance', inputs.provenance); } else if ((await toolkit.buildkit.versionSatisfies(inputs.builder, '>=0.11.0')) && !Bake.hasDockerExporter(bakedef, inputs.load)) {