Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a1fecf3
ci(ff): support feature freeze automation phase 1
v1v Mar 12, 2026
23422b9
ci(ff): support feature freeze automation phase 2
v1v Mar 12, 2026
a666488
update
v1v Mar 12, 2026
eff7847
fix linting
v1v Mar 12, 2026
8f0005e
Merge branch 'main' into feature/support-ff-fleet-server
v1v Mar 23, 2026
de623a9
go mod tidy
v1v Mar 23, 2026
f48d911
Merge branch 'main' into feature/support-ff-fleet-server
v1v Mar 23, 2026
6d46ae9
Merge upstream/main into feature/support-ff-fleet-server
fr4nc1sc0-r4m0n Jul 9, 2026
bf17d6f
fix(ci): update magefile_test.go license header to Elastic License 2.0
fr4nc1sc0-r4m0n Jul 9, 2026
c67df45
Make release automation idempotent on re-run
fr4nc1sc0-r4m0n Jul 9, 2026
64eae34
refactor(release): extract FF automation to dev-tools/mage/release
fr4nc1sc0-r4m0n Jul 9, 2026
815c688
fix(ci): allow local go.mod replace for dev-tools module
fr4nc1sc0-r4m0n Jul 9, 2026
457a0a7
fix(docker): copy dev-tools go.mod before go mod download
fr4nc1sc0-r4m0n Jul 9, 2026
8b52201
Merge branch 'main' into feature/support-ff-fleet-server
fr4nc1sc0-r4m0n Jul 14, 2026
f3e6949
Align fleet-server release automation with ingest-dev fleet-server.mak
fr4nc1sc0-r4m0n Jul 14, 2026
ddee08c
Merge upstream/main into feature/support-ff-fleet-server
fr4nc1sc0-r4m0n Jul 21, 2026
f7af98e
ci(ff): align release automation with beats and elastic-agent
fr4nc1sc0-r4m0n Jul 22, 2026
358baf1
Merge branch 'main' into feature/support-ff-fleet-server
fr4nc1sc0-r4m0n Jul 22, 2026
fb93ee0
fix(release): fall back to git tags when GitHub Releases are empty
fr4nc1sc0-r4m0n Jul 22, 2026
47042ea
ci: wire version-bump pipeline to mage release targets
fr4nc1sc0-r4m0n Jul 24, 2026
c2ef7c9
Merge upstream/main into feature/support-ff-fleet-server
fr4nc1sc0-r4m0n Jul 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion .buildkite/pipeline.version-bump.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,46 @@ notify:
${BUILDKITE_BUILD_URL}
if: build.state == "blocked"

env:
IMAGE_CI_WITH_HOOKS_LATEST: "docker.elastic.co/ci-agent-images/platform-ingest/buildkite-agent-beats-ci-with-hooks:latest"

steps:
# TODO: replace this block step by real version bump logic
# BRANCH is major.minor (e.g. 9.4 for a 9.4.0 minor release, 9.3 for a 9.3.3 patch).
- label: "Bump version minor"
key: bump-version-minor
if: build.env("WORKFLOW") == "minor"
agents:
image: "${IMAGE_CI_WITH_HOOKS_LATEST}"
cpu: "4000m"
memory: "8Gi"
useCustomGlobalHooks: true
env:
CURRENT_RELEASE: "${NEW_VERSION}"
plugins:
- elastic/vault-github-token#v0.2.1: ~
command:
- make mage
- mage release:runMajorMinor
timeout_in_minutes: 60

- label: "Bump version patch"
key: bump-version-patch
if: build.env("WORKFLOW") == "patch"
agents:
image: "${IMAGE_CI_WITH_HOOKS_LATEST}"
cpu: "4000m"
memory: "8Gi"
useCustomGlobalHooks: true
env:
CURRENT_RELEASE: "${NEW_VERSION}"
BASE_BRANCH: "${BRANCH}"
plugins:
- elastic/vault-github-token#v0.2.1: ~
command:
- make mage
- mage release:runPatch
timeout_in_minutes: 60

- block: "Ready to fetch for DRA artifacts?"
prompt: |
Unblock when your team is ready to proceed.
Expand Down
4 changes: 2 additions & 2 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ linters:
min-occurrences: 2

gomoddirectives:
# Allow local `replace` directives. Default is false.
replace-local: false
# Allow local `replace` directives (e.g. dev-tools submodule in go.mod).
replace-local: true
gomodguard:
blocked:
# List of blocked modules.
Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ WORKDIR /fleet-server

# pre-copy/cache go.mod for pre-downloading dependencies and only redownloading them in subsequent builds if they change
COPY go.mod go.sum ./
COPY dev-tools/go.mod dev-tools/go.sum ./dev-tools/
RUN go mod download && go mod verify
RUN go install github.com/magefile/mage # Uses version from go.mod implicitly
ENV PATH="$PATH:/go/bin"
Expand Down
1 change: 1 addition & 0 deletions Dockerfile.build
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ USER fleet-server
WORKDIR /fleet-server/
# pre-copy/cache go.mod for pre-downloading dependencies and only redownloading them in subsequent builds if they change
COPY go.mod go.sum ./
COPY dev-tools/go.mod dev-tools/go.sum ./dev-tools/
RUN go mod download && go mod verify
RUN go install github.com/magefile/mage # uses version in go.mod

Expand Down
2 changes: 2 additions & 0 deletions Dockerfile.fips
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ WORKDIR /fleet-server/

# pre-copy/cache go.mod for pre-downloading dependencies and only redownloading them in subsequent builds if they change
COPY go.mod go.sum ./
COPY dev-tools/go.mod dev-tools/go.sum ./dev-tools/
# GOFIPS140 must be set before go mod download so that the golang.org/fips140 module is cached during image build.
# Without this, the module would be fetched at build time by the host user who lacks write access to the module cache.
ENV GOFIPS140=certified
Expand All @@ -32,6 +33,7 @@ FROM docker.elastic.co/beats-dev/golang-crossbuild:${GO_VERSION}-${SUFFIX} AS bu
WORKDIR /fleet-server
ENV PATH="$PATH:/go/bin"
COPY go.mod go.sum ./
COPY dev-tools/go.mod dev-tools/go.sum ./dev-tools/
RUN go mod download && go mod verify
RUN go install github.com/magefile/mage # uses version in go.mod

Expand Down
101 changes: 101 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Fleet Server Release Automation

Mage-based release workflows for Fleet Server, replacing the former ingest-dev
[`fleet-server.mak`](https://github.com/elastic/ingest-dev/blob/main/release_scripts/fleet-server.mak)
Makefile process. Process shape matches beats and elastic-agent (feature-freeze
and patch merge-timing labels); file updates stay limited to `version/version.go`
and `.mergify.yml`.

## Quick start

```bash
export PROJECT_OWNER="your-user"
export CURRENT_RELEASE="9.6.0" # must already match version/version.go on main
export GITHUB_TOKEN=$(gh auth token)
export DRY_RUN=true

# Feature freeze
mage release:runMajorMinor

# Patch release on an existing release branch
export CURRENT_RELEASE="9.6.1" # must already match version on the release branch
mage release:runPatch

go test ./dev-tools/mage/release/... -count=1
```

Use plain `X.Y.Z` semver for `CURRENT_RELEASE` (no `-test` or `-SNAPSHOT` suffixes).

## Feature freeze (`mage release:runMajorMinor`)

`CURRENT_RELEASE` is the version **already on** `main` (the line being frozen).

| Slot | Branch → base | Changes | Merge label |
|---|---|---|---|
| Release branch | `X.Y` from `main` | pushed | — |
| **PR-A** | `ff-prep-main-{CURRENT}` → `main` | Mergify backport + bump to next minor | `merge:1-ff-day` |
| **PR-B** | `ff-release-{CURRENT}` → `X.Y` | ensure `version.go` = CURRENT (often no-op) | `merge:2-after-branch` |
| **PR-C** | — | **omitted** (no docs/test-env) | — |
| **PR-D** | `ff-prep-next-patch-{NEXT}` → `X.Y` | bump to next patch | `merge:4-after-release` |

## Patch (`mage release:runPatch`)

`CURRENT_RELEASE` is the version **already on** the release branch.

| Slot | Branch → base | Changes | Merge label |
|---|---|---|---|
| **PR-A** | `patch-release-{CURRENT}` → `X.Y` | ensure version (often skipped; no docs) | `merge:1-before-build` |
| **PR-B** | `ff-prep-next-patch-{NEXT}` → `X.Y` | bump to next patch | `merge:4-after-release` |

## Environment variables

| Variable | Required | Default | Description |
|---|---|---|---|
| `CURRENT_RELEASE` | yes | — | Version already on base/release branch |
| `GITHUB_TOKEN` | yes (unless dry run) | — | GitHub API token |
| `DRY_RUN` | no | `false` | Only `true` enables dry run |
| `BASE_BRANCH` | no | `main` | Base branch for feature freeze |
| `PROJECT_OWNER` | no | `elastic` | GitHub owner |
| `PROJECT_REPO` | no | `fleet-server` | GitHub repository |
| `PROJECT_REVIEWERS` | no | `elastic/elastic-agent-control-plane` | PR reviewers |

Derived (not env-overridable): `NEXT_RELEASE` (patch+1), `NEXT_PROJECT_MINOR_VERSION` (minor+1), `RELEASE_BRANCH` (`X.Y`), `LATEST_RELEASE` (patch−1, or GitHub Releases lookup with git-tag fallback when releases are empty).

## Files updated

- `version/version.go` — `DefaultVersion`
- `.mergify.yml` — backport rule (PR-A)

## Idempotency

| Step | Re-run behavior |
|---|---|
| `UpdateVersion` | No-op when version already matches |
| `UpdateMergify` | No-op when backport rule already exists |
| Branch creation | Reuses existing branch |
| `CommitAll` | Skips when worktree is clean |
| `CreatePR` | Returns existing open PR for same head/base |

## Package layout

```
dev-tools/mage/release/
├── cmd/fleet-release/ # nested-module CLI
├── go.mod / go.sum # isolates go-git / go-github
├── config.go
├── release.go
├── mergify.go
├── workflows.go
├── git.go / github.go / issue.go / version.go
└── README.md
```

Root `mage release:*` targets invoke `go run -C dev-tools/mage/release ./cmd/fleet-release …`.

## Testing

```bash
cd dev-tools/mage/release && go test ./... -count=1
```

Discard local workflow changes after review with `git reset --hard HEAD`.
5 changes: 3 additions & 2 deletions dev-tools/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,17 @@ require (
github.com/oapi-codegen/oapi-codegen/v2 v2.5.0 // indirect
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect
github.com/onsi/gomega v1.27.10 // indirect
github.com/perimeterx/marshmallow v1.1.5 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/speakeasy-api/jsonpath v0.6.0 // indirect
github.com/speakeasy-api/openapi-overlay v0.10.2 // indirect
github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect
go.elastic.co/go-licence-detector v0.7.0 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/perf v0.0.0-20250305200902-02a15fd477ba // indirect
golang.org/x/sync v0.14.0 // indirect
golang.org/x/text v0.23.0 // indirect
golang.org/x/text v0.25.0 // indirect
golang.org/x/tools v0.33.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
10 changes: 6 additions & 4 deletions dev-tools/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,19 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/speakeasy-api/jsonpath v0.6.0 h1:IhtFOV9EbXplhyRqsVhHoBmmYjblIRh5D1/g8DHMXJ8=
github.com/speakeasy-api/jsonpath v0.6.0/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw=
github.com/speakeasy-api/openapi-overlay v0.10.2 h1:VOdQ03eGKeiHnpb1boZCGm7x8Haj6gST0P3SGTX95GU=
Expand Down Expand Up @@ -154,8 +156,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
Expand Down
41 changes: 41 additions & 0 deletions dev-tools/mage/release/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Fleet Server release package

Operator reference for `dev-tools/mage/release/`. Release managers should start with [`RELEASE.md`](../../../RELEASE.md) at the repository root.

## Mage targets

| Target | CLI command | Purpose |
|---|---|---|
| `mage release:runMajorMinor` | `run-major-minor` | Feature freeze: release branch + PR-A/B/D |
| `mage release:runPatch` | `run-patch` | Patch: PR-A (often skipped) + next-patch PR-B |
| `mage release:updateVersion` | `update-version` | Update `version/version.go` only |
| `mage release:updateMergify` | `update-mergify` | Append backport rule |
| `mage release:ensureIssueTracker` | `ensure-issue-tracker` | Create/update release checklist issue |

There is **no** `runNextRelease` target; next-patch prep is PR-D inside `runMajorMinor` / PR-B inside `runPatch`.

## Architecture

- Nested Go module keeps `go-git` / `go-github` out of the root `go.mod` / `NOTICE.txt`.
- Root mage wrappers call `go run -C dev-tools/mage/release ./cmd/fleet-release …` with `FLEET_SERVER_REPO_ROOT` set.
- File allowlist: only `version/version.go` and `.mergify.yml`.

## Alignment with beats / elastic-agent

Shared process: `CURRENT_RELEASE` must match `version.go`, merge-timing labels, idempotent branches/PRs, issue tracker, nested module.

Fleet Server differences (from former `fleet-server.mak`):

- No K8s / Helm / docs / test-env updates → **PR-C omitted**
- Patch “docs” PR has no doc files → often skipped when version already matches

## Local testing

```bash
export PROJECT_OWNER="$USER"
export CURRENT_RELEASE="$(grep DefaultVersion version/version.go | sed -E 's/.*"([^"]+)".*/\1/')"
export DRY_RUN=true
export GITHUB_TOKEN="$(gh auth token)"

mage release:runMajorMinor
```
Loading
Loading