Skip to content

Commit

Permalink
Implement standardized versioning (#44)
Browse files Browse the repository at this point in the history
* build: normalize version strings

Normalize version strings so they are consistently reported as vVERSION,
where VERSION is a valid semantic version string.

Custom versions that are not valid semvers are returned as is, and empty
strings are returned as v0.0.0.

* tools/gen-versioned-files: move version file to root as VERSION

* docs: update developer docs for managing VERSION file

* tools/image-tag: report consistent build information

This commit updates tools/image-tag to always report consistent build
information, with escape hatches to force the reported version:

1. If RELEASE_TAG is set (which happens via Drone pipelines), then the
   script emits the value of the RELEASE_TAG environment variable.

2. If a build is being performed against a Git tag, then the script
   emits the value of that Git tag.

3. Finally, if neither of the above are true, the version from the
   VERSION file is used, followed by the prerelease being set to `devel`
   and the short SHA added as build metadata.

Provided healthy workflwos where RELEASE_TAG and Git tags are always
semantic versions, this guarantees that versions reported by builds are
consistent and can be parsed properly.
  • Loading branch information
rfratto authored Mar 19, 2024
1 parent 077fb6d commit 550fec4
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 31 deletions.
23 changes: 23 additions & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# This file is used to determine the semantic version for the build of Grafana
# Alloy being constructed is.
#
# For builds produced against release branches, the major and minor version
# indicated in this file match the release branch. For example, for the branch
# release/v1.0, this file will report v1.0.0. The patch version indicated by this
# file syncs with the patch release being planned. For example, if a v1.0.1
# patch release is planned, this file will report v1.0.1 before that release is
# produced.
#
# For builds produced against main branches, the major and minor version
# reported by this file matches the next minor or major version to be released.
# For example, if v1.0.0 was just released, this file (in the main branch) will
# report v1.1.0, the next release planned.
#
# The string in this file MUST be a valid semantic version prefixed with "v",
# without any pre-release or build information.
#
# This file is ignored when building binaries from a Git tag.
#
# Lines starting with "#" and blank lines are ignored.

v1.0.0
4 changes: 4 additions & 0 deletions docs/developer/release/1-create-release-branch.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@ Patch Releases for that major pr minor version of the agent.

> **NOTE**: Don't create any other branches that are prefixed with `release` when creating PRs or
those branches will collide with our automated release build publish rules.

3. Open a PR against `main` to update the VERSION file at the root of the
repository to the next minor release planned. For example, if you have just
created `release/v1.0`, then VERSION should be updated to `v1.1.0`.
26 changes: 14 additions & 12 deletions docs/developer/release/3-update-version-in-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,6 @@ The project must be updated to reference the upcoming release tag whenever a new

2. Move the unreleased changes we want to add to the release branch from `Main (unreleased)` to `VERSION (YYYY-MM-DD)`.

3. Update appropriate places in the codebase that have the previous version with the new version determined above.

First update `tools/gen-versioned-files/agent-version.txt` with the new `VERSION` and run:

```
make generate-versioned-files
```
Next, commit the changes (including those to `tools/gen-versioned-files/agent-version.txt`, as a workflow will use this version to ensure that the templates and generated files are in sync).
* Do **not** update the `operations/helm` directory. It is updated independently from Agent releases.
3. Create a PR to merge to main (must be merged before continuing).

- Release Candidate example PR [here](https://github.com/grafana/agent/pull/3065)
Expand All @@ -50,6 +38,20 @@ The project must be updated to reference the upcoming release tag whenever a new
Delete the `Main (unreleased)` header and anything underneath it as part of the cherry-pick. Alternatively, do it after the cherry-pick is completed.
6. **If you are creating a patch release,** ensure that the file called `VERSION` in your branch matches the version being published, without any release candidate or build information:
> **NOTE**: Only perform this step for patch releases, and make sure that
> the change is not pushed to the main branch.
After updating `VERSION`, run:
```bash
make generate-versioned-files
```

Next, commit the changes (including those to `VERSION`, as a workflow will use this version to ensure that the templates and generated files are in sync).


6. Create a PR to merge to `release/VERSION_PREFIX` (must be merged before continuing).

- Release Candidate example PR [here](https://github.com/grafana/agent/pull/3066)
Expand Down
2 changes: 1 addition & 1 deletion docs/sources/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: Grafana Alloy
description: Grafana Alloy is a flexible, performant, vendor-neutral, telemetry collector
weight: 350
cascade:
ALLOY_RELEASE: $ALLOY_VERSION
ALLOY_RELEASE: v1.0.0
OTEL_VERSION: v0.87.0
PRODUCT_NAME: Grafana Alloy
PRODUCT_ROOT_NAME: Alloy
Expand Down
21 changes: 21 additions & 0 deletions internal/build/build.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package build

import (
"strings"

"github.com/blang/semver/v4"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/version"
)
Expand All @@ -18,9 +21,27 @@ var (
)

func init() {
Version = normalizeVersion(Version)
injectVersion()
}

// normalizeVersion normalizes the version string to always contain a "v"
// prefix. If version cannot be parsed as a semantic version, version is returned unmodified.
//
// if version is empty, normalizeVersion returns "v0.0.0".
func normalizeVersion(version string) string {
version = strings.TrimSpace(version)
if version == "" {
return "v0.0.0"
}

parsed, err := semver.ParseTolerant(version)
if err != nil {
return version
}
return "v" + parsed.String()
}

func injectVersion() {
version.Version = Version
version.Revision = Revision
Expand Down
33 changes: 33 additions & 0 deletions internal/build/build_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package build

import (
"testing"

"github.com/stretchr/testify/assert"
)

func Test_normalizeVersion(t *testing.T) {
tt := []struct {
input string
expect string
}{
{"", "v0.0.0"},
{"v1.2.3", "v1.2.3"},
{"1.2.3", "v1.2.3"},
{"1.2.3+SHA", "v1.2.3+SHA"},
{"v1.2.3+SHA", "v1.2.3+SHA"},
{"1.2.3-rc.1", "v1.2.3-rc.1"},
{"v1.2.3-rc.1", "v1.2.3-rc.1"},
{"1.2.3-rc.1+SHA", "v1.2.3-rc.1+SHA"},
{"v1.2.3-rc.1+SHA", "v1.2.3-rc.1+SHA"},
{"not_semver", "not_semver"},
}

for _, tc := range tt {
actual := normalizeVersion(tc.input)
assert.Equal(t, tc.expect, actual,
"Expected %q to normalize to %q, got %q",
tc.input, tc.expect, actual,
)
}
}
1 change: 0 additions & 1 deletion tools/gen-versioned-files/agent-version.txt

This file was deleted.

14 changes: 7 additions & 7 deletions tools/gen-versioned-files/gen-versioned-files.sh
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
#!/bin/sh
AGENT_VERSION=$(cat ./tools/gen-versioned-files/agent-version.txt | tr -d '\n')
ALLOY_VERSION=$(sed -e '/^#/d' -e '/^$/d' VERSION | tr -d '\n')

if [ -z "$AGENT_VERSION" ]; then
echo "AGENT_VERSION can't be found. Are you running this from the repo root?"
if [ -z "$ALLOY_VERSION" ]; then
echo "ALLOY_VERSION can't be found. Are you running this from the repo root?"
exit 1
fi

versionMatcher='^v[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?$'
versionMatcher='^v[0-9]+\.[0-9]+\.[0-9]$'

if ! echo "$AGENT_VERSION" | grep -Eq "$versionMatcher"; then
echo "AGENT_VERSION env var is not in the correct format. It should be in the format of vX.Y.Z or vX.Y.Z-rc.N"
if ! echo "$ALLOY_VERSION" | grep -Eq "$versionMatcher"; then
echo "ALLOY_VERSION env var is not in the correct format. It should be in the format of vX.Y.Z"
exit 1
fi

templates=$(find . -type f -name "*.t" -not -path "./.git/*")
for template in $templates; do
echo "Generating ${template%.t}"
sed -e "s/\$AGENT_VERSION/$AGENT_VERSION/g" < "$template" > "${template%.t}"
sed -e "s/\$ALLOY_VERSION/$ALLOY_VERSION/g" < "$template" > "${template%.t}"
done
33 changes: 23 additions & 10 deletions tools/image-tag
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
#!/usr/bin/env bash
#
# image-tag determines which version to embed into a built image.
#
# It prefers the following in precedence order:
#
# 1. RELEASE_TAG environment variable
# 2. The Git tag of the current commit (if any)
# 3. The version in the VERSION file, suffixed with -devel plus build
# information.
set -o errexit
set -o pipefail

VERSION=$(sed -e '/^#/d' -e '/^$/d' VERSION | tr -d '\n')
DETECTED_TAG=$(git describe --match 'v*' --exact-match 2>/dev/null || echo -n "")

if [ ! -z "${RELEASE_TAG}" ]; then
echo ${RELEASE_TAG}
exit 0
elif [ ! -z "${DETECTED_TAG}" ]; then
echo ${DETECTED_TAG}
exit 0
fi

set -o nounset

WIP=$(git diff --quiet || echo '-WIP')
BRANCH=$(git rev-parse --abbrev-ref HEAD | sed 's#/#-#g')

# When 7 chars are not enough to be unique, git automatically uses more.
# We are forcing to 7 here, as we are doing for grafana/grafana as well.
SHA=$(git rev-parse --short=7 HEAD | head -c7)

# If this is a tag, use it, otherwise use <branch>-<hash>
TAG=$(git describe --exact-match 2> /dev/null || echo "${BRANCH}-${SHA}")
echo ${TAG}${WIP}
if [[ -z $(git status -s) ]]; then
# There are no changes; report version as VERSION-devel+SHA.
SHA=$(git rev-parse --short HEAD)
echo ${VERSION}-devel+${SHA}
else
# Git is dirty; tag as VERSION-devel+wip.
echo ${VERSION}-devel+wip
fi

0 comments on commit 550fec4

Please sign in to comment.