diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 5673c18..b51c5f4 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -44,6 +44,8 @@ Plugin releases are immutable Git tags with asset-free GitHub Releases. Before y 1. Update every `github-actions#vX.Y.Z` reference in `README.md` to the plugin version being released; the plugin linter accepts this prospective version on `main` and requires it on the tag build. 1. Wait for the Buildkite Pipelines build for `main` to pass. +The Buildkite app contract changes required for server workflow selection without an explicit selector (#33143 and #33235) are deployed. Before releasing this plugin or promoting it to `latest`, publish a compatible `buildkite-gha` release. Do not publish or promote the wrapper first; older runtimes reject selector-free configurations, and the server contract supplies the trusted trigger context that makes them valid. + When changing runtime integration, update `plugin.yml`, `hooks/command`, `.github/workflows/plugin-smoke.yml`, `tests/command.bats`, and the README together. Make sure the examples and versioned compatibility and security links describe the recommended runtime release. From a clean, up-to-date local `main`, create the immutable lightweight tag: diff --git a/README.md b/README.md index 3fc9861..98d60cf 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ During the preview, start with a simple workflow in a public `github.com` reposi ## Add workflows to a pipeline -Add the plugin to a keyed command step in your pipeline configuration. Select the workflow you want to import explicitly: +For most users, add the plugin to a keyed command step in your pipeline configuration. Select the workflow you want to import explicitly: ```yaml steps: @@ -24,7 +24,7 @@ steps: workflow: .github/workflows/ci.yml ``` -The selector must be an explicit path to a `.yml` or `.yaml` workflow file. When present, the file must be regular, tracked, and inside the repository. When this importer step runs, the plugin uploads one dynamic pipeline containing a Buildkite group for each directly runnable workflow. Each workflow job and static matrix entry becomes a Buildkite Pipelines job that depends on the importer step. The importer step must have a `key` and must be scheduled explicitly on either a Linux amd64 or native macOS arm64 agent. The plugin's `runners` mappings schedule generated workflow jobs only; they do not select or change the importer agent. +An explicit selector must be a path to a `.yml` or `.yaml` workflow file. When present, the file must be regular, tracked, and inside the repository. When this importer step runs, the plugin uploads one dynamic pipeline containing a Buildkite group for each directly runnable workflow. Each workflow job and static matrix entry becomes a Buildkite Pipelines job that depends on the importer step. An explicitly configured importer step must have a `key` and must be scheduled explicitly on either a Linux amd64 or native macOS arm64 agent. The plugin's `runners` mappings schedule generated workflow jobs only; they do not select or change the importer agent. The Git ref after `github-actions#` selects the plugin code. Use a specific release such as `github-actions#v0.13.0` for an immutable pin, or use `github-actions#latest` to follow the newest stable plugin release that has passed the required validation. This is separate from the `version` property below, which selects the `buildkite-gha` runtime. @@ -32,8 +32,8 @@ Configure runtime selection with the following properties: | Option | Required | Default | Description | | --- | --- | --- | --- | -| `workflow` | One of `workflow` or `workflows` | — | One explicit `.yml` or `.yaml` workflow path. Missing or untracked paths are skipped. | -| `workflows` | One of `workflow` or `workflows` | — | Non-empty array of explicit `.yml` or `.yaml` workflow paths. Missing or untracked paths are skipped. | +| `workflow` | Explicit selection only: one of `workflow` or `workflows` | — | One explicit `.yml` or `.yaml` workflow path. Missing or untracked paths are skipped. | +| `workflows` | Explicit selection only: one of `workflow` or `workflows` | — | Non-empty array of explicit `.yml` or `.yaml` workflow paths. Missing or untracked paths are skipped. | | `version` | No | `latest` | Latest stable or an exact `buildkite-gha` release from `0.9.0` onward. | | `source-ref` | No | — | Full `buildkite-gha` source commit to build for development testing; mutually exclusive with `version`. | | `minimum-release-age` | No | `0s` | Minimum release age used by mise when resolving `latest`. | @@ -46,7 +46,7 @@ Configure runtime selection with the following properties: To test unreleased runtime behavior, set `source-ref` to a full lowercase 40-character commit from the public `buildkite/buildkite-gha` repository and omit `version`. The plugin uses mise and Go 1.26.5 to build Linux amd64 and Darwin arm64 executables from that exact source, runs the executable native to the importer agent, and supplies the counterpart to generated jobs. Source commits are for development only and do not use release checksums, attestations, or `minimum-release-age`. -The plugin schema requires exactly one of `workflow` or `workflows` and validates its explicit paths, the runtime-acquisition fields `version`, `source-ref`, and `minimum-release-age`, the boolean `experimental-runner-user` field, and the admission-level shape of `oidc`. It passes behavioral configuration through to the selected `buildkite-gha` runtime, which validates the complete configuration strictly. This allows runtime releases to extend the supported syntax without requiring a companion plugin release. +The plugin schema validates explicit selector paths when present, the runtime-acquisition fields `version`, `source-ref`, and `minimum-release-age`, the boolean `experimental-runner-user` field, and the admission-level shape of `oidc`. It passes behavioral configuration through to the selected `buildkite-gha` runtime, which validates the complete configuration strictly. This allows runtime releases to extend the supported syntax without requiring a companion plugin release. ### Select workflows @@ -68,7 +68,7 @@ plugins: - .github/workflows/release.yml ``` -Configure exactly one selector form. Each present value must identify one regular, tracked `.yml` or `.yaml` file inside the repository. Empty values and arrays, directories, globs, symlinks, files outside the repository, and wildcard selectors are not accepted. Selected paths are canonicalized, sorted, and deduplicated before upload. +For explicit selection, configure exactly one selector form. Each present value must identify one regular, tracked `.yml` or `.yaml` file inside the repository. Empty values and arrays, directories, globs, symlinks, files outside the repository, and wildcard selectors are not accepted. Selected paths are canonicalized, sorted, and deduplicated before upload. Missing or untracked configured paths produce a warning and are skipped. If all configured paths are missing or untracked, the importer succeeds without uploading a pipeline. Remaining workflows are compiled and uploaded in one pipeline transaction. Workflow groups use the workflow's `name`, falling back to its repository path; a supported non-empty `run-name` is appended to the group label. Reusable workflows whose only trigger is `workflow_call` do not create groups, but remain available to matched callers. Selecting only reusable workflows is an error. A safely reportable compilation or trigger-translation error in one workflow instead becomes a failing top-level step, allowing other selected workflows to remain in the uploaded pipeline. @@ -245,6 +245,20 @@ For manual and scheduled builds, the plugin finds the exact commit from the chec Pull request builds receive `pull_request` context. Branch and tag builds receive `push` context. Verified linked merge queue and release webhooks supply `merge_group` and `release` context. Buildkite scheduled builds select workflows with a `schedule` trigger, while manual UI or API builds select workflows with `workflow_dispatch`; dispatch inputs are not available. +### Run from a GitHub Actions Pipeline Trigger + +> [!NOTE] +> GitHub Actions Pipeline Triggers are in private preview and feature flagged off for most organizations. + +When this trigger type is enabled, the Buildkite app and `buildkite-gha` select the workflow associated with the trigger. The minimal pipeline configuration is: + +```yaml +steps: + - plugin: github-actions +``` + +Supported runtime and behavioral options may still be configured using the standard `plugins` form while omitting both `workflow` and `workflows`; the plugin forwards them without inferring trigger context. + ## Configure checkout and credentials Supported, audited `actions/checkout` revisions can check out the event repository at its event commit or a static branch. Checkout runs anonymously when repository-provider credentials are not enabled. Private checkout uses Buildkite repository-provider Git credentials when they are enabled and authorized for the job. Direct and recursive GitHub submodules are supported within the compatibility guide's transport and credential boundaries. diff --git a/plugin.yml b/plugin.yml index cfbb037..bc4ab4b 100644 --- a/plugin.yml +++ b/plugin.yml @@ -10,7 +10,14 @@ requirements: - mktemp - cp configuration: + type: object oneOf: + - not: + anyOf: + - required: + - workflow + - required: + - workflows - required: - workflow - required: diff --git a/tests/command.bats b/tests/command.bats index 1c57eba..4f0cccd 100755 --- a/tests/command.bats +++ b/tests/command.bats @@ -69,6 +69,9 @@ if [[ "\${1:-}" == --no-config && "\${2:-}" == exec && "\${4:-}" == -- && "\${5: echo 'buildkite-gha: plugin: BUILDKITE_PLUGIN_CONFIGURATION is required' >&2 exit 2 fi + if [[ -n "\${MOCK_IMPORTER_ERROR:-}" ]]; then + echo "\$MOCK_IMPORTER_ERROR" >&2 + fi exit "\${MOCK_IMPORTER_EXIT:-0}" fi if [[ "\${1:-}" == --no-config && "\${2:-}" == exec && "\${3:-}" == go@1.26.5 && "\${4:-}" == -- && "\${5:-}" == env && "\${6:-}" == -u && "\${7:-}" == GOBIN && "\${8:-}" == CGO_ENABLED=0 && "\${9:-}" == GOTOOLCHAIN=local ]]; then @@ -163,6 +166,36 @@ teardown() { rm -rf "$TMP"; } grep -Fx "cwd=$PWD" "$MOCK_LOG" } +@test "passes an empty configuration object to buildkite-gha unchanged" { + export BUILDKITE_PLUGIN_CONFIGURATION='{}' + run "$REPO/hooks/command" + [ "$status" -eq 0 ] || { echo "$output"; false; } + grep -Fx 'mise=--no-config exec github:buildkite/buildkite-gha@latest -- buildkite-gha plugin' "$MOCK_LOG" + grep -Fx 'configuration={}' "$MOCK_LOG" +} + +@test "passes selector-free runtime and behavioral options to buildkite-gha unchanged" { + export BUILDKITE_PLUGIN_GITHUB_ACTIONS_VERSION=v0.35.1 + export BUILDKITE_PLUGIN_GITHUB_ACTIONS_MINIMUM_RELEASE_AGE=24h + export BUILDKITE_PLUGIN_CONFIGURATION='{"version":"v0.35.1","minimum-release-age":"24h","experimental-runner-user":false,"runners":[{"runs-on":"ubuntu-latest","queue":"hosted"}],"oidc":{"claims":["organization_id"],"subject-claim":"pipeline_id"}}' + run "$REPO/hooks/command" + [ "$status" -eq 0 ] || { echo "$output"; false; } + grep -Fx 'mise=--no-config exec github:buildkite/buildkite-gha@0.35.1 -- buildkite-gha plugin' "$MOCK_LOG" + grep -Fx 'minimum-release-age=24h' "$MOCK_LOG" + grep -Fx "configuration=$BUILDKITE_PLUGIN_CONFIGURATION" "$MOCK_LOG" +} + +@test "leaves ordinary selector-free failure to buildkite-gha" { + export BUILDKITE_PLUGIN_GITHUB_ACTIONS_VERSION=v0.35.1 + export BUILDKITE_PLUGIN_CONFIGURATION='{"version":"v0.35.1","runners":[{"runs-on":"ubuntu-latest","queue":"hosted"}]}' + export MOCK_IMPORTER_EXIT=2 + export MOCK_IMPORTER_ERROR='buildkite-gha: plugin: workflow or workflows is required outside a GitHub Actions Pipeline Trigger build' + run "$REPO/hooks/command" + [ "$status" -eq 2 ] + [[ "$output" == *"$MOCK_IMPORTER_ERROR"* ]] + grep -Fx "configuration=$BUILDKITE_PLUGIN_CONFIGURATION" "$MOCK_LOG" +} + @test "keeps mise acquisition failures visible in quiet mode" { export MOCK_MISE_ACQUISITION_FAILURE=1 run "$REPO/hooks/command"