close
Skip to content

chore: Release v2.37.0#1137

Merged
malept merged 29 commits intoreleasefrom
tmp-release-stable-v2.37.0-rc.4
Apr 29, 2026
Merged

chore: Release v2.37.0#1137
malept merged 29 commits intoreleasefrom
tmp-release-stable-v2.37.0-rc.4

Conversation

@malept
Copy link
Copy Markdown
Member

@malept malept commented Apr 29, 2026

Merge tmp-release-stable-v2.37.0-rc.4 to release


Rovo Dev code review: Rovo Dev has reviewed this pull request
Any suggestions or improvements have been posted as pull request comments.

dependabot Bot and others added 29 commits March 17, 2026 22:47
Bumps [github.com/magefile/mage](https://github.com/magefile/mage) from 1.15.0 to 1.16.0.
- [Release notes](https://github.com/magefile/mage/releases)
- [Commits](magefile/mage@v1.15.0...v1.16.0)

---
updated-dependencies:
- dependency-name: github.com/magefile/mage
  dependency-version: 1.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.79.1 to 1.79.2.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](grpc/grpc-go@v1.79.1...v1.79.2)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-version: 1.79.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [github.com/magefile/mage](https://github.com/magefile/mage) from 1.16.0 to 1.16.1.
- [Release notes](https://github.com/magefile/mage/releases)
- [Commits](magefile/mage@v1.16.0...v1.16.1)

---
updated-dependencies:
- dependency-name: github.com/magefile/mage
  dependency-version: 1.16.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.79.2 to 1.79.3.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](grpc/grpc-go@v1.79.2...v1.79.3)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-version: 1.79.3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…ge (#1117)

Add ~/.local/share/mise to CircleCI save_cache paths so installed tool
binaries and shims are persisted across builds. This eliminates redundant
GitHub API calls for version resolution on every CI run.

Bump cache key prefix from v1 to v2 on all daily-cache and toggle-cache
keys to force a fresh cache write that includes the new path.
Bumps [github.com/rs/zerolog](https://github.com/rs/zerolog) from 1.34.0 to 1.35.0.
- [Commits](rs/zerolog@v1.34.0...v1.35.0)

---
updated-dependencies:
- dependency-name: github.com/rs/zerolog
  dependency-version: 1.35.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [github.com/magefile/mage](https://github.com/magefile/mage) from 1.16.1 to 1.17.1.
- [Release notes](https://github.com/magefile/mage/releases)
- [Commits](magefile/mage@v1.16.1...v1.17.1)

---
updated-dependencies:
- dependency-name: github.com/magefile/mage
  dependency-version: 1.17.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.79.3 to 1.80.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](grpc/grpc-go@v1.79.3...v1.80.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-version: 1.80.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Marek Nagy <marek.nagy@outreach.io>
* fix(e2e): upgrade go-github import to v84 to match gobox dependency

The gobox v1.111.4 upgrade changed githubauth.NewClient() to return
a go-github/v84 Client, but e2e/config still imported v71, causing
a type mismatch at e2e/e2e.go:88.

Assisted-By: claude-opus 4.6 via OpenCode

* chore: remove devenv.yaml

---------

Co-authored-by: getoutreach-ci-1[bot] <95656460+getoutreach-ci-1[bot]@users.noreply.github.com>
Co-authored-by: Mark Lee <mark.lee@outreach.io>
Bumps [github.com/rs/zerolog](https://github.com/rs/zerolog) from 1.35.0 to 1.35.1.
- [Commits](rs/zerolog@v1.35.0...v1.35.1)

---
updated-dependencies:
- dependency-name: github.com/rs/zerolog
  dependency-version: 1.35.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* fix(mise): pin E2E tool versions and wire CI to use them

Add mise.e2e.toml + mise.e2e.lock pinning the tools that E2E CI jobs
need (devenv 1.64.7, kubecfg 0.28.1, kubectl 1.29.15). Today, those
tools are resolved via unpinned GitHub API lookups during the E2E job's
setup, which is rate-limited and non-reproducible.

Wire CI to consume the new env on E2E jobs:

- A new e2e_mode parameter on the setup_environment orb command exports
  E2E_MODE=true to the mise and machine setup steps.
- shell/ci/env/mise.sh, when E2E_MODE=true, skips the broad 'mise
  install' and instead installs only go, node, and the pinned E2E
  tools, then writes mise.e2e.toml + mise.e2e.lock to a user-wide mise
  config so shims resolve correctly without further network calls.
- shell/circleci/machine.sh, when E2E_MODE=true, uses the same E2E
  helpers when bootstrapping a machine executor.
- shell/circleci/setup.sh skips the asdf install path entirely when
  E2E_MODE=true (E2E jobs do not need the full asdf tool set).
- shell/ci/testing/setup-devenv.sh fails fast if kubectl, kubecfg, or
  devenv are missing on PATH when E2E=true, rather than falling
  through to its unpinned install paths (hardcoded version defaults
  and a GitHub-latest lookup) that would silently defeat the lockfile.
- The e2e job in orbs/shared/jobs/e2e.yaml passes e2e_mode: true.

shell/lib/mise.sh grows env-parameterized helpers (mise_for_env,
mise_configure_global_tools_for_env, mise_install_tools_for_env). The
existing devbase_* trio is reduced to thin wrappers over them, and E2E
call sites invoke the generics directly with 'e2e' as the env arg.

Also extend the stencil:post:mise task to upgrade and lock the new env
alongside the devbase env, so 'mise run stencil:post:mise' keeps both
in sync.

Cache layout changes (restore_cache reshape, save_e2e_cache job,
v2->v1 daily-cache rename) remain in the separate DT-5282 PR.

Refs DT-5316

Assisted-By: claude-opus 4.7 via OpenCode

* revert: "fix: avoid hardcoding tool versions" (#1134)

This reverts the substantive changes from #1134 (commit
fa25cfc). The KUBECTL_VERSION and
KUBECFG_VERSION env-var overrides plus the get_box_field lookups are
incompatible with the lockfile-based E2E install introduced in the
preceding commit on this branch: in E2E mode kubectl/kubecfg are
already on PATH from mise.e2e.lock, so these branches never run; in
non-E2E CI the lockfile is the single source of truth and per-job
overrides reintroduce the version-drift this branch is meant to
prevent.

Keep the more-specific 1.29.15 / v0.28.1 fallbacks introduced by
#1134 as the literal install_tool_with_mise arguments, since
mise.e2e.lock pins those same versions.

Assisted-By: claude-opus 4.7 via OpenCode

* fix(mise): source kubectl/kubecfg versions from mise.e2e.toml

The kubectl/kubecfg install fallbacks in setup-devenv.sh hardcoded
literal versions that duplicated the values pinned in mise.e2e.toml.
Although these code paths are unreachable in E2E mode (the precondition
fails fast if setup_environment didn't install them from the lockfile),
the duplication invited drift between mise.e2e.toml and the script.

Generalize the existing devbase_tool_version_from_mise helper into
tool_version_from_mise_env, parameterized on env, and use it from
setup-devenv.sh to derive both versions from mise.e2e.toml. The
devbase wrapper is preserved as a one-line forwarder for existing
callers.

Assisted-By: claude-opus 4.7 via OpenCode

* fix(mise): source devenv version from mise.e2e.toml

Mirror the kubectl/kubecfg pattern for devenv: when
DEVENV_PRE_RELEASE is unset or false, install the version pinned
in mise.e2e.toml via mise instead of fetching the latest GitHub
release. The existing install_latest_github_release path is kept
as an explicit escape hatch when DEVENV_PRE_RELEASE=true, so the
e2e job's devenv_pre_release orb parameter remains a deliberate
opt-in to release candidates.

Like the kubectl/kubecfg branches, this code is unreachable in
E2E mode (the precondition fails fast if devenv isn't already on
PATH from setup_environment), but eliminating the literal-version
duplication keeps mise.e2e.toml as the single source of truth for
all three E2E-job tools.

Also default DEVENV_PRE_RELEASE to false at the top of the script
to document the contract and harden against `set -u`.

Assisted-By: claude-opus 4.7 via OpenCode

* fix(ci): normalize E2E_MODE truthy values

CircleCI substitutes the YAML boolean `true` from
`<< parameters.e2e_mode >>` into `environment:` mappings as the
literal string "1", not "true". The previous gates
(`[[ ${E2E_MODE:-false} == "true" ]]`) therefore fell through to
the non-E2E branch on every E2E job, and the asdf/full-mise install
ran instead of the pinned E2E-only path. `kubectl` was never
installed, and `make e2e` failed at the new precondition in
`setup-devenv.sh`.

Add a generic `circleci_param_is_true` helper in
`shell/lib/circleci.sh` that accepts the bool-parameter
substitutions documented in the CircleCI reusable-config reference
("may be returned as a '1' for True and '0' for False"), and a
thin `circleci_e2e_mode_enabled` wrapper over it. Route the three
gate sites (`setup.sh`, `machine.sh`, `ci/env/mise.sh`) through
the wrapper, sourcing `circleci.sh` where it wasn't already.

Verified against svcexamples build 1653: all three gates logged
`E2E_MODE='1' len=1`, confirming the substitution behavior.

Assisted-By: claude-opus 4.7 via OpenCode

* Avoid installing devbase tools

* Further reduce tool installation

* Upgrade kubectl to 1.34.7

* Add aws-cli for ECR

* fix(ci): skip devbase tool install in E2E mode

The unconditional devbase_install_mise_tools and devbase_configure_global_tools
calls in shell/ci/env/mise.sh were running even when E2E mode was enabled,
causing tools from mise.devbase.toml to be installed despite the E2E branch
above already handling installs from mise.e2e.toml.

This mirrors the same fix applied to shell/circleci/machine.sh in 0394c75.

Assisted-By: claude-opus 4.7 via opencode

* make fmt

* fix(ci): pin vault in E2E tools

devenv provision in E2E jobs calls vault via find_tool(), which fails
when vault isn't installed. Add vault@2.0.0 (matching mise.devbase.toml)
to mise.e2e.toml so it's installed in E2E mode.

Also update the E2E mode setup log message to point at mise.e2e.toml as
the source of truth rather than hardcoding a stale tool list.

Assisted-By: claude-opus 4.7 via opencode

* Add gotestsum to e2e env

* fix(ci): skip asdf ensure in E2E mode

In E2E mode, devbase installs its required tools via mise from
mise.e2e.toml and does not use asdf. However, root/Makefile invokes
root/ensure_asdf.sh on every make invocation, which calls
asdf_devbase_ensure unconditionally. When asdf is not installed (the
E2E case), each entry in .tool-versions emits a benign but noisy
"asdf: command not found" warning at the start of every make e2e
step.

Gate the call with circleci_e2e_mode_enabled and propagate E2E_MODE
job-wide in orbs/shared/jobs/e2e.yaml so the make e2e step sees it.

Assisted-By: claude-opus 4.7 via OpenCode

* docs(ci): clarify E2E vs E2E_MODE distinction

E2E_MODE (orb-level) gates CI machine bootstrap tool installation,
choosing mise.e2e.toml over mise.devbase.toml. E2E (script-level) is
read by ci/testing/setup-devenv.sh and devspace_start.sh to gate
test-runner behavior after the devenv is provisioned. The two
variables are intentionally distinct: E2E_MODE is CI-only (orb
parameter), while E2E is set both in CI and locally via 'make e2e'.

Add cross-referencing comments at the four assignment sites so
future readers don't waste cycles wondering if the variables are
redundant.

Assisted-By: claude-opus 4.7 via opencode

* Add wait-for-gh-rate-limit

* docs(ci): update stale E2E install log message

The previous message named only devenv and kubectl, but
mise_install_tools_for_env e2e installs everything pinned in
mise.e2e.toml (currently 9+ tools). Point at the source of truth
instead so the message stays accurate as the toolset evolves.
Phrasing now mirrors the analogous message in shell/ci/env/mise.sh.

Assisted-By: claude-opus 4.7 via opencode

* refactor(ci): rename E2E_MODE to INSTALL_E2E_TOOLS

The original name 'E2E_MODE' was vague and easily conflated with the
script-level E2E flag (which is a different, runtime concern). The new
name is self-documenting: it describes what the flag does (install the
E2E toolset during CI bootstrap) rather than describing an opaque mode.

Renames:
- env var: E2E_MODE -> INSTALL_E2E_TOOLS
- orb parameter: e2e_mode -> install_e2e_tools
- shell helper: circleci_e2e_mode_enabled -> circleci_should_install_e2e_tools

This is a mechanical rename across the orb commands/jobs, machine and
mise CI setup scripts, ensure_asdf.sh, and the cross-reference comments
that distinguish INSTALL_E2E_TOOLS (CI bootstrap toolset) from E2E
(test-runner behavior). No behavior changes.

Assisted-By: claude-opus 4.7 via opencode

* fix(ci): honor DEVENV_PRE_RELEASE in E2E mode

Previously, the new "fail fast if devenv missing" assert in E2E mode
made the orb's `devenv_pre_release: true` parameter silently broken
in two ways:

1. When mise.e2e.lock provided devenv, the existing `! command_exists
   devenv` guard short-circuited the fallback, so the pre-release was
   never installed.
2. When mise.e2e.lock did not provide devenv (e.g., drift), the
   fatal assert fired before the pre-release branch was reached.

Skip devenv from the assert when DEVENV_PRE_RELEASE=true and force the
pre-release install regardless of whether devenv is already on PATH,
so the requested override actually takes effect.

Assisted-By: claude-opus 4.7 via OpenCode

* fix(ci): fail loudly when go/node version missing from .tool-versions

The previous `install_tool_with_mise go "$(grep ... | awk ...)"`
pattern silently passed an empty version string when the entry was
missing from .tool-versions, because failures inside command
substitution don't propagate through `set -euo pipefail`. mise then
falls back to whatever it considers a default, defeating the point of
sourcing the version from .tool-versions in the first place.

Capture each version into a variable and fatal if empty, so drift in
the consumer's .tool-versions is caught at bootstrap time instead of
producing an unintended go/node install. Collapsing `grep | awk` into
a single `awk` is a minor side-effect of the rewrite.

Assisted-By: claude-opus 4.7 via OpenCode

* refactor(ci): extract version_from_toolversions helper

Two call sites (shell/ci/env/mise.sh and shell/circleci/machine.sh)
had near-identical inline 'awk $1 == "<tool>" {print $2}' parsing
of .tool-versions, plus separate empty-string guards. Extract a
single helper in shell/lib/mise.sh that returns 1 on miss so callers
can fail fast with '|| fatal' instead of repeating the test.

The helper documents why it returns 1 instead of calling fatal
itself: callers invoke it via command substitution, where a fatal
inside the subshell would not abort the parent under set -e.

No behavior change.

Assisted-By: claude-opus 4.7 via OpenCode
## What this PR does / why we need it

PR #1117 added `~/.local/share/mise` to the shared daily cache, bloating it for every job (~500MB-1GB extra) even though only E2E jobs (machine executor) need cached mise tool installs. Non-E2E jobs run in Docker where most common tools are pre-installed.

This PR splits CircleCI caching into two parallel tracks so each executor type restores only what it can actually use:

| Cache       | Executor             | Key                                                   | Paths                                                       |
|-------------|----------------------|-------------------------------------------------------|-------------------------------------------------------------|
| Daily       | `testbed-docker-aws` | `v1-daily-cache-{{ arch }}-{{ epoch }}`               | `~/.cache`, `~/.asdf`, `~/.outreach/.cache`                 |
| E2E         | `testbed-machine`    | `v1-e2e-daily-cache-{{ arch }}-{{ epoch }}`           | `~/.local/share/mise`, `~/.cache/go-build`, `~/go/pkg/mod`  |
| Daily toggle| `testbed-docker-aws` | `v1-toggle-daily-cache-{{ arch }}-{{ .Revision }}`    | `~/cache-toggle`                                            |
| E2E toggle  | `testbed-machine`    | `v1-toggle-e2e-daily-cache-{{ arch }}-{{ .Revision }}`| `~/cache-toggle-e2e`                                        |

CircleCI scopes cache keys by executor architecture, so a cache saved from a Docker job is unreachable to a machine job. The new `save_e2e_cache` job runs on `testbed-machine` so the E2E save and restore happen under the same arch.

The `install_e2e_tools` parameter on `setup_environment` (added by #1135) now also controls E2E cache restoration: when `true`, it restores `v1-e2e-daily-cache` in addition to selecting the slim E2E mise toolset. The E2E job itself sets `restore_cache: false` because the daily cache is unreachable from machine jobs anyway.

The cache-key prefix reverts from `v2-` (introduced by #1117 to invalidate caches that lacked `~/.local/share/mise`) back to `v1-`, since `~/.local/share/mise` is no longer in the daily cache. Existing `v1-` daily caches on main are layout-compatible with this PR's daily cache.

## Jira ID

[DT-5282]

## Notes for your reviewers

- The new `save_e2e_cache` job and the E2E cache itself are transitional. They will be retired once self-hosted runners land under [DT-4971].
- Out of scope (deferred to follow-up PRs): checksum-based cache keys, full `asdf` removal.
- Repos using the `stencil-golang` Stencil module already provide a `Makefile` `build` target via `devbase`, which the new `save_e2e_cache` job uses to populate the E2E cache.

[DT-4971]: https://outreach-io.atlassian.net/browse/DT-4971
[DT-5282]: https://outreach-io.atlassian.net/browse/DT-5282

Assisted-By: claude-opus 4.7 via OpenCode
@malept malept requested a review from a team as a code owner April 29, 2026 17:58
@getoutreach-ci-2
Copy link
Copy Markdown

Link to code coverage report (posted by coverbot 🤖)

@malept malept merged commit ee13b4c into release Apr 29, 2026
10 checks passed
@malept malept deleted the tmp-release-stable-v2.37.0-rc.4 branch April 29, 2026 18:02
@getoutreach-ci-2
Copy link
Copy Markdown

🎉 This PR is included in version 2.37.0 🎉

The release is available on:

Your semantic-release bot 📦🚀


if ! command -v kubecfg >/dev/null; then
install_tool_with_mise github:getoutreach/kubecfg v0.28.1
if ! command_exists kubectl; then
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Maintainability - Best Practices

Fallback tool installation at lines 68-83 is unreachable in E2E mode due to the fatal assertions above, making this dead code for the E2E path.

Details

📖 Explanation: When E2E=true, the assertions at lines 56-66 will fatal if kubectl, kubecfg, or devenv are missing on PATH. This means the fallback installation logic at lines 68-83 can never execute in E2E mode (the script would have already exited with fatal). These fallbacks appear to be intended for non-E2E CI mode, but the code structure makes this unclear and creates unreachable code in the E2E path.

Uses AI. Verify results. Give Feedback

Comment thread mise.e2e.toml
@@ -0,0 +1,17 @@
[tools]
"github:getoutreach/devenv" = "1.64.7"
"github:getoutreach/kubecfg" = "0.28.1"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Maintainability - Configuration

Version mismatch: mise.devbase.toml specifies kubecfg 0.34.0, but mise.e2e.toml uses 0.28.1 despite the comment stating versions should sync with devbase.

Details

📖 Explanation: The comment at line 4 states "The following is copied from mise.devbase.toml, sync versions from there", but kubecfg is pinned to 0.28.1 in the E2E environment while mise.devbase.toml uses 0.34.0 (as shown in mise.devbase.toml line 30 in the diff). This version skew could lead to behavior differences between E2E tests and regular dev/CI environments. If the older version is intentional for E2E compatibility, the comment should clarify which tools are exceptions to the sync rule.

Suggested change
"github:getoutreach/kubecfg" = "0.28.1"
"github:getoutreach/kubecfg" = "0.34.0"

Uses AI. Verify results. Give Feedback

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants