Skip to content

Commit b8f85c9

Browse files
authoredOct 11, 2024··
fix(ci): get correct previous release version for release notes (#19443) (#20315)
* better release notes Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> * work on fork Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> * don't do unnecessary stuff Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> * fix path Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> * fix path Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> * help debug Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> * refactor, clean up Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> * use a workspace to avoid touching the main go.mod Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> --------- Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
1 parent d542b02 commit b8f85c9

File tree

5 files changed

+262
-15
lines changed

5 files changed

+262
-15
lines changed
 

‎.github/workflows/release.yaml

+11-15
Original file line numberDiff line numberDiff line change
@@ -69,20 +69,16 @@ jobs:
6969
- name: Fetch all tags
7070
run: git fetch --force --tags
7171

72-
- name: Set GORELEASER_PREVIOUS_TAG # Workaround, GoReleaser uses 'git-describe' to determine a previous tag. Our tags are created in realease branches.
73-
run: |
74-
set -xue
75-
if echo ${{ github.ref_name }} | grep -E -- '-rc1+$';then
76-
echo "GORELEASER_PREVIOUS_TAG=$(git -c 'versionsort.suffix=-rc' tag --list --sort=version:refname | tail -n 2 | head -n 1)" >> $GITHUB_ENV
77-
else
78-
echo "This is not the first release on the branch, Using GoReleaser defaults"
79-
fi
80-
8172
- name: Setup Golang
8273
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
8374
with:
8475
go-version: ${{ env.GOLANG_VERSION }}
8576

77+
- name: Set GORELEASER_PREVIOUS_TAG # Workaround, GoReleaser uses 'git-describe' to determine a previous tag. Our tags are created in release branches.
78+
run: |
79+
set -xue
80+
echo "GORELEASER_PREVIOUS_TAG=$(go run hack/get-previous-release/get-previous-version-for-release-notes.go ${{ github.ref_name }})" >> $GITHUB_ENV
81+
8682
- name: Set environment variables for ldflags
8783
id: set_ldflag
8884
run: |
@@ -105,7 +101,7 @@ jobs:
105101
args: release --clean --timeout 55m
106102
env:
107103
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
108-
KUBECTL_VERSION: ${{ env.KUBECTL_VERSION }}
104+
KUBECTL_VERSION: ${{ env.KUBECTL_VERSION }}
109105
GIT_TREE_STATE: ${{ env.GIT_TREE_STATE }}
110106

111107
- name: Generate subject for provenance
@@ -188,7 +184,7 @@ jobs:
188184
fi
189185
190186
cd /tmp && tar -zcf sbom.tar.gz *.spdx
191-
187+
192188
- name: Generate SBOM hash
193189
shell: bash
194190
id: sbom-hash
@@ -197,29 +193,29 @@ jobs:
197193
# base64 -w0 encodes to base64 and outputs on a single line.
198194
# sha256sum /tmp/sbom.tar.gz ... | base64 -w0
199195
echo "hashes=$(sha256sum /tmp/sbom.tar.gz | base64 -w0)" >> "$GITHUB_OUTPUT"
200-
196+
201197
- name: Upload SBOM
202198
uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8
203199
env:
204200
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
205201
with:
206202
files: |
207203
/tmp/sbom.tar.gz
208-
204+
209205
sbom-provenance:
210206
needs: [generate-sbom]
211207
permissions:
212208
actions: read # for detecting the Github Actions environment
213209
id-token: write # Needed for provenance signing and ID
214210
contents: write # Needed for release uploads
215211
if: github.repository == 'argoproj/argo-cd'
216-
# Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator
212+
# Must be referenced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator
217213
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
218214
with:
219215
base64-subjects: "${{ needs.generate-sbom.outputs.hashes }}"
220216
provenance-name: "argocd-sbom.intoto.jsonl"
221217
upload-assets: true
222-
218+
223219
post-release:
224220
needs:
225221
- argocd-image
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"golang.org/x/mod/semver"
6+
"os"
7+
"os/exec"
8+
"regexp"
9+
"strconv"
10+
"strings"
11+
)
12+
13+
/**
14+
This script is used to determine the previous version of a release based on the current version. It is used to help
15+
generate release notes for a new release.
16+
*/
17+
18+
func main() {
19+
if len(os.Args) < 2 {
20+
fmt.Println("Usage: go run get-previous-version-for-release-notes.go <version being released>")
21+
return
22+
}
23+
24+
proposedTag := os.Args[1]
25+
26+
tags, err := getGitTags()
27+
if err != nil {
28+
fmt.Printf("Error getting git tags: %v\n", err)
29+
return
30+
}
31+
32+
previousTag, err := findPreviousTag(proposedTag, tags)
33+
if err != nil {
34+
fmt.Printf("Error finding previous tag: %v\n", err)
35+
os.Exit(1)
36+
}
37+
38+
fmt.Printf("%s\n", previousTag)
39+
}
40+
41+
func extractPatchAndRC(tag string) (string, string, error) {
42+
re := regexp.MustCompile(`^v\d+\.\d+\.(\d+)(?:-rc(\d+))?$`)
43+
matches := re.FindStringSubmatch(tag)
44+
if len(matches) < 2 {
45+
return "", "", fmt.Errorf("invalid tag format: %s", tag)
46+
}
47+
patch := matches[1]
48+
rc := "0"
49+
if len(matches) == 3 && matches[2] != "" {
50+
rc = matches[2]
51+
}
52+
return patch, rc, nil
53+
}
54+
55+
func findPreviousTag(proposedTag string, tags []string) (string, error) {
56+
var previousTag string
57+
proposedMajor := semver.Major(proposedTag)
58+
proposedMinor := semver.MajorMinor(proposedTag)
59+
60+
proposedPatch, proposedRC, err := extractPatchAndRC(proposedTag)
61+
if err != nil {
62+
return "", err
63+
}
64+
65+
// If the current tag is a .0 patch release or a 1 release candidate, adjust to the previous minor release series.
66+
if (proposedPatch == "0" && proposedRC == "0") || proposedRC == "1" {
67+
proposedMinorInt, err := strconv.Atoi(strings.TrimPrefix(proposedMinor, proposedMajor+"."))
68+
if err != nil {
69+
return "", fmt.Errorf("invalid minor version: %v", err)
70+
}
71+
if proposedMinorInt > 0 {
72+
proposedMinor = fmt.Sprintf("%s.%d", proposedMajor, proposedMinorInt-1)
73+
}
74+
}
75+
76+
for _, tag := range tags {
77+
if tag == proposedTag {
78+
continue
79+
}
80+
tagMajor := semver.Major(tag)
81+
tagMinor := semver.MajorMinor(tag)
82+
tagPatch, tagRC, err := extractPatchAndRC(tag)
83+
if err != nil {
84+
continue
85+
}
86+
87+
// Only bother considering tags with the same major and minor version.
88+
if tagMajor == proposedMajor && tagMinor == proposedMinor {
89+
// If it's a non-RC release...
90+
if proposedRC == "0" {
91+
// Only consider non-RC tags.
92+
if tagRC == "0" {
93+
if semver.Compare(tag, previousTag) > 0 {
94+
previousTag = tag
95+
}
96+
}
97+
} else {
98+
if tagRC != "0" && tagPatch == proposedPatch {
99+
if semver.Compare(tag, previousTag) > 0 {
100+
previousTag = tag
101+
}
102+
} else if tagRC == "0" {
103+
if semver.Compare(tag, previousTag) > 0 {
104+
previousTag = tag
105+
}
106+
}
107+
}
108+
}
109+
}
110+
if previousTag == "" {
111+
return "", fmt.Errorf("no matching tag found for tags: " + strings.Join(tags, ", "))
112+
}
113+
return previousTag, nil
114+
}
115+
116+
func getGitTags() ([]string, error) {
117+
cmd := exec.Command("git", "tag", "--sort=-v:refname")
118+
output, err := cmd.Output()
119+
if err != nil {
120+
return nil, fmt.Errorf("error executing git command: %v", err)
121+
}
122+
123+
tags := strings.Split(string(output), "\n")
124+
var semverTags []string
125+
for _, tag := range tags {
126+
if semver.IsValid(tag) {
127+
semverTags = append(semverTags, tag)
128+
}
129+
}
130+
131+
return semverTags, nil
132+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package main
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestFindPreviousTagRules(t *testing.T) {
10+
t.Parallel()
11+
// Sample pulled from git tag --sort=-v:refname output.
12+
tags := []string{
13+
"v2.13.0-rc3",
14+
"v2.13.0-rc2",
15+
"v2.13.0-rc1",
16+
"v2.12.5",
17+
"v2.12.4",
18+
"v2.12.3",
19+
"v2.12.2",
20+
"v2.12.1",
21+
"v2.12.0-rc5",
22+
"v2.12.0-rc4",
23+
"v2.12.0-rc3",
24+
"v2.12.0-rc2",
25+
"v2.12.0-rc1",
26+
"v2.12.0",
27+
"v2.11.11",
28+
"v2.11.10",
29+
"v2.11.9",
30+
"v2.11.8",
31+
"v2.11.7",
32+
"v2.11.6",
33+
"v2.11.5",
34+
"v2.11.4",
35+
"v2.11.3",
36+
"v2.11.2",
37+
"v2.11.1",
38+
"v2.11.0-rc3",
39+
"v2.11.0-rc2",
40+
"v2.11.0-rc1",
41+
"v2.11.0",
42+
"v2.10.17",
43+
"v2.10.16",
44+
"v2.10.15",
45+
"v2.10.14",
46+
"v2.10.13",
47+
"v2.10.12",
48+
"v2.10.11",
49+
"v2.10.10",
50+
"v2.10.9",
51+
"v2.10.8",
52+
"v2.10.7",
53+
"v2.10.6",
54+
"v2.10.5",
55+
"v2.10.4",
56+
"v2.10.3",
57+
"v2.10.2",
58+
"v2.10.1",
59+
"v2.10.0-rc5",
60+
"v2.10.0-rc4",
61+
"v2.10.0-rc3",
62+
"v2.10.0-rc2",
63+
"v2.10.0-rc1",
64+
"v2.10.0",
65+
}
66+
67+
tests := []struct {
68+
name, proposedTag, expected string
69+
expectError bool
70+
}{
71+
// Rule 1: If we're releasing a .0 patch release, get the most recent tag on the previous minor release series.
72+
{"Rule 1: .0 patch release", "v2.13.0", "v2.12.5", false},
73+
// Rule 2: If we're releasing a non-0 patch release, get the most recent tag within the same minor release series.
74+
{"Rule 2: non-0 patch release", "v2.12.6", "v2.12.5", false},
75+
// Rule 3: If we're releasing a 1 release candidate, get the most recent tag on the previous minor release series.
76+
{"Rule 3: 1 release candidate", "v2.14.0-rc1", "v2.13.0-rc3", false},
77+
// Rule 4: If we're releasing a non-1 release candidate, get the most recent rc tag on the current minor release series.
78+
{"Rule 4: non-1 release candidate", "v2.13.0-rc4", "v2.13.0-rc3", false},
79+
}
80+
81+
for _, test := range tests {
82+
t.Run(test.name, func(t *testing.T) {
83+
t.Parallel()
84+
result, err := findPreviousTag(test.proposedTag, tags)
85+
if test.expectError {
86+
assert.Error(t, err)
87+
} else {
88+
assert.NoError(t, err)
89+
assert.Equalf(t, test.expected, test.expected, "for proposed tag %s expected %s but got %s", test.proposedTag, test.expected, result)
90+
}
91+
})
92+
}
93+
}

‎hack/get-previous-release/go.mod

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module github.com/argoproj/argo-cd/get-previous-release
2+
3+
go 1.22.5
4+
5+
require (
6+
github.com/stretchr/testify v1.9.0
7+
golang.org/x/mod v0.21.0
8+
)
9+
10+
require (
11+
github.com/davecgh/go-spew v1.1.1 // indirect
12+
github.com/pmezard/go-difflib v1.0.0 // indirect
13+
gopkg.in/yaml.v3 v3.0.1 // indirect
14+
)

‎hack/get-previous-release/go.sum

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
4+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5+
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
6+
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
7+
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
8+
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
9+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
10+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
11+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
12+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

0 commit comments

Comments
 (0)
Please sign in to comment.