Skip to content

Commit c8e439a

Browse files
authored
CLOUDP-345379: File-based release version control (#2709)
* Add a file-based approach to control release version * unify major-version check * update release documentation * Check the release version match expected next version * fix bump-version-file target * improve docs
1 parent 2fdea1d commit c8e439a

File tree

17 files changed

+200
-76
lines changed

17 files changed

+200
-76
lines changed

.github/actions/build-push-image/action.yaml

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,22 @@
11
name: Build Container Image
22
description: Builds the operator container image for the given architecture
33
inputs:
4-
get-existing-cache:
5-
description: 'Get cache from the previous build'
6-
required: false
7-
default: 'false'
84
platforms:
95
description: The list of platforms for which the image will be built
106
required: true
117
version:
12-
description: The version of the operator will be built
13-
required: true
14-
certified_version:
15-
description: The certified version of the operator will be built
16-
default: ''
17-
required: false
18-
repository:
19-
description: The name of repository to build image
8+
description: The version of the operator binary will be built
209
required: true
2110
file:
2211
description: Name of the dockerfile relative to context
2312
required: false
2413
default: Dockerfile
2514
docker_username:
2615
description: The username to access the docker registry
27-
required: true
16+
required: false
2817
docker_password:
2918
description: The password to access the docker registry
30-
required: true
19+
required: false
3120
push_to_docker:
3221
description: Push image to docker.io
3322
required: false

.github/actions/set-tag/entrypoint.sh

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@ set -eou pipefail
1717

1818
git config --global --add safe.directory /github/workspace
1919

20-
# Get the full commit hash and shorten to 7 characters
20+
commit_id=$(git rev-parse --short HEAD)
21+
22+
# If commit passed shorten to 8 characters
2123
full_commit_sha="${INPUT_COMMIT_SHA:-}"
22-
if [ -z "$full_commit_sha" ]; then
23-
full_commit_sha=$(git rev-parse HEAD)
24+
if [ -n "$full_commit_sha" ]; then
25+
commit_id=$(echo "$full_commit_sha" | cut -c1-8)
2426
fi
25-
commit_id=$(echo "$full_commit_sha" | cut -c1-7)
2627

2728
# Get the full branch name
2829
branch_name="${INPUT_BRANCH_NAME:-}"

.github/workflows/openshift-upgrade-test.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@ jobs:
3333
with:
3434
ref: ${{github.event.pull_request.head.sha}}
3535
fetch-depth: 0 # required for tags
36-
- name: Prepare tag
37-
id: prepare
38-
uses: ./.github/actions/set-tag
3936
- name: Install devbox
4037
uses: jetify-com/[email protected]
4138
with:

.github/workflows/release-image.yml

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -76,17 +76,31 @@ jobs:
7676
RELEASE_TYPE: ${{ github.event.inputs.release_type }}
7777
outputs:
7878
repo: ${{ steps.compute.outputs.repo }}
79+
version: ${{ steps.read_version.outputs.version }}
7980
steps:
80-
- name: Compute
81-
id: compute
82-
run: |
83-
if [ "${RELEASE_TYPE}" == "official-release" ]; then
84-
echo "Setting official release repo mongodb/mongodb-atlas-kubernetes-operator"
85-
echo "repo=mongodb/mongodb-atlas-kubernetes-operator" | tee -a $GITHUB_OUTPUT
86-
else
87-
echo "Setting pre-release repo mongodb/mongodb-atlas-kubernetes-operator-prerelease"
88-
echo "repo=mongodb/mongodb-atlas-kubernetes-operator-prerelease" | tee -a $GITHUB_OUTPUT
89-
fi
81+
- name: Compute
82+
id: compute
83+
run: |
84+
if [ "${RELEASE_TYPE}" == "official-release" ]; then
85+
echo "Setting official release repo mongodb/mongodb-atlas-kubernetes-operator"
86+
echo "repo=mongodb/mongodb-atlas-kubernetes-operator" | tee -a $GITHUB_OUTPUT
87+
else
88+
echo "Setting pre-release repo mongodb/mongodb-atlas-kubernetes-operator-prerelease"
89+
echo "repo=mongodb/mongodb-atlas-kubernetes-operator-prerelease" | tee -a $GITHUB_OUTPUT
90+
fi
91+
- name: Read the next release version
92+
id: read_version
93+
env:
94+
INPUT_VERSION: ${{ github.event.inputs.version }}
95+
run: |
96+
VERSION=$(jq -r '.next' version.json)
97+
98+
if [[ "$INPUT_VERSION" != "$VERSION" ]]; then
99+
echo "::error::Input version '$INPUT_VERSION' does not match the expected 'next' version '$VERSION' from version.json."
100+
exit 1
101+
fi
102+
103+
echo "version=${VERSION}" >> "${GITHUB_OUTPUT}"
90104
91105
# Release-image: Created and uploads a release for the specified operator version given in the image_sha
92106
# Note, with new releases, all the release artifacts will be stored within docs/releases/{version}
@@ -98,7 +112,7 @@ jobs:
98112
- image2commit
99113
- compute-repo
100114
env:
101-
VERSION: ${{ github.event.inputs.version }}
115+
VERSION: ${{ needs.compute-repo.outputs.version }}
102116
RELEASE_TAG: v${{ github.event.inputs.version }}
103117
AUTHORS: ${{ github.event.inputs.authors }}
104118
IMAGE_SHA: ${{ github.event.inputs.image_sha }}
@@ -238,6 +252,10 @@ jobs:
238252
run: |
239253
devbox run -- 'make build-licenses.csv'
240254
255+
- name: Bump version.json
256+
run: |
257+
devbox run -- 'make bump-version-file'
258+
241259
# Create PR on release branch with all updates generated
242260
- name: Create release pr with all updated artefacts
243261
env:

.github/workflows/test-e2e.yml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ jobs:
1515
runs-on: ubuntu-latest
1616
outputs:
1717
test_matrix: ${{ steps.compute.outputs.matrix }}
18+
next_version: ${{ steps.read_version.outputs.version }}
1819
steps:
1920
- uses: actions/checkout@v5
2021

@@ -26,9 +27,14 @@ jobs:
2627
matrix='["v1.31.9-kind", "v1.33.2-kind"]'
2728
fi
2829
echo "matrix=${matrix}" >> "${GITHUB_OUTPUT}"
29-
30+
- name: Read the next release version
31+
id: read_version
32+
run: |
33+
VERSION=$(jq -r '.next' version.json)
34+
echo "version=${VERSION}" >> "${GITHUB_OUTPUT}"
3035
prepare-e2e-image:
3136
runs-on: ubuntu-latest
37+
needs: [prepare-e2e]
3238
outputs:
3339
image_url: ${{ steps.set_image_url.outputs.image_url }}
3440
env:
@@ -58,8 +64,7 @@ jobs:
5864
uses: ./.github/actions/build-push-image
5965
with:
6066
file: fast.Dockerfile
61-
repository: ${{ env.REPO }}
62-
version: ${{ steps.set_tag.outputs.tag }}
67+
version: ${{ needs.prepare-e2e.outputs.next_version }}
6368
tags: ${{ steps.set_image_url.outputs.image_url }}
6469
platforms: linux/amd64,linux/arm64
6570
push_to_docker: false

.github/workflows/tests-e2e2.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,6 @@ jobs:
142142
with:
143143
enable-cache: 'true'
144144

145-
- name: Prepare tag
146-
id: prepare
147-
uses: ./.github/actions/set-tag
148145
- name: Set properties
149146
id: properties
150147
run: |

.github/workflows/tests-selectable.yaml

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,18 @@ jobs:
2828
int_matrix: ${{ steps.set-matrix.outputs.int_matrix }}
2929
e2e_matrix: ${{ steps.set-matrix.outputs.e2e_matrix }}
3030
e2e_gov_matrix: ${{ steps.set-matrix.outputs.e2e_gov_matrix }}
31+
next_version: ${{ steps.read_version.outputs.version }}
3132
steps:
3233
- name: Checkout Code
3334
uses: actions/checkout@v5
3435
with:
3536
ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.branchName || github.event.pull_request.head.sha }}
36-
3737
- name: Setup GO
3838
uses: actions/setup-go@v6
3939
with:
4040
go-version-file: "${{ github.workspace }}/go.mod"
41-
4241
- name: Install Ginkgo
4342
run: go install github.com/onsi/ginkgo/v2/ginkgo@latest
44-
4543
- name: Get test labels from PR or input
4644
env:
4745
TEST_LABELS: ${{ github.event.inputs.testLabels }}
@@ -62,7 +60,6 @@ jobs:
6260
}
6361
console.log("Not a PullRequest or WorkflowDispatch event skipping");
6462
return [];
65-
6663
- name: List available Ginkgo test labels
6764
id: fetch-labels
6865
run: |
@@ -74,7 +71,6 @@ jobs:
7471
7572
echo "Available Integration Tests: $INT_LABELS"
7673
echo "Available E2E Tests: $E2E_LABELS"
77-
7874
- name: Compute Test Matrix
7975
id: set-matrix
8076
env:
@@ -92,6 +88,11 @@ jobs:
9288
echo "int_matrix=$(cat result.json | jq -c .int)" >> $GITHUB_OUTPUT
9389
echo "e2e_matrix=$(cat result.json | jq -c .e2e)" >> $GITHUB_OUTPUT
9490
echo "e2e_gov_matrix=$(cat result.json | jq -c .e2e_gov)" >> $GITHUB_OUTPUT
91+
- name: Read the next release version
92+
id: read_version
93+
run: |
94+
VERSION=$(jq -r '.next' version.json)
95+
echo "version=${VERSION}" >> "${GITHUB_OUTPUT}"
9596
9697
compute:
9798
needs: detect-tests
@@ -138,8 +139,7 @@ jobs:
138139
uses: ./.github/actions/build-push-image
139140
with:
140141
file: fast.Dockerfile
141-
repository: ghcr.io/${{ env.REPOSITORY }}
142-
version: ${{ steps.prepare.outputs.tag }}
142+
version: ${{ needs.detect-tests.outputs.next_version }}
143143
tags: ghcr.io/${{ env.REPOSITORY }}:${{ steps.prepare.outputs.tag }}
144144
platforms: linux/amd64
145145
push_to_docker: false
@@ -178,7 +178,7 @@ jobs:
178178
uses: ./.github/actions/gen-install-scripts
179179
with:
180180
IMAGE_URL: ${{ env.GHCR_REPO }}:${{ steps.prepare.outputs.tag }}
181-
VERSION: ${{ steps.prepare.outputs.tag }}
181+
VERSION: ${{ needs.detect-tests.outputs.next_version }}
182182
ENV: dev
183183

184184
- name: Change URL for the test
@@ -207,8 +207,7 @@ jobs:
207207
uses: ./.github/actions/build-push-image
208208
with:
209209
file: fast.Dockerfile
210-
repository: ${{ env.GHCR_BUNDLES_REPO }}
211-
version: ${{ steps.prepare.outputs.tag }}
210+
version: ${{ needs.detect-tests.outputs.next_version }}
212211
tags: ${{ env.GHCR_BUNDLES_REPO }}:${{ steps.prepare.outputs.tag }}
213212
platforms: linux/amd64
214213
push_to_docker: false
@@ -295,7 +294,7 @@ jobs:
295294
uses: ./.github/actions/gen-install-scripts
296295
with:
297296
IMAGE_URL: ${{ env.GHCR_REPO }}:${{ steps.prepare.outputs.tag }}
298-
VERSION: ${{ steps.prepare.outputs.tag }}
297+
VERSION: ${{ needs.detect-tests.outputs.next_version }}
299298
ENV: dev
300299

301300
- name: Change path for the test

Makefile

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,19 @@ DOCKER_SBOM_PLUGIN_VERSION=0.6.1
1111
# To re-generate a bundle for another specific version without changing the standard setup, you can:
1212
# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2)
1313
# - use environment variables to overwrite this value (e.g export VERSION=0.0.2)
14+
VERSION_FILE=version.json
1415
VERSION ?= $(shell git describe --always --tags --dirty --broken | cut -c 2-)
16+
BUILDTIME ?= $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
17+
GITCOMMIT ?= $(shell git rev-parse --short HEAD 2> /dev/null || true)
18+
19+
VERSION_PACKAGE = github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/version
1520

1621
# LD_FLAGS
17-
LD_FLAG_SET_VERSION = -X github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/version.Version=$(VERSION)
18-
LD_FLAGS_SET_EXPERIMENTAL = -X github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/version.Experimental=$(EXPERIMENTAL)
22+
LD_FLAGS := -X $(VERSION_PACKAGE).Version=$(VERSION)
23+
LD_FLAGS += -X $(VERSION_PACKAGE).GitCommit=$(GITCOMMIT)
24+
LD_FLAGS += -X $(VERSION_PACKAGE).BuildTime=$(BUILDTIME)
1925
ifdef EXPERIMENTAL
20-
LD_FLAGS = $(LD_FLAGS_SET_EXPERIMENTAL) $(LD_FLAG_SET_VERSION)
21-
else
22-
LD_FLAGS = $(LD_FLAG_SET_VERSION)
26+
LD_FLAGS += -X $(VERSION_PACKAGE).Experimental=$(EXPERIMENTAL)
2327
endif
2428

2529
# NEXT_VERSION represents a version that is higher than anything released
@@ -444,8 +448,10 @@ actions.txt: .github/workflows/ ## List GitHub Action dependencies
444448

445449
.PHONY: check-major-version
446450
check-major-version: ## Check that VERSION starts with MAJOR_VERSION
447-
@[[ $(VERSION) == $(MAJOR_VERSION).* ]] && echo "Version OK" || \
448-
(echo "Bad major version for $(VERSION) expected $(MAJOR_VERSION)"; exit 1)
451+
@VERSION_MAJOR=$$(echo "$(VERSION)" | cut -d. -f1 | sed 's/v//'); \
452+
CURRENT_MAJOR=$$(jq -r '.current' $(VERSION_FILE) | cut -d. -f1); \
453+
[ "$$VERSION_MAJOR" = "$$CURRENT_MAJOR" ] || \
454+
(echo "Bad major version for $$VERSION expected $$CURRENT_MAJOR"; exit 1)
449455

450456
tools/makejwt/makejwt: tools/makejwt/*.go
451457
cd tools/makejwt && go test . && go build .
@@ -648,4 +654,13 @@ tools/scandeprecation/scandeprecation: tools/scandeprecation/*.go
648654
.PHONY: slack-deprecations
649655
slack-deprecations: tools/scandeprecation/scandeprecation tools/githubjobs/githubjobs
650656
@echo "Computing and sending deprecation report to Slack..."
651-
GH_RUN_ID=$(GH_RUN_ID) ./tools/githubjobs/githubjobs | grep "javaMethod" | ./tools/scandeprecation/scandeprecations | ./scripts/slackit.sh $(SLACK_WEBHOOK)
657+
GH_RUN_ID=$(GH_RUN_ID) ./tools/githubjobs/githubjobs | grep "javaMethod" | ./tools/scandeprecation/scandeprecations | ./scripts/slackit.sh $(SLACK_WEBHOOK)
658+
659+
.PHONY: bump-version-file
660+
bump-version-file:
661+
@echo "Bumping version in $(VERSION_FILE)..."
662+
663+
jq '(.next | split(".") | map(tonumber) | .[1] += 1 | .[2] = 0 | map(tostring) | join(".")) as $$new_next | .current = .next | .next = $$new_next' $(VERSION_FILE) > $(VERSION_FILE).tmp && mv $(VERSION_FILE).tmp $(VERSION_FILE)
664+
665+
@echo "Version updated successfully:"
666+
@cat $(VERSION_FILE)

docs/dev/release.md

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ At least **one** (1) week before the release the Kubernetes Version testing matr
2323

2424
Please refer to the [CI documentation](ci.md#kubernetes-version-matrix) and submit a pull request, example: https://github.com/mongodb/mongodb-atlas-kubernetes/pull/2161 or https://github.com/mongodb/mongodb-atlas-kubernetes/pull/2082.
2525

26+
## A Note on Versioning with `version.json`
27+
28+
The `version.json` file is the definitive **source of truth** for managing software versions in this project.
29+
30+
* **Source of Truth**: The file contains two primary fields: **`current`**, which reflects the latest stable version that has been released, and **`next`**, which designates the version targeted for the upcoming release.
31+
32+
* **Automatic Updates for next Releases**: After a successful release, the CI pipeline will **automatically** update `version.json`. The `current` field is set to the version that was just released, and the `next` field is incremented to the next minor version (e.g., `2.11.0` would become `2.12.0`, or `2.11.4` would become `2.12.0`).
33+
34+
* **Manual Updates for Patch Releases**: Creating a **patch release** (e.g., `v2.10.1`) is a deliberate exception to the automated process. To prepare for a patch, you must **manually** update the `next` field to the exact patch version via a Pull Request (PR). This manual step ensures the release workflow targets the specific patch instead of accidentally creating the next minor release.
35+
2636
## Release Notes
2737

2838
- Create a draft of the release notes in a Google Document and share with Product and the Docs team.
@@ -42,26 +52,23 @@ You will be prompted to enter:
4252

4353
| Input | Description | Required | Default | Example |
4454
|-------------|-----------------------------------------------------------------------------------------------------|----------|----------|---------------------------------------|
45-
| `version` | The version to be released, including the `v` prefix | Yes | None | `v1.10.3` |
4655
| `authors` | A comma-separated list of MongoDB email addresses responsible for the release | Yes | None | `[email protected],[email protected]` |
4756
| `image_sha` | The 7-character Git commit SHA used for the promoted image, or `'latest'` for the most recent | No | `latest` | `3e79a3f`. |
4857

49-
The inputs `version` and `authors` must be filled out every time you trigger the release workflow. The `image_sha` is optional and defaults to `latest` if left empty.
58+
The input `authors` must be filled out every time you trigger the release workflow. The `image_sha` is optional and defaults to `latest` if left empty.
5059

5160
The `image_sha` corresponds exactly to the 7-character Git commit SHA used to build the operator image; for example, `image_sha: 3e79a3f` means the image was built from Git commit `3e79a3f`. Using `latest` as the `image_sha` means the workflow will release the most recently promoted and tested operator image—not necessarily the latest Git commit—and when `latest` is used, the workflow will echo the corresponding Git commit during the internal steps so the user knows exactly which source is being released.
5261

5362
### Example Release Input
5463

5564
```yaml
56-
version: v1.10.3
5765
5866
image_sha: 3e79a3f
5967
```
6068
6169
or
6270
6371
```yaml
64-
version: v1.10.3
6572
6673
image_sha: latest
6774
```
@@ -332,10 +339,12 @@ And use the URL there to set `OPENSHIFT_UPGRADE_SERVER_API` so that openshift up
332339

333340
### Major version issues when executing the "Create Release Branch" workflow
334341

335-
The release creation will fail if the file `major-version` contents does not match the major version to be released. This file explicitly means the upcoming release is for a particular major version, with potential breaking changes. This allows us to:
342+
The release creation will fail if the major version of the release you're creating is incompatible with the `current` version defined in the `version.json` file. This file acts as the single source of truth for the codebase's version, which helps prevent mistakes.
343+
344+
This check allows us to:
336345

337-
1. Notice if we forgot to update the `major-version` file before releasing the next major version.
338-
2. Notice if we tried to re-release an older major version when the code is already prepared for the next major version.
339-
3. Skip some tests, like `helm update`, when crossing from one major version to the next, as such test is not expected to work across incompatible major version upgrades.
346+
1. **Prevent Mismatches**: It stops the workflow if the version being released (e.g., `v3.0.0`) has a different major version than what the codebase expects (e.g., `current` is `v2.11.0`).
347+
2. **Avoid Incorrect Patching**: It stops you from accidentally trying to release a patch for an older major version (e.g., `v1.2.3`) when the codebase has already moved on to a new major version.
348+
3. **Skip Tests**: Certain tests that are expected to fail, like Helm upgrades, they should be skipped.
340349

341-
If the create release branch job fails due an error such as `Bad major version for X... expected Y..`, review whether or not the `major-version` file was updated as expected. Check as well you are not trying to release a patch for the older major version from the new major version codebase.
350+
If the "Create Release Branch" job fails with an error like `Bad major version for X... expected Y...`, you should review the `current` field in `version.json`. Ensure it correctly reflects the codebase's state and is compatible with the version you intend to release.

0 commit comments

Comments
 (0)