diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 5950e7f9f5..f06d2a4191 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -31,11 +31,11 @@ steps: - api/proto/** - .buildkite/steps/check-protobuf-generation.sh plugins: - - docker-compose#v4.14.0: - config: .buildkite/docker-compose.yml - cli-version: 2 - mount-buildkite-agent: true - run: lint + - docker-compose#v4.14.0: + config: .buildkite/docker-compose.yml + cli-version: 2 + mount-buildkite-agent: true + run: lint - group: ":go::scientist: Tests and Coverage" if_changed: @@ -44,150 +44,150 @@ steps: - "**/fixtures/**" - .buildkite/steps/{tests,test-coverage-report}.sh steps: - - name: ":linux: Linux AMD64 Tests" - key: test-linux-amd64 - command: ".buildkite/steps/tests.sh" - parallelism: 2 - artifact_paths: - - junit-*.xml - - "coverage-*/**" - plugins: - - docker-compose#v4.14.0: - config: .buildkite/docker-compose.yml - cli-version: 2 - propagate-environment: true - run: agent - - test-collector#v1.11.0: - files: "junit-*.xml" - format: "junit" - tags: - - "os=linux" - - "arch=amd64" - - "race=false" + - name: ":linux: Linux AMD64 Tests" + key: test-linux-amd64 + command: ".buildkite/steps/tests.sh" + parallelism: 2 + artifact_paths: + - junit-*.xml + - "coverage-*/**" + plugins: + - docker-compose#v4.14.0: + config: .buildkite/docker-compose.yml + cli-version: 2 + propagate-environment: true + run: agent + - test-collector#v1.11.0: + files: "junit-*.xml" + format: "junit" + tags: + - "os=linux" + - "arch=amd64" + - "race=false" - - name: ":linux: Linux ARM64 Tests" - key: test-linux-arm64 - command: ".buildkite/steps/tests.sh" - parallelism: 2 - artifact_paths: - - junit-*.xml - - "coverage-*/**" - agents: - queue: $AGENT_RUNNERS_LINUX_ARM64_QUEUE - plugins: - - docker-compose#v4.14.0: - config: .buildkite/docker-compose.yml - cli-version: 2 - propagate-environment: true - run: agent - - test-collector#v1.11.0: - files: "junit-*.xml" - format: "junit" - tags: - - "os=linux" - - "arch=arm64" - - "race=false" + - name: ":linux: Linux ARM64 Tests" + key: test-linux-arm64 + command: ".buildkite/steps/tests.sh" + parallelism: 2 + artifact_paths: + - junit-*.xml + - "coverage-*/**" + agents: + queue: $AGENT_RUNNERS_LINUX_ARM64_QUEUE + plugins: + - docker-compose#v4.14.0: + config: .buildkite/docker-compose.yml + cli-version: 2 + propagate-environment: true + run: agent + - test-collector#v1.11.0: + files: "junit-*.xml" + format: "junit" + tags: + - "os=linux" + - "arch=arm64" + - "race=false" - - name: ":windows: Windows AMD64 Tests" - key: test-windows - command: "bash .buildkite\\steps\\tests.sh" - parallelism: 2 - artifact_paths: - - junit-*.xml - - "coverage-*/**" - agents: - queue: $AGENT_RUNNERS_WINDOWS_QUEUE - plugins: - - test-collector#v1.11.0: - files: "junit-*.xml" - format: "junit" - tags: - - "os=windows" - - "arch=arm64" - - "race=false" + - name: ":windows: Windows AMD64 Tests" + key: test-windows + command: "bash .buildkite\\steps\\tests.sh" + parallelism: 2 + artifact_paths: + - junit-*.xml + - "coverage-*/**" + agents: + queue: $AGENT_RUNNERS_WINDOWS_QUEUE + plugins: + - test-collector#v1.11.0: + files: "junit-*.xml" + format: "junit" + tags: + - "os=windows" + - "arch=arm64" + - "race=false" - - name: ":satellite: Detect Data Races" - key: test-race-linux-arm64 - command: ".buildkite/steps/tests.sh -race" - # Extra parallelism because this data race test is slow - parallelism: 3 - artifact_paths: - - junit-*.xml - - "coverage-*/**" - agents: - queue: $AGENT_RUNNERS_LINUX_ARM64_QUEUE - plugins: - - docker-compose#v4.14.0: - config: .buildkite/docker-compose.yml - cli-version: 2 - propagate-environment: true - run: agent - - test-collector#v1.11.0: - files: "junit-*.xml" - format: "junit" - tags: - - "os=linux" - - "arch=arm64" - - "race=true" + - name: ":satellite: Detect Data Races" + key: test-race-linux-arm64 + command: ".buildkite/steps/tests.sh -race" + # Extra parallelism because this data race test is slow + parallelism: 3 + artifact_paths: + - junit-*.xml + - "coverage-*/**" + agents: + queue: $AGENT_RUNNERS_LINUX_ARM64_QUEUE + plugins: + - docker-compose#v4.14.0: + config: .buildkite/docker-compose.yml + cli-version: 2 + propagate-environment: true + run: agent + - test-collector#v1.11.0: + files: "junit-*.xml" + format: "junit" + tags: + - "os=linux" + - "arch=arm64" + - "race=true" - - name: ":coverage: Test coverage report Linux ARM64" - key: test-coverage-linux-arm64 - command: ".buildkite/steps/test-coverage-report.sh coverage-linux-arm64" - artifact_paths: - - "cover.html" - - "cover.out" - depends_on: - - test-linux-arm64 - plugins: - - docker-compose#v4.14.0: - config: .buildkite/docker-compose.yml - cli-version: 2 - run: agent - - artifacts#v1.9.4: - download: "coverage-linux-arm64/**" + - name: ":coverage: Test coverage report Linux ARM64" + key: test-coverage-linux-arm64 + command: ".buildkite/steps/test-coverage-report.sh coverage-linux-arm64" + artifact_paths: + - "cover.html" + - "cover.out" + depends_on: + - test-linux-arm64 + plugins: + - docker-compose#v4.14.0: + config: .buildkite/docker-compose.yml + cli-version: 2 + run: agent + - artifacts#v1.9.4: + download: "coverage-linux-arm64/**" - - name: ":coverage: Test coverage report Linux AMD64" - key: test-coverage-linux-amd64 - command: ".buildkite/steps/test-coverage-report.sh coverage-linux-amd64" - artifact_paths: - - "cover.html" - - "cover.out" - depends_on: - - test-linux-amd64 - plugins: - - docker-compose#v4.14.0: - config: .buildkite/docker-compose.yml - cli-version: 2 - run: agent - - artifacts#v1.9.4: - download: "coverage-linux-amd64/**" + - name: ":coverage: Test coverage report Linux AMD64" + key: test-coverage-linux-amd64 + command: ".buildkite/steps/test-coverage-report.sh coverage-linux-amd64" + artifact_paths: + - "cover.html" + - "cover.out" + depends_on: + - test-linux-amd64 + plugins: + - docker-compose#v4.14.0: + config: .buildkite/docker-compose.yml + cli-version: 2 + run: agent + - artifacts#v1.9.4: + download: "coverage-linux-amd64/**" - - name: ":coverage: Test coverage report Linux ARM64 Race" - key: test-coverage-linux-arm64-race - command: ".buildkite/steps/test-coverage-report.sh coverage-linux-arm64-race" - artifact_paths: - - "cover.html" - - "cover.out" - depends_on: - - test-race-linux-arm64 - plugins: - - docker-compose#v4.14.0: - config: .buildkite/docker-compose.yml - cli-version: 2 - run: agent - - artifacts#v1.9.4: - download: "coverage-linux-arm64-race/**" + - name: ":coverage: Test coverage report Linux ARM64 Race" + key: test-coverage-linux-arm64-race + command: ".buildkite/steps/test-coverage-report.sh coverage-linux-arm64-race" + artifact_paths: + - "cover.html" + - "cover.out" + depends_on: + - test-race-linux-arm64 + plugins: + - docker-compose#v4.14.0: + config: .buildkite/docker-compose.yml + cli-version: 2 + run: agent + - artifacts#v1.9.4: + download: "coverage-linux-arm64-race/**" - - label: ":writing_hand: Annotate with Test Failures" - depends_on: - - test-linux-amd64 - - test-race-linux-arm64 - - test-linux-arm64 - - test-windows - allow_dependency_failure: true - plugins: - - junit-annotate#v1.6.0: - artifacts: junit-*.xml + - label: ":writing_hand: Annotate with Test Failures" + depends_on: + - test-linux-amd64 + - test-race-linux-arm64 + - test-linux-arm64 + - test-windows + allow_dependency_failure: true + plugins: + - junit-annotate#v1.6.0: + artifacts: junit-*.xml # --- end Tests and Coverage --- @@ -418,14 +418,15 @@ steps: - name: ":pipeline: Upload Release Pipeline" key: upload-release-steps depends_on: + - build-debian-packages + - build-github-release + - build-rpm-packages - check-code-committed - check-version-string - - test-windows + - e2e-tests - test-bk-cli - test-docker-amd64 - test-docker-arm64 - - build-rpm-packages - - build-debian-packages - - build-github-release + - test-windows command: ".buildkite/steps/upload-release-steps.sh" - if: build.env("DRY_RUN") == "true" || build.branch =~ /^(main|.*-.*-stable)$$/ + if: build.env("DRY_RUN") == "true" || build.branch =~ /^(main|.*-.*-stable|v\d+)$$/ diff --git a/.buildkite/steps/check-protobuf-generation.sh b/.buildkite/steps/check-protobuf-generation.sh index cbbad46245..590c374b58 100755 --- a/.buildkite/steps/check-protobuf-generation.sh +++ b/.buildkite/steps/check-protobuf-generation.sh @@ -14,6 +14,6 @@ buf generate if ! git diff --no-ext-diff --exit-code; then echo ^^^ +++ echo "Generated protobuf files are out of sync with the source code" - echo "Please run \`buf generate\` in the internal/proto directory locally, and commit the result." + echo "Please run \`buf generate\` in the api/proto directory locally, and commit the result." exit 1 fi diff --git a/.buildkite/steps/upload-release-steps.sh b/.buildkite/steps/upload-release-steps.sh index 6f177c55ed..6648076baa 100755 --- a/.buildkite/steps/upload-release-steps.sh +++ b/.buildkite/steps/upload-release-steps.sh @@ -48,9 +48,13 @@ YAML edge_steps_yaml() { echo "steps:" - trigger_step \ - "edge ${agent_version}.${build_version}" \ - "agent-release-edge" + # Don't create edge releases for beta/RC in this branch + # TODO(v4 cleanup): Re-enable edge releases here + if [[ ! "$agent_version" =~ (beta|rc) ]] ; then + trigger_step \ + "edge ${agent_version}.${build_version}" \ + "agent-release-edge" + fi } output_steps_yaml() { diff --git a/BUILD.bazel b/BUILD.bazel index 5e92e13c69..24bcab97cb 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,7 +1,7 @@ load("@gazelle//:def.bzl", "gazelle") load("@rules_go//go:def.bzl", "go_binary", "go_library") -# gazelle:prefix github.com/buildkite/agent/v3 +# gazelle:prefix github.com/buildkite/agent/v4 gazelle(name = "gazelle") go_binary( @@ -14,7 +14,7 @@ go_binary( go_library( name = "agent_lib", srcs = ["main.go"], - importpath = "github.com/buildkite/agent/v3", + importpath = "github.com/buildkite/agent/v4", visibility = ["//visibility:private"], deps = [ "//clicommand", diff --git a/CHANGELOG.md b/CHANGELOG.md index 82f8d24c7b..97a5219c12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [v4.0.0-beta.1](https://github.com/buildkite/agent/tree/v4.0.0-beta.1) (2026-04-22) +[Full Changelog](https://github.com/buildkite/agent/compare/v3.123.1...v4.0.0-beta.1) + +### Changed +- The following experiments are now default behaviour (promoted): + - `normalised-upload-paths` + - `override-zero-exit-on-cancel` + - `resolve-commit-after-checkout` + - `propagate-agent-config-vars` +- Remove `allow-artifact-path-traversal` experiment +- Remove deprecated Docker support +- `spawn-with-priority` is now a string, removing the `descending-spawn-priority` experiment [#3821](https://github.com/buildkite/agent/pull/3821) (@moskyb) +- Newline after meta data get [#3835](https://github.com/buildkite/agent/pull/3835) (@moskyb) +- Remove deprecated CLI flags [#3834](https://github.com/buildkite/agent/pull/3834) (@moskyb) +- Remove deprecated plugin env vars [#3852](https://github.com/buildkite/agent/pull/3852) (@DrJosh9000) + ## [v3.124.0](https://github.com/buildkite/agent/tree/v3.124.0) (2026-04-28) [Full Changelog](https://github.com/buildkite/agent/compare/v3.123.1...v3.124.0) diff --git a/EXPERIMENTS.md b/EXPERIMENTS.md index 13b0816379..4a7fb7eb27 100644 --- a/EXPERIMENTS.md +++ b/EXPERIMENTS.md @@ -18,25 +18,6 @@ If an experiment doesn't exist, no error will be raised. ## Available Experiments -### `normalised-upload-paths` - -Artifacts found by `buildkite-agent artifact upload` will be uploaded using URI/Unix-style paths, even on Windows. This changes the URLs that artifacts uploaded from Windows agents are stored at, but to one which is URI-compatible. - -Artifact names displayed in Buildkite's web UI, as well as in the API, are changed by this. - -Take `buildkite-agent artifact upload coverage\report.xml` as an example: - -- By default, and without this experiment, this file is uploaded to `s3://example/coverage\report.xml`. -- With this experiment enabled, it would be `s3://example/coverage/report.xml`. - -**Status**: a major improvement for Windows compatibility, we'd like this to be the standard behaviour in 4.0. πŸ‘πŸ‘ - -### `resolve-commit-after-checkout` - -After repository checkout, resolve `BUILDKITE_COMMIT` to a commit hash. This makes `BUILDKITE_COMMIT` useful for builds triggered against non-commit-hash refs such as `HEAD`. - -**Status**: broadly useful, we'd like this to be the standard behaviour in 4.0. πŸ‘πŸ‘ - ### `agent-api` This exposes a local API for interacting with the agent process. @@ -58,17 +39,6 @@ the PTY to modify the stream. (Or do we? That's why this is an experiment) **Status:** Experimental for some opt-in testing before being promoted to always-on. -### `override-zero-exit-on-cancel` - -If the job is cancelled, and the exit status of the process is 0, it is overridden to be 1 instead. - -When cancelling a job, the agent signals the process, which typically causes it to exit with a -non-zero status code. On Windows this is not true - the process exits with code 0 instead, which -makes the job appear to be successful. (It successfully exited, no?) By overriding the status to 1, -a cancelled job should appear as a failure, regardless of the OS the agent is running on. - -**Status:** Experimental for some opt-in testing. We hope to promote this to be the default soonβ„’. - ### `interpolation-prefers-runtime-env` When interpolating the pipeline level environment block, a pipeline level environment variable could take precedence over environment variables depending on the ordering. This may contravene Buildkite's [documentation](https://buildkite.com/docs/pipelines/environment-variables#environment-variable-precedence) that suggests the Job runtime environment takes precedence over that defined by combining environment variables defined in a pipeline. @@ -77,41 +47,66 @@ We previously made this the default behaviour of the agent (as of v3.63.0) but h **Status:** Available as an experiment to allow users who have since depended on this behaviour to re-enable it. If you use this feature please let us know so we may better understand your use case. -### `allow-artifact-path-traversal` - -Uploaded artifacts include a relative path used by the artifact downloader to download the artifact to a suitable location relative to the destination path. In most circumstances the relative paths generated by `artifact upload` won't contain `..` components, and so will always be downloaded at or inside the destination path. - -However, it is possible to upload artifacts using glob patterns containing one or more `..` components, which may be preserved in the artifact path. It is also possible for a user to call the Agent REST API directly in order to upload artifacts with arbitrary paths. - -Leaving this experiment disabled prevents `..` components in artifact paths from traversing up from the destination path. Enabling this experiment permits the less-secure behaviour of allowing artifact paths containing `..` to traverse up the destination path. - -For example, if an artifact was uploaded with the path `../../foo.txt`, then the command: - -```shell -buildkite-agent artifact download '*.txt' . -``` - -has a different effect depending on this experiment: - -- With `allow-artifact-path-traversal` disabled, `foo.txt` is downloaded to `./foo.txt`. -- With `allow-artifact-path-traversal` enabled, `foo.txt` is downloaded to `../../foo.txt`. - -**Status:** This experiment is an escape hatch for a security fix. While the new behaviour is more secure, it may break downloading of legitimately-uploaded artifacts. - -### `descending-spawn-priority` - -When using `--spawn` with `--spawn-with-priority`, the agent assigns ascending priorities to each spawned agent (1, 2, 3, ...). This experiment changes the priorities to be descending (-1, -2, -3, ...) instead. This helps jobs be assigned across all hosts in cases where the value of `--spawn` varies between hosts. - -**Status:** Experimental as an escape hatch to default behaviour. Will soon be promoted to a regular flag. - -### `propagate-agent-config-vars` - -Prepends agent configuration variables (such as `BUILDKITE_GIT_*`, `BUILDKITE_SHELL`, `BUILDKITE_CANCEL_GRACE_PERIOD`, etc.) to the environment file used by the job runner. This is useful in environments like Docker where the agent configuration is not otherwise available to the job process. - -**Status:** Experimental while we test the impact on job environments - ### `zip-plugins` Allows plugins to be downloaded as zip archives instead of being cloned from a Git repository. This is useful for plugins hosted as zip files on HTTP(S) URLs. **Status:** Experimental while we test zip archive support for plugins. + +### `legacy-post-hook-order` + +This experiment is an escape hatch that reverts to the v3 execution order of `post-checkout` and `post-command` hooks. + +In Agent v3, hooks of any kind would run in the same order as one another (for plugins, the order in which plugins are specified for a step). In v4, multiple `post-checkout`, `post-command`, or `pre-exit` hooks execute in _reverse_ order. This change makes it easier for multiple plugins and hooks to compose. + +For example, suppose a step specifies two plugins A and B, and there are also agent and repository hooks. Under version 3, each hook type would execute in the same order: + +- agent pre-checkout +- (pre-checkout is not possible for repository hooks) +- plugin A pre-checkout +- plugin B pre-checkout +- (checkout) +- agent post-checkout +- repository post-checkout +- plugin A post-checkout +- plugin B post-checkout +- agent pre-command +- repository pre-command +- plugin A pre-command +- plugin B pre-command +- (command) +- agent post-command +- repository post-command +- plugin A post-command +- plugin B post-command +- agent pre-exit +- repository pre-exit +- plugin A pre-exit +- plugin B pre-exit + +Under version 4, the execution order is (key differences in bold): + +- agent pre-checkout +- (pre-checkout is not possible for repository hooks) +- plugin A pre-checkout +- plugin B pre-checkout +- (checkout) +- plugin **B** post-checkout +- plugin **A** post-checkout +- **repository** post-checkout +- **agent** post-checkout +- agent pre-command +- repository pre-command +- plugin A pre-command +- plugin B pre-command +- (command) +- plugin **B** post-command +- plugin **A** post-command +- **repository** post-command +- **agent** post-command +- plugin **B** pre-exit +- plugin **A** pre-exit +- **repository** pre-exit +- **agent** pre-exit + +**Status:** This escape-hatch experiment will be removed in a future release, once we are confident that it isn't needed. diff --git a/README.md b/README.md index 13923e25c0..f922a70f80 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Buildkite Agent ![Build status](https://badge.buildkite.com/08e4e12a0a1e478f0994eb1e8d51822c5c74d395.svg?branch=main) -[![Go Reference](https://pkg.go.dev/badge/github.com/buildkite/agent/v3.svg)](https://pkg.go.dev/github.com/buildkite/agent/v3) +[![Go Reference](https://pkg.go.dev/badge/github.com/buildkite/agent/v4.svg)](https://pkg.go.dev/github.com/buildkite/agent/v4) The buildkite-agent is a small, reliable, and cross-platform build runner that makes it easy to run automated builds on your own infrastructure. It’s main @@ -46,7 +46,7 @@ platforms without extras. On Linux hosts it requires `dbus`. [The agents page](https://buildkite.com/organizations/-/agents) on Buildkite has personalised instructions, or you can refer to -[the Buildkite docs](https://buildkite.com/docs/agent/v3/installation). Both +[the Buildkite docs](https://buildkite.com/docs/agent/v4/installation). Both cover installing the agent with Ubuntu (via apt), Debian (via apt), macOS (via homebrew), Windows and Linux. @@ -126,9 +126,11 @@ our Go dependencies. Dependencies are not [vendored](https://go.dev/ref/mod#go-mod-vendor) into the repository unless necessary. -The Go module published by this repo (i.e. the one you could use by adding `import "github.com/buildkite/agent/v3"` to your code) -is **not considered to be versioned using semantic versioning**. Breaking changes may be introduced in minor releases. Use -the agent as a runtime depedency of your Go app at your own risk. +The Go module published by this repo (i.e. the one you could use by adding +`import "github.com/buildkite/agent/v4"` to your code) is **not considered to be +versioned using semantic versioning**. Breaking changes may be introduced in +minor releases. Use the agent as a runtime depedency of your Go app at your own +risk. ## Platform Support @@ -193,12 +195,13 @@ like systems, as well as Windows. - Server 2022 [^1]: See https://github.com/golang/go/issues/23011 for macOS / Go support and -[Supported macOS Versions](./docs/macos.md) for the last supported version of the -Buildkite Agent for versions of macOS prior to those listed above. +[Supported macOS Versions](./docs/macos.md) for the last supported version of +the Buildkite Agent for versions of macOS prior to those listed above. -[^2]: See [Go's Windows support page](https://go.dev/wiki/Windows) for Go / Windows version -compatibility and [Supported Windows Versions](./docs/windows.md) for the last supported version -of the Buildkite Agent for versions of Windows prior to those listed above. +[^2]: See [Go's Windows support page](https://go.dev/wiki/Windows) for Go / +Windows version compatibility and [Supported Windows +Versions](./docs/windows.md) for the last supported version of the Buildkite +Agent for versions of Windows prior to those listed above. ## Contributing diff --git a/agent/BUILD.bazel b/agent/BUILD.bazel index c34dbc1767..1dd22b6b18 100644 --- a/agent/BUILD.bazel +++ b/agent/BUILD.bazel @@ -31,7 +31,7 @@ go_library( "tags.go", "verify_job.go", ], - importpath = "github.com/buildkite/agent/v3/agent", + importpath = "github.com/buildkite/agent/v4/agent", visibility = ["//visibility:public"], deps = [ "//api", diff --git a/agent/agent_configuration.go b/agent/agent_configuration.go index 3f1220e6a0..8d5138836b 100644 --- a/agent/agent_configuration.go +++ b/agent/agent_configuration.go @@ -58,8 +58,8 @@ type AgentConfiguration struct { DisconnectAfterJob bool DisconnectAfterIdleTimeout time.Duration DisconnectAfterUptime time.Duration - CancelGracePeriod int - SignalGracePeriod time.Duration + CancelSignalTimeout time.Duration + CancelCleanupTimeout time.Duration EnableJobLogTmpfile bool JobLogPath string WriteJobLogsToStdout bool @@ -69,10 +69,8 @@ type AgentConfiguration struct { Profile string RedactedVars []string AcquireJob string - TracingBackend string + OpenTelemetryTracing bool TracingServiceName string - TracingPropagateTraceparent bool - TraceContextEncoding string DisableWarningsFor []string AllowMultipartArtifactUpload bool diff --git a/agent/agent_pool.go b/agent/agent_pool.go index 56ac3c0eb5..324126dac6 100644 --- a/agent/agent_pool.go +++ b/agent/agent_pool.go @@ -10,8 +10,8 @@ import ( "sync" "time" - "github.com/buildkite/agent/v3/logger" - "github.com/buildkite/agent/v3/status" + "github.com/buildkite/agent/v4/logger" + "github.com/buildkite/agent/v4/status" "github.com/prometheus/client_golang/prometheus/promhttp" ) diff --git a/agent/agent_worker.go b/agent/agent_worker.go index 8ae8afd330..43dff0e189 100644 --- a/agent/agent_worker.go +++ b/agent/agent_worker.go @@ -11,12 +11,12 @@ import ( "time" "connectrpc.com/connect" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/core" - "github.com/buildkite/agent/v3/internal/process" - "github.com/buildkite/agent/v3/logger" - "github.com/buildkite/agent/v3/metrics" - "github.com/buildkite/agent/v3/status" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/core" + "github.com/buildkite/agent/v4/internal/process" + "github.com/buildkite/agent/v4/logger" + "github.com/buildkite/agent/v4/metrics" + "github.com/buildkite/agent/v4/status" "github.com/buildkite/roko" ) diff --git a/agent/agent_worker_action.go b/agent/agent_worker_action.go index 86c51e2f18..378ca19ec0 100644 --- a/agent/agent_worker_action.go +++ b/agent/agent_worker_action.go @@ -5,9 +5,9 @@ import ( "fmt" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/internal/ptr" - "github.com/buildkite/agent/v3/status" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/internal/ptr" + "github.com/buildkite/agent/v4/status" "github.com/buildkite/roko" ) diff --git a/agent/agent_worker_heartbeat.go b/agent/agent_worker_heartbeat.go index ca4f751b6c..fe42548664 100644 --- a/agent/agent_worker_heartbeat.go +++ b/agent/agent_worker_heartbeat.go @@ -4,7 +4,7 @@ import ( "context" "time" - "github.com/buildkite/agent/v3/status" + "github.com/buildkite/agent/v4/status" ) func (a *AgentWorker) runHeartbeatLoop(ctx context.Context) error { diff --git a/agent/agent_worker_ping.go b/agent/agent_worker_ping.go index 0cfd5cfaa5..d27942382e 100644 --- a/agent/agent_worker_ping.go +++ b/agent/agent_worker_ping.go @@ -6,8 +6,8 @@ import ( "math/rand/v2" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/status" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/status" ) // runPingLoop runs the (classical) loop that pings Buildkite for work. diff --git a/agent/agent_worker_streaming.go b/agent/agent_worker_streaming.go index e2e6630ac3..c5101dc137 100644 --- a/agent/agent_worker_streaming.go +++ b/agent/agent_worker_streaming.go @@ -7,8 +7,8 @@ import ( "time" "connectrpc.com/connect" - agentedgev1 "github.com/buildkite/agent/v3/api/proto/gen" - "github.com/buildkite/agent/v3/status" + agentedgev1 "github.com/buildkite/agent/v4/api/proto/gen" + "github.com/buildkite/agent/v4/status" ) // runStreamingPingLoop runs the streaming loop. It is best-effort diff --git a/agent/agent_worker_test.go b/agent/agent_worker_test.go index 508f073edf..6f1a225bca 100644 --- a/agent/agent_worker_test.go +++ b/agent/agent_worker_test.go @@ -18,11 +18,11 @@ import ( "time" "connectrpc.com/connect" - "github.com/buildkite/agent/v3/api" - agentedgev1 "github.com/buildkite/agent/v3/api/proto/gen" - "github.com/buildkite/agent/v3/core" - "github.com/buildkite/agent/v3/logger" - "github.com/buildkite/agent/v3/metrics" + "github.com/buildkite/agent/v4/api" + agentedgev1 "github.com/buildkite/agent/v4/api/proto/gen" + "github.com/buildkite/agent/v4/core" + "github.com/buildkite/agent/v4/logger" + "github.com/buildkite/agent/v4/metrics" "github.com/google/go-cmp/cmp" "github.com/google/uuid" ) diff --git a/agent/ec2_tags.go b/agent/ec2_tags.go index b74be6fe77..312449853d 100644 --- a/agent/ec2_tags.go +++ b/agent/ec2_tags.go @@ -5,7 +5,7 @@ import ( "fmt" "io" - "github.com/buildkite/agent/v3/internal/awslib" + "github.com/buildkite/agent/v4/internal/awslib" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/feature/ec2/imds" diff --git a/agent/ecs_meta_data.go b/agent/ecs_meta_data.go index 3a19fb9151..ee82164b4b 100644 --- a/agent/ecs_meta_data.go +++ b/agent/ecs_meta_data.go @@ -6,7 +6,7 @@ import ( "strconv" metadata "github.com/brunoscheufler/aws-ecs-metadata-go" - "github.com/buildkite/agent/v3/internal/agenthttp" + "github.com/buildkite/agent/v4/internal/agenthttp" ) type ECSMetadata struct { diff --git a/agent/fake_api_server_test.go b/agent/fake_api_server_test.go index 29e574d4ce..2d65d1459e 100644 --- a/agent/fake_api_server_test.go +++ b/agent/fake_api_server_test.go @@ -12,9 +12,9 @@ import ( "time" "connectrpc.com/connect" - "github.com/buildkite/agent/v3/api" - agentedgev1 "github.com/buildkite/agent/v3/api/proto/gen" - "github.com/buildkite/agent/v3/api/proto/gen/agentedgev1connect" + "github.com/buildkite/agent/v4/api" + agentedgev1 "github.com/buildkite/agent/v4/api/proto/gen" + "github.com/buildkite/agent/v4/api/proto/gen/agentedgev1connect" "github.com/google/uuid" ) diff --git a/agent/header_times_streamer.go b/agent/header_times_streamer.go index 5324d2400c..2eaa1f2202 100644 --- a/agent/header_times_streamer.go +++ b/agent/header_times_streamer.go @@ -8,8 +8,8 @@ import ( "sync" "time" - "github.com/buildkite/agent/v3/logger" - "github.com/buildkite/agent/v3/status" + "github.com/buildkite/agent/v4/logger" + "github.com/buildkite/agent/v4/status" ) // If you change header parsing here make sure to change it in the diff --git a/agent/header_times_streamer_test.go b/agent/header_times_streamer_test.go index b3f9f05018..18ff545a78 100644 --- a/agent/header_times_streamer_test.go +++ b/agent/header_times_streamer_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) func TestHeaderTimesStreamerScanAfterStopDoesNotPanic(t *testing.T) { diff --git a/agent/integration/BUILD.bazel b/agent/integration/BUILD.bazel index 847dd1dfe3..af15b3cd2f 100644 --- a/agent/integration/BUILD.bazel +++ b/agent/integration/BUILD.bazel @@ -3,7 +3,7 @@ load("@rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "integration", srcs = ["test_helpers.go"], - importpath = "github.com/buildkite/agent/v3/agent/integration", + importpath = "github.com/buildkite/agent/v4/agent/integration", visibility = ["//visibility:public"], deps = [ "//agent", diff --git a/agent/integration/config_allowlisting_integration_test.go b/agent/integration/config_allowlisting_integration_test.go index a85b65d27c..ba763f9594 100644 --- a/agent/integration/config_allowlisting_integration_test.go +++ b/agent/integration/config_allowlisting_integration_test.go @@ -7,8 +7,8 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/agent" - "github.com/buildkite/agent/v3/api" + "github.com/buildkite/agent/v4/agent" + "github.com/buildkite/agent/v4/api" "github.com/buildkite/bintest/v3" ) diff --git a/agent/integration/job_environment_integration_test.go b/agent/integration/job_environment_integration_test.go index cb20646e8e..fc581a176c 100644 --- a/agent/integration/job_environment_integration_test.go +++ b/agent/integration/job_environment_integration_test.go @@ -5,9 +5,9 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/agent" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/agent" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/bintest/v3" "github.com/buildkite/go-pipeline" ) diff --git a/agent/integration/job_runner_integration_test.go b/agent/integration/job_runner_integration_test.go index 537d3c5bd0..a1fd421411 100644 --- a/agent/integration/job_runner_integration_test.go +++ b/agent/integration/job_runner_integration_test.go @@ -15,8 +15,8 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/agent" - "github.com/buildkite/agent/v3/api" + "github.com/buildkite/agent/v4/agent" + "github.com/buildkite/agent/v4/api" "github.com/buildkite/bintest/v3" ) diff --git a/agent/integration/job_verification_integration_test.go b/agent/integration/job_verification_integration_test.go index 1a66ac72ea..4da5b1705a 100644 --- a/agent/integration/job_verification_integration_test.go +++ b/agent/integration/job_verification_integration_test.go @@ -4,8 +4,8 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/agent" - "github.com/buildkite/agent/v3/api" + "github.com/buildkite/agent/v4/agent" + "github.com/buildkite/agent/v4/api" "github.com/buildkite/bintest/v3" "github.com/buildkite/go-pipeline" "github.com/buildkite/go-pipeline/signature" diff --git a/agent/integration/main_test.go b/agent/integration/main_test.go index 54ce9f82b5..7bcfe15804 100644 --- a/agent/integration/main_test.go +++ b/agent/integration/main_test.go @@ -7,8 +7,8 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/clicommand" - "github.com/buildkite/agent/v3/version" + "github.com/buildkite/agent/v4/clicommand" + "github.com/buildkite/agent/v4/version" "github.com/urfave/cli" ) diff --git a/agent/integration/test_helpers.go b/agent/integration/test_helpers.go index b8b10f8520..e2ca08fc98 100644 --- a/agent/integration/test_helpers.go +++ b/agent/integration/test_helpers.go @@ -18,11 +18,11 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/agent" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/internal/ptr" - "github.com/buildkite/agent/v3/logger" - "github.com/buildkite/agent/v3/metrics" + "github.com/buildkite/agent/v4/agent" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/internal/ptr" + "github.com/buildkite/agent/v4/logger" + "github.com/buildkite/agent/v4/metrics" "github.com/buildkite/bintest/v3" "github.com/lestrrat-go/jwx/v2/jwk" ) diff --git a/agent/job_logger_test.go b/agent/job_logger_test.go index bf812d7e2a..2b6a2d0569 100644 --- a/agent/job_logger_test.go +++ b/agent/job_logger_test.go @@ -5,7 +5,7 @@ import ( "encoding/json" "testing" - "github.com/buildkite/agent/v3/api" + "github.com/buildkite/agent/v4/api" ) func TestJobLoggerJSONFormat(t *testing.T) { diff --git a/agent/job_runner.go b/agent/job_runner.go index 705d10da17..ff35dbce24 100644 --- a/agent/job_runner.go +++ b/agent/job_runner.go @@ -16,16 +16,16 @@ import ( "sync/atomic" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/core" - envutil "github.com/buildkite/agent/v3/env" - "github.com/buildkite/agent/v3/internal/experiments" - "github.com/buildkite/agent/v3/internal/process" - "github.com/buildkite/agent/v3/internal/shell" - "github.com/buildkite/agent/v3/kubernetes" - "github.com/buildkite/agent/v3/logger" - "github.com/buildkite/agent/v3/metrics" - "github.com/buildkite/agent/v3/status" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/core" + envutil "github.com/buildkite/agent/v4/env" + "github.com/buildkite/agent/v4/internal/experiments" + "github.com/buildkite/agent/v4/internal/process" + "github.com/buildkite/agent/v4/internal/shell" + "github.com/buildkite/agent/v4/kubernetes" + "github.com/buildkite/agent/v4/logger" + "github.com/buildkite/agent/v4/metrics" + "github.com/buildkite/agent/v4/status" "github.com/buildkite/roko" "github.com/buildkite/shellwords" ) @@ -360,7 +360,7 @@ func NewJobRunner(ctx context.Context, l logger.Logger, apiClient *api.Client, c Stdout: r.jobLogs, Stderr: r.jobLogs, InterruptSignal: cancelSignal, - SignalGracePeriod: conf.AgentConfiguration.SignalGracePeriod, + SignalGracePeriod: conf.AgentConfiguration.CancelSignalTimeout, }) } @@ -437,13 +437,12 @@ func (r *JobRunner) createEnvironment(ctx context.Context) ([]string, error) { // We present only the clean environment - i.e only variables configured // on the job upstream - and expose the path in another environment variable. if r.envShellFile != nil { - if experiments.IsEnabled(ctx, experiments.PropagateAgentConfigVars) { - // Note that some variables in this list might not be defined later, - // when something comes to read the file. See below where they are - // added conditionally, e.g. BUILDKITE_TRACING_BACKEND. - // Docker in particular tolerates undefined vars in an env file - // without complaints. - const agentCfgVars = `BUILDKITE_GIT_CHECKOUT_FLAGS + // Note that some variables in this list might not be defined later, + // when something comes to read the file. See below where they are + // added conditionally, e.g. BUILDKITE_OPENTELEMETRY_TRACING. + // Docker in particular tolerates undefined vars in an env file + // without complaints. + const agentCfgVars = `BUILDKITE_GIT_CHECKOUT_FLAGS BUILDKITE_GIT_CLEAN_FLAGS BUILDKITE_GIT_CLONE_FLAGS BUILDKITE_GIT_CLONE_MIRROR_FLAGS @@ -464,8 +463,7 @@ BUILDKITE_HOOKS_SHELL BUILDKITE_SIGNAL_GRACE_PERIOD_SECONDS BUILDKITE_SSH_KEYSCAN BUILDKITE_STRICT_SINGLE_HOOKS -BUILDKITE_TRACE_CONTEXT_ENCODING -BUILDKITE_TRACING_BACKEND +BUILDKITE_OPENTELEMETRY_TRACING BUILDKITE_TRACING_SERVICE_NAME BUILDKITE_TRACING_TRACEPARENT BUILDKITE_TRACING_PROPAGATE_TRACEPARENT @@ -473,9 +471,8 @@ BUILDKITE_AGENT_AWS_KMS_KEY BUILDKITE_AGENT_GCP_KMS_KEY BUILDKITE_AGENT_JWKS_FILE BUILDKITE_AGENT_JWKS_KEY_ID` - if _, err := fmt.Fprintln(r.envShellFile, agentCfgVars); err != nil { - return nil, err - } + if _, err := fmt.Fprintln(r.envShellFile, agentCfgVars); err != nil { + return nil, err } for key, value := range env { @@ -601,9 +598,8 @@ BUILDKITE_AGENT_JWKS_KEY_ID` setEnv("BUILDKITE_AGENT_EXPERIMENT", strings.Join(experiments.Enabled(ctx), ",")) setEnv("BUILDKITE_REDACTED_VARS", strings.Join(r.conf.AgentConfiguration.RedactedVars, ",")) setEnv("BUILDKITE_STRICT_SINGLE_HOOKS", fmt.Sprint(r.conf.AgentConfiguration.StrictSingleHooks)) - setEnv("BUILDKITE_CANCEL_GRACE_PERIOD", strconv.Itoa(r.conf.AgentConfiguration.CancelGracePeriod)) - setEnv("BUILDKITE_SIGNAL_GRACE_PERIOD_SECONDS", strconv.Itoa(int(r.conf.AgentConfiguration.SignalGracePeriod/time.Second))) - setEnv("BUILDKITE_TRACE_CONTEXT_ENCODING", r.conf.AgentConfiguration.TraceContextEncoding) + setEnv("BUILDKITE_CANCEL_SIGNAL_TIMEOUT", r.conf.AgentConfiguration.CancelSignalTimeout.String()) + setEnv("BUILDKITE_CANCEL_CLEANUP_TIMEOUT", r.conf.AgentConfiguration.CancelCleanupTimeout.String()) if !r.conf.AgentConfiguration.AllowMultipartArtifactUpload { setEnv("BUILDKITE_NO_MULTIPART_ARTIFACT_UPLOAD", "true") @@ -661,8 +657,8 @@ BUILDKITE_AGENT_JWKS_KEY_ID` } setEnv("BUILDKITE_PLUGIN_VALIDATION", fmt.Sprint(enablePluginValidation)) - if r.conf.AgentConfiguration.TracingBackend != "" { - setEnv("BUILDKITE_TRACING_BACKEND", r.conf.AgentConfiguration.TracingBackend) + if r.conf.AgentConfiguration.OpenTelemetryTracing { + setEnv("BUILDKITE_OPENTELEMETRY_TRACING", "true") setEnv("BUILDKITE_TRACING_SERVICE_NAME", r.conf.AgentConfiguration.TracingServiceName) // Buildkite backend can provide a traceparent property on the job @@ -672,9 +668,6 @@ BUILDKITE_AGENT_JWKS_KEY_ID` if r.conf.Job.TraceParent != "" { setEnv("BUILDKITE_TRACING_TRACEPARENT", r.conf.Job.TraceParent) } - if r.conf.AgentConfiguration.TracingPropagateTraceparent { - setEnv("BUILDKITE_TRACING_PROPAGATE_TRACEPARENT", "true") - } } setEnv("BUILDKITE_AGENT_DISABLE_WARNINGS_FOR", strings.Join(r.conf.AgentConfiguration.DisableWarningsFor, ",")) diff --git a/agent/job_runner_test.go b/agent/job_runner_test.go index 83ee3d8ef9..516aac5344 100644 --- a/agent/job_runner_test.go +++ b/agent/job_runner_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) func TestTruncateEnv(t *testing.T) { diff --git a/agent/json_job_logger.go b/agent/json_job_logger.go index 85484b2c5c..80bebbf4ba 100644 --- a/agent/json_job_logger.go +++ b/agent/json_job_logger.go @@ -5,7 +5,7 @@ import ( "os" "strings" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) // JSONJobLogger is a wrapper around a JSON Logger that satisfies the diff --git a/agent/json_job_logger_test.go b/agent/json_job_logger_test.go index d40e5f2e6c..dc58d9da49 100644 --- a/agent/json_job_logger_test.go +++ b/agent/json_job_logger_test.go @@ -5,7 +5,7 @@ import ( "encoding/json" "testing" - "github.com/buildkite/agent/v3/api" + "github.com/buildkite/agent/v4/api" "github.com/google/go-cmp/cmp" ) diff --git a/agent/k8s_tags.go b/agent/k8s_tags.go index 82665dfd9d..662036eddb 100644 --- a/agent/k8s_tags.go +++ b/agent/k8s_tags.go @@ -3,7 +3,7 @@ package agent import ( "strings" - "github.com/buildkite/agent/v3/env" + "github.com/buildkite/agent/v4/env" ) const k8sEnvVarPrefix = "BUILDKITE_K8S_" diff --git a/agent/k8s_tags_test.go b/agent/k8s_tags_test.go index df5baea899..f9cb34880e 100644 --- a/agent/k8s_tags_test.go +++ b/agent/k8s_tags_test.go @@ -3,7 +3,7 @@ package agent_test import ( "testing" - "github.com/buildkite/agent/v3/agent" + "github.com/buildkite/agent/v4/agent" "github.com/google/go-cmp/cmp" ) diff --git a/agent/log_streamer.go b/agent/log_streamer.go index eb8bbf0c4b..7dbccc3670 100644 --- a/agent/log_streamer.go +++ b/agent/log_streamer.go @@ -7,9 +7,9 @@ import ( "sync" "sync/atomic" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" - "github.com/buildkite/agent/v3/status" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" + "github.com/buildkite/agent/v4/status" "github.com/dustin/go-humanize" ) diff --git a/agent/log_streamer_test.go b/agent/log_streamer_test.go index eebb464ffd..57adeeb984 100644 --- a/agent/log_streamer_test.go +++ b/agent/log_streamer_test.go @@ -8,8 +8,8 @@ import ( "sync" "testing" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" "github.com/google/go-cmp/cmp" ) diff --git a/agent/pipeline_uploader.go b/agent/pipeline_uploader.go index 9401b9304f..1a255d77a7 100644 --- a/agent/pipeline_uploader.go +++ b/agent/pipeline_uploader.go @@ -11,8 +11,8 @@ import ( "strconv" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/roko" ) diff --git a/agent/pipeline_uploader_test.go b/agent/pipeline_uploader_test.go index f36a5f29fb..b9032c740c 100644 --- a/agent/pipeline_uploader_test.go +++ b/agent/pipeline_uploader_test.go @@ -10,9 +10,9 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/agent" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/agent" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/go-pipeline" "github.com/google/go-cmp/cmp" ) diff --git a/agent/plugin/BUILD.bazel b/agent/plugin/BUILD.bazel index a057b844d6..8c8a34cad1 100644 --- a/agent/plugin/BUILD.bazel +++ b/agent/plugin/BUILD.bazel @@ -7,7 +7,7 @@ go_library( "error.go", "plugin.go", ], - importpath = "github.com/buildkite/agent/v3/agent/plugin", + importpath = "github.com/buildkite/agent/v4/agent/plugin", visibility = ["//visibility:public"], deps = [ "//env", diff --git a/agent/plugin/error.go b/agent/plugin/error.go deleted file mode 100644 index c9be072c4f..0000000000 --- a/agent/plugin/error.go +++ /dev/null @@ -1,119 +0,0 @@ -package plugin - -import ( - "fmt" - "sort" - "strings" -) - -type unit struct{} - -// DeprecatedNameErrors contains a set of DeprecatedNameError -type DeprecatedNameErrors struct { - errs map[DeprecatedNameError]unit -} - -// IsEmpty return true if and only if `e` contains no errors -func (e *DeprecatedNameErrors) IsEmpty() bool { - return e == nil || len(e.errs) == 0 -} - -// Unwrap returns the a slice of errors in a stable order -func (e *DeprecatedNameErrors) Unwrap() []error { - if e == nil { - return nil - } - - if len(e.errs) == 0 { - return []error{} - } - - errs := make([]DeprecatedNameError, 0, len(e.errs)) - for err := range e.errs { - errs = append(errs, err) - } - - sort.Slice(errs, func(i, j int) bool { - if errs[i].old == errs[j].old { - return errs[i].new < errs[j].new - } - return errs[i].old < errs[j].old - }) - - out := make([]error, 0, len(errs)) - for i := range errs { - out = append(out, &errs[i]) - } - - return out -} - -// Error returns each contained error on a new line -func (e *DeprecatedNameErrors) Error() string { - builder := strings.Builder{} - for i, err := range e.Unwrap() { - _, _ = builder.WriteString(err.Error()) - if i < len(e.errs)-1 { - _, _ = builder.WriteRune('\n') - } - } - return builder.String() -} - -// Append adds DeprecatedNameError contained set and returns the reciver. -// Returning the reveiver is necessary to support appending to nil. So this -// should be used just like the builtin `append` function. -func (e *DeprecatedNameErrors) Append(errs ...DeprecatedNameError) *DeprecatedNameErrors { - if e == nil { - e = &DeprecatedNameErrors{errs: map[DeprecatedNameError]unit{}} - } else if e.errs == nil { - e.errs = map[DeprecatedNameError]unit{} - } - - for _, err := range errs { - e.errs[err] = unit{} - } - - return e -} - -// Is returns true if and only if a target contains the same set of -// DeprecatedNameError as the receiver. -func (e *DeprecatedNameErrors) Is(target error) bool { - targetErr, ok := target.(*DeprecatedNameErrors) - if !ok { - return false - } - - if len(e.errs) != len(targetErr.errs) { - return false - } - - for err := range e.errs { - if _, exists := targetErr.errs[err]; !exists { - return false - } - } - - return true -} - -// DeprecatedNameError contains information about environment variable names that -// are deprecated. Both the deprecated name and its replacement are held -type DeprecatedNameError struct { - old string - new string -} - -func NewDeprecatedNameError(oldName, newName string) DeprecatedNameError { - return DeprecatedNameError{old: oldName, new: newName} -} - -func (e *DeprecatedNameError) Error() string { - return fmt.Sprintf("deprecated: %q\nreplacement: %q\n", e.old, e.new) -} - -func (e *DeprecatedNameError) Is(target error) bool { - terr, ok := target.(*DeprecatedNameError) - return ok && *e == *terr -} diff --git a/agent/plugin/error_test.go b/agent/plugin/error_test.go deleted file mode 100644 index fa737252e6..0000000000 --- a/agent/plugin/error_test.go +++ /dev/null @@ -1,116 +0,0 @@ -package plugin - -import ( - "errors" - "math/bits" - "math/rand/v2" - "testing" - "time" -) - -func shuffle[T any](rnd *rand.Rand, arr []T) { - if len(arr) < 2 { - return - } - rnd.Shuffle(len(arr), func(i, j int) { - arr[i], arr[j] = arr[j], arr[i] - }) -} - -func TestDeprecatedNameErrorsOrder(t *testing.T) { - t.Parallel() - - seed1 := uint64(time.Now().UnixNano()) - seed2 := bits.Reverse64(uint64(time.Now().UnixNano())) - t.Logf("seed1 = %d, seed2 = %d", seed1, seed2) - - for _, test := range []struct { - name string - errs []DeprecatedNameError - }{ - { - name: "0_error", - errs: []DeprecatedNameError{}, - }, - { - name: "1_error", - errs: []DeprecatedNameError{ - { - old: "a", - new: "b", - }, - }, - }, - { - name: "2_errors", - errs: []DeprecatedNameError{ - { - old: "a", - new: "b", - }, - { - old: "c", - new: "d", - }, - }, - }, - { - name: "3_errors", - errs: []DeprecatedNameError{ - { - old: "a", - new: "b", - }, - { - old: "c", - new: "d", - }, - { - old: "e", - new: "f", - }, - }, - }, - { - name: "4_errors", - errs: []DeprecatedNameError{ - { - old: "a", - new: "b", - }, - { - old: "c", - new: "d", - }, - { - old: "e", - new: "f", - }, - { - old: "g", - new: "h", - }, - }, - }, - } { - t.Run(test.name, func(t *testing.T) { - t.Parallel() - - randSrc := rand.New(rand.NewPCG(seed1, seed2)) - errs := make([]DeprecatedNameError, len(test.errs)) - copy(errs, test.errs) - shuffle(randSrc, errs) - - var err1, err2 *DeprecatedNameErrors - err1 = err1.Append(test.errs...) - err2 = err2.Append(errs...) - if err1.Error() != err2.Error() { - t.Errorf("expected DeprecatedNameErrors Error() to be ordered") - } - - if !errors.Is(err1, err2) { - t.Errorf("expected DeprecatedNameErrors Is() to not be sensitive to order") - } - }) - } -} diff --git a/agent/plugin/plugin.go b/agent/plugin/plugin.go index 0915e204fc..ba49a6abec 100644 --- a/agent/plugin/plugin.go +++ b/agent/plugin/plugin.go @@ -10,15 +10,14 @@ import ( "regexp" "strings" - "github.com/buildkite/agent/v3/env" + "github.com/buildkite/agent/v4/env" ) var ( - nonIDCharacterRE = regexp.MustCompile(`[^a-zA-Z0-9]`) - consecutiveHyphenRE = regexp.MustCompile(`-+`) - hypenOrSpaceRE = regexp.MustCompile(`-|\s`) - whitespaceRE = regexp.MustCompile(`\s+`) - consecutiveUnderscoreRE = regexp.MustCompile(`_+`) + nonIDCharacterRE = regexp.MustCompile(`[^a-zA-Z0-9]`) + consecutiveHyphenRE = regexp.MustCompile(`-+`) + hypenOrSpaceRE = regexp.MustCompile(`-|\s`) + whitespaceRE = regexp.MustCompile(`\s+`) ) // Plugin describes where to find, and how to configure, an agent plugin. @@ -266,33 +265,6 @@ func flattenConfigToEnvMap(into map[string]string, v any, envPrefix string) erro } } -// addDeprecatedEnvVarAliases provides backward compatibility for environment variable names. -// -// Before v3.48.0 (https://github.com/buildkite/agent/pull/2116), consecutive underscores in -// derived env var names were collapsed (e.g., "some--key__name" β†’ SOME_KEY_NAME). -// Since v3.48.0, consecutive underscores are preserved (e.g., SOME__KEY__NAME). -// -// For compatibility, this function adds the collapsed form for any key containing consecutive -// underscores and returns deprecation errors listing the affected variables. -func addDeprecatedEnvVarAliases(envMap map[string]string) error { - var errs *DeprecatedNameErrors - for k, v := range envMap { - // the form with consecutive underscores is replacing the form without, but the replacement - // is what is expected to be in input map - withoutConsecutiveUnderscores := consecutiveUnderscoreRE.ReplaceAllString(k, "_") - if k != withoutConsecutiveUnderscores { - envMap[withoutConsecutiveUnderscores] = v - errs = errs.Append(DeprecatedNameError{old: withoutConsecutiveUnderscores, new: k}) - } - } - - if !errs.IsEmpty() { - return errs - } - - return nil -} - // ConfigurationToEnvironment converts the plugin configuration values to environment variables. func (p *Plugin) ConfigurationToEnvironment() (*env.Environment, error) { configJSON, err := json.Marshal(p.Configuration) @@ -309,7 +281,6 @@ func (p *Plugin) ConfigurationToEnvironment() (*env.Environment, error) { return env.New(), err } - err = addDeprecatedEnvVarAliases(envMap) return env.FromMap(envMap), err } diff --git a/agent/plugin/plugin_test.go b/agent/plugin/plugin_test.go index cf78087a47..1f17fcf76a 100644 --- a/agent/plugin/plugin_test.go +++ b/agent/plugin/plugin_test.go @@ -400,37 +400,18 @@ func TestConfigurationToEnvironment(t *testing.T) { configJSON: `{ "and _ with a - number": 12 }`, wantEnvMap: map[string]string{ "BUILDKITE_PLUGIN_CONFIGURATION": `{"and _ with a - number":12}`, - "BUILDKITE_PLUGIN_DOCKER_COMPOSE_AND_WITH_A_NUMBER": "12", "BUILDKITE_PLUGIN_DOCKER_COMPOSE_AND___WITH_A______NUMBER": "12", "BUILDKITE_PLUGIN_NAME": "DOCKER_COMPOSE", }, - expectedErr: (&DeprecatedNameErrors{}).Append( - DeprecatedNameError{ - old: "BUILDKITE_PLUGIN_DOCKER_COMPOSE_AND_WITH_A_NUMBER", - new: "BUILDKITE_PLUGIN_DOCKER_COMPOSE_AND___WITH_A______NUMBER", - }, - ), }, { configJSON: `{ "and _ with a - number": 12, "A - B": 13 }`, wantEnvMap: map[string]string{ "BUILDKITE_PLUGIN_CONFIGURATION": `{"A - B":13,"and _ with a - number":12}`, - "BUILDKITE_PLUGIN_DOCKER_COMPOSE_AND_WITH_A_NUMBER": "12", "BUILDKITE_PLUGIN_DOCKER_COMPOSE_AND___WITH_A______NUMBER": "12", - "BUILDKITE_PLUGIN_DOCKER_COMPOSE_A_B": "13", "BUILDKITE_PLUGIN_DOCKER_COMPOSE_A___B": "13", "BUILDKITE_PLUGIN_NAME": "DOCKER_COMPOSE", }, - expectedErr: (&DeprecatedNameErrors{}).Append( - DeprecatedNameError{ - old: "BUILDKITE_PLUGIN_DOCKER_COMPOSE_AND_WITH_A_NUMBER", - new: "BUILDKITE_PLUGIN_DOCKER_COMPOSE_AND___WITH_A______NUMBER", - }, - DeprecatedNameError{ - old: "BUILDKITE_PLUGIN_DOCKER_COMPOSE_A_B", - new: "BUILDKITE_PLUGIN_DOCKER_COMPOSE_A___B", - }, - ), }, { configJSON: `{ "bool-true-key": true, "bool-false-key": false }`, diff --git a/agent/run_job.go b/agent/run_job.go index f47a7bd046..04b9240e8f 100644 --- a/agent/run_job.go +++ b/agent/run_job.go @@ -13,16 +13,15 @@ import ( "sync" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/core" - "github.com/buildkite/agent/v3/internal/experiments" - "github.com/buildkite/agent/v3/internal/job" - "github.com/buildkite/agent/v3/internal/job/hook" - "github.com/buildkite/agent/v3/internal/process" - "github.com/buildkite/agent/v3/kubernetes" - "github.com/buildkite/agent/v3/logger" - "github.com/buildkite/agent/v3/metrics" - "github.com/buildkite/agent/v3/status" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/core" + "github.com/buildkite/agent/v4/internal/job" + "github.com/buildkite/agent/v4/internal/job/hook" + "github.com/buildkite/agent/v4/internal/process" + "github.com/buildkite/agent/v4/kubernetes" + "github.com/buildkite/agent/v4/logger" + "github.com/buildkite/agent/v4/metrics" + "github.com/buildkite/agent/v4/status" "github.com/buildkite/go-pipeline" ) @@ -386,9 +385,7 @@ One or more containers connected to the agent, but then stopped communicating wi if exit.Status == 0 { // On Windows, a signalled process exits 0 rather than non-zero. // This is inconsistent with cancellation on other platforms. - if experiments.IsEnabled(ctx, experiments.OverrideZeroExitOnCancel) { - exit.Status = 1 - } + exit.Status = 1 } } @@ -434,14 +431,8 @@ func (r *JobRunner) cleanup(ctx context.Context, wg *sync.WaitGroup, exit core.P // Write some metrics about the job run jobMetrics := r.conf.MetricsScope.With(metrics.Tags{"exit_code": strconv.Itoa(exit.Status)}) - - if exit.Status == 0 { - jobMetrics.Timing("jobs.duration.success", finishedAt.Sub(r.startedAt)) - jobMetrics.Count("jobs.success", 1) - } else { - jobMetrics.Timing("jobs.duration.error", finishedAt.Sub(r.startedAt)) - jobMetrics.Count("jobs.failed", 1) - } + jobMetrics.Timing("jobs.duration", finishedAt.Sub(r.startedAt)) + jobMetrics.Count("jobs.finished", 1) // Finish the build in the Buildkite Agent API // Once we tell the API we're finished it might assign us new work, so make sure everything else is done first. @@ -600,7 +591,7 @@ func (r *JobRunner) Cancel(reason CancelReason) error { r.agentLogger.Info( "Canceling job %s with a signal grace period of %v (%s)", r.conf.Job.ID, - r.conf.AgentConfiguration.SignalGracePeriod, + r.conf.AgentConfiguration.CancelSignalTimeout, reason, ) @@ -617,11 +608,11 @@ func (r *JobRunner) Cancel(reason CancelReason) error { // Extra time between the end of the signal grace period and the end of the // cancel grace period is the time we (agent side) need to upload logs and // disconnect (if the agent is exiting). - case <-time.After(r.conf.AgentConfiguration.SignalGracePeriod): + case <-time.After(r.conf.AgentConfiguration.CancelSignalTimeout): r.agentLogger.Info( "Job %s hasn't stopped within %v, terminating", r.conf.Job.ID, - r.conf.AgentConfiguration.SignalGracePeriod, + r.conf.AgentConfiguration.CancelSignalTimeout, ) // Terminate the process as we've exceeded our context diff --git a/agent/tags.go b/agent/tags.go index 6baaddad2b..9ae98313c2 100644 --- a/agent/tags.go +++ b/agent/tags.go @@ -10,7 +10,7 @@ import ( "strings" "time" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/roko" "github.com/denisbrodbeck/machineid" ) diff --git a/agent/tags_test.go b/agent/tags_test.go index 928f05166a..b98bc957fd 100644 --- a/agent/tags_test.go +++ b/agent/tags_test.go @@ -9,7 +9,7 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" "github.com/google/go-cmp/cmp" ) diff --git a/api/BUILD.bazel b/api/BUILD.bazel index 2f047e4de6..5b295c0c8a 100644 --- a/api/BUILD.bazel +++ b/api/BUILD.bazel @@ -25,7 +25,7 @@ go_library( "token.go", "uuid.go", ], - importpath = "github.com/buildkite/agent/v3/api", + importpath = "github.com/buildkite/agent/v4/api", visibility = ["//visibility:public"], deps = [ "//api/proto/gen", diff --git a/api/api_internal_test.go b/api/api_internal_test.go index 60c8cd1b07..57a9fa8d49 100644 --- a/api/api_internal_test.go +++ b/api/api_internal_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) func TestNewRequestBuildkiteTimeoutMilliseconds(t *testing.T) { diff --git a/api/client.go b/api/client.go index bf09cc661a..72d8deb0e4 100644 --- a/api/client.go +++ b/api/client.go @@ -16,8 +16,8 @@ import ( "strings" "time" - "github.com/buildkite/agent/v3/internal/agenthttp" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/internal/agenthttp" + "github.com/buildkite/agent/v4/logger" "github.com/google/go-querystring/query" ) diff --git a/api/client_test.go b/api/client_test.go index fb45a8490d..c596b14b1d 100644 --- a/api/client_test.go +++ b/api/client_test.go @@ -9,8 +9,8 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" ) func TestRegisteringAndConnectingClient(t *testing.T) { diff --git a/api/oidc_test.go b/api/oidc_test.go index 70dcc57568..acff04749a 100644 --- a/api/oidc_test.go +++ b/api/oidc_test.go @@ -10,8 +10,8 @@ import ( "net/url" "testing" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" "github.com/google/go-cmp/cmp" ) diff --git a/api/pings_streaming.go b/api/pings_streaming.go index f591680a30..f272a77448 100644 --- a/api/pings_streaming.go +++ b/api/pings_streaming.go @@ -7,8 +7,8 @@ import ( "net/url" "connectrpc.com/connect" - agentedgev1 "github.com/buildkite/agent/v3/api/proto/gen" - "github.com/buildkite/agent/v3/api/proto/gen/agentedgev1connect" + agentedgev1 "github.com/buildkite/agent/v4/api/proto/gen" + "github.com/buildkite/agent/v4/api/proto/gen/agentedgev1connect" ) // StreamPings opens a ConnectRPC channel for streaming pings. It returns an diff --git a/api/proto/BUILD.bazel b/api/proto/BUILD.bazel index c60ce05f00..efd980920c 100644 --- a/api/proto/BUILD.bazel +++ b/api/proto/BUILD.bazel @@ -12,7 +12,7 @@ proto_library( go_proto_library( name = "agentedge_v1_go_proto", compilers = ["@io_bazel_rules_go//proto:go_grpc_v2"], - importpath = "github.com/buildkite/agent/v3/api/proto", + importpath = "github.com/buildkite/agent/v4/api/proto", proto = ":agentedge_v1_proto", visibility = ["//visibility:public"], deps = ["//buf/validate:validate_proto"], @@ -21,6 +21,6 @@ go_proto_library( go_library( name = "proto", embed = [":agentedge_v1_go_proto"], - importpath = "github.com/buildkite/agent/v3/api/proto", + importpath = "github.com/buildkite/agent/v4/api/proto", visibility = ["//visibility:public"], ) diff --git a/api/proto/buf.gen.yaml b/api/proto/buf.gen.yaml index 9cb9c34231..c0ca21f00e 100644 --- a/api/proto/buf.gen.yaml +++ b/api/proto/buf.gen.yaml @@ -12,7 +12,7 @@ managed: enabled: true override: - file_option: go_package_prefix - value: github.com/buildkite/agent/v3/api/proto/gen + value: github.com/buildkite/agent/v4/api/proto/gen disable: - file_option: go_package module: buf.build/bufbuild/protovalidate diff --git a/api/proto/gen/BUILD.bazel b/api/proto/gen/BUILD.bazel index b261951747..c3af33f897 100644 --- a/api/proto/gen/BUILD.bazel +++ b/api/proto/gen/BUILD.bazel @@ -3,7 +3,7 @@ load("@rules_go//go:def.bzl", "go_library") go_library( name = "gen", srcs = ["agentedge.pb.go"], - importpath = "github.com/buildkite/agent/v3/api/proto/gen", + importpath = "github.com/buildkite/agent/v4/api/proto/gen", visibility = ["//visibility:public"], deps = [ "@build_buf_gen_go_bufbuild_protovalidate_protocolbuffers_go//buf/validate", diff --git a/api/proto/gen/agentedge.pb.go b/api/proto/gen/agentedge.pb.go index 08c33aebac..608974b49d 100644 --- a/api/proto/gen/agentedge.pb.go +++ b/api/proto/gen/agentedge.pb.go @@ -418,7 +418,7 @@ const file_agentedge_proto_rawDesc = "" + "\x02id\x18\x01 \x01(\tR\x02id2j\n" + "\x10AgentEdgeService\x12V\n" + "\vStreamPings\x12 .agentedge.v1.StreamPingsRequest\x1a!.agentedge.v1.StreamPingsResponse\"\x000\x01B\xac\x01\n" + - "\x10com.agentedge.v1B\x0eAgentedgeProtoP\x01Z7github.com/buildkite/agent/v3/api/proto/gen;agentedgev1\xa2\x02\x03AXX\xaa\x02\fAgentedge.V1\xca\x02\fAgentedge\\V1\xe2\x02\x18Agentedge\\V1\\GPBMetadata\xea\x02\rAgentedge::V1b\x06proto3" + "\x10com.agentedge.v1B\x0eAgentedgeProtoP\x01Z7github.com/buildkite/agent/v4/api/proto/gen;agentedgev1\xa2\x02\x03AXX\xaa\x02\fAgentedge.V1\xca\x02\fAgentedge\\V1\xe2\x02\x18Agentedge\\V1\\GPBMetadata\xea\x02\rAgentedge::V1b\x06proto3" var ( file_agentedge_proto_rawDescOnce sync.Once diff --git a/api/proto/gen/agentedgev1connect/BUILD.bazel b/api/proto/gen/agentedgev1connect/BUILD.bazel index 0b9767e103..e317bfb551 100644 --- a/api/proto/gen/agentedgev1connect/BUILD.bazel +++ b/api/proto/gen/agentedgev1connect/BUILD.bazel @@ -3,7 +3,7 @@ load("@rules_go//go:def.bzl", "go_library") go_library( name = "agentedgev1connect", srcs = ["agentedge.connect.go"], - importpath = "github.com/buildkite/agent/v3/api/proto/gen/agentedgev1connect", + importpath = "github.com/buildkite/agent/v4/api/proto/gen/agentedgev1connect", visibility = ["//visibility:public"], deps = [ "//api/proto/gen", diff --git a/api/proto/gen/agentedgev1connect/agentedge.connect.go b/api/proto/gen/agentedgev1connect/agentedge.connect.go index f2738d669f..1f5c42972b 100644 --- a/api/proto/gen/agentedgev1connect/agentedge.connect.go +++ b/api/proto/gen/agentedgev1connect/agentedge.connect.go @@ -8,7 +8,7 @@ import ( connect "connectrpc.com/connect" context "context" errors "errors" - gen "github.com/buildkite/agent/v3/api/proto/gen" + gen "github.com/buildkite/agent/v4/api/proto/gen" http "net/http" strings "strings" ) diff --git a/api/secrets_test.go b/api/secrets_test.go index 1ef7b77dd6..738dba08ec 100644 --- a/api/secrets_test.go +++ b/api/secrets_test.go @@ -10,8 +10,8 @@ import ( "path" "testing" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" "github.com/google/go-cmp/cmp" ) diff --git a/clicommand/BUILD.bazel b/clicommand/BUILD.bazel index 900a04a789..0b56a7b2a7 100644 --- a/clicommand/BUILD.bazel +++ b/clicommand/BUILD.bazel @@ -53,7 +53,7 @@ go_library( "tool_sign.go", ], embedsrcs = ["dummy.md.gz"], - importpath = "github.com/buildkite/agent/v3/clicommand", + importpath = "github.com/buildkite/agent/v4/clicommand", visibility = ["//visibility:public"], deps = [ "//agent", diff --git a/clicommand/agent_pause.go b/clicommand/agent_pause.go index ce170b331c..13879fbcc2 100644 --- a/clicommand/agent_pause.go +++ b/clicommand/agent_pause.go @@ -6,8 +6,8 @@ import ( "slices" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/roko" "github.com/urfave/cli" ) diff --git a/clicommand/agent_pause_test.go b/clicommand/agent_pause_test.go index ba97d7e2a2..e4ba1cc84d 100644 --- a/clicommand/agent_pause_test.go +++ b/clicommand/agent_pause_test.go @@ -7,7 +7,7 @@ import ( "slices" "testing" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) func newAgentPauseTestServer(t *testing.T) *httptest.Server { diff --git a/clicommand/agent_resume.go b/clicommand/agent_resume.go index 5265321b63..04850d4e3a 100644 --- a/clicommand/agent_resume.go +++ b/clicommand/agent_resume.go @@ -6,8 +6,8 @@ import ( "slices" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/roko" "github.com/urfave/cli" ) diff --git a/clicommand/agent_resume_test.go b/clicommand/agent_resume_test.go index 281707a6b0..2d8976f747 100644 --- a/clicommand/agent_resume_test.go +++ b/clicommand/agent_resume_test.go @@ -7,7 +7,7 @@ import ( "slices" "testing" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) func newAgentResumeTestServer(t *testing.T) *httptest.Server { diff --git a/clicommand/agent_start.go b/clicommand/agent_start.go index afb26f845c..7bb06851d6 100644 --- a/clicommand/agent_start.go +++ b/clicommand/agent_start.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "io" - "maps" "net/url" "os" "os/signal" @@ -23,23 +22,22 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/kms" - "github.com/buildkite/agent/v3/agent" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/core" - "github.com/buildkite/agent/v3/internal/agentapi" - "github.com/buildkite/agent/v3/internal/awslib" - awssigner "github.com/buildkite/agent/v3/internal/cryptosigner/aws" - gcpsigner "github.com/buildkite/agent/v3/internal/cryptosigner/gcp" - "github.com/buildkite/agent/v3/internal/experiments" - "github.com/buildkite/agent/v3/internal/job/hook" - "github.com/buildkite/agent/v3/internal/osutil" - "github.com/buildkite/agent/v3/internal/process" - "github.com/buildkite/agent/v3/internal/shell" - "github.com/buildkite/agent/v3/logger" - "github.com/buildkite/agent/v3/metrics" - "github.com/buildkite/agent/v3/status" - "github.com/buildkite/agent/v3/tracetools" - "github.com/buildkite/agent/v3/version" + "github.com/buildkite/agent/v4/agent" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/core" + "github.com/buildkite/agent/v4/internal/agentapi" + "github.com/buildkite/agent/v4/internal/awslib" + awssigner "github.com/buildkite/agent/v4/internal/cryptosigner/aws" + gcpsigner "github.com/buildkite/agent/v4/internal/cryptosigner/gcp" + "github.com/buildkite/agent/v4/internal/experiments" + "github.com/buildkite/agent/v4/internal/job/hook" + "github.com/buildkite/agent/v4/internal/osutil" + "github.com/buildkite/agent/v4/internal/process" + "github.com/buildkite/agent/v4/internal/shell" + "github.com/buildkite/agent/v4/logger" + "github.com/buildkite/agent/v4/metrics" + "github.com/buildkite/agent/v4/status" + "github.com/buildkite/agent/v4/version" "github.com/buildkite/shellwords" "github.com/lestrrat-go/jwx/v2/jwk" "github.com/urfave/cli" @@ -98,7 +96,7 @@ type AgentStartConfig struct { Priority string `cli:"priority"` Spawn int `cli:"spawn"` SpawnPerCPU int `cli:"spawn-per-cpu"` - SpawnWithPriority bool `cli:"spawn-with-priority"` + SpawnWithPriority string `cli:"spawn-with-priority"` RedactedVars []string `cli:"redacted-vars" normalize:"list"` CancelSignal string `cli:"cancel-signal"` @@ -112,13 +110,13 @@ type AgentStartConfig struct { VerificationJWKSFile string `cli:"verification-jwks-file" normalize:"filepath"` VerificationFailureBehavior string `cli:"verification-failure-behavior"` - AcquireJob string `cli:"acquire-job"` - DisconnectAfterJob bool `cli:"disconnect-after-job"` - DisconnectAfterIdleTimeout int `cli:"disconnect-after-idle-timeout"` - DisconnectAfterUptime int `cli:"disconnect-after-uptime"` - CancelGracePeriod int `cli:"cancel-grace-period"` - SignalGracePeriodSeconds int `cli:"signal-grace-period-seconds"` - ReflectExitStatus bool `cli:"reflect-exit-status"` + AcquireJob string `cli:"acquire-job"` + DisconnectAfterJob bool `cli:"disconnect-after-job"` + DisconnectAfterIdleTimeout int `cli:"disconnect-after-idle-timeout"` + DisconnectAfterUptime int `cli:"disconnect-after-uptime"` + CancelSignalTimeout time.Duration `cli:"cancel-signal-timeout"` + CancelCleanupTimeout time.Duration `cli:"cancel-cleanup-timeout"` + ReflectExitStatus bool `cli:"reflect-exit-status"` EnableJobLogTmpfile bool `cli:"enable-job-log-tmpfile"` JobLogPath string `cli:"job-log-path" normalize:"filepath"` @@ -187,21 +185,17 @@ type AgentStartConfig struct { HealthCheckAddr string `cli:"health-check-addr"` - // Datadog statsd metrics config - MetricsDatadog bool `cli:"metrics-datadog"` - MetricsDatadogHost string `cli:"metrics-datadog-host"` - MetricsDatadogDistributions bool `cli:"metrics-datadog-distributions"` + // Metrics config + OpenTelemetryMetrics bool `cli:"opentelemetry-metrics"` // Tracing config - TracingBackend string `cli:"tracing-backend"` - TracingServiceName string `cli:"tracing-service-name"` - TracingPropagateTraceparent bool `cli:"tracing-propagate-traceparent"` + OpenTelemetryTracing bool `cli:"opentelemetry-tracing"` + TracingServiceName string `cli:"tracing-service-name"` // Other shared flags StrictSingleHooks bool `cli:"strict-single-hooks"` KubernetesExec bool `cli:"kubernetes-exec"` KubernetesContainerStartTimeout time.Duration `cli:"kubernetes-container-start-timeout"` - TraceContextEncoding string `cli:"trace-context-encoding"` NoMultipartArtifactUpload bool `cli:"no-multipart-artifact-upload"` // API + agent behaviour @@ -213,16 +207,6 @@ type AgentStartConfig struct { Token string `cli:"token" validate:"required"` Endpoint string `cli:"endpoint" validate:"required"` NoHTTP2 bool `cli:"no-http2"` - // Deprecated - KubernetesLogCollectionGracePeriod time.Duration `cli:"kubernetes-log-collection-grace-period"` - NoSSHFingerprintVerification bool `cli:"no-automatic-ssh-fingerprint-verification" deprecated-and-renamed-to:"NoSSHKeyscan"` - MetaData []string `cli:"meta-data" deprecated-and-renamed-to:"Tags"` - MetaDataEC2 bool `cli:"meta-data-ec2" deprecated-and-renamed-to:"TagsFromEC2"` - MetaDataEC2Tags bool `cli:"meta-data-ec2-tags" deprecated-and-renamed-to:"TagsFromEC2Tags"` - MetaDataGCP bool `cli:"meta-data-gcp" deprecated-and-renamed-to:"TagsFromGCP"` - TagsFromEC2 bool `cli:"tags-from-ec2" deprecated-and-renamed-to:"TagsFromEC2MetaData"` - TagsFromGCP bool `cli:"tags-from-gcp" deprecated-and-renamed-to:"TagsFromGCPMetaData"` - DisconnectAfterJobTimeout int `cli:"disconnect-after-job-timeout" deprecated:"Use disconnect-after-idle-timeout instead"` } func (asc AgentStartConfig) Features(ctx context.Context) []string { @@ -246,18 +230,10 @@ func (asc AgentStartConfig) Features(ctx context.Context) []string { features = append(features, "acquire-job") } - if asc.TracingBackend == tracetools.BackendDatadog { - features = append(features, "datadog-tracing") - } - - if asc.TracingBackend == tracetools.BackendOpenTelemetry { + if asc.OpenTelemetryTracing { features = append(features, "opentelemetry-tracing") } - if asc.TracingPropagateTraceparent { - features = append(features, "propagate-traceparent") - } - if asc.DisconnectAfterJob { features = append(features, "disconnect-after-job") } @@ -302,8 +278,8 @@ func (asc AgentStartConfig) Features(ctx context.Context) []string { features = append(features, "env-godebug") } - if asc.MetricsDatadog { - features = append(features, "datadog-metrics") + if asc.OpenTelemetryMetrics { + features = append(features, "opentelemetry-metrics") } return features @@ -416,7 +392,7 @@ var AgentStartCommand = cli.Command{ Usage: "The maximum uptime in seconds before the agent stops accepting new jobs and shuts down after any running jobs complete. The default of 0 means no timeout", EnvVar: "BUILDKITE_AGENT_DISCONNECT_AFTER_UPTIME", }, - cancelGracePeriodFlag, + cancelSignalTimeoutFlag, cli.BoolFlag{ Name: "enable-job-log-tmpfile", Usage: "Store the job logs in a temporary file β€²BUILDKITE_JOB_LOG_TMPFILEβ€² that is accessible during the job and removed at the end of the job (default: false)", @@ -640,20 +616,9 @@ var AgentStartCommand = cli.Command{ EnvVar: "BUILDKITE_ALLOWED_PLUGINS", }, cli.BoolFlag{ - Name: "metrics-datadog", - Usage: "Send metrics to DogStatsD for Datadog (default: false)", - EnvVar: "BUILDKITE_METRICS_DATADOG", - }, - cli.StringFlag{ - Name: "metrics-datadog-host", - Usage: "The dogstatsd instance to send metrics to using udp", - EnvVar: "BUILDKITE_METRICS_DATADOG_HOST", - Value: "127.0.0.1:8125", - }, - cli.BoolFlag{ - Name: "metrics-datadog-distributions", - Usage: "Use Datadog Distributions for Timing metrics (default: false)", - EnvVar: "BUILDKITE_METRICS_DATADOG_DISTRIBUTIONS", + Name: "opentelemetry-metrics", + Usage: "Enable agent metrics export over OpenTelemetry OTLP. Configure OTLP with standard OTEL_EXPORTER_OTLP_* env vars (default: false)", + EnvVar: "BUILDKITE_OPENTELEMETRY_METRICS", }, cli.StringFlag{ Name: "log-format", @@ -673,27 +638,22 @@ var AgentStartCommand = cli.Command{ Value: 0, EnvVar: "BUILDKITE_AGENT_SPAWN_PER_CPU", }, - cli.BoolFlag{ + cli.StringFlag{ Name: "spawn-with-priority", - Usage: "Assign priorities to every spawned agent (when using --spawn or --spawn-per-cpu) equal to the agent's index (default: false)", + Usage: `Assign priorities to every spawned agent (when using --spawn or --spawn-per-cpu). Pass "static" (1, 1, 1, ...), "ascending" (1, 2, 3, ...), or "descending" (-1, -2, -3, ...). Descending helps jobs be assigned across all hosts when the value of --spawn varies between hosts`, + Value: "static", EnvVar: "BUILDKITE_AGENT_SPAWN_WITH_PRIORITY", }, cancelSignalFlag, - signalGracePeriodSecondsFlag, - cli.StringFlag{ - Name: "tracing-backend", - Usage: `Enable tracing for build jobs by specifying a backend, "datadog" or "opentelemetry"`, - EnvVar: "BUILDKITE_TRACING_BACKEND", - Value: "", - }, + cancelCleanupTimeoutFlag, cli.BoolFlag{ - Name: "tracing-propagate-traceparent", - Usage: `Enable accepting traceparent context from Buildkite control plane (only supported for OpenTelemetry backend) (default: false)`, - EnvVar: "BUILDKITE_TRACING_PROPAGATE_TRACEPARENT", + Name: "opentelemetry-tracing", + Usage: "Enable tracing for build jobs with OpenTelemetry OTLP. Configure OTLP with standard OTEL_EXPORTER_OTLP_* env vars (default: false)", + EnvVar: "BUILDKITE_OPENTELEMETRY_TRACING", }, cli.StringFlag{ Name: "tracing-service-name", - Usage: "Service name to use when reporting traces.", + Usage: "Service name to use when reporting telemetry.", EnvVar: "BUILDKITE_TRACING_SERVICE_NAME", Value: "buildkite-agent", }, @@ -772,53 +732,7 @@ var AgentStartCommand = cli.Command{ // Other shared flags RedactedVars, StrictSingleHooksFlag, - TraceContextEncodingFlag, NoMultipartArtifactUploadFlag, - - // Deprecated flags which will be removed in v4 - KubernetesLogCollectionGracePeriodFlag, - cli.StringSliceFlag{ - Name: "meta-data", - Value: &cli.StringSlice{}, - Hidden: true, - EnvVar: "BUILDKITE_AGENT_META_DATA", - }, - cli.BoolFlag{ - Name: "meta-data-ec2", - Hidden: true, - EnvVar: "BUILDKITE_AGENT_META_DATA_EC2", - }, - cli.BoolFlag{ - Name: "meta-data-ec2-tags", - Hidden: true, - EnvVar: "BUILDKITE_AGENT_META_DATA_EC2_TAGS", - }, - cli.BoolFlag{ - Name: "meta-data-gcp", - Hidden: true, - EnvVar: "BUILDKITE_AGENT_META_DATA_GCP", - }, - cli.BoolFlag{ - Name: "no-automatic-ssh-fingerprint-verification", - Hidden: true, - EnvVar: "BUILDKITE_NO_AUTOMATIC_SSH_FINGERPRINT_VERIFICATION", - }, - cli.BoolFlag{ - Name: "tags-from-ec2", - Usage: "Include the host's EC2 meta-data as tags (instance-id, instance-type, and ami-id)", - EnvVar: "BUILDKITE_AGENT_TAGS_FROM_EC2", - }, - cli.BoolFlag{ - Name: "tags-from-gcp", - Usage: "Include the host's Google Cloud instance meta-data as tags (instance-id, machine-type, preemptible, project-id, region, and zone)", - EnvVar: "BUILDKITE_AGENT_TAGS_FROM_GCP", - }, - cli.IntFlag{ - Name: "disconnect-after-job-timeout", - Hidden: true, - Usage: "When --disconnect-after-job is specified, the number of seconds to wait for a job before shutting down", - EnvVar: "BUILDKITE_AGENT_DISCONNECT_AFTER_JOB_TIMEOUT", - }, ), Action: func(c *cli.Context) error { ctx := context.Background() @@ -849,6 +763,11 @@ var AgentStartCommand = cli.Command{ cfg.PingMode = agent.PingModePollOnly } + validSpawnWithPriorities := []string{"static", "ascending", "descending"} + if !slices.Contains(validSpawnWithPriorities, cfg.SpawnWithPriority) { + return fmt.Errorf("invalid spawn-with-priority, must be one of %v", validSpawnWithPriorities) + } + if cfg.VerificationJWKSFile != "" { if !slices.Contains(verificationFailureBehaviors, cfg.VerificationFailureBehavior) { return fmt.Errorf( @@ -906,11 +825,6 @@ var AgentStartCommand = cli.Command{ cfg.Shell = DefaultShell() } - // Handle deprecated DisconnectAfterJobTimeout - if cfg.DisconnectAfterJobTimeout > 0 { - cfg.DisconnectAfterIdleTimeout = cfg.DisconnectAfterJobTimeout - } - var ec2TagTimeout time.Duration if t := cfg.WaitForEC2TagsTimeout; t != "" { var err error @@ -947,30 +861,11 @@ var AgentStartCommand = cli.Command{ } } - signalGracePeriod, err := signalGracePeriod(cfg.CancelGracePeriod, cfg.SignalGracePeriodSeconds) - if err != nil { - return err - } - - if _, err := tracetools.ParseEncoding(cfg.TraceContextEncoding); err != nil { - return fmt.Errorf("while parsing trace context encoding: %v", err) - } - mc := metrics.NewCollector(l, metrics.CollectorConfig{ - Datadog: cfg.MetricsDatadog, - DatadogHost: cfg.MetricsDatadogHost, - DatadogDistributions: cfg.MetricsDatadogDistributions, + Enabled: cfg.OpenTelemetryMetrics, + ServiceName: cfg.TracingServiceName, }) - // Sense check supported tracing backends, we don't want bootstrapped jobs to silently have no tracing - if _, has := tracetools.ValidTracingBackends[cfg.TracingBackend]; !has { - return fmt.Errorf( - "the given tracing backend %q is not supported. Valid backends are: %q", - cfg.TracingBackend, - slices.Collect(maps.Keys(tracetools.ValidTracingBackends)), - ) - } - if experiments.IsEnabled(ctx, experiments.AgentAPI) { shutdown, err := runAgentAPI(ctx, l, cfg.SocketsPath) if err != nil { @@ -981,7 +876,10 @@ var AgentStartCommand = cli.Command{ // if the agent is provided a KMS key ID, it should use the KMS signer, otherwise // it should load the JWKS from the file - var verificationJWKS any + var ( + verificationJWKS any + err error + ) switch { case cfg.SigningAWSKMSKey != "": @@ -1085,8 +983,8 @@ var AgentStartCommand = cli.Command{ DisconnectAfterJob: cfg.DisconnectAfterJob, DisconnectAfterIdleTimeout: time.Duration(cfg.DisconnectAfterIdleTimeout) * time.Second, DisconnectAfterUptime: time.Duration(cfg.DisconnectAfterUptime) * time.Second, - CancelGracePeriod: cfg.CancelGracePeriod, - SignalGracePeriod: signalGracePeriod, + CancelSignalTimeout: cfg.CancelSignalTimeout, + CancelCleanupTimeout: cfg.CancelCleanupTimeout, EnableJobLogTmpfile: cfg.EnableJobLogTmpfile, JobLogPath: cfg.JobLogPath, WriteJobLogsToStdout: cfg.WriteJobLogsToStdout, @@ -1095,10 +993,8 @@ var AgentStartCommand = cli.Command{ HooksShell: cfg.HooksShell, RedactedVars: cfg.RedactedVars, AcquireJob: cfg.AcquireJob, - TracingBackend: cfg.TracingBackend, + OpenTelemetryTracing: cfg.OpenTelemetryTracing, TracingServiceName: cfg.TracingServiceName, - TracingPropagateTraceparent: cfg.TracingPropagateTraceparent, - TraceContextEncoding: cfg.TraceContextEncoding, AllowMultipartArtifactUpload: !cfg.NoMultipartArtifactUpload, KubernetesExec: cfg.KubernetesExec, KubernetesContainerStartTimeout: cfg.KubernetesContainerStartTimeout, @@ -1219,11 +1115,11 @@ var AgentStartCommand = cli.Command{ tags, err := agent.FetchTags(ctx, l, agent.FetchTagsConfig{ Tags: cfg.Tags, TagsFromK8s: cfg.KubernetesExec, - TagsFromEC2MetaData: (cfg.TagsFromEC2MetaData || cfg.TagsFromEC2), + TagsFromEC2MetaData: cfg.TagsFromEC2MetaData, TagsFromEC2MetaDataPaths: cfg.TagsFromEC2MetaDataPaths, TagsFromEC2Tags: cfg.TagsFromEC2Tags, TagsFromECSMetaData: cfg.TagsFromECSMetaData, - TagsFromGCPMetaData: (cfg.TagsFromGCPMetaData || cfg.TagsFromGCP), + TagsFromGCPMetaData: cfg.TagsFromGCPMetaData, TagsFromGCPMetaDataPaths: cfg.TagsFromGCPMetaDataPaths, TagsFromGCPLabels: cfg.TagsFromGCPLabels, TagsFromHost: cfg.TagsFromHost, @@ -1300,17 +1196,23 @@ var AgentStartCommand = cli.Command{ // Handle per-spawn name interpolation, replacing %spawn with the spawn index registerReq.Name = strings.ReplaceAll(cfg.Name, "%spawn", strconv.Itoa(i)) - if cfg.SpawnWithPriority { - p := i - if experiments.IsEnabled(ctx, experiments.DescendingSpawnPriority) { - // This experiment helps jobs be assigned across all hosts - // in cases where the value of --spawn varies between hosts. - p = -i - } - l.Info("Assigning priority %d for agent %d", p, i) - registerReq.Priority = strconv.Itoa(p) + var priority string + switch cfg.SpawnWithPriority { + case "static": + priority = cfg.Priority + + case "ascending": + priority = strconv.Itoa(i) + + case "descending": + priority = strconv.Itoa(-i) + + default: + return fmt.Errorf("unknown spawn-with-priority value %s", cfg.SpawnWithPriority) } + registerReq.Priority = priority + // Register the agent with the buildkite API reg, err := client.Register(ctx, registerReq) if err != nil { @@ -1326,7 +1228,7 @@ var AgentStartCommand = cli.Command{ agent.AgentWorkerConfig{ AgentConfiguration: agentConf, CancelSignal: cancelSig, - SignalGracePeriod: signalGracePeriod, + SignalGracePeriod: cfg.CancelSignalTimeout, Debug: cfg.Debug, DebugHTTP: cfg.DebugHTTP, SpawnIndex: i, @@ -1350,7 +1252,7 @@ var AgentStartCommand = cli.Command{ poolSigs := &poolSignals{ log: l, pool: pool, - cancelGracePeriod: time.Duration(cfg.CancelGracePeriod) * time.Second, + cancelGracePeriod: cfg.CancelSignalTimeout + cfg.CancelCleanupTimeout, // Under Kubernetes, there is no user interactively signalling us, // so on SIGTERM, stop un-gracefully. skipGraceful: cfg.KubernetesExec, diff --git a/clicommand/agent_start_test.go b/clicommand/agent_start_test.go index 42738d292f..0c41278cac 100644 --- a/clicommand/agent_start_test.go +++ b/clicommand/agent_start_test.go @@ -1,18 +1,29 @@ package clicommand import ( + "context" "errors" "os" "path/filepath" "runtime" + "slices" "testing" - "github.com/buildkite/agent/v3/core" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/core" + "github.com/buildkite/agent/v4/logger" "github.com/google/go-cmp/cmp" "github.com/urfave/cli" ) +func TestAgentStartFeatures_OpenTelemetryTracing(t *testing.T) { + t.Parallel() + + features := AgentStartConfig{OpenTelemetryTracing: true}.Features(context.Background()) + if !slices.Contains(features, "opentelemetry-tracing") { + t.Fatalf("Features() = %v, want opentelemetry-tracing", features) + } +} + func setupHooksPath(t *testing.T) (string, func()) { t.Helper() diff --git a/clicommand/agent_stop.go b/clicommand/agent_stop.go index e928275a4b..4cee59e89c 100644 --- a/clicommand/agent_stop.go +++ b/clicommand/agent_stop.go @@ -6,8 +6,8 @@ import ( "slices" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/roko" "github.com/urfave/cli" ) diff --git a/clicommand/agent_stop_test.go b/clicommand/agent_stop_test.go index 9e4fa5356c..c88af91837 100644 --- a/clicommand/agent_stop_test.go +++ b/clicommand/agent_stop_test.go @@ -7,7 +7,7 @@ import ( "slices" "testing" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) func newAgentStopTestServer(t *testing.T) *httptest.Server { diff --git a/clicommand/annotate.go b/clicommand/annotate.go index 9d10a68cf9..6a7d2e68c1 100644 --- a/clicommand/annotate.go +++ b/clicommand/annotate.go @@ -8,10 +8,10 @@ import ( "slices" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/internal/redact" - "github.com/buildkite/agent/v3/internal/stdin" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/internal/redact" + "github.com/buildkite/agent/v4/internal/stdin" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/roko" "github.com/urfave/cli" ) diff --git a/clicommand/annotate_test.go b/clicommand/annotate_test.go index 77ccf3800f..48a795ff26 100644 --- a/clicommand/annotate_test.go +++ b/clicommand/annotate_test.go @@ -9,7 +9,7 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) func newAnnotateTestServer(t *testing.T) *httptest.Server { diff --git a/clicommand/annotation_remove.go b/clicommand/annotation_remove.go index 4550507a65..c215c5c3ff 100644 --- a/clicommand/annotation_remove.go +++ b/clicommand/annotation_remove.go @@ -6,7 +6,7 @@ import ( "slices" "time" - "github.com/buildkite/agent/v3/api" + "github.com/buildkite/agent/v4/api" "github.com/buildkite/roko" "github.com/urfave/cli" ) diff --git a/clicommand/artifact_download.go b/clicommand/artifact_download.go index fff027bee9..0b23724db2 100644 --- a/clicommand/artifact_download.go +++ b/clicommand/artifact_download.go @@ -5,8 +5,8 @@ import ( "fmt" "slices" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/internal/artifact" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/internal/artifact" "github.com/urfave/cli" ) diff --git a/clicommand/artifact_search.go b/clicommand/artifact_search.go index 7538b98a4b..2b6edef6d3 100644 --- a/clicommand/artifact_search.go +++ b/clicommand/artifact_search.go @@ -8,8 +8,8 @@ import ( "strings" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/internal/artifact" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/internal/artifact" "github.com/urfave/cli" ) diff --git a/clicommand/artifact_shasum.go b/clicommand/artifact_shasum.go index dbe47e4be8..00825fa05c 100644 --- a/clicommand/artifact_shasum.go +++ b/clicommand/artifact_shasum.go @@ -7,9 +7,9 @@ import ( "os" "slices" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/internal/artifact" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/internal/artifact" + "github.com/buildkite/agent/v4/logger" "github.com/urfave/cli" ) diff --git a/clicommand/artifact_shasum_test.go b/clicommand/artifact_shasum_test.go index ff4d001fdd..01ab824756 100644 --- a/clicommand/artifact_shasum_test.go +++ b/clicommand/artifact_shasum_test.go @@ -9,7 +9,7 @@ import ( "slices" "testing" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) func newArtifactTestServer(t *testing.T) *httptest.Server { diff --git a/clicommand/artifact_upload.go b/clicommand/artifact_upload.go index f543ac4eb6..183323a912 100644 --- a/clicommand/artifact_upload.go +++ b/clicommand/artifact_upload.go @@ -5,8 +5,8 @@ import ( "fmt" "slices" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/internal/artifact" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/internal/artifact" "github.com/urfave/cli" ) @@ -82,9 +82,6 @@ type ArtifactUploadConfig struct { GlobResolveFollowSymlinks bool `cli:"glob-resolve-follow-symlinks"` UploadSkipSymlinks bool `cli:"upload-skip-symlinks"` NoMultipartUpload bool `cli:"no-multipart-artifact-upload"` - - // deprecated - FollowSymlinks bool `cli:"follow-symlinks" deprecated-and-renamed-to:"GlobResolveFollowSymlinks"` } var ArtifactUploadCommand = cli.Command{ @@ -125,11 +122,6 @@ var ArtifactUploadCommand = cli.Command{ Usage: "After the glob has been resolved to a list of files to upload, skip uploading those that are symlinks to files (default: false)", EnvVar: "BUILDKITE_ARTIFACT_UPLOAD_SKIP_SYMLINKS", }, - cli.BoolFlag{ // Deprecated - Name: "follow-symlinks", - Usage: "Follow symbolic links while resolving globs. Note this argument is deprecated. Use `--glob-resolve-follow-symlinks` instead (default: false)", - EnvVar: "BUILDKITE_AGENT_ARTIFACT_SYMLINKS", - }, NoMultipartArtifactUploadFlag, }), Action: func(c *cli.Context) error { @@ -153,9 +145,7 @@ var ArtifactUploadCommand = cli.Command{ Literal: cfg.Literal, Delimiter: cfg.Delimiter, - // If the deprecated flag was set to true, pretend its replacement was set to true too - // this works as long as the user only sets one of the two flags - GlobResolveFollowSymlinks: (cfg.GlobResolveFollowSymlinks || cfg.FollowSymlinks), + GlobResolveFollowSymlinks: cfg.GlobResolveFollowSymlinks, UploadSkipSymlinks: cfg.UploadSkipSymlinks, }) diff --git a/clicommand/bootstrap.go b/clicommand/bootstrap.go index ff5b4c6624..340f98c9d7 100644 --- a/clicommand/bootstrap.go +++ b/clicommand/bootstrap.go @@ -11,11 +11,11 @@ import ( "syscall" "time" - "github.com/buildkite/agent/v3/internal/job" - "github.com/buildkite/agent/v3/internal/process" - "github.com/buildkite/agent/v3/internal/self" - "github.com/buildkite/agent/v3/logger" - "github.com/buildkite/agent/v3/tracetools" + "github.com/buildkite/agent/v4/internal/job" + "github.com/buildkite/agent/v4/internal/process" + "github.com/buildkite/agent/v4/internal/self" + "github.com/buildkite/agent/v4/logger" + "github.com/buildkite/agent/v4/tracetools" "github.com/urfave/cli" ) @@ -37,7 +37,7 @@ command phase that executes the specified command in the created environment. You can run only specific phases with the --phases flag. The bootstrap is also responsible for executing hooks around the phases. -See https://buildkite.com/docs/agent/v3/hooks for more details. +See https://buildkite.com/docs/agent/v4/hooks for more details. Example: @@ -48,71 +48,69 @@ Example: $ buildkite-agent bootstrap --build-path builds` type BootstrapConfig struct { - Command string `cli:"command"` - JobID string `cli:"job" validate:"required"` - Repository string `cli:"repository" validate:"required"` - Commit string `cli:"commit" validate:"required"` - Branch string `cli:"branch" validate:"required"` - Tag string `cli:"tag"` - RefSpec string `cli:"refspec"` - Plugins string `cli:"plugins"` - Secrets string `cli:"secrets"` - PullRequest string `cli:"pullrequest"` - PullRequestUsingMergeRefspec bool `cli:"pull-request-using-merge-refspec"` - GitSubmodules bool `cli:"git-submodules"` - SSHKeyscan bool `cli:"ssh-keyscan"` - AgentName string `cli:"agent" validate:"required"` - Queue string `cli:"queue"` - OrganizationSlug string `cli:"organization" validate:"required"` - PipelineSlug string `cli:"pipeline" validate:"required"` - PipelineProvider string `cli:"pipeline-provider" validate:"required"` - AutomaticArtifactUploadPaths string `cli:"artifact-upload-paths"` - ArtifactUploadDestination string `cli:"artifact-upload-destination"` - CleanCheckout bool `cli:"clean-checkout"` - SkipCheckout bool `cli:"skip-checkout"` - GitSkipFetchExistingCommits bool `cli:"git-skip-fetch-existing-commits"` - GitCheckoutFlags string `cli:"git-checkout-flags"` - GitCloneFlags string `cli:"git-clone-flags"` - GitFetchFlags string `cli:"git-fetch-flags"` - GitCloneMirrorFlags string `cli:"git-clone-mirror-flags"` - GitCleanFlags string `cli:"git-clean-flags"` - GitMirrorsPath string `cli:"git-mirrors-path" normalize:"filepath"` - GitMirrorCheckoutMode string `cli:"git-mirror-checkout-mode"` - GitMirrorsLockTimeout int `cli:"git-mirrors-lock-timeout"` - GitMirrorsSkipUpdate bool `cli:"git-mirrors-skip-update"` - GitSubmoduleCloneConfig []string `cli:"git-submodule-clone-config" normalize:"list"` - BinPath string `cli:"bin-path" normalize:"filepath"` - BuildPath string `cli:"build-path" normalize:"filepath"` - HooksPath string `cli:"hooks-path" normalize:"filepath"` - AdditionalHooksPaths []string `cli:"additional-hooks-paths" normalize:"list"` - SocketsPath string `cli:"sockets-path" normalize:"filepath"` - PluginsPath string `cli:"plugins-path" normalize:"filepath"` - CommandEval bool `cli:"command-eval"` - PluginsEnabled bool `cli:"plugins-enabled"` - PluginValidation bool `cli:"plugin-validation"` - PluginsAlwaysCloneFresh bool `cli:"plugins-always-clone-fresh"` - LocalHooksEnabled bool `cli:"local-hooks-enabled"` - StrictSingleHooks bool `cli:"strict-single-hooks"` - PTY bool `cli:"pty"` - LogLevel string `cli:"log-level"` - Debug bool `cli:"debug"` - Shell string `cli:"shell"` - HooksShell string `cli:"hooks-shell"` - Experiments []string `cli:"experiment" normalize:"list"` - Phases []string `cli:"phases" normalize:"list"` - Profile string `cli:"profile"` - CancelSignal string `cli:"cancel-signal"` - CancelGracePeriod int `cli:"cancel-grace-period"` - SignalGracePeriodSeconds int `cli:"signal-grace-period-seconds"` - RedactedVars []string `cli:"redacted-vars" normalize:"list"` - TracingBackend string `cli:"tracing-backend"` - TracingServiceName string `cli:"tracing-service-name"` - TracingTraceParent string `cli:"tracing-traceparent"` - TracingPropagateTraceparent bool `cli:"tracing-propagate-traceparent"` - TraceContextEncoding string `cli:"trace-context-encoding"` - NoJobAPI bool `cli:"no-job-api"` - DisableWarningsFor []string `cli:"disable-warnings-for" normalize:"list"` - CheckoutAttempts int `cli:"checkout-attempts"` + Command string `cli:"command"` + JobID string `cli:"job" validate:"required"` + Repository string `cli:"repository" validate:"required"` + Commit string `cli:"commit" validate:"required"` + Branch string `cli:"branch" validate:"required"` + Tag string `cli:"tag"` + RefSpec string `cli:"refspec"` + Plugins string `cli:"plugins"` + Secrets string `cli:"secrets"` + PullRequest string `cli:"pullrequest"` + PullRequestUsingMergeRefspec bool `cli:"pull-request-using-merge-refspec"` + GitSubmodules bool `cli:"git-submodules"` + SSHKeyscan bool `cli:"ssh-keyscan"` + AgentName string `cli:"agent" validate:"required"` + Queue string `cli:"queue"` + OrganizationSlug string `cli:"organization" validate:"required"` + PipelineSlug string `cli:"pipeline" validate:"required"` + PipelineProvider string `cli:"pipeline-provider" validate:"required"` + AutomaticArtifactUploadPaths string `cli:"artifact-upload-paths"` + ArtifactUploadDestination string `cli:"artifact-upload-destination"` + CleanCheckout bool `cli:"clean-checkout"` + SkipCheckout bool `cli:"skip-checkout"` + GitSkipFetchExistingCommits bool `cli:"git-skip-fetch-existing-commits"` + GitCheckoutFlags string `cli:"git-checkout-flags"` + GitCloneFlags string `cli:"git-clone-flags"` + GitFetchFlags string `cli:"git-fetch-flags"` + GitCloneMirrorFlags string `cli:"git-clone-mirror-flags"` + GitCleanFlags string `cli:"git-clean-flags"` + GitMirrorsPath string `cli:"git-mirrors-path" normalize:"filepath"` + GitMirrorCheckoutMode string `cli:"git-mirror-checkout-mode"` + GitMirrorsLockTimeout int `cli:"git-mirrors-lock-timeout"` + GitMirrorsSkipUpdate bool `cli:"git-mirrors-skip-update"` + GitSubmoduleCloneConfig []string `cli:"git-submodule-clone-config" normalize:"list"` + BinPath string `cli:"bin-path" normalize:"filepath"` + BuildPath string `cli:"build-path" normalize:"filepath"` + HooksPath string `cli:"hooks-path" normalize:"filepath"` + AdditionalHooksPaths []string `cli:"additional-hooks-paths" normalize:"list"` + SocketsPath string `cli:"sockets-path" normalize:"filepath"` + PluginsPath string `cli:"plugins-path" normalize:"filepath"` + CommandEval bool `cli:"command-eval"` + PluginsEnabled bool `cli:"plugins-enabled"` + PluginValidation bool `cli:"plugin-validation"` + PluginsAlwaysCloneFresh bool `cli:"plugins-always-clone-fresh"` + LocalHooksEnabled bool `cli:"local-hooks-enabled"` + StrictSingleHooks bool `cli:"strict-single-hooks"` + PTY bool `cli:"pty"` + LogLevel string `cli:"log-level"` + Debug bool `cli:"debug"` + Shell string `cli:"shell"` + HooksShell string `cli:"hooks-shell"` + Experiments []string `cli:"experiment" normalize:"list"` + Phases []string `cli:"phases" normalize:"list"` + Profile string `cli:"profile"` + CancelSignal string `cli:"cancel-signal"` + CancelSignalTimeout time.Duration `cli:"cancel-signal-timeout"` + CancelCleanupTimeout time.Duration `cli:"cancel-cleanup-timeout"` + RedactedVars []string `cli:"redacted-vars" normalize:"list"` + OpenTelemetryTracing bool `cli:"opentelemetry-tracing"` + TracingServiceName string `cli:"tracing-service-name"` + TracingTraceParent string `cli:"tracing-traceparent"` + NoJobAPI bool `cli:"no-job-api"` + DisableWarningsFor []string `cli:"disable-warnings-for" normalize:"list"` + CheckoutAttempts int `cli:"checkout-attempts"` } var BootstrapCommand = cli.Command{ @@ -319,11 +317,10 @@ var BootstrapCommand = cli.Command{ Usage: "The specific phases to execute. The order they're defined is irrelevant.", EnvVar: "BUILDKITE_BOOTSTRAP_PHASES", }, - cli.StringFlag{ - Name: "tracing-backend", - Usage: "The name of the tracing backend to use.", - EnvVar: "BUILDKITE_TRACING_BACKEND", - Value: "", + cli.BoolFlag{ + Name: "opentelemetry-tracing", + Usage: "Enable tracing for build jobs with OpenTelemetry OTLP. Configure OTLP with standard OTEL_EXPORTER_OTLP_* env vars (default: false)", + EnvVar: "BUILDKITE_OPENTELEMETRY_TRACING", }, cli.StringFlag{ Name: "tracing-service-name", @@ -337,12 +334,6 @@ var BootstrapCommand = cli.Command{ EnvVar: "BUILDKITE_TRACING_TRACEPARENT", Value: "", }, - cli.BoolFlag{ - Name: "tracing-propagate-traceparent", - Usage: "Accept traceparent from Buildkite control plane (default: false)", - EnvVar: "BUILDKITE_TRACING_PROPAGATE_TRACEPARENT", - }, - cli.BoolFlag{ Name: "no-job-api", Usage: "Disables the Job API, which gives commands in jobs some abilities to introspect and mutate the state of the job (default: false)", @@ -354,8 +345,8 @@ var BootstrapCommand = cli.Command{ EnvVar: "BUILDKITE_AGENT_DISABLE_WARNINGS_FOR", }, cancelSignalFlag, - cancelGracePeriodFlag, - signalGracePeriodSecondsFlag, + cancelSignalTimeoutFlag, + cancelCleanupTimeoutFlag, // Global flags DebugFlag, @@ -364,7 +355,6 @@ var BootstrapCommand = cli.Command{ ProfileFlag, RedactedVars, StrictSingleHooksFlag, - TraceContextEncodingFlag, }, Action: func(c *cli.Context) error { ctx := context.Background() @@ -407,14 +397,9 @@ var BootstrapCommand = cli.Command{ return fmt.Errorf("failed to parse cancel-signal: %w", err) } - signalGracePeriod, err := signalGracePeriod(cfg.CancelGracePeriod, cfg.SignalGracePeriodSeconds) - if err != nil { - return err - } - - traceContextCodec, err := tracetools.ParseEncoding(cfg.TraceContextEncoding) - if err != nil { - return fmt.Errorf("while parsing trace context encoding: %v", err) + tracingBackend := tracetools.BackendNone + if cfg.OpenTelemetryTracing { + tracingBackend = tracetools.BackendOpenTelemetry } // Configure the bootstraper @@ -427,7 +412,7 @@ var BootstrapCommand = cli.Command{ BuildPath: cfg.BuildPath, SocketsPath: cfg.SocketsPath, CancelSignal: cancelSig, - SignalGracePeriod: signalGracePeriod, + SignalGracePeriod: cfg.CancelSignalTimeout, CleanCheckout: cfg.CleanCheckout, SkipCheckout: cfg.SkipCheckout, GitSkipFetchExistingCommits: cfg.GitSkipFetchExistingCommits, @@ -471,11 +456,9 @@ var BootstrapCommand = cli.Command{ HooksShell: cfg.HooksShell, StrictSingleHooks: cfg.StrictSingleHooks, Tag: cfg.Tag, - TracingBackend: cfg.TracingBackend, + TracingBackend: tracingBackend, TracingServiceName: cfg.TracingServiceName, - TraceContextCodec: traceContextCodec, TracingTraceParent: cfg.TracingTraceParent, - TracingPropagateTraceparent: cfg.TracingPropagateTraceparent, JobAPI: !cfg.NoJobAPI, DisabledWarnings: cfg.DisableWarningsFor, Secrets: cfg.Secrets, diff --git a/clicommand/build_cancel.go b/clicommand/build_cancel.go index 3987d4e93e..79eb879e55 100644 --- a/clicommand/build_cancel.go +++ b/clicommand/build_cancel.go @@ -6,8 +6,8 @@ import ( "slices" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/roko" "github.com/urfave/cli" ) diff --git a/clicommand/build_cancel_test.go b/clicommand/build_cancel_test.go index 071ddea12d..217c4c8107 100644 --- a/clicommand/build_cancel_test.go +++ b/clicommand/build_cancel_test.go @@ -8,7 +8,7 @@ import ( "slices" "testing" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) func TestBuildCancel(t *testing.T) { diff --git a/clicommand/cache_restore.go b/clicommand/cache_restore.go index 261b5e4323..6d77243b9a 100644 --- a/clicommand/cache_restore.go +++ b/clicommand/cache_restore.go @@ -4,7 +4,7 @@ import ( "context" "slices" - "github.com/buildkite/agent/v3/internal/cache" + "github.com/buildkite/agent/v4/internal/cache" "github.com/urfave/cli" ) diff --git a/clicommand/cache_save.go b/clicommand/cache_save.go index d92724f231..ca68f0417b 100644 --- a/clicommand/cache_save.go +++ b/clicommand/cache_save.go @@ -5,7 +5,7 @@ import ( "fmt" "slices" - "github.com/buildkite/agent/v3/internal/cache" + "github.com/buildkite/agent/v4/internal/cache" "github.com/urfave/cli" ) diff --git a/clicommand/cancel_signal.go b/clicommand/cancel_signal.go index b4d7025ebb..89922ae217 100644 --- a/clicommand/cancel_signal.go +++ b/clicommand/cancel_signal.go @@ -1,25 +1,22 @@ package clicommand import ( - "fmt" "time" "github.com/urfave/cli" ) const ( - defaultCancelGracePeriodSecs = 10 - defaultSignalGracePeriodSecs = -1 - defaultSignalGracePeriod = (defaultCancelGracePeriodSecs + defaultSignalGracePeriodSecs) * time.Second + defaultCancelSignalTimeout = 10 * time.Second + defaultCancelCleanupTimeout = 5 * time.Second ) var ( - cancelGracePeriodFlag = cli.IntFlag{ - Name: "cancel-grace-period", - Value: defaultCancelGracePeriodSecs, - Usage: "The number of seconds a canceled or timed out job is given " + - "to gracefully terminate and upload its artifacts", - EnvVar: "BUILDKITE_CANCEL_GRACE_PERIOD", + cancelSignalTimeoutFlag = cli.DurationFlag{ + Name: "cancel-signal-timeout", + Value: defaultCancelSignalTimeout, + Usage: "The amount of time given to a subprocess to handle the cancel signal before SIGKILL is sent", + EnvVar: "BUILDKITE_CANCEL_SIGNAL_TIMEOUT", } cancelSignalFlag = cli.StringFlag{ Name: "cancel-signal", @@ -27,46 +24,10 @@ var ( Usage: "The signal to use for cancellation", EnvVar: "BUILDKITE_CANCEL_SIGNAL", } - signalGracePeriodSecondsFlag = cli.IntFlag{ - Name: "signal-grace-period-seconds", - Value: defaultSignalGracePeriodSecs, - Usage: "The number of seconds given to a subprocess to handle being sent β€²cancel-signalβ€². " + - "After this period has elapsed, SIGKILL will be sent. " + - "Negative values are taken relative to β€²cancel-grace-periodβ€². " + - "The default value (-1) means that the effective signal grace period is equal to β€²cancel-grace-periodβ€² minus 1.", - EnvVar: "BUILDKITE_SIGNAL_GRACE_PERIOD_SECONDS", + cancelCleanupTimeoutFlag = cli.DurationFlag{ + Name: "cancel-cleanup-timeout", + Value: defaultCancelCleanupTimeout, + Usage: "The amount of time given to the agent after the process exits or is killed to upload logs and artifacts", + EnvVar: "BUILDKITE_CANCEL_CLEANUP_TIMEOUT", } ) - -// signalGracePeriod computes the signal grace period based on the various -// possible flag configurations: -// - If signalGracePeriodSecs is negative, it is relative to -// cancelGracePeriodSecs. -// - If cancelGracePeriodSecs is less than signalGracePeriodSecs that is an -// error. -// -// If the combination is invalid, both the defaultSignalGracePeriod and an error -// is returned. -func signalGracePeriod(cancelGracePeriodSecs, signalGracePeriodSecs int) (time.Duration, error) { - // Treat a negative signal grace period as relative to the cancel grace period - if signalGracePeriodSecs < 0 { - if cancelGracePeriodSecs < -signalGracePeriodSecs { - return defaultSignalGracePeriod, fmt.Errorf( - "cancel-grace-period (%d) must be at least as big as signal-grace-period-seconds (%d)", - cancelGracePeriodSecs, - signalGracePeriodSecs, - ) - } - signalGracePeriodSecs = cancelGracePeriodSecs + signalGracePeriodSecs - } - - if cancelGracePeriodSecs <= signalGracePeriodSecs { - return defaultSignalGracePeriod, fmt.Errorf( - "cancel-grace-period (%d) must be greater than signal-grace-period-seconds (%d)", - cancelGracePeriodSecs, - signalGracePeriodSecs, - ) - } - - return time.Duration(signalGracePeriodSecs) * time.Second, nil -} diff --git a/clicommand/env_dump.go b/clicommand/env_dump.go index 4d29b27e90..cb38a94aed 100644 --- a/clicommand/env_dump.go +++ b/clicommand/env_dump.go @@ -6,7 +6,7 @@ import ( "fmt" "os" - "github.com/buildkite/agent/v3/env" + "github.com/buildkite/agent/v4/env" "github.com/urfave/cli" ) diff --git a/clicommand/env_get.go b/clicommand/env_get.go index 479b04304c..196da0a003 100644 --- a/clicommand/env_get.go +++ b/clicommand/env_get.go @@ -5,8 +5,8 @@ import ( "encoding/json" "fmt" - "github.com/buildkite/agent/v3/env" - "github.com/buildkite/agent/v3/jobapi" + "github.com/buildkite/agent/v4/env" + "github.com/buildkite/agent/v4/jobapi" "github.com/urfave/cli" ) diff --git a/clicommand/env_set.go b/clicommand/env_set.go index 728b665015..7f986c2938 100644 --- a/clicommand/env_set.go +++ b/clicommand/env_set.go @@ -7,8 +7,8 @@ import ( "fmt" "os" - "github.com/buildkite/agent/v3/env" - "github.com/buildkite/agent/v3/jobapi" + "github.com/buildkite/agent/v4/env" + "github.com/buildkite/agent/v4/jobapi" "github.com/urfave/cli" ) diff --git a/clicommand/env_unset.go b/clicommand/env_unset.go index 7c3d6a6f92..f5ed4b4062 100644 --- a/clicommand/env_unset.go +++ b/clicommand/env_unset.go @@ -7,7 +7,7 @@ import ( "fmt" "os" - "github.com/buildkite/agent/v3/jobapi" + "github.com/buildkite/agent/v4/jobapi" "github.com/urfave/cli" ) diff --git a/clicommand/git_credentials_helper.go b/clicommand/git_credentials_helper.go index df18f84636..b130e247e6 100644 --- a/clicommand/git_credentials_helper.go +++ b/clicommand/git_credentials_helper.go @@ -9,8 +9,8 @@ import ( "os" "strings" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" "github.com/urfave/cli" ) diff --git a/clicommand/global.go b/clicommand/global.go index 98ed849b37..b4fef13926 100644 --- a/clicommand/global.go +++ b/clicommand/global.go @@ -7,13 +7,12 @@ import ( "os" "reflect" "strings" - "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/cliconfig" - "github.com/buildkite/agent/v3/internal/experiments" - "github.com/buildkite/agent/v3/logger" - "github.com/buildkite/agent/v3/version" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/cliconfig" + "github.com/buildkite/agent/v4/internal/experiments" + "github.com/buildkite/agent/v4/logger" + "github.com/buildkite/agent/v4/version" "github.com/oleiade/reflections" "github.com/urfave/cli" ) @@ -101,13 +100,6 @@ var ( EnvVar: "BUILDKITE_CONTAINER_ID", } - KubernetesLogCollectionGracePeriodFlag = cli.DurationFlag{ - Name: "kubernetes-log-collection-grace-period", - Usage: "Deprecated, do not use", - EnvVar: "BUILDKITE_KUBERNETES_LOG_COLLECTION_GRACE_PERIOD", - Value: 50 * time.Second, - } - NoMultipartArtifactUploadFlag = cli.BoolFlag{ Name: "no-multipart-artifact-upload", Usage: "For Buildkite-hosted artifacts, disables the use of multipart uploads. Has no effect on uploads to other destinations such as custom cloud buckets (default: false)", @@ -138,13 +130,6 @@ var ( "*_API_KEY", }, } - - TraceContextEncodingFlag = cli.StringFlag{ - Name: "trace-context-encoding", - Usage: "Sets the inner encoding for BUILDKITE_TRACE_CONTEXT. Must be either json or gob", - Value: "gob", - EnvVar: "BUILDKITE_TRACE_CONTEXT_ENCODING", - } ) // File path flags shared between agent start and bootstrap diff --git a/clicommand/job_update.go b/clicommand/job_update.go index 63768fadc9..7b7046784c 100644 --- a/clicommand/job_update.go +++ b/clicommand/job_update.go @@ -8,8 +8,8 @@ import ( "slices" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/internal/redact" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/internal/redact" "github.com/buildkite/roko" "github.com/urfave/cli" ) diff --git a/clicommand/kubernetes_bootstrap.go b/clicommand/kubernetes_bootstrap.go index cfa43450a6..e20ed6f9c2 100644 --- a/clicommand/kubernetes_bootstrap.go +++ b/clicommand/kubernetes_bootstrap.go @@ -11,9 +11,9 @@ import ( "syscall" "time" - "github.com/buildkite/agent/v3/env" - "github.com/buildkite/agent/v3/internal/process" - "github.com/buildkite/agent/v3/kubernetes" + "github.com/buildkite/agent/v4/env" + "github.com/buildkite/agent/v4/internal/process" + "github.com/buildkite/agent/v4/kubernetes" "github.com/urfave/cli" ) @@ -125,13 +125,23 @@ var KubernetesBootstrapCommand = cli.Command{ } cancelSignal = cs } - cancelGracePeriodSecs := environ.GetInt("BUILDKITE_CANCEL_GRACE_PERIOD", defaultCancelGracePeriodSecs) - cancelGracePeriod := time.Duration(cancelGracePeriodSecs) * time.Second - signalGracePeriodSecs := environ.GetInt("BUILDKITE_SIGNAL_GRACE_PERIOD_SECONDS", defaultSignalGracePeriodSecs) - signalGracePeriod, err := signalGracePeriod(cancelGracePeriodSecs, signalGracePeriodSecs) - if err != nil { - return err + cancelSignalTimeout := defaultCancelSignalTimeout + if s, has := environ.Get("BUILDKITE_CANCEL_SIGNAL_TIMEOUT"); has { + d, err := time.ParseDuration(s) + if err != nil { + return fmt.Errorf("failed to parse BUILDKITE_CANCEL_SIGNAL_TIMEOUT: %w", err) + } + cancelSignalTimeout = d + } + cancelCleanupTimeout := defaultCancelCleanupTimeout + if s, has := environ.Get("BUILDKITE_CANCEL_CLEANUP_TIMEOUT"); has { + d, err := time.ParseDuration(s) + if err != nil { + return fmt.Errorf("failed to parse BUILDKITE_CANCEL_CLEANUP_TIMEOUT: %w", err) + } + cancelCleanupTimeout = d } + cancelGracePeriod := cancelSignalTimeout + cancelCleanupTimeout // BUILDKITE_KUBERNETES_EXEC is a legacy environment variable. It was used to activate the socket // on the bootstrap command, and to activate the socket server on `buildkite-agent start`. @@ -211,7 +221,7 @@ var KubernetesBootstrapCommand = cli.Command{ Dir: buildPath, PTY: runInPTY, InterruptSignal: cancelSignal, - SignalGracePeriod: signalGracePeriod, + SignalGracePeriod: cancelSignalTimeout, }) // We aren't expecting the user to Ctrl-C the process (we're in k8s), diff --git a/clicommand/lock_acquire.go b/clicommand/lock_acquire.go index afd22b40e3..034f1e5b24 100644 --- a/clicommand/lock_acquire.go +++ b/clicommand/lock_acquire.go @@ -6,7 +6,7 @@ import ( "fmt" "time" - "github.com/buildkite/agent/v3/lock" + "github.com/buildkite/agent/v4/lock" "github.com/urfave/cli" ) diff --git a/clicommand/lock_do.go b/clicommand/lock_do.go index 21fe32334a..998dc19aff 100644 --- a/clicommand/lock_do.go +++ b/clicommand/lock_do.go @@ -6,7 +6,7 @@ import ( "fmt" "time" - "github.com/buildkite/agent/v3/lock" + "github.com/buildkite/agent/v4/lock" "github.com/urfave/cli" ) diff --git a/clicommand/lock_done.go b/clicommand/lock_done.go index ee882d0146..14de098bdc 100644 --- a/clicommand/lock_done.go +++ b/clicommand/lock_done.go @@ -5,7 +5,7 @@ import ( "errors" "fmt" - "github.com/buildkite/agent/v3/lock" + "github.com/buildkite/agent/v4/lock" "github.com/urfave/cli" ) diff --git a/clicommand/lock_get.go b/clicommand/lock_get.go index e0d9315a3b..f291d299e8 100644 --- a/clicommand/lock_get.go +++ b/clicommand/lock_get.go @@ -5,7 +5,7 @@ import ( "errors" "fmt" - "github.com/buildkite/agent/v3/lock" + "github.com/buildkite/agent/v4/lock" "github.com/urfave/cli" ) diff --git a/clicommand/lock_release.go b/clicommand/lock_release.go index fd5e6c1f78..4a4f8e1394 100644 --- a/clicommand/lock_release.go +++ b/clicommand/lock_release.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/buildkite/agent/v3/lock" + "github.com/buildkite/agent/v4/lock" "github.com/urfave/cli" ) diff --git a/clicommand/meta_data_exists.go b/clicommand/meta_data_exists.go index a99d97abea..fe97af9e62 100644 --- a/clicommand/meta_data_exists.go +++ b/clicommand/meta_data_exists.go @@ -6,7 +6,7 @@ import ( "slices" "time" - "github.com/buildkite/agent/v3/api" + "github.com/buildkite/agent/v4/api" "github.com/buildkite/roko" "github.com/urfave/cli" ) diff --git a/clicommand/meta_data_get.go b/clicommand/meta_data_get.go index f7f9482d20..1ed7c4ea28 100644 --- a/clicommand/meta_data_get.go +++ b/clicommand/meta_data_get.go @@ -6,7 +6,7 @@ import ( "slices" "time" - "github.com/buildkite/agent/v3/api" + "github.com/buildkite/agent/v4/api" "github.com/buildkite/roko" "github.com/urfave/cli" ) @@ -102,15 +102,14 @@ var MetaDataGetCommand = cli.Command{ cfg.Key, cfg.Default, ) - _, _ = fmt.Fprint(c.App.Writer, cfg.Default) + _, _ = fmt.Fprintln(c.App.Writer, cfg.Default) return nil } return fmt.Errorf("failed to get meta-data: %w", err) } - // TODO: in the next agent magor version, we should terminate with a newline using fmt.FPrintln - _, err = fmt.Fprint(c.App.Writer, metaData.Value) + _, err = fmt.Fprintln(c.App.Writer, metaData.Value) return err }, } diff --git a/clicommand/meta_data_keys.go b/clicommand/meta_data_keys.go index 73a9d2dc87..9179611d13 100644 --- a/clicommand/meta_data_keys.go +++ b/clicommand/meta_data_keys.go @@ -6,7 +6,7 @@ import ( "slices" "time" - "github.com/buildkite/agent/v3/api" + "github.com/buildkite/agent/v4/api" "github.com/buildkite/roko" "github.com/urfave/cli" ) diff --git a/clicommand/meta_data_set.go b/clicommand/meta_data_set.go index 3db5664b7f..73f2319f17 100644 --- a/clicommand/meta_data_set.go +++ b/clicommand/meta_data_set.go @@ -10,8 +10,8 @@ import ( "strings" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/internal/redact" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/internal/redact" "github.com/buildkite/roko" "github.com/urfave/cli" ) diff --git a/clicommand/oidc_request_token.go b/clicommand/oidc_request_token.go index 9ae46cbba0..f5ac359176 100644 --- a/clicommand/oidc_request_token.go +++ b/clicommand/oidc_request_token.go @@ -7,8 +7,8 @@ import ( "slices" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/jobapi" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/jobapi" "github.com/buildkite/roko" "github.com/urfave/cli" ) diff --git a/clicommand/pipeline_upload.go b/clicommand/pipeline_upload.go index 5b805c464e..8646eea854 100644 --- a/clicommand/pipeline_upload.go +++ b/clicommand/pipeline_upload.go @@ -18,18 +18,17 @@ import ( "drjosh.dev/zzglob" "github.com/aws/aws-sdk-go-v2/service/kms" - "github.com/buildkite/agent/v3/agent" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/env" - "github.com/buildkite/agent/v3/internal/awslib" - awssigner "github.com/buildkite/agent/v3/internal/cryptosigner/aws" - gcpsigner "github.com/buildkite/agent/v3/internal/cryptosigner/gcp" - "github.com/buildkite/agent/v3/internal/experiments" - "github.com/buildkite/agent/v3/internal/redact" - "github.com/buildkite/agent/v3/internal/replacer" - "github.com/buildkite/agent/v3/internal/stdin" - "github.com/buildkite/agent/v3/logger" - "github.com/buildkite/agent/v3/tracetools" + "github.com/buildkite/agent/v4/agent" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/env" + "github.com/buildkite/agent/v4/internal/awslib" + awssigner "github.com/buildkite/agent/v4/internal/cryptosigner/aws" + gcpsigner "github.com/buildkite/agent/v4/internal/cryptosigner/gcp" + "github.com/buildkite/agent/v4/internal/experiments" + "github.com/buildkite/agent/v4/internal/redact" + "github.com/buildkite/agent/v4/internal/replacer" + "github.com/buildkite/agent/v4/internal/stdin" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/go-pipeline" "github.com/buildkite/go-pipeline/jwkutil" "github.com/buildkite/go-pipeline/ordered" @@ -618,14 +617,6 @@ func (cfg *PipelineUploadConfig) parseAndInterpolate(ctx context.Context, src st // yield below default: // yes, interpolation - // Pass the trace context from our environment to the pipeline. - if tracing, has := environ.Get(tracetools.EnvVarTraceContextKey); has { - if result.Env == nil { - result.Env = ordered.NewMap[string, string](1) - } - result.Env.Set(tracetools.EnvVarTraceContextKey, tracing) - } - // Do the interpolation. preferRuntimeEnv := experiments.IsEnabled(ctx, experiments.InterpolationPrefersRuntimeEnv) err = result.Interpolate(environ, preferRuntimeEnv) diff --git a/clicommand/pipeline_upload_test.go b/clicommand/pipeline_upload_test.go index 57d1b6e8be..0dc157009e 100644 --- a/clicommand/pipeline_upload_test.go +++ b/clicommand/pipeline_upload_test.go @@ -7,9 +7,9 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/env" - "github.com/buildkite/agent/v3/internal/experiments" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/env" + "github.com/buildkite/agent/v4/internal/experiments" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/go-pipeline" "github.com/buildkite/go-pipeline/ordered" "github.com/google/go-cmp/cmp" diff --git a/clicommand/profiler.go b/clicommand/profiler.go index c456d0f5c4..592dbafefe 100644 --- a/clicommand/profiler.go +++ b/clicommand/profiler.go @@ -7,7 +7,7 @@ import ( "runtime/pprof" "runtime/trace" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) type profilerMode string diff --git a/clicommand/redactor_add.go b/clicommand/redactor_add.go index cebda15b3a..fe8176e987 100644 --- a/clicommand/redactor_add.go +++ b/clicommand/redactor_add.go @@ -11,8 +11,8 @@ import ( "slices" "strings" - "github.com/buildkite/agent/v3/jobapi" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/jobapi" + "github.com/buildkite/agent/v4/logger" "github.com/urfave/cli" ) diff --git a/clicommand/redactor_add_test.go b/clicommand/redactor_add_test.go index 19ef9f34f8..401644a7b6 100644 --- a/clicommand/redactor_add_test.go +++ b/clicommand/redactor_add_test.go @@ -5,8 +5,8 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/clicommand" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/clicommand" + "github.com/buildkite/agent/v4/logger" "github.com/google/go-cmp/cmp" ) diff --git a/clicommand/secret_get.go b/clicommand/secret_get.go index cc51c9ea35..6def4fdefd 100644 --- a/clicommand/secret_get.go +++ b/clicommand/secret_get.go @@ -10,10 +10,10 @@ import ( "slices" "strings" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/internal/secrets" - "github.com/buildkite/agent/v3/jobapi" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/internal/secrets" + "github.com/buildkite/agent/v4/jobapi" + "github.com/buildkite/agent/v4/logger" "github.com/urfave/cli" ) diff --git a/clicommand/secret_get_test.go b/clicommand/secret_get_test.go index ec479e64c5..98625c28e4 100644 --- a/clicommand/secret_get_test.go +++ b/clicommand/secret_get_test.go @@ -10,7 +10,7 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" "github.com/google/go-cmp/cmp" ) diff --git a/clicommand/step_cancel.go b/clicommand/step_cancel.go index e77709becb..7264acf20f 100644 --- a/clicommand/step_cancel.go +++ b/clicommand/step_cancel.go @@ -6,8 +6,8 @@ import ( "slices" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/roko" "github.com/urfave/cli" ) @@ -63,7 +63,7 @@ var StepCancelCommand = cli.Command{ cli.Int64Flag{ Name: "force-grace-period-seconds", - Value: defaultCancelGracePeriodSecs, + Value: int64((defaultCancelSignalTimeout + defaultCancelCleanupTimeout) / time.Second), Usage: "The number of seconds to wait for agents to finish uploading artifacts before transitioning unfinished jobs to a canceled state. β€²--forceβ€² must also be supplied for this to take affect", EnvVar: "BUILDKITE_STEP_CANCEL_FORCE_GRACE_PERIOD_SECONDS,BUILDKITE_CANCEL_GRACE_PERIOD", }, diff --git a/clicommand/step_cancel_test.go b/clicommand/step_cancel_test.go index 92b699b841..36006cf530 100644 --- a/clicommand/step_cancel_test.go +++ b/clicommand/step_cancel_test.go @@ -8,7 +8,7 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) func TestStepCancel(t *testing.T) { diff --git a/clicommand/step_get.go b/clicommand/step_get.go index 1eac751245..4ffe71acdf 100644 --- a/clicommand/step_get.go +++ b/clicommand/step_get.go @@ -6,7 +6,7 @@ import ( "slices" "time" - "github.com/buildkite/agent/v3/api" + "github.com/buildkite/agent/v4/api" "github.com/buildkite/roko" "github.com/urfave/cli" ) diff --git a/clicommand/step_update.go b/clicommand/step_update.go index 1c3566e2ad..25e70455af 100644 --- a/clicommand/step_update.go +++ b/clicommand/step_update.go @@ -8,8 +8,8 @@ import ( "slices" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/internal/redact" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/internal/redact" "github.com/buildkite/roko" "github.com/urfave/cli" ) diff --git a/clicommand/tool_sign.go b/clicommand/tool_sign.go index e8fe4d1a5e..f5a0f7e9fd 100644 --- a/clicommand/tool_sign.go +++ b/clicommand/tool_sign.go @@ -10,12 +10,12 @@ import ( "strings" "github.com/aws/aws-sdk-go-v2/service/kms" - "github.com/buildkite/agent/v3/internal/awslib" - "github.com/buildkite/agent/v3/internal/bkgql" - awssigner "github.com/buildkite/agent/v3/internal/cryptosigner/aws" - gcpsigner "github.com/buildkite/agent/v3/internal/cryptosigner/gcp" - "github.com/buildkite/agent/v3/internal/stdin" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/internal/awslib" + "github.com/buildkite/agent/v4/internal/bkgql" + awssigner "github.com/buildkite/agent/v4/internal/cryptosigner/aws" + gcpsigner "github.com/buildkite/agent/v4/internal/cryptosigner/gcp" + "github.com/buildkite/agent/v4/internal/stdin" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/go-pipeline" "github.com/buildkite/go-pipeline/jwkutil" "github.com/buildkite/go-pipeline/signature" diff --git a/cliconfig/BUILD.bazel b/cliconfig/BUILD.bazel index 4ced882296..1e9fcbbadd 100644 --- a/cliconfig/BUILD.bazel +++ b/cliconfig/BUILD.bazel @@ -6,7 +6,7 @@ go_library( "file.go", "loader.go", ], - importpath = "github.com/buildkite/agent/v3/cliconfig", + importpath = "github.com/buildkite/agent/v4/cliconfig", visibility = ["//visibility:public"], deps = [ "//internal/osutil", diff --git a/cliconfig/file.go b/cliconfig/file.go index a206259dce..1840b57fda 100644 --- a/cliconfig/file.go +++ b/cliconfig/file.go @@ -7,7 +7,7 @@ import ( "os" "strings" - "github.com/buildkite/agent/v3/internal/osutil" + "github.com/buildkite/agent/v4/internal/osutil" ) type File struct { diff --git a/cliconfig/loader.go b/cliconfig/loader.go index 6361a21d39..555316ef3f 100644 --- a/cliconfig/loader.go +++ b/cliconfig/loader.go @@ -12,8 +12,8 @@ import ( "strings" "time" - "github.com/buildkite/agent/v3/internal/osutil" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/internal/osutil" + "github.com/buildkite/agent/v4/logger" "github.com/oleiade/reflections" "github.com/urfave/cli" ) diff --git a/core/BUILD.bazel b/core/BUILD.bazel index 55cffbe27a..3f9e583832 100644 --- a/core/BUILD.bazel +++ b/core/BUILD.bazel @@ -11,7 +11,7 @@ go_library( "options.go", "process_exit.go", ], - importpath = "github.com/buildkite/agent/v3/core", + importpath = "github.com/buildkite/agent/v4/core", visibility = ["//visibility:public"], deps = [ "//api", diff --git a/core/api_client.go b/core/api_client.go index be75be2c65..78f3fb7c1b 100644 --- a/core/api_client.go +++ b/core/api_client.go @@ -3,7 +3,7 @@ package core import ( "context" - "github.com/buildkite/agent/v3/api" + "github.com/buildkite/agent/v4/api" ) // APIClient defines the subset of client methods needed by core. diff --git a/core/client.go b/core/client.go index 8094fafdaa..da1fc2d818 100644 --- a/core/client.go +++ b/core/client.go @@ -12,10 +12,10 @@ import ( "sync" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/internal/system" - "github.com/buildkite/agent/v3/logger" - "github.com/buildkite/agent/v3/version" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/internal/system" + "github.com/buildkite/agent/v4/logger" + "github.com/buildkite/agent/v4/version" "github.com/buildkite/roko" "github.com/denisbrodbeck/machineid" ) diff --git a/core/controller.go b/core/controller.go index dce0842495..63f8a31c87 100644 --- a/core/controller.go +++ b/core/controller.go @@ -3,9 +3,9 @@ package core import ( "context" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" - "github.com/buildkite/agent/v3/version" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" + "github.com/buildkite/agent/v4/version" ) // Controller is a client for the Buildkite Agent API. It is useful for diff --git a/core/job_controller.go b/core/job_controller.go index 39dc577cf6..c64b5c71ad 100644 --- a/core/job_controller.go +++ b/core/job_controller.go @@ -6,7 +6,7 @@ import ( "sync" "time" - "github.com/buildkite/agent/v3/api" + "github.com/buildkite/agent/v4/api" ) // JobController provides simple functionality to a job runner - the ability to diff --git a/core/options.go b/core/options.go index dee49fe3ba..b9edf6e041 100644 --- a/core/options.go +++ b/core/options.go @@ -3,7 +3,7 @@ package core import ( "time" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) type controllerConfig struct { diff --git a/docs/images/agent-start.dot b/docs/images/agent-start.dot index ec39bb75a3..db4f6619ea 100644 --- a/docs/images/agent-start.dot +++ b/docs/images/agent-start.dot @@ -10,7 +10,7 @@ digraph { subgraph cluster_clicommand { label="clicommand" - URL="https://pkg.go.dev/github.com/buildkite/agent/v3/clicommand" + URL="https://pkg.go.dev/github.com/buildkite/agent/v4/clicommand" "AgentStartCommand.Action" "handlePoolSignals" @@ -21,7 +21,7 @@ digraph { subgraph cluster_agent { label="agent" - URL="https://pkg.go.dev/github.com/buildkite/agent/v3/agent" + URL="https://pkg.go.dev/github.com/buildkite/agent/v4/agent" "AgentPool.Start" "AgentPool.Start." @@ -55,7 +55,7 @@ digraph { subgraph cluster_api { label="api" - URL="https://pkg.go.dev/github.com/buildkite/agent/v3/api" + URL="https://pkg.go.dev/github.com/buildkite/agent/v4/api" "Client.AcceptJob" "Client.GetJobStatus" @@ -68,7 +68,7 @@ digraph { subgraph cluster_process { label="process" - URL="https://pkg.go.dev/github.com/buildkite/agent/v3/internal/process" + URL="https://pkg.go.dev/github.com/buildkite/agent/v4/internal/process" "Scanner.ScanLines" "Process.Run" diff --git a/docs/images/agent-start.svg b/docs/images/agent-start.svg index 01b64365e3..83e80a6459 100644 --- a/docs/images/agent-start.svg +++ b/docs/images/agent-start.svg @@ -41,7 +41,7 @@ cluster_clicommand cluster_agent cluster_api cluster_process AgentStartCommand.Action 0 { diff --git a/internal/artifact/download_test.go b/internal/artifact/download_test.go index 236a02065e..153868ba0b 100644 --- a/internal/artifact/download_test.go +++ b/internal/artifact/download_test.go @@ -5,8 +5,6 @@ package artifact import ( "context" "testing" - - "github.com/buildkite/agent/v3/internal/experiments" ) func TestTargetPath(t *testing.T) { @@ -65,26 +63,3 @@ func TestTargetPath(t *testing.T) { } } } - -func TestTargetPath_AllowPathTraversal(t *testing.T) { - t.Parallel() - tests := []struct { - dlPath, destPath, want string - }{ - // artifact_download documentation examples - {dlPath: "app/logs/a.log", destPath: "foo/app/", want: "foo/app/app/logs/a.log"}, - {dlPath: "app/logs/a.log", destPath: "foo/app", want: "foo/app/logs/a.log"}, - {dlPath: "app/logs/a.log", destPath: ".", want: "app/logs/a.log"}, - - // The download path _can_ walk up the destination path - {dlPath: "../../../../etc/passwd", destPath: "dist/foo", want: "../../etc/passwd"}, - } - ctx, _ := experiments.Enable(context.Background(), experiments.AllowArtifactPathTraversal) - - for _, test := range tests { - got := targetPath(ctx, test.dlPath, test.destPath) - if got != test.want { - t.Errorf("targetPath(%q, %q) = %q, want %q", test.dlPath, test.destPath, got, test.want) - } - } -} diff --git a/internal/artifact/downloader.go b/internal/artifact/downloader.go index d4650f55c4..8b9c46e222 100644 --- a/internal/artifact/downloader.go +++ b/internal/artifact/downloader.go @@ -11,9 +11,9 @@ import ( "sync" "github.com/aws/aws-sdk-go-v2/service/s3" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/internal/agenthttp" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/internal/agenthttp" + "github.com/buildkite/agent/v4/logger" ) type DownloaderConfig struct { diff --git a/internal/artifact/downloader_test.go b/internal/artifact/downloader_test.go index 0109381e67..ce4b7ac05d 100644 --- a/internal/artifact/downloader_test.go +++ b/internal/artifact/downloader_test.go @@ -8,8 +8,8 @@ import ( "os" "testing" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" ) func TestArtifactDownloaderConnectsToEndpoint(t *testing.T) { diff --git a/internal/artifact/gs_downloader.go b/internal/artifact/gs_downloader.go index 63998c630d..fcea6f4290 100644 --- a/internal/artifact/gs_downloader.go +++ b/internal/artifact/gs_downloader.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" storage "google.golang.org/api/storage/v1" ) diff --git a/internal/artifact/gs_uploader.go b/internal/artifact/gs_uploader.go index 1d30458acf..e8e1777148 100644 --- a/internal/artifact/gs_uploader.go +++ b/internal/artifact/gs_uploader.go @@ -10,8 +10,8 @@ import ( "path/filepath" "strings" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" "golang.org/x/oauth2/google" "google.golang.org/api/googleapi" "google.golang.org/api/option" diff --git a/internal/artifact/s3.go b/internal/artifact/s3.go index 66b2158a52..1d0b57b4f5 100644 --- a/internal/artifact/s3.go +++ b/internal/artifact/s3.go @@ -9,8 +9,8 @@ import ( "os" "strings" - "github.com/buildkite/agent/v3/internal/awslib" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/internal/awslib" + "github.com/buildkite/agent/v4/logger" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" diff --git a/internal/artifact/s3_downloader.go b/internal/artifact/s3_downloader.go index cda362e2e9..695e4f2dc8 100644 --- a/internal/artifact/s3_downloader.go +++ b/internal/artifact/s3_downloader.go @@ -8,8 +8,8 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/s3" - "github.com/buildkite/agent/v3/internal/agenthttp" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/internal/agenthttp" + "github.com/buildkite/agent/v4/logger" ) type S3DownloaderConfig struct { diff --git a/internal/artifact/s3_downloader_test.go b/internal/artifact/s3_downloader_test.go index b7d3d2eb6d..abcea42ff4 100644 --- a/internal/artifact/s3_downloader_test.go +++ b/internal/artifact/s3_downloader_test.go @@ -3,7 +3,7 @@ package artifact import ( "testing" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) func TestS3DowloaderBucketPath(t *testing.T) { diff --git a/internal/artifact/s3_uploader.go b/internal/artifact/s3_uploader.go index b731a784d9..6e32933da6 100644 --- a/internal/artifact/s3_uploader.go +++ b/internal/artifact/s3_uploader.go @@ -14,8 +14,8 @@ import ( "github.com/aws/aws-sdk-go-v2/feature/s3/manager" "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/aws/aws-sdk-go-v2/service/s3/types" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/roko" ) diff --git a/internal/artifact/searcher.go b/internal/artifact/searcher.go index 7ff9577b65..7ef6fd2e46 100644 --- a/internal/artifact/searcher.go +++ b/internal/artifact/searcher.go @@ -4,8 +4,8 @@ import ( "context" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/roko" ) diff --git a/internal/artifact/searcher_test.go b/internal/artifact/searcher_test.go index 9f4eb19116..e7aef71bf4 100644 --- a/internal/artifact/searcher_test.go +++ b/internal/artifact/searcher_test.go @@ -8,8 +8,8 @@ import ( "os" "testing" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" "github.com/google/go-cmp/cmp" ) diff --git a/internal/artifact/uploader.go b/internal/artifact/uploader.go index d74ffd75f1..52775cd609 100644 --- a/internal/artifact/uploader.go +++ b/internal/artifact/uploader.go @@ -19,10 +19,9 @@ import ( "time" "drjosh.dev/zzglob" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/internal/experiments" - "github.com/buildkite/agent/v3/internal/mime" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/internal/mime" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/roko" "github.com/dustin/go-humanize" ) @@ -330,10 +329,8 @@ func (c *artifactCollector) worker(ctx context.Context, filesCh <-chan string) e return fmt.Errorf("resolving relative path for file %s: %w", file, err) } - if experiments.IsEnabled(ctx, experiments.NormalisedUploadPaths) { - // Convert any Windows paths to Unix/URI form - path = filepath.ToSlash(path) - } + // Convert any Windows paths to Unix/URI form + path = filepath.ToSlash(path) // Build an artifact object using the paths we have. artifact, err := c.build(path, absolutePath) diff --git a/internal/artifact/uploader_test.go b/internal/artifact/uploader_test.go index 6f049839a4..29bddb30ea 100644 --- a/internal/artifact/uploader_test.go +++ b/internal/artifact/uploader_test.go @@ -9,9 +9,8 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/internal/experiments" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" "github.com/google/go-cmp/cmp" ) @@ -38,9 +37,10 @@ func TestCollect(t *testing.T) { Name string Path []string AbsolutePath string - FileSize int + FileSize int64 Sha1Sum string Sha256Sum string + ContentType string }{ { Name: "Mr Freeze.jpg", @@ -49,6 +49,7 @@ func TestCollect(t *testing.T) { FileSize: 362371, Sha1Sum: "f5bc7bc9f5f9c3e543dde0eb44876c6f9acbfb6b", Sha256Sum: "0c657a363d92093e68224e0716ed8b8b5d4bbc3dfe9b026e32b241fc9b369d47", + ContentType: "image/jpeg", }, { Name: "Commando.jpg", @@ -57,6 +58,7 @@ func TestCollect(t *testing.T) { FileSize: 113000, Sha1Sum: "811d7cb0317582e22ebfeb929d601cdabea4b3c0", Sha256Sum: "fcfbe62fd7b6638165a61e8de901ac9df93fc1389906f2772bdefed5de115426", + ContentType: "image/jpeg", }, { Name: "The Terminator.jpg", @@ -65,6 +67,7 @@ func TestCollect(t *testing.T) { FileSize: 47301, Sha1Sum: "ed76566ede9cb6edc975fcadca429665aad8785a", Sha256Sum: "5b4228a4bbef3d9f676e0a2e8cf6ea06759124ef0fbdb27a6c35df8759fcd39d", + ContentType: "image/jpeg", }, { Name: "Smile.gif", @@ -73,6 +76,7 @@ func TestCollect(t *testing.T) { FileSize: 2038453, Sha1Sum: "bd4caf2e01e59777744ac1d52deafa01c2cb9bfd", Sha256Sum: "fc5e8608c7772e4ae834fbc47eec3d902099eb3599f5191e40d9e3d9b3764b0e", + ContentType: "image/gif", }, } @@ -84,63 +88,12 @@ func TestCollect(t *testing.T) { Delimiter: ";", }) - // For the normalised-upload-paths experiment, uploaded artifact paths are - // normalised with Unix/URI style path separators, even on Windows. - // Without the experiment on, we use the file path given by the file system - // - // To simulate that in this test, we collect artifacts from the file system - // twice, once with the experiment explicitly disabled, and one with it - // enabled. We then check the test cases against both sets of artifacts, - // comparing to paths processed with filepath.Join (which uses native OS - // path separators), and then with the experiment enabled and with the - // path.Join function instead (which uses Unix/URI-style path separators, - // regardless of platform) - - ctxExpEnabled, _ := experiments.Enable(ctx, experiments.NormalisedUploadPaths) - ctxExpDisabled := experiments.Disable(ctx, experiments.NormalisedUploadPaths) - - artifactsWithoutExperimentEnabled, err := uploader.collect(ctxExpDisabled) - if err != nil { - t.Fatalf("[normalised-upload-paths disabled] uploader.Collect() error = %v", err) - } - if got, want := len(artifactsWithoutExperimentEnabled), 5; got != want { - t.Errorf("len(artifactsWithoutExperimentEnabled) = %d, want %d", got, want) - } - - artifactsWithExperimentEnabled, err := uploader.collect(ctxExpEnabled) + artifacts, err := uploader.collect(ctx) if err != nil { - t.Fatalf("[normalised-upload-paths enabled] uploader.Collect() error = %v", err) - } - if got, want := len(artifactsWithExperimentEnabled), 5; got != want { - t.Errorf("len(artifactsWithExperimentEnabled) = %d, want %d", got, want) + t.Fatalf("uploader.Collect() error = %v", err) } - - // These test cases use filepath.Join, which uses per-OS path separators; - // this is the behaviour without normalised-upload-paths. - for _, tc := range testCases { - t.Run(tc.Name, func(t *testing.T) { - t.Parallel() - a := findArtifact(artifactsWithoutExperimentEnabled, tc.Name) - if a == nil { - t.Fatalf("findArtifact(%q) == nil", tc.Name) - } - - if got, want := a.Path, filepath.Join(tc.Path...); got != want { - t.Errorf("a.Path = %q, want %q", got, want) - } - if got, want := a.AbsolutePath, tc.AbsolutePath; got != want { - t.Errorf("a.AbsolutePath = %q, want %q", got, want) - } - if got, want := int(a.FileSize), tc.FileSize; got != want { - t.Errorf("int(a.FileSize) = %d, want %d", got, want) - } - if got, want := a.Sha1Sum, tc.Sha1Sum; got != want { - t.Errorf("a.Sha1Sum = %q, want %q", got, want) - } - if got, want := a.Sha256Sum, tc.Sha256Sum; got != want { - t.Errorf("a.Sha256Sum = %q, want %q", got, want) - } - }) + if got, want := len(artifacts), 5; got != want { + t.Errorf("len(artifacts) = %d, want %d", got, want) } // These test cases uses filepath.ToSlash(), which always emits forward-slashes. @@ -148,8 +101,8 @@ func TestCollect(t *testing.T) { for _, tc := range testCases { t.Run(tc.Name, func(t *testing.T) { t.Parallel() - a := findArtifact(artifactsWithExperimentEnabled, tc.Name) - if a == nil { + got := findArtifact(artifacts, tc.Name) + if got == nil { t.Fatalf("findArtifact(%q) == nil", tc.Name) } @@ -159,20 +112,17 @@ func TestCollect(t *testing.T) { // So forward-slash joining them with path.Join(tc.Path...} isn't enough. forwardSlashed := filepath.ToSlash(filepath.Join(tc.Path...)) - if got, want := a.Path, forwardSlashed; got != want { - t.Errorf("a.Path = %q, want %q", got, want) - } - if got, want := a.AbsolutePath, tc.AbsolutePath; got != want { - t.Errorf("a.AbsolutePath = %q, want %q", got, want) - } - if got, want := int(a.FileSize), tc.FileSize; got != want { - t.Errorf("int(a.FileSize) = %d, want %d", got, want) - } - if got, want := a.Sha1Sum, tc.Sha1Sum; got != want { - t.Errorf("a.Sha1Sum = %q, want %q", got, want) + want := &api.Artifact{ + Path: forwardSlashed, + AbsolutePath: tc.AbsolutePath, + FileSize: tc.FileSize, + Sha1Sum: tc.Sha1Sum, + Sha256Sum: tc.Sha256Sum, + ContentType: tc.ContentType, } - if got, want := a.Sha256Sum, tc.Sha256Sum; got != want { - t.Errorf("a.Sha256Sum = %q, want %q", got, want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("findArtifact diff (-got +want):\n%s", diff) } }) } @@ -245,8 +195,20 @@ func TestCollectWithSomeGlobsThatDontMatchAnythingFollowingSymlinks(t *testing.T t.Fatalf("uploader.Collect() error = %v", err) } - if len(artifacts) != 5 { - t.Errorf("len(artifacts) = %d, want 5", len(artifacts)) + got := []string{} + for _, a := range artifacts { + got = append(got, a.Path) + } + slices.Sort(got) + want := []string{ + "fixtures/Mr Freeze.jpg", + "fixtures/folder/Commando.jpg", + "fixtures/links/folder-link/terminator2.jpg", + "fixtures/links/terminator/terminator2.jpg", + "fixtures/this is a folder with a space/The Terminator.jpg", + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("uploader.collect(ctx) collected paths diff (-got +want):\n%s", diff) } } @@ -267,17 +229,19 @@ func TestCollectWithDuplicateMatches(t *testing.T) { t.Fatalf("uploader.Collect() error = %v", err) } - paths := []string{} + got := []string{} for _, a := range artifacts { - paths = append(paths, a.Path) + got = append(got, a.Path) } - if diff := cmp.Diff(slices.Sorted(slices.Values(paths)), slices.Sorted(slices.Values([]string{ - filepath.Join("fixtures", "Mr Freeze.jpg"), - filepath.Join("fixtures", "folder", "Commando.jpg"), - filepath.Join("fixtures", "this is a folder with a space", "The Terminator.jpg"), - filepath.Join("fixtures", "links", "terminator", "terminator2.jpg"), - }))); diff != "" { - t.Errorf("paths sorted diff (-got +want):\n%s", diff) + slices.Sort(got) + want := []string{ + "fixtures/Mr Freeze.jpg", + "fixtures/folder/Commando.jpg", + "fixtures/links/terminator/terminator2.jpg", + "fixtures/this is a folder with a space/The Terminator.jpg", + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("uploader.collect(ctx) collected paths diff (-got +want):\n%s", diff) } } @@ -299,18 +263,20 @@ func TestCollectWithDuplicateMatchesFollowingSymlinks(t *testing.T) { t.Fatalf("uploader.Collect() error = %v", err) } - paths := []string{} + got := []string{} for _, a := range artifacts { - paths = append(paths, a.Path) + got = append(got, a.Path) } - if diff := cmp.Diff(slices.Sorted(slices.Values(paths)), slices.Sorted(slices.Values([]string{ - filepath.Join("fixtures", "Mr Freeze.jpg"), - filepath.Join("fixtures", "folder", "Commando.jpg"), - filepath.Join("fixtures", "this is a folder with a space", "The Terminator.jpg"), - filepath.Join("fixtures", "links", "terminator", "terminator2.jpg"), - filepath.Join("fixtures", "links", "folder-link", "terminator2.jpg"), - }))); diff != "" { - t.Errorf("paths sorted diff (-got +want):\n%s", diff) + slices.Sort(got) + want := []string{ + "fixtures/Mr Freeze.jpg", + "fixtures/folder/Commando.jpg", + "fixtures/links/folder-link/terminator2.jpg", + "fixtures/links/terminator/terminator2.jpg", + "fixtures/this is a folder with a space/The Terminator.jpg", + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("uploader.collect(ctx) collected paths diff (-got +want):\n%s", diff) } } @@ -331,16 +297,18 @@ func TestCollectMatchesUploadSymlinks(t *testing.T) { t.Fatalf("uploader.Collect() error = %v", err) } - paths := []string{} + got := []string{} for _, a := range artifacts { - paths = append(paths, a.Path) + got = append(got, a.Path) } - if diff := cmp.Diff(slices.Sorted(slices.Values(paths)), slices.Sorted(slices.Values([]string{ - filepath.Join("fixtures", "Mr Freeze.jpg"), - filepath.Join("fixtures", "folder", "Commando.jpg"), - filepath.Join("fixtures", "this is a folder with a space", "The Terminator.jpg"), - }))); diff != "" { - t.Errorf("paths sorted diff (-got +want):\n%s", diff) + slices.Sort(got) + want := []string{ + "fixtures/Mr Freeze.jpg", + "fixtures/folder/Commando.jpg", + "fixtures/this is a folder with a space/The Terminator.jpg", + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("uploader.collect(ctx) collected paths diff (-got +want):\n%s", diff) } } @@ -367,11 +335,11 @@ func TestCollect_Literal(t *testing.T) { got = append(got, a.Path) } want := []string{ - filepath.Join("fixtures", "links", "folder-link", "terminator2.jpg"), - filepath.Join("fixtures", "gifs", "Smile.gif"), + "fixtures/links/folder-link/terminator2.jpg", + "fixtures/gifs/Smile.gif", } if diff := cmp.Diff(got, want); diff != "" { - t.Errorf("uploader.collect artifact paths diff (-got +want)\n%s", diff) + t.Errorf("uploader.collect artifact paths diff (-got +want) (-got +want)\n%s", diff) } } diff --git a/internal/awslib/BUILD.bazel b/internal/awslib/BUILD.bazel index 3141a734c3..26f14292b8 100644 --- a/internal/awslib/BUILD.bazel +++ b/internal/awslib/BUILD.bazel @@ -3,7 +3,7 @@ load("@rules_go//go:def.bzl", "go_library") go_library( name = "awslib", srcs = ["awsv2.go"], - importpath = "github.com/buildkite/agent/v3/internal/awslib", + importpath = "github.com/buildkite/agent/v4/internal/awslib", visibility = ["//:__subpackages__"], deps = [ "@com_github_aws_aws_sdk_go_v2//aws", diff --git a/internal/bkgql/BUILD.bazel b/internal/bkgql/BUILD.bazel index 43b36ae0c8..779acff109 100644 --- a/internal/bkgql/BUILD.bazel +++ b/internal/bkgql/BUILD.bazel @@ -6,7 +6,7 @@ go_library( "client.go", "generated.go", ], - importpath = "github.com/buildkite/agent/v3/internal/bkgql", + importpath = "github.com/buildkite/agent/v4/internal/bkgql", visibility = ["//:__subpackages__"], deps = [ "//internal/agenthttp", diff --git a/internal/bkgql/client.go b/internal/bkgql/client.go index fedb22c0b3..a8313168c4 100644 --- a/internal/bkgql/client.go +++ b/internal/bkgql/client.go @@ -7,7 +7,7 @@ import ( "time" "github.com/Khan/genqlient/graphql" - "github.com/buildkite/agent/v3/internal/agenthttp" + "github.com/buildkite/agent/v4/internal/agenthttp" ) const ( diff --git a/internal/cache/BUILD.bazel b/internal/cache/BUILD.bazel index 4089ec208a..92a27098fc 100644 --- a/internal/cache/BUILD.bazel +++ b/internal/cache/BUILD.bazel @@ -3,7 +3,7 @@ load("@rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "cache", srcs = ["cache.go"], - importpath = "github.com/buildkite/agent/v3/internal/cache", + importpath = "github.com/buildkite/agent/v4/internal/cache", visibility = ["//:__subpackages__"], deps = [ "//logger", diff --git a/internal/cache/cache.go b/internal/cache/cache.go index a78c459fbd..2e1bacd273 100644 --- a/internal/cache/cache.go +++ b/internal/cache/cache.go @@ -8,8 +8,8 @@ import ( "strings" "sync" - "github.com/buildkite/agent/v3/logger" - "github.com/buildkite/agent/v3/version" + "github.com/buildkite/agent/v4/logger" + "github.com/buildkite/agent/v4/version" "github.com/buildkite/zstash" "github.com/buildkite/zstash/api" "github.com/buildkite/zstash/cache" diff --git a/internal/cache/cache_test.go b/internal/cache/cache_test.go index 3cab4b532f..d0e8cf5935 100644 --- a/internal/cache/cache_test.go +++ b/internal/cache/cache_test.go @@ -10,7 +10,7 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/zstash" "github.com/buildkite/zstash/cache" "github.com/google/go-cmp/cmp" diff --git a/internal/cryptosigner/aws/BUILD.bazel b/internal/cryptosigner/aws/BUILD.bazel index eb8d6bacfc..366d87683b 100644 --- a/internal/cryptosigner/aws/BUILD.bazel +++ b/internal/cryptosigner/aws/BUILD.bazel @@ -3,7 +3,7 @@ load("@rules_go//go:def.bzl", "go_library") go_library( name = "aws", srcs = ["kms.go"], - importpath = "github.com/buildkite/agent/v3/internal/cryptosigner/aws", + importpath = "github.com/buildkite/agent/v4/internal/cryptosigner/aws", visibility = ["//:__subpackages__"], deps = [ "@com_github_aws_aws_sdk_go_v2//aws", diff --git a/internal/cryptosigner/gcp/BUILD.bazel b/internal/cryptosigner/gcp/BUILD.bazel index 5ab215bcf6..7708010dd5 100644 --- a/internal/cryptosigner/gcp/BUILD.bazel +++ b/internal/cryptosigner/gcp/BUILD.bazel @@ -3,7 +3,7 @@ load("@rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "gcp", srcs = ["kms.go"], - importpath = "github.com/buildkite/agent/v3/internal/cryptosigner/gcp", + importpath = "github.com/buildkite/agent/v4/internal/cryptosigner/gcp", visibility = ["//:__subpackages__"], deps = [ "@com_github_lestrrat_go_jwx_v2//jwa", diff --git a/internal/e2e/BUILD.bazel b/internal/e2e/BUILD.bazel index 9101c80237..974554dd9a 100644 --- a/internal/e2e/BUILD.bazel +++ b/internal/e2e/BUILD.bazel @@ -3,6 +3,6 @@ load("@rules_go//go:def.bzl", "go_library") go_library( name = "e2e", srcs = ["doc.go"], - importpath = "github.com/buildkite/agent/v3/internal/e2e", + importpath = "github.com/buildkite/agent/v4/internal/e2e", visibility = ["//:__subpackages__"], ) diff --git a/internal/e2e/main_test.go b/internal/e2e/main_test.go index 655bb50c42..b53793fdd0 100644 --- a/internal/e2e/main_test.go +++ b/internal/e2e/main_test.go @@ -7,8 +7,8 @@ import ( "os" "testing" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" ) func TestMain(m *testing.M) { diff --git a/internal/e2e/testcase.go b/internal/e2e/testcase.go index b0556545dc..07aba65d29 100644 --- a/internal/e2e/testcase.go +++ b/internal/e2e/testcase.go @@ -20,7 +20,7 @@ import ( "text/template" "time" - "github.com/buildkite/agent/v3/version" + "github.com/buildkite/agent/v4/version" "github.com/buildkite/go-buildkite/v4" "github.com/buildkite/roko" diff --git a/internal/experiments/BUILD.bazel b/internal/experiments/BUILD.bazel index d99bb994e8..fb4cd63763 100644 --- a/internal/experiments/BUILD.bazel +++ b/internal/experiments/BUILD.bazel @@ -3,7 +3,7 @@ load("@rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "experiments", srcs = ["experiments.go"], - importpath = "github.com/buildkite/agent/v3/internal/experiments", + importpath = "github.com/buildkite/agent/v4/internal/experiments", visibility = ["//:__subpackages__"], deps = ["//logger"], ) diff --git a/internal/experiments/experiments.go b/internal/experiments/experiments.go index f01c10930d..f3a2181a44 100644 --- a/internal/experiments/experiments.go +++ b/internal/experiments/experiments.go @@ -9,7 +9,7 @@ import ( "fmt" "sync" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) type State string @@ -24,54 +24,57 @@ const ( const ( // Available experiments AgentAPI = "agent-api" - AllowArtifactPathTraversal = "allow-artifact-path-traversal" - DescendingSpawnPriority = "descending-spawn-priority" InterpolationPrefersRuntimeEnv = "interpolation-prefers-runtime-env" - NormalisedUploadPaths = "normalised-upload-paths" - OverrideZeroExitOnCancel = "override-zero-exit-on-cancel" PTYRaw = "pty-raw" - ResolveCommitAfterCheckout = "resolve-commit-after-checkout" - PropagateAgentConfigVars = "propagate-agent-config-vars" + LegacyPostHookOrder = "legacy-post-hook-order" ZipPlugins = "zip-plugins" - // Promoted experiments - ANSITimestamps = "ansi-timestamps" - AvoidRecursiveTrap = "avoid-recursive-trap" - FlockFileLocks = "flock-file-locks" - GitMirrors = "git-mirrors" - InbuiltStatusPage = "inbuilt-status-page" - IsolatedPluginCheckout = "isolated-plugin-checkout" - JobAPI = "job-api" - KubernetesExec = "kubernetes-exec" - PolyglotHooks = "polyglot-hooks" - UseZZGlob = "use-zzglob" + // Promoted or removed experiments - un-export these to ensure no new code + // can depend on them. + descendingSpawnPriority = "descending-spawn-priority" + allowArtifactPathTraversal = "allow-artifact-path-traversal" + ansiTimestamps = "ansi-timestamps" + avoidRecursiveTrap = "avoid-recursive-trap" + flockFileLocks = "flock-file-locks" + gitMirrors = "git-mirrors" + inbuiltStatusPage = "inbuilt-status-page" + isolatedPluginCheckout = "isolated-plugin-checkout" + jobAPI = "job-api" + kubernetesExec = "kubernetes-exec" + normalisedUploadPaths = "normalised-upload-paths" + overrideZeroExitOnCancel = "override-zero-exit-on-cancel" + polyglotHooks = "polyglot-hooks" + propagateAgentConfigVars = "propagate-agent-config-vars" + resolveCommitAfterCheckout = "resolve-commit-after-checkout" + useZZGlob = "use-zzglob" ) var ( Available = map[string]struct{}{ AgentAPI: {}, - AllowArtifactPathTraversal: {}, - DescendingSpawnPriority: {}, InterpolationPrefersRuntimeEnv: {}, - NormalisedUploadPaths: {}, - OverrideZeroExitOnCancel: {}, + LegacyPostHookOrder: {}, PTYRaw: {}, - ResolveCommitAfterCheckout: {}, - PropagateAgentConfigVars: {}, ZipPlugins: {}, } Promoted = map[string]string{ - ANSITimestamps: standardPromotionMsg(ANSITimestamps, "v3.48.0"), - AvoidRecursiveTrap: standardPromotionMsg(AvoidRecursiveTrap, "v3.66.0"), - FlockFileLocks: standardPromotionMsg(FlockFileLocks, "v3.48.0"), - GitMirrors: standardPromotionMsg(GitMirrors, "v3.47.0"), - InbuiltStatusPage: standardPromotionMsg(InbuiltStatusPage, "v3.48.0"), - IsolatedPluginCheckout: standardPromotionMsg(IsolatedPluginCheckout, "v3.67.0"), - JobAPI: standardPromotionMsg(JobAPI, "v3.64.0"), - KubernetesExec: "The kubernetes-exec experiment has been replaced with the --kubernetes-exec flag as of agent v3.74.0", - PolyglotHooks: standardPromotionMsg(PolyglotHooks, "v3.85.0"), - UseZZGlob: standardPromotionMsg(UseZZGlob, "v3.104.0"), + descendingSpawnPriority: "The `descending-spawn-priority` has been replaced with `--spawn-with-priority descending` as of agent v4", + ansiTimestamps: standardPromotionMsg(ansiTimestamps, "v3.48.0"), + allowArtifactPathTraversal: "The allow-artifact-path-traversal escape-hatch experiment has been removed as of agent v4, because the path traversal behaviour was insecure", + avoidRecursiveTrap: standardPromotionMsg(avoidRecursiveTrap, "v3.66.0"), + flockFileLocks: standardPromotionMsg(flockFileLocks, "v3.48.0"), + gitMirrors: standardPromotionMsg(gitMirrors, "v3.47.0"), + inbuiltStatusPage: standardPromotionMsg(inbuiltStatusPage, "v3.48.0"), + isolatedPluginCheckout: standardPromotionMsg(isolatedPluginCheckout, "v3.67.0"), + jobAPI: standardPromotionMsg(jobAPI, "v3.64.0"), + kubernetesExec: "The kubernetes-exec experiment has been replaced with the --kubernetes-exec flag as of agent v3.74.0", + normalisedUploadPaths: standardPromotionMsg(normalisedUploadPaths, "v4"), + overrideZeroExitOnCancel: standardPromotionMsg(overrideZeroExitOnCancel, "v4"), + polyglotHooks: standardPromotionMsg(polyglotHooks, "v3.85.0"), + propagateAgentConfigVars: standardPromotionMsg(propagateAgentConfigVars, "v4"), + resolveCommitAfterCheckout: standardPromotionMsg(resolveCommitAfterCheckout, "v4"), + useZZGlob: standardPromotionMsg(useZZGlob, "v3.104.0"), } // Used to track experiments possibly in use. diff --git a/internal/file/BUILD.bazel b/internal/file/BUILD.bazel index d3079a4ce2..3e659b00e6 100644 --- a/internal/file/BUILD.bazel +++ b/internal/file/BUILD.bazel @@ -6,7 +6,7 @@ go_library( "is_opened.go", "opened_by.go", ], - importpath = "github.com/buildkite/agent/v3/internal/file", + importpath = "github.com/buildkite/agent/v4/internal/file", visibility = ["//:__subpackages__"], deps = ["//internal/shell"], ) diff --git a/internal/file/is_opened.go b/internal/file/is_opened.go index 34ecf35c13..e29a4ed739 100644 --- a/internal/file/is_opened.go +++ b/internal/file/is_opened.go @@ -5,7 +5,7 @@ import ( "os" "strconv" - "github.com/buildkite/agent/v3/internal/shell" + "github.com/buildkite/agent/v4/internal/shell" ) // IsOpened returns true if the file at the given path is opened by the current process. diff --git a/internal/file/opened_by.go b/internal/file/opened_by.go index db987c0122..c9737eb38d 100644 --- a/internal/file/opened_by.go +++ b/internal/file/opened_by.go @@ -8,7 +8,7 @@ import ( "regexp" "strconv" - "github.com/buildkite/agent/v3/internal/shell" + "github.com/buildkite/agent/v4/internal/shell" ) const stderrFd = 2 diff --git a/internal/job/BUILD.bazel b/internal/job/BUILD.bazel index a3a858188e..89a51e83c2 100644 --- a/internal/job/BUILD.bazel +++ b/internal/job/BUILD.bazel @@ -17,7 +17,7 @@ go_library( "ssh.go", "tracing.go", ], - importpath = "github.com/buildkite/agent/v3/internal/job", + importpath = "github.com/buildkite/agent/v4/internal/job", visibility = ["//:__subpackages__"], deps = [ "//agent/plugin", diff --git a/internal/job/api.go b/internal/job/api.go index e9eefa5540..f0ec72e524 100644 --- a/internal/job/api.go +++ b/internal/job/api.go @@ -3,9 +3,9 @@ package job import ( "fmt" - "github.com/buildkite/agent/v3/internal/redact" - "github.com/buildkite/agent/v3/internal/socket" - "github.com/buildkite/agent/v3/jobapi" + "github.com/buildkite/agent/v4/internal/redact" + "github.com/buildkite/agent/v4/internal/socket" + "github.com/buildkite/agent/v4/jobapi" ) // startJobAPI starts the job API server, iff the OS of the box supports it otherwise it returns a diff --git a/internal/job/artifacts.go b/internal/job/artifacts.go index aa1909a48f..3d52d83e46 100644 --- a/internal/job/artifacts.go +++ b/internal/job/artifacts.go @@ -3,8 +3,8 @@ package job import ( "context" - "github.com/buildkite/agent/v3/internal/self" - "github.com/buildkite/agent/v3/tracetools" + "github.com/buildkite/agent/v4/internal/self" + "github.com/buildkite/agent/v4/tracetools" ) func (e *Executor) artifactPhase(ctx context.Context) error { @@ -12,10 +12,9 @@ func (e *Executor) artifactPhase(ctx context.Context) error { return nil } - spanName := e.implementationSpecificSpanName("artifacts", "artifact upload") - span, ctx := tracetools.StartSpanFromContext(ctx, spanName, e.TracingBackend) + span, ctx := tracetools.StartSpanFromContext(ctx, "artifacts", e.TracingBackend) var err error - defer func() { span.FinishWithError(err) }() + defer func() { tracetools.FinishWithError(span, err) }() err = e.preArtifactHooks(ctx) if err != nil { @@ -39,7 +38,7 @@ func (e *Executor) artifactPhase(ctx context.Context) error { func (e *Executor) preArtifactHooks(ctx context.Context) error { span, ctx := tracetools.StartSpanFromContext(ctx, "pre-artifact", e.TracingBackend) var err error - defer func() { span.FinishWithError(err) }() + defer func() { tracetools.FinishWithError(span, err) }() if err = e.executeGlobalHook(ctx, "pre-artifact"); err != nil { return err @@ -60,7 +59,7 @@ func (e *Executor) preArtifactHooks(ctx context.Context) error { func (e *Executor) uploadArtifacts(ctx context.Context) error { span, _ := tracetools.StartSpanFromContext(ctx, "artifact-upload", e.TracingBackend) var err error - defer func() { span.FinishWithError(err) }() + defer func() { tracetools.FinishWithError(span, err) }() e.shell.Headerf("Uploading artifacts") args := []string{"artifact", "upload", e.AutomaticArtifactUploadPaths} @@ -81,7 +80,7 @@ func (e *Executor) uploadArtifacts(ctx context.Context) error { func (e *Executor) postArtifactHooks(ctx context.Context) error { span, _ := tracetools.StartSpanFromContext(ctx, "post-artifact", e.TracingBackend) var err error - defer func() { span.FinishWithError(err) }() + defer func() { tracetools.FinishWithError(span, err) }() if err = e.executeGlobalHook(ctx, "post-artifact"); err != nil { return err diff --git a/internal/job/checkout.go b/internal/job/checkout.go index af93dbf8ce..0b6da0b150 100644 --- a/internal/job/checkout.go +++ b/internal/job/checkout.go @@ -1,6 +1,7 @@ package job import ( + "cmp" "context" "errors" "fmt" @@ -11,11 +12,11 @@ import ( "strings" "time" - "github.com/buildkite/agent/v3/internal/experiments" - "github.com/buildkite/agent/v3/internal/osutil" - "github.com/buildkite/agent/v3/internal/self" - "github.com/buildkite/agent/v3/internal/shell" - "github.com/buildkite/agent/v3/tracetools" + "github.com/buildkite/agent/v4/internal/experiments" + "github.com/buildkite/agent/v4/internal/osutil" + "github.com/buildkite/agent/v4/internal/self" + "github.com/buildkite/agent/v4/internal/shell" + "github.com/buildkite/agent/v4/tracetools" "github.com/buildkite/roko" "github.com/buildkite/shellwords" ) @@ -134,7 +135,7 @@ func (e *Executor) refreshCheckoutRoot() error { func (e *Executor) CheckoutPhase(ctx context.Context) error { span, ctx := tracetools.StartSpanFromContext(ctx, "checkout", e.TracingBackend) var err error - defer func() { span.FinishWithError(err) }() + defer func() { tracetools.FinishWithError(span, err) }() if err = e.executeGlobalHook(ctx, "pre-checkout"); err != nil { return err @@ -189,16 +190,24 @@ func (e *Executor) CheckoutPhase(ctx context.Context) error { } // Run post-checkout hooks - if err := e.executeGlobalHook(ctx, "post-checkout"); err != nil { - return err - } - - if err := e.executeLocalHook(ctx, "post-checkout"); err != nil { - return err - } - - if err := e.executePluginHook(ctx, "post-checkout", e.pluginCheckouts); err != nil { - return err + if experiments.IsEnabled(ctx, experiments.LegacyPostHookOrder) { + // Legacy order = same order as pre-checkout + if err := cmp.Or( + e.executeGlobalHook(ctx, "post-checkout"), + e.executeLocalHook(ctx, "post-checkout"), + e.executePluginHook(ctx, "post-checkout", e.pluginCheckouts), + ); err != nil { + return err + } + } else { + // Modern order = reverse, to make composition easier + if err := cmp.Or( + e.executePluginHook(ctx, "post-checkout", e.pluginCheckoutsReversed), + e.executeLocalHook(ctx, "post-checkout"), + e.executeGlobalHook(ctx, "post-checkout"), + ); err != nil { + return err + } } // Capture the new checkout path so we can see if it's changed. @@ -810,13 +819,13 @@ func (e *Executor) fetchSource(ctx context.Context) error { // hook exists. It performs the default checkout on the Repository provided in the config func (e *Executor) defaultCheckoutPhase(ctx context.Context) error { span, _ := tracetools.StartSpanFromContext(ctx, "repo-checkout", e.TracingBackend) - span.AddAttributes(map[string]string{ + tracetools.AddAttributes(span, map[string]string{ "checkout.repo_name": e.Repository, "checkout.refspec": e.RefSpec, "checkout.commit": e.Commit, }) var err error - defer func() { span.FinishWithError(err) }() + defer func() { tracetools.FinishWithError(span, err) }() if e.SSHKeyscan { addRepositoryHostToSSHKnownHosts(ctx, e.shell, e.Repository) @@ -826,7 +835,7 @@ func (e *Executor) defaultCheckoutPhase(ctx context.Context) error { // If we can, get a mirror of the git repository to use for reference later if e.GitMirrorsPath != "" && e.Repository != "" { - span.AddAttributes(map[string]string{"checkout.is_using_git_mirrors": "true"}) + tracetools.AddAttributes(span, map[string]string{"checkout.is_using_git_mirrors": "true"}) mirrorDir, err = e.getOrUpdateMirrorDir(ctx, e.Repository) if err != nil { return fmt.Errorf("getting/updating git mirror: %w", err) @@ -1040,10 +1049,7 @@ func (e *Executor) defaultCheckoutPhase(ctx context.Context) error { } // resolve BUILDKITE_COMMIT based on the local git repo - if experiments.IsEnabled(ctx, experiments.ResolveCommitAfterCheckout) { - e.shell.Commentf("Using resolve-commit-after-checkout experiment πŸ§ͺ") - e.resolveCommit(ctx) - } + e.resolveCommit(ctx) return nil } diff --git a/internal/job/checkout_test.go b/internal/job/checkout_test.go index a23167d737..bf8aa2c8c6 100644 --- a/internal/job/checkout_test.go +++ b/internal/job/checkout_test.go @@ -6,9 +6,9 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/internal/job/githttptest" - "github.com/buildkite/agent/v3/internal/race" - "github.com/buildkite/agent/v3/internal/shell" + "github.com/buildkite/agent/v4/internal/job/githttptest" + "github.com/buildkite/agent/v4/internal/race" + "github.com/buildkite/agent/v4/internal/shell" ) func TestDefaultCheckoutPhase(t *testing.T) { diff --git a/internal/job/config.go b/internal/job/config.go index ab59d0b0e9..cc7c93951b 100644 --- a/internal/job/config.go +++ b/internal/job/config.go @@ -7,9 +7,8 @@ import ( "strings" "time" - "github.com/buildkite/agent/v3/env" - "github.com/buildkite/agent/v3/internal/process" - "github.com/buildkite/agent/v3/tracetools" + "github.com/buildkite/agent/v4/env" + "github.com/buildkite/agent/v4/internal/process" ) // Config provides the configuration for the job executor. Some of the keys are @@ -189,12 +188,6 @@ type ExecutorConfig struct { // Traceing context information TracingTraceParent string - // Accept traceparent context from Buildkite control plane - TracingPropagateTraceparent bool - - // Encoding (within base64) for the trace context environment variable. - TraceContextCodec tracetools.Codec - // Whether to start the JobAPI JobAPI bool diff --git a/internal/job/config_test.go b/internal/job/config_test.go index 00c3448f0e..e973356a95 100644 --- a/internal/job/config_test.go +++ b/internal/job/config_test.go @@ -3,7 +3,7 @@ package job import ( "testing" - "github.com/buildkite/agent/v3/env" + "github.com/buildkite/agent/v4/env" "github.com/google/go-cmp/cmp" ) diff --git a/internal/job/docker.go b/internal/job/docker.go deleted file mode 100644 index 79405647da..0000000000 --- a/internal/job/docker.go +++ /dev/null @@ -1,161 +0,0 @@ -package job - -import ( - "context" - "errors" - "fmt" - "slices" - "strings" - - "github.com/buildkite/agent/v3/internal/shell" -) - -var dockerEnv = []string{ - "BUILDKITE_DOCKER_COMPOSE_CONTAINER", - "BUILDKITE_DOCKER_COMPOSE_FILE", - "BUILDKITE_DOCKER", - "BUILDKITE_DOCKER_FILE", - "BUILDKITE_DOCKER_COMPOSE_BUILD_ALL", - "BUILDKITE_DOCKER_COMPOSE_LEAVE_VOLUMES", -} - -func hasDeprecatedDockerIntegration(sh *shell.Shell) bool { - return slices.ContainsFunc(dockerEnv, sh.Env.Exists) -} - -func runDeprecatedDockerIntegration(ctx context.Context, sh *shell.Shell, cmd []string) error { - warnNotSet := func(k1, k2 string) { - sh.Warningf("%s is set, but without %s, which it requires. You should be able to safely remove this from your pipeline.", k1, k2) - } - - switch { - case sh.Env.Exists("BUILDKITE_DOCKER_COMPOSE_CONTAINER"): - sh.Warningf("BUILDKITE_DOCKER_COMPOSE_CONTAINER is set, which is deprecated in Agent v3 and will be removed in v4. Consider using the :docker: docker-compose plugin instead at https://github.com/buildkite-plugins/docker-compose-buildkite-plugin.") - return runDockerComposeCommand(ctx, sh, cmd) - - case sh.Env.Exists("BUILDKITE_DOCKER"): - sh.Warningf("BUILDKITE_DOCKER is set, which is deprecated in Agent v3 and will be removed in v4. Consider using the docker plugin instead at https://github.com/buildkite-plugins/docker-buildkite-plugin.") - return runDockerCommand(ctx, sh, cmd) - - case sh.Env.Exists("BUILDKITE_DOCKER_COMPOSE_FILE"): - warnNotSet("BUILDKITE_DOCKER_COMPOSE_FILE", "BUILDKITE_DOCKER_COMPOSE_CONTAINER") - - case sh.Env.Exists("BUILDKITE_DOCKER_COMPOSE_BUILD_ALL"): - warnNotSet("BUILDKITE_DOCKER_COMPOSE_BUILD_ALL", "BUILDKITE_DOCKER_COMPOSE_CONTAINER") - - case sh.Env.Exists("BUILDKITE_DOCKER_COMPOSE_LEAVE_VOLUMES"): - warnNotSet("BUILDKITE_DOCKER_COMPOSE_LEAVE_VOLUMES", "BUILDKITE_DOCKER_COMPOSE_CONTAINER") - - case sh.Env.Exists("BUILDKITE_DOCKER_COMPOSE_LEAVE_VOLUMES"): - warnNotSet("BUILDKITE_DOCKER_COMPOSE_LEAVE_VOLUMES", "BUILDKITE_DOCKER_COMPOSE_CONTAINER") - } - - return errors.New("failed to find any docker env") -} - -func tearDownDeprecatedDockerIntegration(ctx context.Context, sh *shell.Shell) error { - if container, ok := sh.Env.Get("DOCKER_CONTAINER"); ok { - sh.Printf("~~~ Cleaning up Docker containers") - - if err := sh.Command("docker", "rm", "-f", "-v", container).Run(ctx); err != nil { - return err - } - } else if projectName, ok := sh.Env.Get("COMPOSE_PROJ_NAME"); ok { - sh.Printf("~~~ Cleaning up Docker containers") - - // Friendly kill - _ = runDockerCompose(ctx, sh, projectName, "kill") - - if sh.Env.GetBool("BUILDKITE_DOCKER_COMPOSE_LEAVE_VOLUMES", false) { - _ = runDockerCompose(ctx, sh, projectName, "rm", "--force", "--all") - } else { - _ = runDockerCompose(ctx, sh, projectName, "rm", "--force", "--all", "-v") - } - - return runDockerCompose(ctx, sh, projectName, "down") - } - - return nil -} - -// runDockerCommand executes a command inside a docker container that is built as needed -// Ported from https://github.com/buildkite/agent/blob/2b8f1d569b659e07de346c0e3ae7090cb98e49ba/templates/bootstrap.sh#L439 -func runDockerCommand(ctx context.Context, sh *shell.Shell, cmd []string) error { - jobId, _ := sh.Env.Get("BUILDKITE_JOB_ID") - dockerContainer := fmt.Sprintf("buildkite_%s_container", jobId) - dockerImage := fmt.Sprintf("buildkite_%s_image", jobId) - - dockerFile, _ := sh.Env.Get("BUILDKITE_DOCKER_FILE") - if dockerFile == "" { - dockerFile = "Dockerfile" - } - - sh.Env.Set("DOCKER_CONTAINER", dockerContainer) - sh.Env.Set("DOCKER_IMAGE", dockerImage) - - sh.Printf("~~~ :docker: Building Docker image %s", dockerImage) - shCmd := sh.Command("docker", "build", "-f", dockerFile, "-t", dockerImage, ".") - if err := shCmd.Run(ctx); err != nil { - return err - } - - sh.Headerf(":docker: Running command (in Docker container)") - shCmd = sh.Command("docker", append([]string{"run", "--name", dockerContainer, dockerImage}, cmd...)...) - if err := shCmd.Run(ctx); err != nil { - return err - } - - return nil -} - -// runDockerComposeCommand executes a command with docker-compose -// Ported from https://github.com/buildkite/agent/blob/2b8f1d569b659e07de346c0e3ae7090cb98e49ba/templates/bootstrap.sh#L462 -func runDockerComposeCommand(ctx context.Context, sh *shell.Shell, cmd []string) error { - composeContainer, _ := sh.Env.Get("BUILDKITE_DOCKER_COMPOSE_CONTAINER") - jobId, _ := sh.Env.Get("BUILDKITE_JOB_ID") - - // Compose strips dashes and underscores, so we'll remove them - // to match the docker container names - projectName := strings.ReplaceAll("buildkite"+jobId, "-", "") - - sh.Env.Set("COMPOSE_PROJ_NAME", projectName) - sh.Headerf(":docker: Building Docker images") - - if sh.Env.GetBool("BUILDKITE_DOCKER_COMPOSE_BUILD_ALL", false) { - if err := runDockerCompose(ctx, sh, projectName, "build", "--pull"); err != nil { - return err - } - } else { - if err := runDockerCompose(ctx, sh, projectName, "build", "--pull", composeContainer); err != nil { - return err - } - } - - sh.Headerf(":docker: Running command (in Docker Compose container)") - return runDockerCompose(ctx, sh, projectName, append([]string{"run", composeContainer}, cmd...)...) -} - -func runDockerCompose(ctx context.Context, sh *shell.Shell, projectName string, commandArgs ...string) error { - args := []string{} - - composeFile, _ := sh.Env.Get("BUILDKITE_DOCKER_COMPOSE_FILE") - if composeFile == "" { - composeFile = "docker-compose.yml" - } - - // composeFile might be multiple files, spaces or colons - for chunk := range strings.FieldsSeq(composeFile) { - for file := range strings.SplitSeq(chunk, ":") { - args = append(args, "-f", file) - } - } - - args = append(args, "-p", projectName) - - if sh.Env.GetBool("BUILDKITE_AGENT_DEBUG", false) { - args = append(args, "--verbose") - } - - args = append(args, commandArgs...) - return sh.Command("docker-compose", args...).Run(ctx) -} diff --git a/internal/job/executor.go b/internal/job/executor.go index 85795c7c51..d23f3093a5 100644 --- a/internal/job/executor.go +++ b/internal/job/executor.go @@ -22,21 +22,22 @@ import ( "syscall" "time" - "github.com/buildkite/agent/v3/agent/plugin" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/env" - "github.com/buildkite/agent/v3/internal/file" - "github.com/buildkite/agent/v3/internal/job/hook" - "github.com/buildkite/agent/v3/internal/osutil" - "github.com/buildkite/agent/v3/internal/process" - "github.com/buildkite/agent/v3/internal/redact" - "github.com/buildkite/agent/v3/internal/replacer" - "github.com/buildkite/agent/v3/internal/secrets" - "github.com/buildkite/agent/v3/internal/shell" - "github.com/buildkite/agent/v3/internal/shellscript" - "github.com/buildkite/agent/v3/internal/tempfile" - "github.com/buildkite/agent/v3/logger" - "github.com/buildkite/agent/v3/tracetools" + "github.com/buildkite/agent/v4/agent/plugin" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/env" + "github.com/buildkite/agent/v4/internal/experiments" + "github.com/buildkite/agent/v4/internal/file" + "github.com/buildkite/agent/v4/internal/job/hook" + "github.com/buildkite/agent/v4/internal/osutil" + "github.com/buildkite/agent/v4/internal/process" + "github.com/buildkite/agent/v4/internal/redact" + "github.com/buildkite/agent/v4/internal/replacer" + "github.com/buildkite/agent/v4/internal/secrets" + "github.com/buildkite/agent/v4/internal/shell" + "github.com/buildkite/agent/v4/internal/shellscript" + "github.com/buildkite/agent/v4/internal/tempfile" + "github.com/buildkite/agent/v4/logger" + "github.com/buildkite/agent/v4/tracetools" "github.com/buildkite/go-pipeline" "github.com/buildkite/roko" "github.com/buildkite/shellwords" @@ -61,7 +62,8 @@ type Executor struct { plugins []*plugin.Plugin // Plugin checkouts from the plugin phases - pluginCheckouts []*pluginCheckout + pluginCheckouts []*pluginCheckout + pluginCheckoutsReversed []*pluginCheckout // Directories to clean up at end of job execution cleanupDirs []string @@ -125,7 +127,6 @@ func (e *Executor) Run(ctx context.Context) (exitCode int) { shell.WithPTY(e.RunInPty), shell.WithStdout(preRedactedStdout), // shell -> redactor -> real stdout shell.WithSignalGracePeriod(e.SignalGracePeriod), - shell.WithTraceContextCodec(e.TraceContextCodec), ) if err != nil { fmt.Printf("Error creating shell: %v", err) @@ -137,7 +138,7 @@ func (e *Executor) Run(ctx context.Context) (exitCode int) { var err error span, ctx, stopper := e.startTracing(ctx) defer stopper() - defer func() { span.FinishWithError(err) }() + defer func() { tracetools.FinishWithError(span, err) }() // Listen for cancellation. Once ctx is cancelled, some tasks can run // afterwards during the signal grace period. These use graceCtx. @@ -272,7 +273,7 @@ func (e *Executor) Run(ctx context.Context) (exitCode int) { // shouldn't override each other in reporting. if commandErr != nil { e.shell.Printf("user command error: %v", commandErr) - span.RecordError(commandErr) + tracetools.RecordError(span, commandErr) } // Only upload artifacts as part of the command phase. @@ -346,36 +347,18 @@ type HookConfig struct { PluginName string } -func (e *Executor) tracingImplementationSpecificHookScope(scope string) string { - if e.TracingBackend != tracetools.BackendDatadog { - return scope - } - - // In olden times, when the datadog tracing backend was written, these hook scopes were named "local" and "global" - // We need to maintain backwards compatibility with the old names for span attribute reasons, so we map them here - switch scope { - case HookScopeRepository: - return "local" - case HookScopeAgent: - return "global" - default: - return scope - } -} - // executeHook runs a hook script with the hookRunner func (e *Executor) executeHook(ctx context.Context, hookCfg HookConfig) error { - scopeName := e.tracingImplementationSpecificHookScope(hookCfg.Scope) - spanName := e.implementationSpecificSpanName(fmt.Sprintf("%s %s hook", scopeName, hookCfg.Name), "hook.execute") + spanName := fmt.Sprintf("%s %s hook", hookCfg.Scope, hookCfg.Name) span, ctx := tracetools.StartSpanFromContext(ctx, spanName, e.TracingBackend) var err error - defer func() { span.FinishWithError(err) }() - span.AddAttributes(map[string]string{ - "hook.type": scopeName, + defer func() { tracetools.FinishWithError(span, err) }() + tracetools.AddAttributes(span, map[string]string{ + "hook.type": hookCfg.Scope, "hook.name": hookCfg.Name, "hook.command": hookCfg.Path, }) - span.AddAttributes(hookCfg.SpanAttributes) + tracetools.AddAttributes(span, hookCfg.SpanAttributes) hookName := hookCfg.Scope if hookCfg.PluginName != "" { @@ -859,7 +842,7 @@ func addRepositoryHostToSSHKnownHosts(ctx context.Context, sh *shell.Shell, repo func (e *Executor) setUp(ctx context.Context) error { span, ctx := tracetools.StartSpanFromContext(ctx, "environment", e.TracingBackend) var err error - defer func() { span.FinishWithError(err) }() + defer func() { tracetools.FinishWithError(span, err) }() // Add the $BUILDKITE_BIN_PATH to the $PATH if we've been given one if e.BinPath != "" { @@ -1001,7 +984,7 @@ func (e *Executor) fetchAndSetSecrets(ctx context.Context) error { func (e *Executor) tearDown(ctx context.Context) error { span, ctx := tracetools.StartSpanFromContext(ctx, "pre-exit", e.TracingBackend) var err error - defer func() { span.FinishWithError(err) }() + defer func() { tracetools.FinishWithError(span, err) }() // In vanilla agent usage, there's always a command phase. // But over in agent-stack-k8s, which splits the agent phases among @@ -1010,24 +993,27 @@ func (e *Executor) tearDown(ctx context.Context) error { // Unfortunately pre-exit hooks are often not written with this split in // mind. if e.includePhase("command") { - if err = e.executeGlobalHook(ctx, "pre-exit"); err != nil { - return err - } - - if err = e.executeLocalHook(ctx, "pre-exit"); err != nil { - return err - } - - if err = e.executePluginHook(ctx, "pre-exit", e.pluginCheckouts); err != nil { - return err + if experiments.IsEnabled(ctx, experiments.LegacyPostHookOrder) { + // Legacy order = same order as environment + if err := cmp.Or( + e.executeGlobalHook(ctx, "pre-exit"), + e.executeLocalHook(ctx, "pre-exit"), + e.executePluginHook(ctx, "pre-exit", e.pluginCheckouts), + ); err != nil { + return err + } + } else { + // Modern order = reverse, to make composition easier + if err := cmp.Or( + e.executePluginHook(ctx, "pre-exit", e.pluginCheckoutsReversed), + e.executeLocalHook(ctx, "pre-exit"), + e.executeGlobalHook(ctx, "pre-exit"), + ); err != nil { + return err + } } } - // Support deprecated BUILDKITE_DOCKER* env vars - if hasDeprecatedDockerIntegration(e.shell) { - return tearDownDeprecatedDockerIntegration(ctx, e.shell) - } - for _, dir := range e.cleanupDirs { if err = os.RemoveAll(dir); err != nil { e.shell.Warningf("Failed to remove dir %s: %v", dir, err) @@ -1039,9 +1025,8 @@ func (e *Executor) tearDown(ctx context.Context) error { // runPreCommandHooks runs the pre-command hooks and adds tracing spans. func (e *Executor) runPreCommandHooks(ctx context.Context) (err error) { - spanName := e.implementationSpecificSpanName("pre-command", "pre-command hooks") - span, ctx := tracetools.StartSpanFromContext(ctx, spanName, e.TracingBackend) - defer func() { span.FinishWithError(err) }() + span, ctx := tracetools.StartSpanFromContext(ctx, "pre-command", e.TracingBackend) + defer func() { tracetools.FinishWithError(span, err) }() if err := e.executeGlobalHook(ctx, "pre-command"); err != nil { return err @@ -1069,17 +1054,23 @@ func (e *Executor) runCommand(ctx context.Context) error { // runPostCommandHooks runs the post-command hooks and adds tracing spans. func (e *Executor) runPostCommandHooks(ctx context.Context) (err error) { - spanName := e.implementationSpecificSpanName("post-command", "post-command hooks") - span, ctx := tracetools.StartSpanFromContext(ctx, spanName, e.TracingBackend) - defer func() { span.FinishWithError(err) }() - - if err := e.executeGlobalHook(ctx, "post-command"); err != nil { - return err - } - if err := e.executeLocalHook(ctx, "post-command"); err != nil { - return err + span, ctx := tracetools.StartSpanFromContext(ctx, "post-command", e.TracingBackend) + defer func() { tracetools.FinishWithError(span, err) }() + + if experiments.IsEnabled(ctx, experiments.LegacyPostHookOrder) { + // Legacy order = same order as pre-command + return cmp.Or( + e.executeGlobalHook(ctx, "post-command"), + e.executeLocalHook(ctx, "post-command"), + e.executePluginHook(ctx, "post-command", e.pluginCheckouts), + ) } - return e.executePluginHook(ctx, "post-command", e.pluginCheckouts) + // Modern order = reverse, to make composition easier + return cmp.Or( + e.executePluginHook(ctx, "post-command", e.pluginCheckoutsReversed), + e.executeLocalHook(ctx, "post-command"), + e.executeGlobalHook(ctx, "post-command"), + ) } // CommandPhase determines how to run the build, and then runs it @@ -1088,7 +1079,7 @@ func (e *Executor) CommandPhase(ctx context.Context) (hookErr, commandErr error) span, ctx := tracetools.StartSpanFromContext(ctx, "command", e.TracingBackend) defer func() { - span.FinishWithError(hookErr) + tracetools.FinishWithError(span, hookErr) }() // Run postCommandHooks, even if there is an error from the command, but not if there is an @@ -1155,11 +1146,10 @@ func (e *Executor) defaultCommandPhase(ctx context.Context) error { } }() - spanName := e.implementationSpecificSpanName("default command hook", "hook.execute") - span, ctx := tracetools.StartSpanFromContext(ctx, spanName, e.TracingBackend) + span, ctx := tracetools.StartSpanFromContext(ctx, "default command hook", e.TracingBackend) var err error - defer func() { span.FinishWithError(err) }() - span.AddAttributes(map[string]string{ + defer func() { tracetools.FinishWithError(span, err) }() + tracetools.AddAttributes(span, map[string]string{ "hook.name": "command", "hook.type": "default", }) @@ -1172,7 +1162,7 @@ func (e *Executor) defaultCommandPhase(ctx context.Context) error { scriptFileName := strings.ReplaceAll(e.Command, "\n", "") pathToCommand, err := filepath.Abs(filepath.Join(e.shell.Getwd(), scriptFileName)) commandIsScript := err == nil && osutil.FileExists(pathToCommand) - span.AddAttributes(map[string]string{"hook.command": pathToCommand}) + tracetools.AddAttributes(span, map[string]string{"hook.command": pathToCommand}) // If the command isn't a script, then it's something we need // to eval. But before we even try running it, we should double @@ -1264,15 +1254,6 @@ func (e *Executor) defaultCommandPhase(ctx context.Context) error { cmdToExec = e.Command } - // Support deprecated BUILDKITE_DOCKER* env vars - if hasDeprecatedDockerIntegration(e.shell) { - if e.Debug { - e.shell.Commentf("Detected deprecated docker environment variables") - } - err = runDeprecatedDockerIntegration(ctx, e.shell, []string{cmdToExec}) - return err - } - var cmd []string cmd = append(cmd, interpreter...) cmd = append(cmd, cmdToExec) diff --git a/internal/job/executor_test.go b/internal/job/executor_test.go index 32aa84d600..120d795261 100644 --- a/internal/job/executor_test.go +++ b/internal/job/executor_test.go @@ -2,14 +2,10 @@ package job import ( "context" - "reflect" "testing" - "github.com/buildkite/agent/v3/internal/shell" - "github.com/buildkite/agent/v3/tracetools" - "github.com/google/go-cmp/cmp" - "github.com/opentracing/opentracing-go" - "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/opentracer" + "github.com/buildkite/agent/v4/internal/shell" + "github.com/buildkite/agent/v4/tracetools" ) var agentNameTests = []struct { @@ -52,7 +48,7 @@ func TestDirForRepository(t *testing.T) { func TestStartTracing_NoTracingBackend(t *testing.T) { var err error - // When there's no tracing backend, the tracer should be a no-op. + // When there's no tracing backend, the span should be non-recording. e := New(ExecutorConfig{}) oriCtx := context.Background() @@ -62,45 +58,9 @@ func TestStartTracing_NoTracingBackend(t *testing.T) { } span, _, stopper := e.startTracing(oriCtx) - if diff := cmp.Diff(span, &tracetools.NoopSpan{}); diff != "" { - t.Errorf("e.startTracing(oriCtx) diff (-got +want):\n%s", diff) - } - span.FinishWithError(nil) // Finish the nil span, just for completeness' sake - - // If you call opentracing.GlobalTracer() without having set it first, it returns a NoopTracer - // In this test case, we haven't touched opentracing at all, so we get the NoopTracer - if got, want := reflect.TypeOf(opentracing.GlobalTracer()), reflect.TypeOf(opentracing.NoopTracer{}); got != want { - t.Errorf("opentracing.GlobalTracer() = %v, want %v", got, want) - } - stopper() -} - -func TestStartTracing_Datadog(t *testing.T) { - var err error - - // With the Datadog tracing backend, the global tracer should be from Datadog. - cfg := ExecutorConfig{TracingBackend: "datadog"} - e := New(cfg) - - oriCtx := context.Background() - e.shell, err = shell.New() - if err != nil { - t.Errorf("shell.New() error = %v, want nil", err) - } - - span, ctx, stopper := e.startTracing(oriCtx) - span.FinishWithError(nil) - - if got, want := reflect.TypeOf(opentracing.GlobalTracer()), reflect.TypeOf(opentracer.New()); got != want { - t.Errorf("opentracing.GlobalTracer() = %v, want %v", got, want) - } - spanImpl, ok := span.(*tracetools.OpenTracingSpan) - if got := ok; !got { - t.Errorf("span.(*tracetools.OpenTracingSpan) = %t, want true", got) - } - - if got, want := opentracing.SpanFromContext(ctx), spanImpl.Span; !reflect.DeepEqual(got, want) { - t.Errorf("opentracing.SpanFromContext(ctx) = %v, want %v", got, want) + if span.IsRecording() { + t.Errorf("span.IsRecording() = true, want false (no tracing backend should produce a non-recording span)") } + tracetools.FinishWithError(span, nil) // Finish the span, just for completeness' sake stopper() } diff --git a/internal/job/git.go b/internal/job/git.go index aef370940a..d532aaf805 100644 --- a/internal/job/git.go +++ b/internal/job/git.go @@ -13,7 +13,7 @@ import ( "strings" "time" - "github.com/buildkite/agent/v3/internal/shell" + "github.com/buildkite/agent/v4/internal/shell" "github.com/buildkite/roko" "github.com/buildkite/shellwords" ) diff --git a/internal/job/git_test.go b/internal/job/git_test.go index 2cf6b62df8..d4055c243c 100644 --- a/internal/job/git_test.go +++ b/internal/job/git_test.go @@ -6,7 +6,7 @@ import ( "os" "testing" - "github.com/buildkite/agent/v3/internal/shell" + "github.com/buildkite/agent/v4/internal/shell" "github.com/google/go-cmp/cmp" ) diff --git a/internal/job/githttptest/BUILD.bazel b/internal/job/githttptest/BUILD.bazel index 319d210ce8..23c49ddd30 100644 --- a/internal/job/githttptest/BUILD.bazel +++ b/internal/job/githttptest/BUILD.bazel @@ -3,6 +3,6 @@ load("@rules_go//go:def.bzl", "go_library") go_library( name = "githttptest", srcs = ["githttptest.go"], - importpath = "github.com/buildkite/agent/v3/internal/job/githttptest", + importpath = "github.com/buildkite/agent/v4/internal/job/githttptest", visibility = ["//:__subpackages__"], ) diff --git a/internal/job/hook/BUILD.bazel b/internal/job/hook/BUILD.bazel index f2a6740a5c..ac17799012 100644 --- a/internal/job/hook/BUILD.bazel +++ b/internal/job/hook/BUILD.bazel @@ -8,7 +8,7 @@ go_library( "type.go", "wrapper.go", ], - importpath = "github.com/buildkite/agent/v3/internal/job/hook", + importpath = "github.com/buildkite/agent/v4/internal/job/hook", visibility = ["//:__subpackages__"], deps = [ "//env", diff --git a/internal/job/hook/main_test.go b/internal/job/hook/main_test.go index d08d8a27a2..1be4a9ab64 100644 --- a/internal/job/hook/main_test.go +++ b/internal/job/hook/main_test.go @@ -5,8 +5,8 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/clicommand" - "github.com/buildkite/agent/v3/version" + "github.com/buildkite/agent/v4/clicommand" + "github.com/buildkite/agent/v4/version" "github.com/urfave/cli" ) diff --git a/internal/job/hook/type.go b/internal/job/hook/type.go index da56e08780..a3f35957b6 100644 --- a/internal/job/hook/type.go +++ b/internal/job/hook/type.go @@ -4,7 +4,7 @@ import ( "fmt" "os" - "github.com/buildkite/agent/v3/internal/shellscript" + "github.com/buildkite/agent/v4/internal/shellscript" ) const ( diff --git a/internal/job/hook/type_test.go b/internal/job/hook/type_test.go index 833264a058..bca203d8e1 100644 --- a/internal/job/hook/type_test.go +++ b/internal/job/hook/type_test.go @@ -8,7 +8,7 @@ import ( "path/filepath" "testing" - "github.com/buildkite/agent/v3/internal/job/hook" + "github.com/buildkite/agent/v4/internal/job/hook" ) type testCase struct { diff --git a/internal/job/hook/wrapper.go b/internal/job/hook/wrapper.go index c02802130a..e1fbbbf2f5 100644 --- a/internal/job/hook/wrapper.go +++ b/internal/job/hook/wrapper.go @@ -9,9 +9,9 @@ import ( "runtime" "text/template" - "github.com/buildkite/agent/v3/env" - "github.com/buildkite/agent/v3/internal/shellscript" - "github.com/buildkite/agent/v3/internal/tempfile" + "github.com/buildkite/agent/v4/env" + "github.com/buildkite/agent/v4/internal/shellscript" + "github.com/buildkite/agent/v4/internal/tempfile" ) type TemplateType int diff --git a/internal/job/hook/wrapper_test.go b/internal/job/hook/wrapper_test.go index bb1e8736ee..4ad4229676 100644 --- a/internal/job/hook/wrapper_test.go +++ b/internal/job/hook/wrapper_test.go @@ -9,10 +9,10 @@ import ( "runtime" "testing" - "github.com/buildkite/agent/v3/env" - "github.com/buildkite/agent/v3/internal/job/hook" - "github.com/buildkite/agent/v3/internal/shell" - "github.com/buildkite/agent/v3/internal/tempfile" + "github.com/buildkite/agent/v4/env" + "github.com/buildkite/agent/v4/internal/job/hook" + "github.com/buildkite/agent/v4/internal/shell" + "github.com/buildkite/agent/v4/internal/tempfile" "github.com/google/go-cmp/cmp" ) diff --git a/internal/job/integration/BUILD.bazel b/internal/job/integration/BUILD.bazel index 54d9018f92..1a2c08e700 100644 --- a/internal/job/integration/BUILD.bazel +++ b/internal/job/integration/BUILD.bazel @@ -7,7 +7,7 @@ go_library( "executor_tester.go", "git.go", ], - importpath = "github.com/buildkite/agent/v3/internal/job/integration", + importpath = "github.com/buildkite/agent/v4/internal/job/integration", visibility = ["//:__subpackages__"], deps = [ "//clicommand", diff --git a/internal/job/integration/artifact_integration_test.go b/internal/job/integration/artifact_integration_test.go index 1f7e2e44ea..543065108f 100644 --- a/internal/job/integration/artifact_integration_test.go +++ b/internal/job/integration/artifact_integration_test.go @@ -5,7 +5,7 @@ import ( "path/filepath" "testing" - "github.com/buildkite/agent/v3/internal/job" + "github.com/buildkite/agent/v4/internal/job" "github.com/buildkite/bintest/v3" ) diff --git a/internal/job/integration/checkout_git_mirrors_integration_test.go b/internal/job/integration/checkout_git_mirrors_integration_test.go index f35385f6f6..b914c23dba 100644 --- a/internal/job/integration/checkout_git_mirrors_integration_test.go +++ b/internal/job/integration/checkout_git_mirrors_integration_test.go @@ -10,8 +10,7 @@ import ( "sync/atomic" "testing" - "github.com/buildkite/agent/v3/internal/experiments" - "github.com/buildkite/agent/v3/internal/job" + "github.com/buildkite/agent/v4/internal/job" "github.com/buildkite/bintest/v3" ) @@ -48,6 +47,7 @@ func TestCheckingOutGitHubPullRequests_WithGitMirrors(t *testing.T) { {"rev-parse", "FETCH_HEAD"}, {"-c", "advice.detachedHead=false", "checkout", "-f", "FETCH_HEAD"}, {"clean", "-ffxdq"}, + {"rev-parse", "HEAD"}, {"--no-pager", "log", "-1", "HEAD", "-s", "--no-color", gitShowFormatArg}, }) @@ -59,46 +59,6 @@ func TestCheckingOutGitHubPullRequests_WithGitMirrors(t *testing.T) { tester.RunAndCheck(t, env...) } -func TestWithResolvingCommitExperiment_WithGitMirrors(t *testing.T) { - t.Parallel() - - ctx, _ := experiments.Enable(mainCtx, experiments.ResolveCommitAfterCheckout) - tester, err := NewExecutorTester(ctx) - if err != nil { - t.Fatalf("NewExecutorTester() error = %v", err) - } - defer tester.Close() - - if err := tester.EnableGitMirrors(); err != nil { - t.Fatalf("EnableGitMirrors() error = %v", err) - } - - env := []string{ - "BUILDKITE_GIT_CLONE_FLAGS=-v", - "BUILDKITE_GIT_CLONE_MIRROR_FLAGS=--bare", - "BUILDKITE_GIT_CLEAN_FLAGS=-fdq", - "BUILDKITE_GIT_FETCH_FLAGS=-v", - } - - // Actually execute git commands, but with expectations - git := tester. - MustMock(t, "git"). - PassthroughToLocalCommand() - - // But assert which ones are called - git.ExpectAll([][]any{ - {"clone", "--mirror", "--bare", "--", tester.Repo.Path, matchSubDir(tester.GitMirrorsDir)}, - {"clone", "-v", "--reference", matchSubDir(tester.GitMirrorsDir), "--", tester.Repo.Path, "."}, - {"clean", "-fdq"}, - {"fetch", "-v", "--", "origin", "main"}, - {"-c", "advice.detachedHead=false", "checkout", "-f", "FETCH_HEAD"}, - {"clean", "-fdq"}, - {"rev-parse", "HEAD"}, - }) - - tester.RunAndCheck(t, env...) -} - func TestCheckingOutLocalGitProject_WithGitMirrors(t *testing.T) { t.Parallel() @@ -132,6 +92,7 @@ func TestCheckingOutLocalGitProject_WithGitMirrors(t *testing.T) { {"fetch", "-v", "--", "origin", "main"}, {"-c", "advice.detachedHead=false", "checkout", "-f", "FETCH_HEAD"}, {"clean", "-fdq"}, + {"rev-parse", "HEAD"}, {"--no-pager", "log", "-1", "HEAD", "-s", "--no-color", gitShowFormatArg}, }) @@ -208,6 +169,7 @@ func TestCheckingOutLocalGitProjectWithSubmodules_WithGitMirrors(t *testing.T) { {"submodule", "foreach", "--recursive", "git reset --hard"}, {"clean", "-fdq"}, {"submodule", "foreach", "--recursive", "git clean -fdq"}, + {"rev-parse", "HEAD"}, {"--no-pager", "log", "-1", "HEAD", "-s", "--no-color", gitShowFormatArg}, }) @@ -278,6 +240,7 @@ func TestCheckingOutLocalGitProjectWithSubmodulesDisabled_WithGitMirrors(t *test {"fetch", "-v", "--", "origin", "main"}, {"-c", "advice.detachedHead=false", "checkout", "-f", "FETCH_HEAD"}, {"clean", "-fdq"}, + {"rev-parse", "HEAD"}, {"--no-pager", "log", "-1", "HEAD", "-s", "--no-color", gitShowFormatArg}, }) @@ -322,6 +285,7 @@ func TestCheckingOutShallowCloneOfLocalGitProject_WithGitMirrors(t *testing.T) { {"fetch", "--depth=1", "--", "origin", "main"}, {"-c", "advice.detachedHead=false", "checkout", "-f", "FETCH_HEAD"}, {"clean", "-fdq"}, + {"rev-parse", "HEAD"}, {"--no-pager", "log", "-1", "HEAD", "-s", "--no-color", gitShowFormatArg}, }) @@ -712,6 +676,7 @@ func TestGitMirrorEnv(t *testing.T) { {"fetch", "-v", "--", "origin", "main"}, {"-c", "advice.detachedHead=false", "checkout", "-f", "FETCH_HEAD"}, {"clean", "-fdq"}, + {"rev-parse", "HEAD"}, {"--no-pager", "log", "-1", "HEAD", "-s", "--no-color", gitShowFormatArg}, }) @@ -792,6 +757,7 @@ func TestCheckingOutWithCustomRefspec_WithGitMirrors(t *testing.T) { {"fetch", "-v", "--prune", "--", "origin", customRef}, // Mirror fetches custom refspec (correct!) {"-c", "advice.detachedHead=false", "checkout", "-f", "FETCH_HEAD"}, {"clean", "-ffxdq"}, + {"rev-parse", "HEAD"}, {"--no-pager", "log", "-1", "HEAD", "-s", "--no-color", gitShowFormatArg}, }) diff --git a/internal/job/integration/checkout_integration_test.go b/internal/job/integration/checkout_integration_test.go index e584e246ec..bdf7a54615 100644 --- a/internal/job/integration/checkout_integration_test.go +++ b/internal/job/integration/checkout_integration_test.go @@ -12,8 +12,7 @@ import ( "sync/atomic" "testing" - "github.com/buildkite/agent/v3/internal/experiments" - "github.com/buildkite/agent/v3/internal/job" + "github.com/buildkite/agent/v4/internal/job" "github.com/buildkite/bintest/v3" ) @@ -29,41 +28,6 @@ var commitPattern = bintest.MatchPattern(`(?ms)\Acommit [0-9a-f]+\nabbrev-commit // We expect this arg multiple times, just define it once. const gitShowFormatArg = "--format=commit %H%nabbrev-commit %h%nAuthor: %an <%ae>%n%n%w(0,4,4)%B" -func TestWithResolvingCommitExperiment(t *testing.T) { - t.Parallel() - - ctx, _ := experiments.Enable(mainCtx, experiments.ResolveCommitAfterCheckout) - tester, err := NewExecutorTester(ctx) - if err != nil { - t.Fatalf("NewExecutorTester() error = %v", err) - } - defer tester.Close() - - env := []string{ - "BUILDKITE_GIT_CLONE_FLAGS=-v", - "BUILDKITE_GIT_CLONE_MIRROR_FLAGS=--bare", - "BUILDKITE_GIT_CLEAN_FLAGS=-fdq", - "BUILDKITE_GIT_FETCH_FLAGS=-v", - } - - // Actually execute git commands, but with expectations - git := tester. - MustMock(t, "git"). - PassthroughToLocalCommand() - - // But assert which ones are called - git.ExpectAll([][]any{ - {"clone", "-v", "--", tester.Repo.Path, "."}, - {"clean", "-fdq"}, - {"fetch", "-v", "--", "origin", "main"}, - {"-c", "advice.detachedHead=false", "checkout", "-f", "FETCH_HEAD"}, - {"clean", "-fdq"}, - {"rev-parse", "HEAD"}, - }) - - tester.RunAndCheck(t, env...) -} - func TestCheckingOutLocalGitProject(t *testing.T) { t.Parallel() @@ -92,6 +56,7 @@ func TestCheckingOutLocalGitProject(t *testing.T) { {"fetch", "-v", "--", "origin", "main"}, {"-c", "advice.detachedHead=false", "checkout", "-f", "FETCH_HEAD"}, {"clean", "-fdq"}, + {"rev-parse", "HEAD"}, {"--no-pager", "log", "-1", "HEAD", "-s", "--no-color", gitShowFormatArg}, }) @@ -162,6 +127,7 @@ func TestCheckingOutLocalGitProjectWithSubmodules(t *testing.T) { {"submodule", "foreach", "--recursive", "git reset --hard"}, {"clean", "-fdq"}, {"submodule", "foreach", "--recursive", "git clean -fdq"}, + {"rev-parse", "HEAD"}, {"--no-pager", "log", "-1", "HEAD", "-s", "--no-color", gitShowFormatArg}, }) @@ -223,6 +189,7 @@ func TestCheckingOutLocalGitProjectWithSubmodulesDisabled(t *testing.T) { {"fetch", "-v", "--", "origin", "main"}, {"-c", "advice.detachedHead=false", "checkout", "-f", "FETCH_HEAD"}, {"clean", "-fdq"}, + {"rev-parse", "HEAD"}, {"--no-pager", "log", "-1", "HEAD", "-s", "--no-color", gitShowFormatArg}, }) @@ -262,6 +229,7 @@ func TestCheckingOutShallowCloneOfLocalGitProject(t *testing.T) { {"fetch", "--depth=1", "--", "origin", "main"}, {"-c", "advice.detachedHead=false", "checkout", "-f", "FETCH_HEAD"}, {"clean", "-fdq"}, + {"rev-parse", "HEAD"}, {"--no-pager", "log", "-1", "HEAD", "-s", "--no-color", gitShowFormatArg}, }) @@ -313,6 +281,7 @@ func TestCheckingOutLocalGitProjectWithShortCommitHash(t *testing.T) { {"fetch", "-v", "--prune", "--", "origin", "+refs/heads/*:refs/remotes/origin/*", "+refs/tags/*:refs/tags/*"}, {"-c", "advice.detachedHead=false", "checkout", "-f", shortCommitHash}, {"clean", "-ffxdq"}, + {"rev-parse", shortCommitHash}, {"--no-pager", "log", "-1", shortCommitHash, "-s", "--no-color", gitShowFormatArg}, }) @@ -587,6 +556,7 @@ func TestCheckingOutGitHubPullRequestMergeRefspec(t *testing.T) { {"-c", "advice.detachedHead=false", "checkout", "-f", "FETCH_HEAD"}, {"clean", "-ffxdq"}, {"rev-parse", "FETCH_HEAD"}, + {"rev-parse", "HEAD"}, }) tester.RunAndCheck(t, env...) @@ -695,6 +665,7 @@ func TestCheckoutErrorIsRetried(t *testing.T) { {"fetch", "-v", "--", "origin", "main"}, {"-c", "advice.detachedHead=false", "checkout", "-f", "FETCH_HEAD"}, {"clean", "-fdq"}, + {"rev-parse", "HEAD"}, {"--no-pager", "log", "-1", "HEAD", "-s", "--no-color", gitShowFormatArg}, }) @@ -757,6 +728,7 @@ func TestFetchErrorIsRetried(t *testing.T) { {"fetch", "-v", "--prune", "--depth=1", "--", "origin", "main"}, {"-c", "advice.detachedHead=false", "checkout", "-f", "FETCH_HEAD"}, {"clean", "-ffxdq"}, + {"rev-parse", "HEAD"}, {"--no-pager", "log", "-1", "HEAD", "-s", "--no-color", gitShowFormatArg}, }) @@ -1108,6 +1080,7 @@ func TestGitCheckoutWithCommitResolved(t *testing.T) { {"fetch", "-v", "--prune", "--", "origin", "main"}, {"-c", "advice.detachedHead=false", "checkout", "-f", "FETCH_HEAD"}, {"clean", "-ffxdq"}, + {"rev-parse", "HEAD"}, }) agent := tester.MockAgent(t) @@ -1135,6 +1108,7 @@ func TestGitCheckoutWithoutCommitResolved(t *testing.T) { {"fetch", "-v", "--prune", "--", "origin", "main"}, {"-c", "advice.detachedHead=false", "checkout", "-f", "FETCH_HEAD"}, {"clean", "-ffxdq"}, + {"rev-parse", "HEAD"}, }) agent := tester.MockAgent(t) @@ -1162,6 +1136,7 @@ func TestGitCheckoutWithoutCommitResolvedAndNoMetaData(t *testing.T) { {"fetch", "-v", "--prune", "--", "origin", "main"}, {"-c", "advice.detachedHead=false", "checkout", "-f", "FETCH_HEAD"}, {"clean", "-ffxdq"}, + {"rev-parse", "HEAD"}, {"--no-pager", "log", "-1", "HEAD", "-s", "--no-color", gitShowFormatArg}, }) @@ -1218,6 +1193,7 @@ func TestMultipleRemoteURLsFallsBackToGetURL(t *testing.T) { {"fetch", "-v", "--", "origin", "main"}, {"-c", "advice.detachedHead=false", "checkout", "-f", "FETCH_HEAD"}, {"clean", "-fdq"}, + {"rev-parse", "HEAD"}, {"--no-pager", "log", "-1", "HEAD", "-s", "--no-color", gitShowFormatArg}, }) diff --git a/internal/job/integration/command_integration_test.go b/internal/job/integration/command_integration_test.go index 2a96040742..be20e35d68 100644 --- a/internal/job/integration/command_integration_test.go +++ b/internal/job/integration/command_integration_test.go @@ -4,7 +4,7 @@ import ( "runtime" "testing" - "github.com/buildkite/agent/v3/internal/job" + "github.com/buildkite/agent/v4/internal/job" "github.com/buildkite/bintest/v3" ) diff --git a/internal/job/integration/docker_integration_test.go b/internal/job/integration/docker_integration_test.go deleted file mode 100644 index 6bdc7248ad..0000000000 --- a/internal/job/integration/docker_integration_test.go +++ /dev/null @@ -1,273 +0,0 @@ -package integration - -import ( - "runtime" - "testing" - - "github.com/buildkite/agent/v3/internal/job" - "github.com/buildkite/bintest/v3" -) - -func argumentForCommand(cmd string) any { - // This is unpleasant, but we have to work around the fact that we generate - // batch scripts for windows and plain commands for everything else - if runtime.GOOS == "windows" { - return bintest.MatchPattern("buildkite-script-.+.bat$") - } - return cmd -} - -func TestRunningCommandWithDocker(t *testing.T) { - tester, err := NewExecutorTester(mainCtx) - if err != nil { - t.Fatalf("NewExecutorTester() error = %v", err) - } - defer tester.Close() - - // Mock out the meta-data calls to the agent after checkout - agent := tester.MockAgent(t) - agent. - Expect("meta-data", "exists", job.CommitMetadataKey). - AndExitWith(0) - - env := []string{ - "BUILDKITE_DOCKER=llamas", - } - - jobId := "1111-1111-1111-1111" - imageId := "buildkite_" + jobId + "_image" - containerId := "buildkite_" + jobId + "_container" - - docker := tester.MustMock(t, "docker") - docker.ExpectAll([][]any{ - {"build", "-f", "Dockerfile", "-t", imageId, "."}, - {"run", "--name", containerId, imageId, argumentForCommand("true")}, - {"rm", "-f", "-v", containerId}, - }) - - expectCommandHooks("0", t, tester) - - tester.RunAndCheck(t, env...) -} - -func TestRunningCommandWithDockerAndCustomDockerfile(t *testing.T) { - tester, err := NewExecutorTester(mainCtx) - if err != nil { - t.Fatalf("NewExecutorTester() error = %v", err) - } - defer tester.Close() - - // Mock out the meta-data calls to the agent after checkout - agent := tester.MockAgent(t) - agent. - Expect("meta-data", "exists", job.CommitMetadataKey). - AndExitWith(0) - - env := []string{ - "BUILDKITE_DOCKER=llamas", - "BUILDKITE_DOCKER_FILE=Dockerfile.llamas", - } - - jobId := "1111-1111-1111-1111" - imageId := "buildkite_" + jobId + "_image" - containerId := "buildkite_" + jobId + "_container" - - docker := tester.MustMock(t, "docker") - docker.ExpectAll([][]any{ - {"build", "-f", "Dockerfile.llamas", "-t", imageId, "."}, - {"run", "--name", containerId, imageId, argumentForCommand("true")}, - {"rm", "-f", "-v", containerId}, - }) - - expectCommandHooks("0", t, tester) - - tester.RunAndCheck(t, env...) -} - -func TestRunningFailingCommandWithDocker(t *testing.T) { - tester, err := NewExecutorTester(mainCtx) - if err != nil { - t.Fatalf("NewExecutorTester() error = %v", err) - } - defer tester.Close() - - // Mock out the meta-data calls to the agent after checkout - agent := tester.MockAgent(t) - agent. - Expect("meta-data", "exists", job.CommitMetadataKey). - AndExitWith(0) - - env := []string{ - "BUILDKITE_DOCKER=llamas", - } - - jobId := "1111-1111-1111-1111" - imageId := "buildkite_" + jobId + "_image" - containerId := "buildkite_" + jobId + "_container" - - docker := tester.MustMock(t, "docker") - docker.ExpectAll([][]any{ - {"build", "-f", "Dockerfile", "-t", imageId, "."}, - {"rm", "-f", "-v", containerId}, - }) - - docker.Expect("run", "--name", containerId, imageId, argumentForCommand("true")). - AndExitWith(1) - - expectCommandHooks("1", t, tester) - - if err = tester.Run(t, env...); err == nil { - t.Fatalf("tester.Run(t, %v) = %v, want non-nil error", env, err) - } - - tester.CheckMocks(t) -} - -func TestRunningCommandWithDockerCompose(t *testing.T) { - tester, err := NewExecutorTester(mainCtx) - if err != nil { - t.Fatalf("NewExecutorTester() error = %v", err) - } - defer tester.Close() - - // Mock out the meta-data calls to the agent after checkout - agent := tester.MockAgent(t) - agent. - Expect("meta-data", "exists", job.CommitMetadataKey). - AndExitWith(0) - - env := []string{ - "BUILDKITE_DOCKER_COMPOSE_CONTAINER=llamas", - } - - projectName := "buildkite1111111111111111" - - dockerCompose := tester.MustMock(t, "docker-compose") - dockerCompose.ExpectAll([][]any{ - {"-f", "docker-compose.yml", "-p", projectName, "--verbose", "build", "--pull", "llamas"}, - {"-f", "docker-compose.yml", "-p", projectName, "--verbose", "run", "llamas", argumentForCommand("true")}, - {"-f", "docker-compose.yml", "-p", projectName, "--verbose", "kill"}, - {"-f", "docker-compose.yml", "-p", projectName, "--verbose", "rm", "--force", "--all", "-v"}, - {"-f", "docker-compose.yml", "-p", projectName, "--verbose", "down"}, - }) - - expectCommandHooks("0", t, tester) - - tester.RunAndCheck(t, env...) -} - -func TestRunningFailingCommandWithDockerCompose(t *testing.T) { - tester, err := NewExecutorTester(mainCtx) - if err != nil { - t.Fatalf("NewExecutorTester() error = %v", err) - } - defer tester.Close() - - // Mock out the meta-data calls to the agent after checkout - agent := tester.MockAgent(t) - agent. - Expect("meta-data", "exists", job.CommitMetadataKey). - AndExitWith(0) - - env := []string{ - "BUILDKITE_DOCKER_COMPOSE_CONTAINER=llamas", - } - - projectName := "buildkite1111111111111111" - - dockerCompose := tester.MustMock(t, "docker-compose") - dockerCompose.ExpectAll([][]any{ - {"-f", "docker-compose.yml", "-p", projectName, "--verbose", "build", "--pull", "llamas"}, - {"-f", "docker-compose.yml", "-p", projectName, "--verbose", "kill"}, - {"-f", "docker-compose.yml", "-p", projectName, "--verbose", "rm", "--force", "--all", "-v"}, - {"-f", "docker-compose.yml", "-p", projectName, "--verbose", "down"}, - }) - - dockerCompose.Expect("-f", "docker-compose.yml", "-p", projectName, "--verbose", "run", "llamas", argumentForCommand("true")). - AndWriteToStderr("Nope!"). - AndExitWith(1) - - expectCommandHooks("1", t, tester) - - if err = tester.Run(t, env...); err == nil { - t.Fatalf("tester.Run(t, %v) = %v, want non-nil error", env, err) - } - - tester.CheckMocks(t) -} - -func TestRunningCommandWithDockerComposeAndExtraConfig(t *testing.T) { - tester, err := NewExecutorTester(mainCtx) - if err != nil { - t.Fatalf("NewExecutorTester() error = %v", err) - } - defer tester.Close() - - // Mock out the meta-data calls to the agent after checkout - agent := tester.MockAgent(t) - agent. - Expect("meta-data", "exists", job.CommitMetadataKey). - AndExitWith(0) - - env := []string{ - "BUILDKITE_DOCKER_COMPOSE_CONTAINER=llamas", - "BUILDKITE_DOCKER_COMPOSE_FILE=dc1.yml:dc2.yml:dc3.yml", - } - - projectName := "buildkite1111111111111111" - - dockerCompose := tester.MustMock(t, "docker-compose") - dockerCompose.ExpectAll([][]any{ - {"-f", "dc1.yml", "-f", "dc2.yml", "-f", "dc3.yml", "-p", projectName, "--verbose", "build", "--pull", "llamas"}, - {"-f", "dc1.yml", "-f", "dc2.yml", "-f", "dc3.yml", "-p", projectName, "--verbose", "run", "llamas", argumentForCommand("true")}, - {"-f", "dc1.yml", "-f", "dc2.yml", "-f", "dc3.yml", "-p", projectName, "--verbose", "kill"}, - {"-f", "dc1.yml", "-f", "dc2.yml", "-f", "dc3.yml", "-p", projectName, "--verbose", "rm", "--force", "--all", "-v"}, - {"-f", "dc1.yml", "-f", "dc2.yml", "-f", "dc3.yml", "-p", projectName, "--verbose", "down"}, - }) - - expectCommandHooks("0", t, tester) - - tester.RunAndCheck(t, env...) -} - -func TestRunningCommandWithDockerComposeAndBuildAll(t *testing.T) { - tester, err := NewExecutorTester(mainCtx) - if err != nil { - t.Fatalf("NewExecutorTester() error = %v", err) - } - defer tester.Close() - - // Mock out the meta-data calls to the agent after checkout - agent := tester.MockAgent(t) - agent. - Expect("meta-data", "exists", job.CommitMetadataKey). - AndExitWith(0) - - env := []string{ - "BUILDKITE_DOCKER_COMPOSE_CONTAINER=llamas", - "BUILDKITE_DOCKER_COMPOSE_BUILD_ALL=true", - } - - dockerCompose := tester.MustMock(t, "docker-compose") - dockerCompose.IgnoreUnexpectedInvocations() - dockerCompose.Expect("-f", "docker-compose.yml", "-p", "buildkite1111111111111111", "--verbose", "build", "--pull").Once() - - tester.RunAndCheck(t, env...) -} - -func expectCommandHooks(exitStatus string, t *testing.T, tester *ExecutorTester) { - tester.ExpectGlobalHook("pre-command").Once() - tester.ExpectLocalHook("pre-command").Once() - tester.ExpectGlobalHook("post-command").Once() - tester.ExpectLocalHook("post-command").Once() - - preExitFunc := func(c *bintest.Call) { - if got, want := c.GetEnv("BUILDKITE_COMMAND_EXIT_STATUS"), exitStatus; got != want { - t.Errorf("c.GetEnv(BUILDKITE_COMMAND_EXIT_STATUS) = %q, want %q", got, want) - } - c.Exit(0) - } - - tester.ExpectGlobalHook("pre-exit").Once().AndCallFunc(preExitFunc) - tester.ExpectLocalHook("pre-exit").Once().AndCallFunc(preExitFunc) -} diff --git a/internal/job/integration/executor_tester.go b/internal/job/integration/executor_tester.go index bc22448b6f..70ffaa5964 100644 --- a/internal/job/integration/executor_tester.go +++ b/internal/job/integration/executor_tester.go @@ -18,12 +18,11 @@ import ( "syscall" "testing" - "github.com/buildkite/agent/v3/clicommand" - "github.com/buildkite/agent/v3/env" - "github.com/buildkite/agent/v3/internal/experiments" - "github.com/buildkite/agent/v3/internal/job" - "github.com/buildkite/agent/v3/internal/shell" - + "github.com/buildkite/agent/v4/clicommand" + "github.com/buildkite/agent/v4/env" + "github.com/buildkite/agent/v4/internal/experiments" + "github.com/buildkite/agent/v4/internal/job" + "github.com/buildkite/agent/v4/internal/shell" "github.com/buildkite/bintest/v3" ) diff --git a/internal/job/integration/hooks_integration_test.go b/internal/job/integration/hooks_integration_test.go index b95683ce30..84e89d4e7f 100644 --- a/internal/job/integration/hooks_integration_test.go +++ b/internal/job/integration/hooks_integration_test.go @@ -11,8 +11,8 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/internal/job" - "github.com/buildkite/agent/v3/internal/shell" + "github.com/buildkite/agent/v4/internal/job" + "github.com/buildkite/agent/v4/internal/shell" "github.com/buildkite/bintest/v3" ) diff --git a/internal/job/integration/job_api_integration_test.go b/internal/job/integration/job_api_integration_test.go index 18f4a5f5f6..cf032bda7b 100644 --- a/internal/job/integration/job_api_integration_test.go +++ b/internal/job/integration/job_api_integration_test.go @@ -10,7 +10,7 @@ import ( "net/http" "testing" - "github.com/buildkite/agent/v3/jobapi" + "github.com/buildkite/agent/v4/jobapi" "github.com/buildkite/bintest/v3" ) diff --git a/internal/job/integration/main_test.go b/internal/job/integration/main_test.go index 0aaece751c..dd7ff305f0 100644 --- a/internal/job/integration/main_test.go +++ b/internal/job/integration/main_test.go @@ -7,9 +7,9 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/clicommand" - "github.com/buildkite/agent/v3/internal/experiments" - "github.com/buildkite/agent/v3/version" + "github.com/buildkite/agent/v4/clicommand" + "github.com/buildkite/agent/v4/internal/experiments" + "github.com/buildkite/agent/v4/version" "github.com/buildkite/bintest/v3" "github.com/urfave/cli" ) diff --git a/internal/job/integration/plugin_integration_test.go b/internal/job/integration/plugin_integration_test.go index 344a48c563..3b801b3c3b 100644 --- a/internal/job/integration/plugin_integration_test.go +++ b/internal/job/integration/plugin_integration_test.go @@ -12,8 +12,8 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/internal/experiments" - "github.com/buildkite/agent/v3/internal/shell" + "github.com/buildkite/agent/v4/internal/experiments" + "github.com/buildkite/agent/v4/internal/shell" "github.com/buildkite/bintest/v3" ) diff --git a/internal/job/integration/redaction_integration_test.go b/internal/job/integration/redaction_integration_test.go index dc11558c9e..819c1a5bff 100644 --- a/internal/job/integration/redaction_integration_test.go +++ b/internal/job/integration/redaction_integration_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/jobapi" + "github.com/buildkite/agent/v4/jobapi" "github.com/buildkite/bintest/v3" ) diff --git a/internal/job/integration/secrets_integration_test.go b/internal/job/integration/secrets_integration_test.go index 192d893b37..1538ae3ef6 100644 --- a/internal/job/integration/secrets_integration_test.go +++ b/internal/job/integration/secrets_integration_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/jobapi" + "github.com/buildkite/agent/v4/jobapi" "github.com/buildkite/bintest/v3" "github.com/buildkite/go-pipeline" ) diff --git a/internal/job/integration/test-binary-hook/BUILD.bazel b/internal/job/integration/test-binary-hook/BUILD.bazel index 689f67bd50..7f9978b8c4 100644 --- a/internal/job/integration/test-binary-hook/BUILD.bazel +++ b/internal/job/integration/test-binary-hook/BUILD.bazel @@ -3,7 +3,7 @@ load("@rules_go//go:def.bzl", "go_binary", "go_library") go_library( name = "test-binary-hook_lib", srcs = ["main.go"], - importpath = "github.com/buildkite/agent/v3/internal/job/integration/test-binary-hook", + importpath = "github.com/buildkite/agent/v4/internal/job/integration/test-binary-hook", visibility = ["//visibility:private"], deps = ["//jobapi"], ) diff --git a/internal/job/integration/test-binary-hook/main.go b/internal/job/integration/test-binary-hook/main.go index 19581cffc9..a26d3ee140 100644 --- a/internal/job/integration/test-binary-hook/main.go +++ b/internal/job/integration/test-binary-hook/main.go @@ -5,7 +5,7 @@ import ( "fmt" "log" - "github.com/buildkite/agent/v3/jobapi" + "github.com/buildkite/agent/v4/jobapi" ) // This file gets built and commited to this repo, then used as part of the hooks integration test to ensure that the diff --git a/internal/job/knownhosts.go b/internal/job/knownhosts.go index 37fb5028cb..db86fc57ca 100644 --- a/internal/job/knownhosts.go +++ b/internal/job/knownhosts.go @@ -9,8 +9,8 @@ import ( "strings" "time" - "github.com/buildkite/agent/v3/internal/osutil" - "github.com/buildkite/agent/v3/internal/shell" + "github.com/buildkite/agent/v4/internal/osutil" + "github.com/buildkite/agent/v4/internal/shell" "golang.org/x/crypto/ssh/knownhosts" ) diff --git a/internal/job/knownhosts_test.go b/internal/job/knownhosts_test.go index 0ca51904d5..3292017d50 100644 --- a/internal/job/knownhosts_test.go +++ b/internal/job/knownhosts_test.go @@ -7,7 +7,7 @@ import ( "os" "testing" - "github.com/buildkite/agent/v3/internal/shell" + "github.com/buildkite/agent/v4/internal/shell" "github.com/gliderlabs/ssh" ) diff --git a/internal/job/plugin.go b/internal/job/plugin.go index b996e6c908..0fddd6e3b4 100644 --- a/internal/job/plugin.go +++ b/internal/job/plugin.go @@ -13,10 +13,10 @@ import ( "strings" "time" - "github.com/buildkite/agent/v3/agent/plugin" - "github.com/buildkite/agent/v3/internal/experiments" - "github.com/buildkite/agent/v3/internal/job/hook" - "github.com/buildkite/agent/v3/internal/osutil" + "github.com/buildkite/agent/v4/agent/plugin" + "github.com/buildkite/agent/v4/internal/experiments" + "github.com/buildkite/agent/v4/internal/job/hook" + "github.com/buildkite/agent/v4/internal/osutil" "github.com/buildkite/roko" "github.com/buildkite/shellwords" ) @@ -163,6 +163,10 @@ func (e *Executor) PluginPhase(ctx context.Context) error { // Store the checkouts for future use e.pluginCheckouts = checkouts + // Create a reversed copy of the slice + e.pluginCheckoutsReversed = slices.Clone(e.pluginCheckouts) + slices.Reverse(e.pluginCheckoutsReversed) + // Now we can run plugin environment hooks too return e.executePluginHook(ctx, "environment", checkouts) } @@ -210,6 +214,10 @@ func (e *Executor) VendoredPluginPhase(ctx context.Context) error { // Finally append our vendored checkouts to the rest for subsequent hooks e.pluginCheckouts = append(e.pluginCheckouts, vendoredCheckouts...) + // Create a reversed copy of the slice + e.pluginCheckoutsReversed = slices.Clone(e.pluginCheckouts) + slices.Reverse(e.pluginCheckoutsReversed) + // Now we can run plugin environment hooks too return e.executePluginHook(ctx, "environment", vendoredCheckouts) } @@ -255,18 +263,7 @@ func (e *Executor) executePluginHook(ctx context.Context, name string, checkouts hookTypeSeen[name] = true envMap, err := p.ConfigurationToEnvironment() - if dnerr := (&plugin.DeprecatedNameErrors{}); errors.As(err, &dnerr) { - e.shell.Headerf("Deprecated environment variables for plugin %s", p.Plugin.Name()) - e.shell.Printf("%s", strings.Join([]string{ - "The way that environment variables are derived from the plugin configuration is changing.", - "We'll export both the deprecated and the replacement names for now,", - "You may be able to avoid this by removing consecutive underscore, hyphen, or whitespace", - "characters in your plugin configuration.", - }, " ")) - for _, err := range dnerr.Unwrap() { - e.shell.Printf("%s", err.Error()) - } - } else if err != nil { + if err != nil { e.shell.Warningf("Error configuring plugin environment: %s", err) } diff --git a/internal/job/plugin_zip.go b/internal/job/plugin_zip.go index 63f0316881..bfcfc8698a 100644 --- a/internal/job/plugin_zip.go +++ b/internal/job/plugin_zip.go @@ -15,10 +15,10 @@ import ( "strings" "time" - "github.com/buildkite/agent/v3/agent/plugin" - "github.com/buildkite/agent/v3/internal/agenthttp" - "github.com/buildkite/agent/v3/internal/osutil" - "github.com/buildkite/agent/v3/version" + "github.com/buildkite/agent/v4/agent/plugin" + "github.com/buildkite/agent/v4/internal/agenthttp" + "github.com/buildkite/agent/v4/internal/osutil" + "github.com/buildkite/agent/v4/version" "github.com/buildkite/roko" ) diff --git a/internal/job/ssh.go b/internal/job/ssh.go index dab26dbb33..e9b7690e80 100644 --- a/internal/job/ssh.go +++ b/internal/job/ssh.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "github.com/buildkite/agent/v3/internal/shell" + "github.com/buildkite/agent/v4/internal/shell" "github.com/buildkite/roko" ) diff --git a/internal/job/ssh_test.go b/internal/job/ssh_test.go index caa8c50b34..818172deca 100644 --- a/internal/job/ssh_test.go +++ b/internal/job/ssh_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/internal/shell" + "github.com/buildkite/agent/v4/internal/shell" "github.com/buildkite/bintest/v3" ) diff --git a/internal/job/tracing.go b/internal/job/tracing.go index caaf13e63a..89822c3793 100644 --- a/internal/job/tracing.go +++ b/internal/job/tracing.go @@ -5,14 +5,12 @@ import ( "fmt" "maps" "os" - "slices" "strconv" "strings" - "github.com/buildkite/agent/v3/env" - "github.com/buildkite/agent/v3/tracetools" - "github.com/buildkite/agent/v3/version" - "github.com/opentracing/opentracing-go" + "github.com/buildkite/agent/v4/env" + "github.com/buildkite/agent/v4/tracetools" + "github.com/buildkite/agent/v4/version" "go.opentelemetry.io/contrib/propagators/aws/xray" "go.opentelemetry.io/contrib/propagators/b3" "go.opentelemetry.io/contrib/propagators/jaeger" @@ -26,90 +24,28 @@ import ( sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.4.0" "go.opentelemetry.io/otel/trace" - ddext "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext" - "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/opentracer" - "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" ) -// stopper lets us abstract the tracer wrap up code so we can plug in different tracing -// library implementations that are opentracing compatible. Opentracing itself -// doesn't have a Stop function on its Tracer interface. +// stopper lets us abstract the tracer wrap up code. type stopper func() func noopStopper() {} -func (e *Executor) startTracing(ctx context.Context) (tracetools.Span, context.Context, stopper) { +func (e *Executor) startTracing(ctx context.Context) (trace.Span, context.Context, stopper) { switch e.TracingBackend { - case tracetools.BackendDatadog: - // Newer versions of the tracing libs print out diagnostic info which spams the - // Buildkite agent logs. Disable it by default unless it's been explicitly set. - if _, has := os.LookupEnv("DD_TRACE_STARTUP_LOGS"); !has { - if err := os.Setenv("DD_TRACE_STARTUP_LOGS", "false"); err != nil { - e.shell.Warningf("Couldn't set DD_TRACE_STARTUP_LOGS: %v", err) - } - } - - return e.startTracingDatadog(ctx) - case tracetools.BackendOpenTelemetry: return e.startTracingOpenTelemetry(ctx) case tracetools.BackendNone: - return &tracetools.NoopSpan{}, ctx, noopStopper + span, ctx := tracetools.StartSpanFromContext(ctx, "noop", tracetools.BackendNone) + return span, ctx, noopStopper default: e.shell.Commentf("An invalid tracing backend was provided: %q. Tracing will not occur.", e.TracingBackend) e.TracingBackend = tracetools.BackendNone // Ensure that we don't do any tracing after this, some of the stuff in tracetools uses the job's tracking backend - return &tracetools.NoopSpan{}, ctx, noopStopper - } -} - -func (e *Executor) ddResourceName() string { - label, ok := e.shell.Env.Get("BUILDKITE_LABEL") - if !ok { - label = "job" - } - - return e.OrganizationSlug + "/" + e.PipelineSlug + "/" + label -} - -// startTracingDatadog sets up tracing based on the config values. It uses opentracing as an -// abstraction so the agent can support multiple libraries if needbe. -func (e *Executor) startTracingDatadog(ctx context.Context) (tracetools.Span, context.Context, stopper) { - opts := []tracer.StartOption{ - tracer.WithService(e.TracingServiceName), - tracer.WithSampler(tracer.NewAllSampler()), - tracer.WithAnalytics(true), - } - - tags := Merge(GenericTracingExtras(e, e.shell.Env), DDTracingExtras()) - opts = slices.Grow(opts, len(tags)) - for k, v := range tags { - opts = append(opts, tracer.WithGlobalTag(k, v)) - } - - opentracing.SetGlobalTracer(opentracer.New(opts...)) - - wireContext := e.extractDDTraceCtx() - - span := opentracing.StartSpan("job.run", - opentracing.ChildOf(wireContext), - opentracing.Tag{Key: ddext.ResourceName, Value: e.ddResourceName()}, - ) - ctx = opentracing.ContextWithSpan(ctx, span) - - return tracetools.NewOpenTracingSpan(span), ctx, tracer.Stop -} - -// extractTraceCtx pulls encoded distributed tracing information from the env vars. -// Note: This should match the injectTraceCtx code in shell. -func (e *Executor) extractDDTraceCtx() opentracing.SpanContext { - sctx, err := tracetools.DecodeTraceContext(e.shell.Env.Dump(), e.TraceContextCodec) - if err != nil { - // Return nil so a new span will be created - return nil + span, ctx := tracetools.StartSpanFromContext(ctx, "noop", tracetools.BackendNone) + return span, ctx, noopStopper } - return sctx } func (e *Executor) otRootSpanName() string { @@ -127,7 +63,7 @@ func (e *Executor) otRootSpanName() string { return base + "job" } -func (e *Executor) startTracingOpenTelemetry(ctx context.Context) (tracetools.Span, context.Context, stopper) { +func (e *Executor) startTracingOpenTelemetry(ctx context.Context) (trace.Span, context.Context, stopper) { // Set up trace exporter based on protocol protocol := os.Getenv("OTEL_EXPORTER_OTLP_PROTOCOL") // default to grpc to avoid breaking change @@ -144,11 +80,13 @@ func (e *Executor) startTracingOpenTelemetry(ctx context.Context) (tracetools.Sp exporter, err = otlptracehttp.New(ctx) default: e.shell.Errorf("Unsupported OTLP protocol: %s. Disabling tracing.", protocol) - return &tracetools.NoopSpan{}, ctx, noopStopper + span, ctx := tracetools.StartSpanFromContext(ctx, "noop", tracetools.BackendNone) + return span, ctx, noopStopper } if err != nil { e.shell.Errorf("Error creating OTLP trace exporter %s. Disabling tracing.", err) - return &tracetools.NoopSpan{}, ctx, noopStopper + span, ctx := tracetools.StartSpanFromContext(ctx, "noop", tracetools.BackendNone) + return span, ctx, noopStopper } attributes := []attribute.KeyValue{ @@ -187,7 +125,7 @@ func (e *Executor) startTracingOpenTelemetry(ctx context.Context) (tracetools.Sp trace.WithSchemaURL(semconv.SchemaURL), ) - ctx = e.contextWithTraceparentIfEnabled(ctx) + ctx = e.contextWithTraceparentIfPresent(ctx) ctx, span := tracer.Start(ctx, e.otRootSpanName(), trace.WithAttributes( attribute.String("analytics.event", "true"), @@ -200,19 +138,14 @@ func (e *Executor) startTracingOpenTelemetry(ctx context.Context) (tracetools.Sp _ = tracerProvider.Shutdown(ctx) } - return tracetools.NewOpenTelemetrySpan(span), ctx, stop + return span, ctx, stop } // accepting traceparent from Buildkite control plane is an opt-in feature as its // technically a breaking change to the behaviour, and if the server-side tracing // isn't set up correctly, agent traces may end up without root spans to link to -func (e *Executor) contextWithTraceparentIfEnabled(ctx context.Context) context.Context { - if !e.TracingPropagateTraceparent { - return ctx - } - +func (e *Executor) contextWithTraceparentIfPresent(ctx context.Context) context.Context { if e.TracingTraceParent == "" { - e.shell.Warningf("tracing-propagate-traceparent enabled, but no traceparent provided by server") return ctx } @@ -297,13 +230,6 @@ func GenericTracingExtras(e *Executor, env *env.Environment) map[string]any { return result } -func DDTracingExtras() map[string]any { - return map[string]any{ - ddext.AnalyticsEvent: true, - ddext.SamplingPriority: ddext.PriorityUserKeep, - } -} - func Merge(ms ...map[string]any) map[string]any { fullCap := 0 for _, m := range ms { @@ -336,14 +262,3 @@ func toOpenTelemetryAttributes(extras map[string]any) ([]attribute.KeyValue, map return attrs, unknownAttrTypes } - -func (e *Executor) implementationSpecificSpanName(otelName, ddName string) string { - switch e.TracingBackend { - case tracetools.BackendDatadog: - return ddName - case tracetools.BackendOpenTelemetry: - fallthrough - default: - return otelName - } -} diff --git a/internal/mime/BUILD.bazel b/internal/mime/BUILD.bazel index cd2d20065a..bc1c507380 100644 --- a/internal/mime/BUILD.bazel +++ b/internal/mime/BUILD.bazel @@ -3,7 +3,7 @@ load("@rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "mime", srcs = ["mime.go"], - importpath = "github.com/buildkite/agent/v3/internal/mime", + importpath = "github.com/buildkite/agent/v4/internal/mime", visibility = ["//:__subpackages__"], ) diff --git a/internal/olfactor/BUILD.bazel b/internal/olfactor/BUILD.bazel index ffe586bb34..2847579d13 100644 --- a/internal/olfactor/BUILD.bazel +++ b/internal/olfactor/BUILD.bazel @@ -3,7 +3,7 @@ load("@rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "olfactor", srcs = ["olfactor.go"], - importpath = "github.com/buildkite/agent/v3/internal/olfactor", + importpath = "github.com/buildkite/agent/v4/internal/olfactor", visibility = ["//:__subpackages__"], deps = [ "//internal/replacer", diff --git a/internal/olfactor/olfactor.go b/internal/olfactor/olfactor.go index b6aa4a5ff1..d9cdf253bf 100644 --- a/internal/olfactor/olfactor.go +++ b/internal/olfactor/olfactor.go @@ -3,8 +3,8 @@ package olfactor import ( "io" - "github.com/buildkite/agent/v3/internal/replacer" - "github.com/buildkite/agent/v3/internal/trie" + "github.com/buildkite/agent/v4/internal/replacer" + "github.com/buildkite/agent/v4/internal/trie" ) // Olfactor may be used for 'sniffing' an io stream for strings. In other diff --git a/internal/olfactor/olfactor_test.go b/internal/olfactor/olfactor_test.go index 8fa1ff1442..88a9700c55 100644 --- a/internal/olfactor/olfactor_test.go +++ b/internal/olfactor/olfactor_test.go @@ -4,7 +4,7 @@ import ( "io" "testing" - "github.com/buildkite/agent/v3/internal/olfactor" + "github.com/buildkite/agent/v4/internal/olfactor" ) func TestOlfactor(t *testing.T) { diff --git a/internal/osutil/BUILD.bazel b/internal/osutil/BUILD.bazel index ebcfe302e6..1c748c80fc 100644 --- a/internal/osutil/BUILD.bazel +++ b/internal/osutil/BUILD.bazel @@ -10,7 +10,7 @@ go_library( "umask.go", "umask_unix.go", ], - importpath = "github.com/buildkite/agent/v3/internal/osutil", + importpath = "github.com/buildkite/agent/v4/internal/osutil", visibility = ["//:__subpackages__"], deps = select({ "@rules_go//go/platform:aix": [ diff --git a/internal/process/BUILD.bazel b/internal/process/BUILD.bazel index 01cd24770d..90782d7196 100644 --- a/internal/process/BUILD.bazel +++ b/internal/process/BUILD.bazel @@ -16,7 +16,7 @@ go_library( "signal_windows.go", "timestamper.go", ], - importpath = "github.com/buildkite/agent/v3/internal/process", + importpath = "github.com/buildkite/agent/v4/internal/process", visibility = ["//visibility:public"], deps = [ "//internal/experiments", diff --git a/internal/process/main_test.go b/internal/process/main_test.go index 185a997e25..b57054c245 100644 --- a/internal/process/main_test.go +++ b/internal/process/main_test.go @@ -10,7 +10,7 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/internal/process" + "github.com/buildkite/agent/v4/internal/process" ) // Invoked by `go test`, switch between helper and running tests based on env diff --git a/internal/process/process.go b/internal/process/process.go index fb1ee0f1e9..9fa4424f68 100644 --- a/internal/process/process.go +++ b/internal/process/process.go @@ -17,8 +17,8 @@ import ( "syscall" "time" - "github.com/buildkite/agent/v3/internal/experiments" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/internal/experiments" + "github.com/buildkite/agent/v4/logger" ) const ( diff --git a/internal/process/process_test.go b/internal/process/process_test.go index b573a6b30e..a5c1e69961 100644 --- a/internal/process/process_test.go +++ b/internal/process/process_test.go @@ -13,9 +13,9 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/internal/experiments" - "github.com/buildkite/agent/v3/internal/process" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/internal/experiments" + "github.com/buildkite/agent/v4/internal/process" + "github.com/buildkite/agent/v4/logger" ) func TestProcessOutput(t *testing.T) { diff --git a/internal/process/run.go b/internal/process/run.go index 72cbfc75c3..4ec61ab89c 100644 --- a/internal/process/run.go +++ b/internal/process/run.go @@ -4,7 +4,7 @@ import ( "os/exec" "strings" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) func Run(l logger.Logger, command string, arg ...string) (string, error) { diff --git a/internal/process/scanner.go b/internal/process/scanner.go index 090dd8cf25..3da3d2208e 100644 --- a/internal/process/scanner.go +++ b/internal/process/scanner.go @@ -4,7 +4,7 @@ import ( "bufio" "io" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) type Scanner struct { diff --git a/internal/process/scanner_test.go b/internal/process/scanner_test.go index b2f5b767fb..fff9703f6d 100644 --- a/internal/process/scanner_test.go +++ b/internal/process/scanner_test.go @@ -8,8 +8,8 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/internal/process" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/internal/process" + "github.com/buildkite/agent/v4/logger" "github.com/google/go-cmp/cmp" ) diff --git a/internal/process/signal_test.go b/internal/process/signal_test.go index cfd09314be..ec3626d17d 100644 --- a/internal/process/signal_test.go +++ b/internal/process/signal_test.go @@ -5,7 +5,7 @@ import ( "syscall" "testing" - "github.com/buildkite/agent/v3/internal/process" + "github.com/buildkite/agent/v4/internal/process" ) func TestSignalStringUnix(t *testing.T) { diff --git a/internal/process/timestamper_test.go b/internal/process/timestamper_test.go index cb6e7ad2ca..0bbca064f1 100644 --- a/internal/process/timestamper_test.go +++ b/internal/process/timestamper_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/internal/process" + "github.com/buildkite/agent/v4/internal/process" "github.com/google/go-cmp/cmp" ) diff --git a/internal/ptr/BUILD.bazel b/internal/ptr/BUILD.bazel index a2da047c22..6094cd8de0 100644 --- a/internal/ptr/BUILD.bazel +++ b/internal/ptr/BUILD.bazel @@ -3,6 +3,6 @@ load("@rules_go//go:def.bzl", "go_library") go_library( name = "ptr", srcs = ["to.go"], - importpath = "github.com/buildkite/agent/v3/internal/ptr", + importpath = "github.com/buildkite/agent/v4/internal/ptr", visibility = ["//:__subpackages__"], ) diff --git a/internal/race/BUILD.bazel b/internal/race/BUILD.bazel index 8067e09f15..805787bb03 100644 --- a/internal/race/BUILD.bazel +++ b/internal/race/BUILD.bazel @@ -6,6 +6,6 @@ go_library( "race_disabled.go", "race_enabled.go", ], - importpath = "github.com/buildkite/agent/v3/internal/race", + importpath = "github.com/buildkite/agent/v4/internal/race", visibility = ["//:__subpackages__"], ) diff --git a/internal/redact/BUILD.bazel b/internal/redact/BUILD.bazel index 62c827c670..ad260fda15 100644 --- a/internal/redact/BUILD.bazel +++ b/internal/redact/BUILD.bazel @@ -3,7 +3,7 @@ load("@rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "redact", srcs = ["redact.go"], - importpath = "github.com/buildkite/agent/v3/internal/redact", + importpath = "github.com/buildkite/agent/v4/internal/redact", visibility = ["//:__subpackages__"], deps = [ "//env", diff --git a/internal/redact/redact.go b/internal/redact/redact.go index 72f952fe36..2588f871df 100644 --- a/internal/redact/redact.go +++ b/internal/redact/redact.go @@ -10,8 +10,8 @@ import ( "slices" "strings" - "github.com/buildkite/agent/v3/env" - "github.com/buildkite/agent/v3/internal/replacer" + "github.com/buildkite/agent/v4/env" + "github.com/buildkite/agent/v4/internal/replacer" ) // LengthMin is the shortest string length that will be considered a diff --git a/internal/redact/redact_test.go b/internal/redact/redact_test.go index 8d035fc636..815b48fc1c 100644 --- a/internal/redact/redact_test.go +++ b/internal/redact/redact_test.go @@ -3,7 +3,7 @@ package redact import ( "testing" - "github.com/buildkite/agent/v3/env" + "github.com/buildkite/agent/v4/env" "github.com/google/go-cmp/cmp" ) diff --git a/internal/replacer/BUILD.bazel b/internal/replacer/BUILD.bazel index 34c6c88f42..2f0fc6628c 100644 --- a/internal/replacer/BUILD.bazel +++ b/internal/replacer/BUILD.bazel @@ -6,7 +6,7 @@ go_library( "mux.go", "replacer.go", ], - importpath = "github.com/buildkite/agent/v3/internal/replacer", + importpath = "github.com/buildkite/agent/v4/internal/replacer", visibility = ["//:__subpackages__"], ) diff --git a/internal/replacer/replacer_test.go b/internal/replacer/replacer_test.go index 10457a4690..a0df33c155 100644 --- a/internal/replacer/replacer_test.go +++ b/internal/replacer/replacer_test.go @@ -8,8 +8,8 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/internal/redact" - "github.com/buildkite/agent/v3/internal/replacer" + "github.com/buildkite/agent/v4/internal/redact" + "github.com/buildkite/agent/v4/internal/replacer" "github.com/google/go-cmp/cmp" ) diff --git a/internal/secrets/BUILD.bazel b/internal/secrets/BUILD.bazel index 60a0f34675..6ef087e265 100644 --- a/internal/secrets/BUILD.bazel +++ b/internal/secrets/BUILD.bazel @@ -6,7 +6,7 @@ go_library( "doc.go", "secret.go", ], - importpath = "github.com/buildkite/agent/v3/internal/secrets", + importpath = "github.com/buildkite/agent/v4/internal/secrets", visibility = ["//:__subpackages__"], deps = [ "//api", diff --git a/internal/secrets/secret.go b/internal/secrets/secret.go index 3f14be944f..3291f0438b 100644 --- a/internal/secrets/secret.go +++ b/internal/secrets/secret.go @@ -6,8 +6,8 @@ import ( "sync" "time" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/roko" "golang.org/x/sync/semaphore" ) diff --git a/internal/secrets/secret_test.go b/internal/secrets/secret_test.go index edf95cffb9..d224ce12ea 100644 --- a/internal/secrets/secret_test.go +++ b/internal/secrets/secret_test.go @@ -16,8 +16,8 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/buildkite/agent/v3/api" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/api" + "github.com/buildkite/agent/v4/logger" ) var noSleep = WithRetrySleepFunc(func(time.Duration) {}) diff --git a/internal/self/BUILD.bazel b/internal/self/BUILD.bazel index c5965487a3..2aa3c1ba20 100644 --- a/internal/self/BUILD.bazel +++ b/internal/self/BUILD.bazel @@ -3,6 +3,6 @@ load("@rules_go//go:def.bzl", "go_library") go_library( name = "self", srcs = ["self.go"], - importpath = "github.com/buildkite/agent/v3/internal/self", + importpath = "github.com/buildkite/agent/v4/internal/self", visibility = ["//:__subpackages__"], ) diff --git a/internal/shell/BUILD.bazel b/internal/shell/BUILD.bazel index 05d65aca36..6829bf9c39 100644 --- a/internal/shell/BUILD.bazel +++ b/internal/shell/BUILD.bazel @@ -10,7 +10,7 @@ go_library( "shell.go", "test.go", ], - importpath = "github.com/buildkite/agent/v3/internal/shell", + importpath = "github.com/buildkite/agent/v4/internal/shell", visibility = ["//:__subpackages__"], deps = [ "//env", diff --git a/internal/shell/logger_test.go b/internal/shell/logger_test.go index dd8ea7ab3e..1b2ebc1fe0 100644 --- a/internal/shell/logger_test.go +++ b/internal/shell/logger_test.go @@ -7,7 +7,7 @@ import ( "runtime" "testing" - "github.com/buildkite/agent/v3/internal/shell" + "github.com/buildkite/agent/v4/internal/shell" "github.com/google/go-cmp/cmp" ) diff --git a/internal/shell/main_test.go b/internal/shell/main_test.go index 621c8221e1..1581a95f40 100644 --- a/internal/shell/main_test.go +++ b/internal/shell/main_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/internal/shell" + "github.com/buildkite/agent/v4/internal/shell" ) var errMissingFilename = errors.New("missing file name") diff --git a/internal/shell/shell.go b/internal/shell/shell.go index 8c1ae877c3..5b2f7e5aae 100644 --- a/internal/shell/shell.go +++ b/internal/shell/shell.go @@ -19,15 +19,13 @@ import ( "syscall" "time" - "github.com/buildkite/agent/v3/env" - "github.com/buildkite/agent/v3/internal/olfactor" - "github.com/buildkite/agent/v3/internal/process" - "github.com/buildkite/agent/v3/internal/shellscript" - "github.com/buildkite/agent/v3/logger" - "github.com/buildkite/agent/v3/tracetools" + "github.com/buildkite/agent/v4/env" + "github.com/buildkite/agent/v4/internal/olfactor" + "github.com/buildkite/agent/v4/internal/process" + "github.com/buildkite/agent/v4/internal/shellscript" + "github.com/buildkite/agent/v4/logger" "github.com/buildkite/shellwords" "github.com/gofrs/flock" - "github.com/opentracing/opentracing-go" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" "go.opentelemetry.io/otel/trace" @@ -81,9 +79,6 @@ type Shell struct { // Defaults to [os.Stdout]. stdout io.Writer - // How to encode trace contexts. - traceContextCodec tracetools.Codec - // Current working directory that shell commands get executed in wd string } @@ -107,14 +102,9 @@ func WithSignalGracePeriod(d time.Duration) NewShellOpt { return func(s *Shell) { s.signalGracePeriod = d } } -func WithTraceContextCodec(c tracetools.Codec) NewShellOpt { - return func(s *Shell) { s.traceContextCodec = c } -} - // New returns a new Shell. The default stdout is [os.Stdout], the default logger // writes to [os.Stderr], the initial working directory is the result of calling -// [os.Getwd], the default environment variable set is read from [os.Environ], -// and the default trace context encoding is Gob. +// [os.Getwd], and the default environment variable set is read from [os.Environ]. func New(opts ...NewShellOpt) (*Shell, error) { // Start with an empty shell. shell := &Shell{} @@ -134,9 +124,6 @@ func New(opts ...NewShellOpt) (*Shell, error) { if shell.stdout == nil { shell.stdout = os.Stdout } - if shell.traceContextCodec == nil { - shell.traceContextCodec = tracetools.CodecGob{} - } if shell.wd == "" { wd, err := os.Getwd() if err != nil { @@ -164,7 +151,6 @@ func (s *Shell) CloneWithStdin(r io.Reader) *Shell { wd: s.wd, interruptSignal: s.interruptSignal, signalGracePeriod: s.signalGracePeriod, - traceContextCodec: s.traceContextCodec, } } @@ -549,16 +535,6 @@ func WithStringSearch(m map[string]bool) RunCommandOpt { return func(c *runConfi // injectTraceCtx adds tracing information to the given env vars to support // distributed tracing across jobs/builds. func (s *Shell) injectTraceCtx(ctx context.Context, env *env.Environment) { - // OpenTracing path (for Datadog backend) - if span := opentracing.SpanFromContext(ctx); span != nil { - if err := tracetools.EncodeTraceContext(span, env.Dump(), s.traceContextCodec); err != nil { - if s.debug { - s.Warningf("Failed to encode trace context: %v", err) - } - } - return - } - // OpenTelemetry path (for OpenTelemetry backend) if span := trace.SpanFromContext(ctx); span.SpanContext().IsValid() { carrier := propagation.MapCarrier{} diff --git a/internal/shell/shell_test.go b/internal/shell/shell_test.go index fe0ce6b5c0..3dea64d056 100644 --- a/internal/shell/shell_test.go +++ b/internal/shell/shell_test.go @@ -15,9 +15,9 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/internal/process" - "github.com/buildkite/agent/v3/internal/replacer" - "github.com/buildkite/agent/v3/internal/shell" + "github.com/buildkite/agent/v4/internal/process" + "github.com/buildkite/agent/v4/internal/replacer" + "github.com/buildkite/agent/v4/internal/shell" "github.com/buildkite/bintest/v3" "github.com/google/go-cmp/cmp" ) diff --git a/internal/shell/test.go b/internal/shell/test.go index 62d4cceaad..95931b55f2 100644 --- a/internal/shell/test.go +++ b/internal/shell/test.go @@ -6,7 +6,7 @@ import ( "runtime" "testing" - "github.com/buildkite/agent/v3/env" + "github.com/buildkite/agent/v4/env" ) // NewTestShell creates a shell with suitable defaults for tests. Note that it diff --git a/internal/shellscript/BUILD.bazel b/internal/shellscript/BUILD.bazel index f9b3e8f84e..bc6957eba4 100644 --- a/internal/shellscript/BUILD.bazel +++ b/internal/shellscript/BUILD.bazel @@ -3,7 +3,7 @@ load("@rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "shellscript", srcs = ["shellscript.go"], - importpath = "github.com/buildkite/agent/v3/internal/shellscript", + importpath = "github.com/buildkite/agent/v4/internal/shellscript", visibility = ["//:__subpackages__"], deps = ["@com_github_buildkite_shellwords//:shellwords"], ) diff --git a/internal/socket/BUILD.bazel b/internal/socket/BUILD.bazel index cb89cac8ac..498c79318d 100644 --- a/internal/socket/BUILD.bazel +++ b/internal/socket/BUILD.bazel @@ -11,7 +11,7 @@ go_library( "server.go", "utils.go", ], - importpath = "github.com/buildkite/agent/v3/internal/socket", + importpath = "github.com/buildkite/agent/v4/internal/socket", visibility = ["//:__subpackages__"], deps = select({ "@rules_go//go/platform:windows": [ diff --git a/internal/stdin/BUILD.bazel b/internal/stdin/BUILD.bazel index 24e2bac888..e2623d9e88 100644 --- a/internal/stdin/BUILD.bazel +++ b/internal/stdin/BUILD.bazel @@ -3,7 +3,7 @@ load("@rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "stdin", srcs = ["stdin.go"], - importpath = "github.com/buildkite/agent/v3/internal/stdin", + importpath = "github.com/buildkite/agent/v4/internal/stdin", visibility = ["//:__subpackages__"], ) diff --git a/internal/stdin/main_test.go b/internal/stdin/main_test.go index 9055f8fce2..ddbcaacf1b 100644 --- a/internal/stdin/main_test.go +++ b/internal/stdin/main_test.go @@ -7,7 +7,7 @@ import ( "runtime" "testing" - "github.com/buildkite/agent/v3/internal/stdin" + "github.com/buildkite/agent/v4/internal/stdin" ) // Derived from TestStatStdin in https://golang.org/src/os/os_test.go diff --git a/internal/system/BUILD.bazel b/internal/system/BUILD.bazel index 41f746aa5c..df9007fe6b 100644 --- a/internal/system/BUILD.bazel +++ b/internal/system/BUILD.bazel @@ -7,7 +7,7 @@ go_library( "version_dump.go", "version_dump_windows.go", ], - importpath = "github.com/buildkite/agent/v3/internal/system", + importpath = "github.com/buildkite/agent/v4/internal/system", visibility = ["//:__subpackages__"], deps = select({ "@rules_go//go/platform:aix": [ diff --git a/internal/system/version_dump.go b/internal/system/version_dump.go index 96777430b7..4338414d9e 100644 --- a/internal/system/version_dump.go +++ b/internal/system/version_dump.go @@ -5,8 +5,8 @@ package system import ( "runtime" - "github.com/buildkite/agent/v3/internal/process" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/internal/process" + "github.com/buildkite/agent/v4/logger" ) // Returns a dump of the raw operating system information diff --git a/internal/system/version_dump_windows.go b/internal/system/version_dump_windows.go index 39ba050ea6..9a7432021b 100644 --- a/internal/system/version_dump_windows.go +++ b/internal/system/version_dump_windows.go @@ -5,7 +5,7 @@ package system import ( "fmt" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" "golang.org/x/sys/windows" ) diff --git a/internal/tempfile/BUILD.bazel b/internal/tempfile/BUILD.bazel index 08aecb50c0..489dac0860 100644 --- a/internal/tempfile/BUILD.bazel +++ b/internal/tempfile/BUILD.bazel @@ -6,7 +6,7 @@ go_library( "doc.go", "tempfile.go", ], - importpath = "github.com/buildkite/agent/v3/internal/tempfile", + importpath = "github.com/buildkite/agent/v4/internal/tempfile", visibility = ["//:__subpackages__"], ) diff --git a/internal/tempfile/tempfile_test.go b/internal/tempfile/tempfile_test.go index d4cfc2c785..9dff8d61a7 100644 --- a/internal/tempfile/tempfile_test.go +++ b/internal/tempfile/tempfile_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/internal/tempfile" + "github.com/buildkite/agent/v4/internal/tempfile" ) func TestNew(t *testing.T) { diff --git a/internal/trie/BUILD.bazel b/internal/trie/BUILD.bazel index 5e7848c688..145ea63dc1 100644 --- a/internal/trie/BUILD.bazel +++ b/internal/trie/BUILD.bazel @@ -3,7 +3,7 @@ load("@rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "trie", srcs = ["trie.go"], - importpath = "github.com/buildkite/agent/v3/internal/trie", + importpath = "github.com/buildkite/agent/v4/internal/trie", visibility = ["//:__subpackages__"], ) diff --git a/internal/trie/trie_test.go b/internal/trie/trie_test.go index a730e2a1d4..2be7019135 100644 --- a/internal/trie/trie_test.go +++ b/internal/trie/trie_test.go @@ -3,7 +3,7 @@ package trie_test import ( "testing" - "github.com/buildkite/agent/v3/internal/trie" + "github.com/buildkite/agent/v4/internal/trie" "github.com/google/go-cmp/cmp" ) diff --git a/jobapi/BUILD.bazel b/jobapi/BUILD.bazel index 5da00c50d6..612bbea029 100644 --- a/jobapi/BUILD.bazel +++ b/jobapi/BUILD.bazel @@ -12,7 +12,7 @@ go_library( "server.go", "socket.go", ], - importpath = "github.com/buildkite/agent/v3/jobapi", + importpath = "github.com/buildkite/agent/v4/jobapi", visibility = ["//visibility:public"], deps = [ "//env", diff --git a/jobapi/client.go b/jobapi/client.go index 275f9492d1..9d3841b590 100644 --- a/jobapi/client.go +++ b/jobapi/client.go @@ -6,7 +6,7 @@ import ( "net/http" "os" - "github.com/buildkite/agent/v3/internal/socket" + "github.com/buildkite/agent/v4/internal/socket" ) const ( diff --git a/jobapi/client_test.go b/jobapi/client_test.go index 07680b2735..7d811240f5 100644 --- a/jobapi/client_test.go +++ b/jobapi/client_test.go @@ -13,7 +13,7 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/internal/socket" + "github.com/buildkite/agent/v4/internal/socket" "github.com/google/go-cmp/cmp" ) diff --git a/jobapi/env.go b/jobapi/env.go index ee96aeb4fb..6396738ae0 100644 --- a/jobapi/env.go +++ b/jobapi/env.go @@ -7,8 +7,8 @@ import ( "net/http" "slices" - "github.com/buildkite/agent/v3/env" - "github.com/buildkite/agent/v3/internal/socket" + "github.com/buildkite/agent/v4/env" + "github.com/buildkite/agent/v4/internal/socket" ) func (s *Server) getEnv(w http.ResponseWriter, _ *http.Request) { diff --git a/jobapi/payloads.go b/jobapi/payloads.go index e69c139c05..dbc4870da8 100644 --- a/jobapi/payloads.go +++ b/jobapi/payloads.go @@ -3,7 +3,7 @@ package jobapi import ( "sort" - "github.com/buildkite/agent/v3/internal/socket" + "github.com/buildkite/agent/v4/internal/socket" ) // ErrorResponse is the response body for any errors that occur. diff --git a/jobapi/redactions.go b/jobapi/redactions.go index bca16436e2..2f779bf80e 100644 --- a/jobapi/redactions.go +++ b/jobapi/redactions.go @@ -5,7 +5,7 @@ import ( "fmt" "net/http" - "github.com/buildkite/agent/v3/internal/socket" + "github.com/buildkite/agent/v4/internal/socket" ) func (s *Server) createRedaction(w http.ResponseWriter, r *http.Request) { diff --git a/jobapi/routes.go b/jobapi/routes.go index 35e40ee766..3056235496 100644 --- a/jobapi/routes.go +++ b/jobapi/routes.go @@ -3,7 +3,7 @@ package jobapi import ( "net/http" - "github.com/buildkite/agent/v3/internal/socket" + "github.com/buildkite/agent/v4/internal/socket" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" ) diff --git a/jobapi/server.go b/jobapi/server.go index ba24159aeb..07c42c9368 100644 --- a/jobapi/server.go +++ b/jobapi/server.go @@ -7,10 +7,10 @@ import ( "sync" "time" - "github.com/buildkite/agent/v3/env" - "github.com/buildkite/agent/v3/internal/replacer" - "github.com/buildkite/agent/v3/internal/shell" - "github.com/buildkite/agent/v3/internal/socket" + "github.com/buildkite/agent/v4/env" + "github.com/buildkite/agent/v4/internal/replacer" + "github.com/buildkite/agent/v4/internal/shell" + "github.com/buildkite/agent/v4/internal/socket" ) // ServerOpts provides a way to configure a Server diff --git a/jobapi/server_test.go b/jobapi/server_test.go index a18c958a6f..2601b78f5a 100644 --- a/jobapi/server_test.go +++ b/jobapi/server_test.go @@ -15,11 +15,11 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/env" - "github.com/buildkite/agent/v3/internal/redact" - "github.com/buildkite/agent/v3/internal/replacer" - "github.com/buildkite/agent/v3/internal/shell" - "github.com/buildkite/agent/v3/jobapi" + "github.com/buildkite/agent/v4/env" + "github.com/buildkite/agent/v4/internal/redact" + "github.com/buildkite/agent/v4/internal/replacer" + "github.com/buildkite/agent/v4/internal/shell" + "github.com/buildkite/agent/v4/jobapi" "github.com/google/go-cmp/cmp" ) diff --git a/kubernetes/BUILD.bazel b/kubernetes/BUILD.bazel index f644b3d4ff..77798fabec 100644 --- a/kubernetes/BUILD.bazel +++ b/kubernetes/BUILD.bazel @@ -9,7 +9,7 @@ go_library( "umask.go", "umask_windows.go", ], - importpath = "github.com/buildkite/agent/v3/kubernetes", + importpath = "github.com/buildkite/agent/v4/kubernetes", visibility = ["//visibility:public"], deps = [ "//internal/process", diff --git a/kubernetes/kubernetes_test.go b/kubernetes/kubernetes_test.go index 8a5e2df8c0..f1dc053b5d 100644 --- a/kubernetes/kubernetes_test.go +++ b/kubernetes/kubernetes_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) func TestOrderedClients(t *testing.T) { diff --git a/kubernetes/runner.go b/kubernetes/runner.go index f1bb88ce58..328782533c 100644 --- a/kubernetes/runner.go +++ b/kubernetes/runner.go @@ -15,8 +15,8 @@ import ( "syscall" "time" - "github.com/buildkite/agent/v3/internal/process" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/internal/process" + "github.com/buildkite/agent/v4/logger" ) func init() { diff --git a/lock/BUILD.bazel b/lock/BUILD.bazel index 97c1df4659..117892bb5f 100644 --- a/lock/BUILD.bazel +++ b/lock/BUILD.bazel @@ -3,7 +3,7 @@ load("@rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "lock", srcs = ["lock.go"], - importpath = "github.com/buildkite/agent/v3/lock", + importpath = "github.com/buildkite/agent/v4/lock", visibility = ["//visibility:public"], deps = ["//internal/agentapi"], ) diff --git a/lock/lock.go b/lock/lock.go index 7ccbd389f2..b3dd71a7df 100644 --- a/lock/lock.go +++ b/lock/lock.go @@ -12,7 +12,7 @@ import ( "sync" "time" - "github.com/buildkite/agent/v3/internal/agentapi" + "github.com/buildkite/agent/v4/internal/agentapi" ) // For local sockets, we can afford to be fairly chatty. 100ms is an arbitrary diff --git a/lock/lock_test.go b/lock/lock_test.go index 6a34a0aa87..b3ebc16fb5 100644 --- a/lock/lock_test.go +++ b/lock/lock_test.go @@ -10,8 +10,8 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/internal/agentapi" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/internal/agentapi" + "github.com/buildkite/agent/v4/logger" ) var testSocketCounter uint32 diff --git a/logger/BUILD.bazel b/logger/BUILD.bazel index 877e08ae0e..0850e96ce7 100644 --- a/logger/BUILD.bazel +++ b/logger/BUILD.bazel @@ -9,7 +9,7 @@ go_library( "level.go", "log.go", ], - importpath = "github.com/buildkite/agent/v3/logger", + importpath = "github.com/buildkite/agent/v4/logger", visibility = ["//visibility:public"], deps = [ "//version", diff --git a/logger/buffer_test.go b/logger/buffer_test.go index a35b22ad22..03151024d0 100644 --- a/logger/buffer_test.go +++ b/logger/buffer_test.go @@ -3,7 +3,7 @@ package logger_test import ( "testing" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" "github.com/google/go-cmp/cmp" ) diff --git a/logger/log.go b/logger/log.go index b7884b16df..c2ccdf7794 100644 --- a/logger/log.go +++ b/logger/log.go @@ -16,7 +16,7 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/version" + "github.com/buildkite/agent/v4/version" "golang.org/x/term" ) diff --git a/logger/log_test.go b/logger/log_test.go index 8a5083b9fd..d7ffbbf93f 100644 --- a/logger/log_test.go +++ b/logger/log_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" ) func TestConsoleLogger(t *testing.T) { diff --git a/main.go b/main.go index 174e5704e6..1ea304f244 100644 --- a/main.go +++ b/main.go @@ -10,8 +10,8 @@ import ( "fmt" "os" - "github.com/buildkite/agent/v3/clicommand" - "github.com/buildkite/agent/v3/version" + "github.com/buildkite/agent/v4/clicommand" + "github.com/buildkite/agent/v4/version" "github.com/urfave/cli" ) diff --git a/metrics/BUILD.bazel b/metrics/BUILD.bazel index 5f359df4c3..a27d435bdf 100644 --- a/metrics/BUILD.bazel +++ b/metrics/BUILD.bazel @@ -3,10 +3,17 @@ load("@rules_go//go:def.bzl", "go_library") go_library( name = "metrics", srcs = ["metrics.go"], - importpath = "github.com/buildkite/agent/v3/metrics", + importpath = "github.com/buildkite/agent/v4/metrics", visibility = ["//visibility:public"], deps = [ "//logger", - "@com_github_datadog_datadog_go_v5//statsd", + "//version", + "@io_opentelemetry_go_otel//attribute", + "@io_opentelemetry_go_otel//semconv/v1.4.0:v1_4_0", + "@io_opentelemetry_go_otel_exporters_otlp_otlpmetric_otlpmetricgrpc//:otlpmetricgrpc", + "@io_opentelemetry_go_otel_exporters_otlp_otlpmetric_otlpmetrichttp//:otlpmetrichttp", + "@io_opentelemetry_go_otel_metric//:metric", + "@io_opentelemetry_go_otel_sdk//metric", + "@io_opentelemetry_go_otel_sdk//resource", ], ) diff --git a/metrics/metrics.go b/metrics/metrics.go index e63b050524..71fbbbc5d8 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -1,77 +1,170 @@ -// Package metrics provides a wrapper around Datadog metrics collection. +// Package metrics provides a wrapper around OpenTelemetry metrics collection. // // It is intended for internal use by buildkite-agent only. package metrics import ( + "context" + "errors" "fmt" + "os" "regexp" "sort" - "strings" + "sync" "time" - "github.com/DataDog/datadog-go/v5/statsd" - "github.com/buildkite/agent/v3/logger" + "github.com/buildkite/agent/v4/logger" + "github.com/buildkite/agent/v4/version" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" + otelmetric "go.opentelemetry.io/otel/metric" + sdkmetric "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/resource" + semconv "go.opentelemetry.io/otel/semconv/v1.4.0" ) const ( - // Number of statsd commands that are buffered before - // being sent to statsd - statsdBufferLen = 10 - - // The default port for dogstatsd - defaultDogStatsdPort = 8125 + defaultOTLPProtocol = "grpc" + defaultServiceName = "buildkite-agent" ) type Collector struct { config CollectorConfig logger logger.Logger - client *statsd.Client + + mu sync.Mutex + started int + provider *sdkmetric.MeterProvider + meter otelmetric.Meter + counters map[string]otelmetric.Int64Counter + histograms map[string]otelmetric.Float64Histogram } type CollectorConfig struct { - Datadog bool - DatadogHost string - DatadogDistributions bool + Enabled bool + ServiceName string } func NewCollector(l logger.Logger, c CollectorConfig) *Collector { + if c.ServiceName == "" { + c.ServiceName = defaultServiceName + } + return &Collector{ - config: c, - logger: l, + config: c, + logger: l, + counters: make(map[string]otelmetric.Int64Counter), + histograms: make(map[string]otelmetric.Float64Histogram), } } -var portSuffixRegexp = regexp.MustCompile(`:\d+$`) - func (c *Collector) Start() error { - if c.config.Datadog { - if !portSuffixRegexp.MatchString(c.config.DatadogHost) { - c.config.DatadogHost += fmt.Sprintf(":%d", defaultDogStatsdPort) - } + c.mu.Lock() + defer c.mu.Unlock() - c.logger.Info("Starting datadog metrics collection to %s", c.config.DatadogHost) + c.started++ + if c.started > 1 { + return nil + } - var err error - c.client, err = statsd.New(c.config.DatadogHost, - statsd.WithMaxMessagesPerPayload(statsdBufferLen), - statsd.WithNamespace("buildkite."), - ) - if err != nil { - return err - } + if !c.config.Enabled { + return nil } + + protocol := otlpProtocol() + c.logger.Info("Starting OpenTelemetry metrics collection using OTLP/%s", protocol) + + provider, err := c.newMeterProvider(context.Background(), protocol) + if err != nil { + c.started-- + return err + } + + c.provider = provider + c.meter = provider.Meter( + "buildkite-agent", + otelmetric.WithInstrumentationVersion(version.Version()), + otelmetric.WithSchemaURL(semconv.SchemaURL), + ) + c.counters = make(map[string]otelmetric.Int64Counter) + c.histograms = make(map[string]otelmetric.Float64Histogram) return nil } func (c *Collector) Stop() error { - if c.config.Datadog && c.client != nil { + c.mu.Lock() + if c.started == 0 { + c.mu.Unlock() + return nil + } + + c.started-- + if c.started > 0 { + c.mu.Unlock() + return nil + } + + provider := c.provider + c.provider = nil + c.meter = nil + c.counters = make(map[string]otelmetric.Int64Counter) + c.histograms = make(map[string]otelmetric.Float64Histogram) + c.mu.Unlock() + + if provider != nil { c.logger.Info("Stopping metrics collection") - return c.client.Close() + + ctx := context.Background() + flushErr := provider.ForceFlush(ctx) + shutdownErr := provider.Shutdown(ctx) + return errors.Join(flushErr, shutdownErr) } + return nil } +func (c *Collector) newMeterProvider(ctx context.Context, protocol string) (*sdkmetric.MeterProvider, error) { + var ( + exporter sdkmetric.Exporter + err error + ) + + switch protocol { + case "grpc": + exporter, err = otlpmetricgrpc.New(ctx) + case "http/protobuf", "http": + exporter, err = otlpmetrichttp.New(ctx) + default: + return nil, fmt.Errorf("unsupported OTLP protocol %q", protocol) + } + if err != nil { + return nil, err + } + + resources := resource.NewWithAttributes( + semconv.SchemaURL, + semconv.ServiceNameKey.String(c.config.ServiceName), + semconv.ServiceVersionKey.String(version.Version()), + semconv.DeploymentEnvironmentKey.String("ci"), + ) + + return sdkmetric.NewMeterProvider( + sdkmetric.WithReader(sdkmetric.NewPeriodicReader(exporter)), + sdkmetric.WithResource(resources), + ), nil +} + +func otlpProtocol() string { + if protocol := os.Getenv("OTEL_EXPORTER_OTLP_METRICS_PROTOCOL"); protocol != "" { + return protocol + } + if protocol := os.Getenv("OTEL_EXPORTER_OTLP_PROTOCOL"); protocol != "" { + return protocol + } + return defaultOTLPProtocol +} + func (c *Collector) Scope(tags Tags) *Scope { return &Scope{ Tags: tags, @@ -86,28 +179,14 @@ type Scope struct { // Timing sends timing information in milliseconds. func (s *Scope) Timing(name string, value time.Duration, tags ...Tags) { - if s.c.client == nil { + histogram, ok := s.c.histogram(name) + if !ok { return } - mergedTags := s.mergeTags(tags...).StringSlice() - s.c.logger.Debug("Metrics timing %s=%v %v", name, value, mergedTags) - - var err error - if s.c.config.DatadogDistributions { - // Datadog recommends that, as distributions are a new distinct metric, - // they belong to a new metric name. We handle this by just slamming - // .distribution to end of all metrics that we submit this way - if !strings.HasSuffix(name, ".distribution") { - name = name + ".distribution" - } - err = s.c.client.Distribution(name, float64(value.Milliseconds()), mergedTags, 1) - } else { - err = s.c.client.Timing(name, value, mergedTags, 1) - } - if err != nil { - s.c.logger.Error("Metrics timing failed: %v", err) - } + mergedTags := s.mergeTags(tags...) + s.c.logger.Debug("Metrics timing %s=%v %v", name, value, mergedTags.StringSlice()) + histogram.Record(context.Background(), float64(value.Milliseconds()), otelmetric.WithAttributes(mergedTags.Attributes()...)) } // With returns a scope with more tags added @@ -118,18 +197,62 @@ func (s *Scope) With(tags Tags) *Scope { } } -// Count tracks how many times something happened per second. +// Count tracks how many times something happened. func (s *Scope) Count(name string, value int64, tags ...Tags) { - if s.c.client == nil { + counter, ok := s.c.counter(name) + if !ok { return } - mergedTags := s.mergeTags(tags...).StringSlice() - s.c.logger.Debug("Metrics count %s=%v %v", name, value, mergedTags) + mergedTags := s.mergeTags(tags...) + s.c.logger.Debug("Metrics count %s=%v %v", name, value, mergedTags.StringSlice()) + counter.Add(context.Background(), value, otelmetric.WithAttributes(mergedTags.Attributes()...)) +} + +func (c *Collector) counter(name string) (otelmetric.Int64Counter, bool) { + metricName := formatName(name) + + c.mu.Lock() + defer c.mu.Unlock() + + if c.meter == nil { + return nil, false + } + if counter, ok := c.counters[metricName]; ok { + return counter, true + } + + counter, err := c.meter.Int64Counter(metricName) + if err != nil { + c.logger.Error("Metrics counter creation failed: %v", err) + return nil, false + } + + c.counters[metricName] = counter + return counter, true +} + +func (c *Collector) histogram(name string) (otelmetric.Float64Histogram, bool) { + metricName := formatName(name) + + c.mu.Lock() + defer c.mu.Unlock() - if err := s.c.client.Count(name, value, mergedTags, 1); err != nil { - s.c.logger.Error("Metrics count failed: %v", err) + if c.meter == nil { + return nil, false + } + if histogram, ok := c.histograms[metricName]; ok { + return histogram, true + } + + histogram, err := c.meter.Float64Histogram(metricName, otelmetric.WithUnit("ms")) + if err != nil { + c.logger.Error("Metrics histogram creation failed: %v", err) + return nil, false } + + c.histograms[metricName] = histogram + return histogram, true } func (s *Scope) mergeTags(tagsSlice ...Tags) Tags { @@ -147,6 +270,16 @@ func (s *Scope) mergeTags(tagsSlice ...Tags) Tags { type Tags map[string]string +func (tags Tags) Attributes() []attribute.KeyValue { + attrs := make([]attribute.KeyValue, 0, len(tags)) + for k, v := range tags { + if k != "" && v != "" { + attrs = append(attrs, attribute.String(formatName(k), formatName(v))) + } + } + return attrs +} + func (tags Tags) StringSlice() []string { var stringSlice []string for k, v := range tags { @@ -158,8 +291,7 @@ func (tags Tags) StringSlice() []string { return stringSlice } -// Datadog allows '.', '_' and alphas only. -// If we don't validate this here then the datadog error logs can fill up disk really quickly +// Keep metric names and tag keys portable across OpenTelemetry exporters. var nameRegex = regexp.MustCompile(`[^\._a-zA-Z0-9]+`) func formatName(name string) string { diff --git a/packaging/linux/root/usr/share/buildkite-agent/buildkite-agent.cfg b/packaging/linux/root/usr/share/buildkite-agent/buildkite-agent.cfg index 98f4e35cef..f68c78b84a 100644 --- a/packaging/linux/root/usr/share/buildkite-agent/buildkite-agent.cfg +++ b/packaging/linux/root/usr/share/buildkite-agent/buildkite-agent.cfg @@ -66,16 +66,9 @@ plugins-path="/etc/buildkite-agent/plugins" # Don't show colors in logging # no-color=true -# The next two options are relevant to the Datadog integration, available 3.7.0 and on -# See https://buildkite.com/docs/agent/v3/configuration#metrics-datadog -# Send metrics to DogStatsD running on metrics-datadog-host -# metrics-datadog=true - -# Host to collect Buildkite metrics -# datadog-agent will need to run DogStatsD, presumed on port 8125. -# See https://buildkite.com/docs/agent/v3/configuration#metrics-datadog-host -# Specify port below like my-host:8126 if not using 8125 -# metrics-datadog-host=127.0.0.1 +# Enable OpenTelemetry metrics export over OTLP. +# Configure the endpoint and protocol with the standard OTEL_EXPORTER_OTLP_* env vars. +# opentelemetry-metrics=true # If set and valid, the given tracing backend will be enabled. Eg: datadog, opentelemetry # tracing-backend="" diff --git a/packaging/linux/root/usr/share/buildkite-agent/hooks/checkout.sample b/packaging/linux/root/usr/share/buildkite-agent/hooks/checkout.sample index b91c233688..e3e490314e 100755 --- a/packaging/linux/root/usr/share/buildkite-agent/hooks/checkout.sample +++ b/packaging/linux/root/usr/share/buildkite-agent/hooks/checkout.sample @@ -5,6 +5,6 @@ # behaviour # Note that as the script is sourced not run directly, the shebang line will be ignored -# See https://buildkite.com/docs/agent/v3/hooks#creating-hook-scripts +# See https://buildkite.com/docs/agent/v4/hooks#creating-hook-scripts set -e diff --git a/packaging/linux/root/usr/share/buildkite-agent/hooks/command.sample b/packaging/linux/root/usr/share/buildkite-agent/hooks/command.sample index 7d16de425b..d207fb4f96 100755 --- a/packaging/linux/root/usr/share/buildkite-agent/hooks/command.sample +++ b/packaging/linux/root/usr/share/buildkite-agent/hooks/command.sample @@ -4,6 +4,6 @@ # the build command. # Note that as the script is sourced not run directly, the shebang line will be ignored -# See https://buildkite.com/docs/agent/v3/hooks#creating-hook-scripts +# See https://buildkite.com/docs/agent/v4/hooks#creating-hook-scripts set -e diff --git a/packaging/linux/root/usr/share/buildkite-agent/hooks/environment.sample b/packaging/linux/root/usr/share/buildkite-agent/hooks/environment.sample index 8628211f7e..28ce88f72c 100755 --- a/packaging/linux/root/usr/share/buildkite-agent/hooks/environment.sample +++ b/packaging/linux/root/usr/share/buildkite-agent/hooks/environment.sample @@ -9,6 +9,6 @@ # export SECRET_VAR=token # Note that as the script is sourced not run directly, the shebang line will be ignored -# See https://buildkite.com/docs/agent/v3/hooks#creating-hook-scripts +# See https://buildkite.com/docs/agent/v4/hooks#creating-hook-scripts set -e diff --git a/packaging/linux/root/usr/share/buildkite-agent/hooks/post-artifact.sample b/packaging/linux/root/usr/share/buildkite-agent/hooks/post-artifact.sample index 0eeaf06a0a..b7c82dc7b8 100755 --- a/packaging/linux/root/usr/share/buildkite-agent/hooks/post-artifact.sample +++ b/packaging/linux/root/usr/share/buildkite-agent/hooks/post-artifact.sample @@ -3,6 +3,6 @@ # The `post-artifact` hook will run just after artifacts are uploaded # Note that as the script is sourced not run directly, the shebang line will be ignored -# See https://buildkite.com/docs/agent/v3/hooks#creating-hook-scripts +# See https://buildkite.com/docs/agent/v4/hooks#creating-hook-scripts set -e diff --git a/packaging/linux/root/usr/share/buildkite-agent/hooks/post-checkout.sample b/packaging/linux/root/usr/share/buildkite-agent/hooks/post-checkout.sample index 9dc4ee510e..05c4d8defa 100755 --- a/packaging/linux/root/usr/share/buildkite-agent/hooks/post-checkout.sample +++ b/packaging/linux/root/usr/share/buildkite-agent/hooks/post-checkout.sample @@ -4,6 +4,6 @@ # your pipelines source code. # Note that as the script is sourced not run directly, the shebang line will be ignored -# See https://buildkite.com/docs/agent/v3/hooks#creating-hook-scripts +# See https://buildkite.com/docs/agent/v4/hooks#creating-hook-scripts set -e diff --git a/packaging/linux/root/usr/share/buildkite-agent/hooks/post-command.sample b/packaging/linux/root/usr/share/buildkite-agent/hooks/post-command.sample index 4a0190e99d..e9840a12a8 100755 --- a/packaging/linux/root/usr/share/buildkite-agent/hooks/post-command.sample +++ b/packaging/linux/root/usr/share/buildkite-agent/hooks/post-command.sample @@ -4,6 +4,6 @@ # build commands # Note that as the script is sourced not run directly, the shebang line will be ignored -# See https://buildkite.com/docs/agent/v3/hooks#creating-hook-scripts +# See https://buildkite.com/docs/agent/v4/hooks#creating-hook-scripts set -e diff --git a/packaging/linux/root/usr/share/buildkite-agent/hooks/pre-artifact.sample b/packaging/linux/root/usr/share/buildkite-agent/hooks/pre-artifact.sample index 8a7a9f3776..8216736751 100755 --- a/packaging/linux/root/usr/share/buildkite-agent/hooks/pre-artifact.sample +++ b/packaging/linux/root/usr/share/buildkite-agent/hooks/pre-artifact.sample @@ -3,6 +3,6 @@ # The `pre-artifact` hook will run just before artifacts are uploaded # Note that as the script is sourced not run directly, the shebang line will be ignored -# See https://buildkite.com/docs/agent/v3/hooks#creating-hook-scripts +# See https://buildkite.com/docs/agent/v4/hooks#creating-hook-scripts set -e diff --git a/packaging/linux/root/usr/share/buildkite-agent/hooks/pre-checkout.sample b/packaging/linux/root/usr/share/buildkite-agent/hooks/pre-checkout.sample index 66a628eea8..d5937ab1d6 100755 --- a/packaging/linux/root/usr/share/buildkite-agent/hooks/pre-checkout.sample +++ b/packaging/linux/root/usr/share/buildkite-agent/hooks/pre-checkout.sample @@ -4,7 +4,7 @@ # checked out from your SCM provider # Note that as the script is sourced not run directly, the shebang line will be ignored -# See https://buildkite.com/docs/agent/v3/hooks#creating-hook-scripts +# See https://buildkite.com/docs/agent/v4/hooks#creating-hook-scripts set -e diff --git a/packaging/linux/root/usr/share/buildkite-agent/hooks/pre-command.sample b/packaging/linux/root/usr/share/buildkite-agent/hooks/pre-command.sample index 0ce3102c8c..f83caf38f9 100755 --- a/packaging/linux/root/usr/share/buildkite-agent/hooks/pre-command.sample +++ b/packaging/linux/root/usr/share/buildkite-agent/hooks/pre-command.sample @@ -3,6 +3,6 @@ # The `pre-command` hook will run just before your build command runs # Note that as the script is sourced not run directly, the shebang line will be ignored -# See https://buildkite.com/docs/agent/v3/hooks#creating-hook-scripts +# See https://buildkite.com/docs/agent/v4/hooks#creating-hook-scripts set -e diff --git a/packaging/linux/root/usr/share/buildkite-agent/hooks/pre-exit.sample b/packaging/linux/root/usr/share/buildkite-agent/hooks/pre-exit.sample index 6e6f133a78..d152be50f7 100755 --- a/packaging/linux/root/usr/share/buildkite-agent/hooks/pre-exit.sample +++ b/packaging/linux/root/usr/share/buildkite-agent/hooks/pre-exit.sample @@ -3,6 +3,6 @@ # The `pre-exit` hook will run just before your build job finishes # Note that as the script is sourced not run directly, the shebang line will be ignored -# See https://buildkite.com/docs/agent/v3/hooks#creating-hook-scripts +# See https://buildkite.com/docs/agent/v4/hooks#creating-hook-scripts set -e diff --git a/scripts/build-binary.sh b/scripts/build-binary.sh index 52b0c39932..b6d37a78eb 100755 --- a/scripts/build-binary.sh +++ b/scripts/build-binary.sh @@ -47,7 +47,7 @@ export CGO_ENABLED=0 "$(dirname $0)"/generate-acknowledgements.sh mkdir -p $BUILD_PATH -go build -v -ldflags "-X github.com/buildkite/agent/v3/version.buildNumber=${BUILD_NUMBER}" -o "${BUILD_PATH}/${BINARY_FILENAME}" . +go build -v -ldflags "-X github.com/buildkite/agent/v4/version.buildNumber=${BUILD_NUMBER}" -o "${BUILD_PATH}/${BINARY_FILENAME}" . chmod +x "${BUILD_PATH}/${BINARY_FILENAME}" diff --git a/status/BUILD.bazel b/status/BUILD.bazel index 1e025a5932..0af0567b25 100644 --- a/status/BUILD.bazel +++ b/status/BUILD.bazel @@ -4,7 +4,7 @@ go_library( name = "status", srcs = ["status.go"], embedsrcs = ["status.html.tmpl"], - importpath = "github.com/buildkite/agent/v3/status", + importpath = "github.com/buildkite/agent/v4/status", visibility = ["//visibility:public"], deps = ["//version"], ) diff --git a/status/status.go b/status/status.go index 49d40fda91..857330c338 100644 --- a/status/status.go +++ b/status/status.go @@ -20,7 +20,7 @@ import ( "sync" "time" - "github.com/buildkite/agent/v3/version" + "github.com/buildkite/agent/v4/version" ) const errorTmplSrc = `
❌ {{.Operation}}: {{.Error}}
diff --git a/status/status_test.go b/status/status_test.go index c28a472632..43fd272502 100644 --- a/status/status_test.go +++ b/status/status_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - "github.com/buildkite/agent/v3/version" + "github.com/buildkite/agent/v4/version" ) func TestSmokeErrorTemplate(t *testing.T) { diff --git a/test/fixtures/hook/BUILD.bazel b/test/fixtures/hook/BUILD.bazel index fe62039cb2..1e48a6e404 100644 --- a/test/fixtures/hook/BUILD.bazel +++ b/test/fixtures/hook/BUILD.bazel @@ -3,7 +3,7 @@ load("@rules_go//go:def.bzl", "go_binary", "go_library") go_library( name = "hook_lib", srcs = ["main.go"], - importpath = "github.com/buildkite/agent/v3/test/fixtures/hook", + importpath = "github.com/buildkite/agent/v4/test/fixtures/hook", visibility = ["//visibility:private"], ) diff --git a/tracetools/BUILD.bazel b/tracetools/BUILD.bazel index 19de24916b..302aab8ae2 100644 --- a/tracetools/BUILD.bazel +++ b/tracetools/BUILD.bazel @@ -7,7 +7,7 @@ go_library( "propagate.go", "span.go", ], - importpath = "github.com/buildkite/agent/v3/tracetools", + importpath = "github.com/buildkite/agent/v4/tracetools", visibility = ["//visibility:public"], deps = [ "@com_github_opentracing_opentracing_go//:opentracing-go", diff --git a/tracetools/propagate.go b/tracetools/propagate.go deleted file mode 100644 index d901da896c..0000000000 --- a/tracetools/propagate.go +++ /dev/null @@ -1,97 +0,0 @@ -package tracetools - -import ( - "bytes" - "encoding/base64" - "encoding/gob" - "encoding/json" - "fmt" - "io" - - "github.com/opentracing/opentracing-go" - "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" -) - -// EnvVarTraceContextKey is the env var key that will be used to store/retrieve the -// encoded trace context information into env var maps. -const EnvVarTraceContextKey = "BUILDKITE_TRACE_CONTEXT" - -// EncodeTraceContext will serialize and encode tracing data into a string and place -// it into the given env vars map. -func EncodeTraceContext(span opentracing.Span, env map[string]string, codec Codec) error { - textmap := tracer.TextMapCarrier{} - if err := span.Tracer().Inject(span.Context(), opentracing.TextMap, &textmap); err != nil { - return err - } - - buf := bytes.NewBuffer(nil) - enc := codec.NewEncoder(buf) - if err := enc.Encode(textmap); err != nil { - return err - } - - env[EnvVarTraceContextKey] = base64.URLEncoding.EncodeToString(buf.Bytes()) - return nil -} - -// DecodeTraceContext will decode, deserialize, and extract the tracing data from the -// given env var map. -func DecodeTraceContext(env map[string]string, codec Codec) (opentracing.SpanContext, error) { - s, has := env[EnvVarTraceContextKey] - if !has { - return nil, opentracing.ErrSpanContextNotFound - } - - contextBytes, err := base64.URLEncoding.DecodeString(s) - if err != nil { - return nil, err - } - - dec := codec.NewDecoder(bytes.NewReader(contextBytes)) - textmap := opentracing.TextMapCarrier{} - if err := dec.Decode(&textmap); err != nil { - return nil, err - } - - return opentracing.GlobalTracer().Extract(opentracing.TextMap, textmap) -} - -// Encoder impls can encode values. Decoder impls can decode values. -type ( - Encoder interface{ Encode(v any) error } - Decoder interface{ Decode(v any) error } -) - -// Codec implementations produce encoders/decoders. -type Codec interface { - NewEncoder(io.Writer) Encoder - NewDecoder(io.Reader) Decoder - String() string -} - -// CodecGob marshals and unmarshals with https://pkg.go.dev/encoding/gob. -type CodecGob struct{} - -func (CodecGob) NewEncoder(w io.Writer) Encoder { return gob.NewEncoder(w) } -func (CodecGob) NewDecoder(r io.Reader) Decoder { return gob.NewDecoder(r) } -func (CodecGob) String() string { return "gob" } - -// CodecJSON marshals and unmarshals with https://pkg.go.dev/encoding/json. -type CodecJSON struct{} - -func (CodecJSON) NewEncoder(w io.Writer) Encoder { return json.NewEncoder(w) } -func (CodecJSON) NewDecoder(r io.Reader) Decoder { return json.NewDecoder(r) } -func (CodecJSON) String() string { return "json" } - -// ParseEncoding converts an encoding to the associated codec. -// An empty string is parsed as "gob". -func ParseEncoding(encoding string) (Codec, error) { - switch encoding { - case "", "gob": - return CodecGob{}, nil - case "json": - return CodecJSON{}, nil - default: - return nil, fmt.Errorf("invalid encoding %q", encoding) - } -} diff --git a/tracetools/propagate_example_test.go b/tracetools/propagate_example_test.go deleted file mode 100644 index ec3913a87f..0000000000 --- a/tracetools/propagate_example_test.go +++ /dev/null @@ -1,82 +0,0 @@ -package tracetools - -import ( - "fmt" - "time" - - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/mocktracer" - "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" -) - -func ExampleEncodeTraceContext() { - // Start and configure the tracer to use the propagator. - // A more realistic example would connect to, say, a real DataDog agent - // instead of using mocktracer. - t := mocktracer.New() - opentracing.SetGlobalTracer(t) - defer tracer.Stop() - - childEnv := map[string]string{} - - // Pretend this is the parent process' code - func() { - span := opentracing.StartSpan("parent process") - defer span.Finish() - - span.SetBaggageItem("asd", "zxc") - - // Do stuff.. - time.Sleep(time.Millisecond * 20) - - // Now say we want to launch a child process. - // Prepare it's env vars. This will be the carrier for the tracing data. - if err := EncodeTraceContext(span, childEnv, CodecGob{}); err != nil { - fmt.Println("oops an error for parent process trace injection") - } - // Now childEnv will contain the encoded data set with the env var key. - // Print stuff out for the purpose of the example test. - if childEnv["BUILDKITE_TRACE_CONTEXT"] == "" { - fmt.Println("oops empty tracing data in env vars") - } else { - fmt.Println("prepared child env carrier data") - } - - // Normally, you'd now launch a child process with code like: - // cmd := exec.Command("echo", "hello", "i", "am", "a", "child") - // cmd.Env = ... // Propagate the env vars here - // cmd.Run() - // The important thing is the Env propagation - }() - - // Pretend this is the child process' code - func() { - // Make sure tracing is setup the same way (same env var key) - // Normally you'd use os.Environ or similar here (the list of strings is - // supported). We're just reusing childEnv for test simplicity. - sctx, err := DecodeTraceContext(childEnv, CodecGob{}) - if err != nil { - fmt.Println("oops an error for child process trace extraction") - } else { - fmt.Println("extracted tracing data for child process") - } - - sctx.ForeachBaggageItem(func(k, v string) bool { - fmt.Printf("bag: %s=%s\n", k, v) - return true - }) - - // Now you can start a 'root' span for the child that will also be linked to - // the parent process. - span := opentracing.StartSpan("child process", opentracing.ChildOf(sctx)) - defer span.Finish() - - // Do stuff... - time.Sleep(time.Millisecond * 30) - }() - - // Output: - // prepared child env carrier data - // extracted tracing data for child process - // bag: asd=zxc -} diff --git a/tracetools/propagate_test.go b/tracetools/propagate_test.go deleted file mode 100644 index 65092df409..0000000000 --- a/tracetools/propagate_test.go +++ /dev/null @@ -1,150 +0,0 @@ -package tracetools - -import ( - "bytes" - "context" - "encoding/base64" - "encoding/gob" - "errors" - "maps" - "slices" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/mocktracer" -) - -func stubGlobalTracer() func() { - oriTracer := opentracing.GlobalTracer() - opentracing.SetGlobalTracer(mocktracer.New()) - return func() { - opentracing.SetGlobalTracer(oriTracer) - } -} - -func TestDecodeTraceContext(t *testing.T) { - t.Cleanup(stubGlobalTracer()) - - t.Run("No context info", func(t *testing.T) { - sctx, err := DecodeTraceContext(map[string]string{}, CodecGob{}) - if sctx != nil { - t.Errorf("DecodeTraceContext({}, gob) = %v, want nil", sctx) - } - if want := opentracing.ErrSpanContextNotFound; !errors.Is(err, want) { - t.Errorf("DecodeTraceContext({}, gob) error = %v, want %v", err, want) - } - }) - - t.Run("Invalid bsae64 context string", func(t *testing.T) { - sctx, err := DecodeTraceContext(map[string]string{ - EnvVarTraceContextKey: "asd", - }, CodecGob{}) - if sctx != nil { - t.Errorf("DecodeTraceContext({}, gob) = %v, want nil", sctx) - } - if want := base64.CorruptInputError(0); !errors.Is(err, want) { - t.Errorf("DecodeTraceContext({}, gob) error = %v, want %v", err, want) - } - }) - - t.Run("Invalid context data", func(t *testing.T) { - buf := bytes.NewBuffer([]byte{}) - err := gob.NewEncoder(buf).Encode("asd") - if err != nil { - t.Fatalf("gob.NewEncoder(buf).Encode(\"asd\") error = %v", err) - } - s := base64.URLEncoding.EncodeToString(buf.Bytes()) - input := map[string]string{EnvVarTraceContextKey: s} - sctx, err := DecodeTraceContext(input, CodecGob{}) - if sctx != nil { - t.Errorf("DecodeTraceContext(%v, gob) = %v, want nil", input, sctx) - } - if err == nil { // gob returns string errors, not typed errors... - t.Errorf("DecodeTraceContext(%v, gob) error = %v, want gob decoding error", input, err) - } - }) - - for _, encoding := range []string{"", "gob", "json"} { - t.Run(encoding, func(t *testing.T) { - codec, err := ParseEncoding(encoding) - if err != nil { - t.Fatalf("ParseEncoding(%q) error = %v", encoding, err) - } - - span := opentracing.StartSpan("job.run") - env := map[string]string{} - if err := EncodeTraceContext(span, env, codec); err != nil { - t.Fatalf("EncodeTraceContext(span, %v, %v) error = %v", env, codec, err) - } - - sctx, err := DecodeTraceContext(env, codec) - if err != nil { - t.Fatalf("DecodeTraceContext(%v, %v) error = %v", env, codec, err) - } - if sctx == nil { - t.Errorf("DecodeTraceContext(%v, %v) = %v, want non-nil span context", env, codec, sctx) - } - }) - } -} - -func TestEncodeTraceContext(t *testing.T) { - t.Cleanup(stubGlobalTracer()) - - testCases := []struct { - encoding string - want opentracing.TextMapCarrier - }{ - { - encoding: "json", - want: opentracing.TextMapCarrier{"mockpfx-ids-sampled": "true", "mockpfx-ids-spanid": "46", "mockpfx-ids-traceid": "43"}, - }, - { - encoding: "gob", - want: opentracing.TextMapCarrier{"mockpfx-ids-sampled": "true", "mockpfx-ids-spanid": "50", "mockpfx-ids-traceid": "47"}, - }, - } - for _, test := range testCases { - t.Run(test.encoding, func(t *testing.T) { - codec, err := ParseEncoding(test.encoding) - if err != nil { - t.Fatalf("ParseEncoding(%q) error = %v", test.encoding, err) - } - - ctx := context.Background() - parent := opentracing.StartSpan("job.parent") - ctx = opentracing.ContextWithSpan(ctx, parent) - - span, _ := opentracing.StartSpanFromContext(ctx, "job.run") - env := map[string]string{} - if err := EncodeTraceContext(span, env, codec); err != nil { - t.Fatalf("EncodeTraceContext(span, %v, %v) error = %v", env, codec, err) - } - if got := env[EnvVarTraceContextKey]; got == "" { - t.Errorf("after EncodeTraceContext(span, env, %v): env[%q] = %q, want non-empty encoded trace context", codec, EnvVarTraceContextKey, got) - } - - contextBytes, err := base64.URLEncoding.DecodeString(env[EnvVarTraceContextKey]) - if err != nil { - t.Fatalf("base64.URLEncoding.DecodeString(%q) error = %v", env[EnvVarTraceContextKey], err) - } - - dec := codec.NewDecoder(bytes.NewReader(contextBytes)) - textmap := opentracing.TextMapCarrier{} - if err := dec.Decode(&textmap); err != nil { - t.Fatalf("Codec(%v).NewDecoder(%q).Decode(&opentracing.TextMapCarrier{}) error = %v", codec, contextBytes, err) - } - // The content of the trace context will vary, but the keys should - // remain the same. - gotKeys := slices.Collect(maps.Keys(textmap)) - slices.Sort(gotKeys) - - wantKeys := slices.Collect(maps.Keys(test.want)) - slices.Sort(wantKeys) - if diff := cmp.Diff(gotKeys, wantKeys); diff != "" { - t.Errorf("decoded textmap keys diff (-got +want):\n%s", diff) - } - }) - } -} diff --git a/tracetools/span.go b/tracetools/span.go index 8c7e80fd0f..f36e7cfe37 100644 --- a/tracetools/span.go +++ b/tracetools/span.go @@ -3,127 +3,66 @@ package tracetools import ( "context" - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/ext" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/trace" - ddext "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext" + "go.opentelemetry.io/otel/trace/noop" ) const ( - BackendDatadog = "datadog" BackendOpenTelemetry = "opentelemetry" BackendNone = "" ) var ValidTracingBackends = map[string]struct{}{ - BackendDatadog: {}, BackendOpenTelemetry: {}, BackendNone: {}, } -// StartSpanFromContext will start a span appropriate to the given tracing backend from the given context with the given -// operation name. It will also do some common/repeated setup on the span to keep code a little more DRY. -// If an unknown tracing backend is specified, it will return a span that noops on every operation -func StartSpanFromContext(ctx context.Context, operation, tracingBackend string) (Span, context.Context) { - switch tracingBackend { - case BackendDatadog: - span, ctx := opentracing.StartSpanFromContext(ctx, operation) - span.SetTag(ddext.AnalyticsEvent, true) // Make the span available for analytics in Datadog - return NewOpenTracingSpan(span), ctx +// noopTracer is used when tracing is disabled. Spans started from it are +// non-recording and will not export any data. +var noopTracer = noop.NewTracerProvider().Tracer("buildkite-agent") +// StartSpanFromContext starts a span appropriate to the given tracing backend +// from the given context with the given operation name. It also does some +// common/repeated setup on the span to keep code a little more DRY. If an +// unknown tracing backend is specified, it will return a non-recording span. +func StartSpanFromContext(ctx context.Context, operation, tracingBackend string) (trace.Span, context.Context) { + switch tracingBackend { case BackendOpenTelemetry: ctx, span := otel.Tracer("buildkite-agent").Start(ctx, operation) span.SetAttributes(attribute.String("analytics.event", "true")) - return &OpenTelemetrySpan{Span: span}, ctx + return span, ctx case BackendNone: fallthrough default: - return &NoopSpan{}, ctx + ctx, span := noopTracer.Start(ctx, operation) + return span, ctx } } -type Span interface { - AddAttributes(map[string]string) - FinishWithError(error) - RecordError(error) -} - -type OpenTracingSpan struct { - Span opentracing.Span -} - -func NewOpenTracingSpan(base opentracing.Span) *OpenTracingSpan { - return &OpenTracingSpan{Span: base} -} - -// AddAttributes adds the given map of attributes to the span as OpenTracing tags -func (s *OpenTracingSpan) AddAttributes(attributes map[string]string) { +// AddAttributes adds the given map of string attributes to the span. +func AddAttributes(span trace.Span, attributes map[string]string) { for k, v := range attributes { - s.Span.SetTag(k, v) + span.SetAttributes(attribute.String(k, v)) } } -// FinishWithError adds error information to the OpenTracingSpan if error isn't nil, and records the span as having finished -func (s *OpenTracingSpan) FinishWithError(err error) { - s.RecordError(err) - s.Span.Finish() +// FinishWithError records error information on the span (if err isn't nil) and +// ends the span. +func FinishWithError(span trace.Span, err error) { + RecordError(span, err) + span.End() } -// RecordError records an error on the given span -func (s *OpenTracingSpan) RecordError(err error) { +// RecordError records an error on the span. No-op when err is nil. +func RecordError(span trace.Span, err error) { if err == nil { return } - - ext.LogError(s.Span, err) -} - -type OpenTelemetrySpan struct { - Span trace.Span + span.RecordError(err) + span.SetStatus(codes.Error, "failed") } - -func NewOpenTelemetrySpan(base trace.Span) *OpenTelemetrySpan { - return &OpenTelemetrySpan{Span: base} -} - -// AddAttributes adds the given attributes to the OpenTelemetry span. Only string attributes are accepted. -func (s *OpenTelemetrySpan) AddAttributes(attributes map[string]string) { - for k, v := range attributes { - s.Span.SetAttributes(attribute.String(k, v)) - } -} - -// FinishWithError adds error information to the OpenTelemetry span if error isn't nil, and records the span as having finished -func (s *OpenTelemetrySpan) FinishWithError(err error) { - s.RecordError(err) - s.Span.End() -} - -// RecordError records an error on the given OpenTelemetry span. No-op when error is nil -func (s *OpenTelemetrySpan) RecordError(err error) { - if err == nil { - return - } - - s.Span.RecordError(err) - s.Span.SetStatus(codes.Error, "failed") -} - -// NoopSpan is an implementation of the Span interface that does nothing for every method implemented -// The intended use case is for instances where the user doesn't have tracing enabled - using NoopSpan, we can still act -// as though tracing is enabled, but every time we do something tracing related, nothing happens. -type NoopSpan struct{} - -// AddAttributes is a noop -func (s *NoopSpan) AddAttributes(attributes map[string]string) {} - -// FinishWithError is a noop -func (s *NoopSpan) FinishWithError(err error) {} - -// RecordError is a noop -func (s *NoopSpan) RecordError(err error) {} diff --git a/tracetools/span_test.go b/tracetools/span_test.go index b7a08c46f2..f2cbccff82 100644 --- a/tracetools/span_test.go +++ b/tracetools/span_test.go @@ -2,48 +2,15 @@ package tracetools import ( "errors" - "reflect" "slices" "testing" - "github.com/google/go-cmp/cmp" - "github.com/opentracing/opentracing-go" - "github.com/opentracing/opentracing-go/log" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace/embedded" ) -// TestOpenTracingSpan is a simple opentracing-compatible span to help test. -type TestOpenTracingSpan struct { - ctx opentracing.SpanContext - finished bool - fields []log.Field - tags map[string]any -} - -func (t *TestOpenTracingSpan) Finish() { t.finished = true } -func (t *TestOpenTracingSpan) FinishWithOptions(_ opentracing.FinishOptions) { t.finished = true } -func (t *TestOpenTracingSpan) Context() opentracing.SpanContext { return t.ctx } -func (t *TestOpenTracingSpan) SetOperationName(_ string) opentracing.Span { return t } -func (t *TestOpenTracingSpan) SetTag(k string, v any) opentracing.Span { - t.tags[k] = v - return t -} -func (t *TestOpenTracingSpan) LogFields(f ...log.Field) { t.fields = append(t.fields, f...) } -func (t *TestOpenTracingSpan) LogKV(_ ...any) {} -func (t *TestOpenTracingSpan) SetBaggageItem(_, _ string) opentracing.Span { return t } -func (t *TestOpenTracingSpan) BaggageItem(_ string) string { return "" } -func (t *TestOpenTracingSpan) Tracer() opentracing.Tracer { return nil } -func (t *TestOpenTracingSpan) LogEvent(_ string) {} -func (t *TestOpenTracingSpan) LogEventWithPayload(_ string, _ any) {} -func (t *TestOpenTracingSpan) Log(_ opentracing.LogData) {} - -func newTestOpenTracingSpan() *OpenTracingSpan { - return &OpenTracingSpan{Span: &TestOpenTracingSpan{tags: map[string]any{}}} -} - type TestOtelSpan struct { embedded.Span @@ -81,130 +48,58 @@ func (t *TestOtelSpan) AddEvent(name string, _ ...trace.EventOption) { t.events = append(t.events, name) } -func newTestOtelSpan() *OpenTelemetrySpan { - return &OpenTelemetrySpan{Span: &TestOtelSpan{events: []string{}, attributes: []attribute.KeyValue{}}} +func newTestOtelSpan() *TestOtelSpan { + return &TestOtelSpan{events: []string{}, attributes: []attribute.KeyValue{}} } -func TestAddAttribute_OpenTracing(t *testing.T) { - t.Parallel() - - span := newTestOpenTracingSpan() - implSpan, ok := span.Span.(*TestOpenTracingSpan) - if got := ok; !got { - t.Errorf("span.Span.(*TestOpenTracingSpan) = %t, want true", got) - } - - if got := len(implSpan.tags); got != 0 { - t.Errorf("implSpan.tags = %v, want 0", got) - } - - span.AddAttributes(map[string]string{"colour": "green", "flavour": "spicy"}) - if diff := cmp.Diff(implSpan.tags, map[string]any{"colour": "green", "flavour": "spicy"}); diff != "" { - t.Errorf("implSpan.tags diff (-got +want):\n%s", diff) - } -} - -func TestAddAttributeToSpan_OpenTelemetry(t *testing.T) { +func TestAddAttributes(t *testing.T) { t.Parallel() span := newTestOtelSpan() - implSpan, ok := span.Span.(*TestOtelSpan) - if got := ok; !got { - t.Errorf("span.Span.(*TestOtelSpan) = %t, want true", got) - } - if got := len(implSpan.attributes); got != 0 { - t.Errorf("implSpan.attributes = %v, want 0", got) + if got := len(span.attributes); got != 0 { + t.Errorf("span.attributes = %v, want 0", got) } - span.AddAttributes(map[string]string{"colour": "blue", "flavour": "bittersweet"}) - if got, want := implSpan.attributes, attribute.String("colour", "blue"); !slices.Contains(got, want) { - t.Errorf("implSpan.attributes = %v, want containing %v", got, want) + AddAttributes(span, map[string]string{"colour": "blue", "flavour": "bittersweet"}) + if got, want := span.attributes, attribute.String("colour", "blue"); !slices.Contains(got, want) { + t.Errorf("span.attributes = %v, want containing %v", got, want) } - if got, want := implSpan.attributes, attribute.String("flavour", "bittersweet"); !slices.Contains(got, want) { - t.Errorf("implSpan.attributes = %v, want containing %v", got, want) + if got, want := span.attributes, attribute.String("flavour", "bittersweet"); !slices.Contains(got, want) { + t.Errorf("span.attributes = %v, want containing %v", got, want) } } -func TestFinishWithError_OpenTracing(t *testing.T) { - t.Parallel() - err := errors.New("test error") - - span := newTestOpenTracingSpan() - implSpan, ok := span.Span.(*TestOpenTracingSpan) - if got := ok; !got { - t.Errorf("span.Span.(*TestOpenTracingSpan) = %t, want true", got) - } - - span.FinishWithError(err) - if got := implSpan.finished; !got { - t.Errorf("implSpan.finished = %t, want true", got) - } - if diff := cmp.Diff(implSpan.tags["error"], true); diff != "" { - t.Errorf("implSpan.tags[\"error\"] diff (-got +want):\n%s", diff) - } - if got, want := implSpan.fields, []log.Field{log.Event("error"), log.Error(err)}; !reflect.DeepEqual(got, want) { - t.Errorf("implSpan.fields = %v, want %v", got, want) - } - - span = newTestOpenTracingSpan() - implSpan, ok = span.Span.(*TestOpenTracingSpan) - if got := ok; !got { - t.Errorf("span.Span.(*TestOpenTracingSpan) = %t, want true", got) - } - - span.FinishWithError(nil) - if got := implSpan.finished; !got { - t.Errorf("implSpan.finished = %t, want true", got) - } - got := implSpan.tags - want := "error" - if _, has := got[want]; has { - t.Errorf("implSpan.tags = %v, want containing %q", got, want) - } - if got := len(implSpan.fields); got != 0 { - t.Errorf("implSpan.fields = %v, want 0", got) - } -} - -func TestFinishWithError_OpenTelemetry(t *testing.T) { +func TestFinishWithError(t *testing.T) { t.Parallel() err := errors.New("test error") span := newTestOtelSpan() - implSpan, ok := span.Span.(*TestOtelSpan) - if got := ok; !got { - t.Errorf("span.Span.(*TestOtelSpan) = %t, want true", got) - } - span.FinishWithError(err) - if got := implSpan.finished; !got { - t.Errorf("implSpan.finished = %t, want true", got) + FinishWithError(span, err) + if got := span.finished; !got { + t.Errorf("span.finished = %t, want true", got) } - if err, want := implSpan.err, err; !errors.Is(err, want) { - t.Errorf("implSpan.err error = %v, want %v", err, want) + if err, want := span.err, err; !errors.Is(err, want) { + t.Errorf("span.err error = %v, want %v", err, want) } - if got, want := codes.Error, implSpan.statusCode; got != want { + if got, want := codes.Error, span.statusCode; got != want { t.Errorf("codes.Error = %d, want %d", got, want) } - if got, want := implSpan.statusDesc, "failed"; got != want { - t.Errorf("implSpan.statusDesc = %q, want %q", got, want) + if got, want := span.statusDesc, "failed"; got != want { + t.Errorf("span.statusDesc = %q, want %q", got, want) } span = newTestOtelSpan() - implSpan, ok = span.Span.(*TestOtelSpan) - if got := ok; !got { - t.Errorf("span.Span.(*TestOtelSpan) = %t, want true", got) - } - span.FinishWithError(nil) - if got := implSpan.finished; !got { - t.Errorf("implSpan.finished = %t, want true", got) + FinishWithError(span, nil) + if got := span.finished; !got { + t.Errorf("span.finished = %t, want true", got) } - if err := implSpan.err; err != nil { - t.Errorf("implSpan.err error = %v, want nil", err) + if err := span.err; err != nil { + t.Errorf("span.err error = %v, want nil", err) } - if got, want := codes.Unset, implSpan.statusCode; got != want { + if got, want := codes.Unset, span.statusCode; got != want { t.Errorf("codes.Unset = %d, want %d", got, want) } } diff --git a/version/BUILD.bazel b/version/BUILD.bazel index 270bb7e8cb..d00c0a88a9 100644 --- a/version/BUILD.bazel +++ b/version/BUILD.bazel @@ -5,7 +5,7 @@ go_library( srcs = ["version.go"], data = ["VERSION"], embedsrcs = ["VERSION"], - importpath = "github.com/buildkite/agent/v3/version", + importpath = "github.com/buildkite/agent/v4/version", visibility = ["//visibility:public"], ) diff --git a/version/VERSION b/version/VERSION index 58efbe7b41..a35737f9ae 100644 --- a/version/VERSION +++ b/version/VERSION @@ -1 +1 @@ -3.124.0 +4.0.0-beta.1 diff --git a/version/version.go b/version/version.go index d93d5ee0dd..02d59d1b3f 100644 --- a/version/version.go +++ b/version/version.go @@ -16,7 +16,7 @@ var ( baseVersion string // buildNumber is filled in by scripts/build-binary.sh by passing -ldflags - // "-X github.com/buildkite/agent/v3/version.buildNumber=${BUILDKITE_BUILD_NUMBER}" + // "-X github.com/buildkite/agent/v4/version.buildNumber=${BUILDKITE_BUILD_NUMBER}" buildNumber = "x" ) @@ -27,11 +27,11 @@ func Version() string { // BuildNumber returns the build number of the CI pipeline that built the agent. // You can override buildVersion at compile time by using the ldflag: // -// "-X github.com/buildkite/agent/v3/version.buildNumber=abc" +// "-X github.com/buildkite/agent/v4/version.buildNumber=abc" // // An easy way to test this is: // -// $ go run -buildvcs=true -ldflags "-X github.com/buildkite/agent/v3/version.buildNumber=abc" . --version +// $ go run -buildvcs=true -ldflags "-X github.com/buildkite/agent/v4/version.buildNumber=abc" . --version // // On CI, the binaries are always built with the buildVersion variable set. func BuildNumber() string {