blob: 5f79e1bc7ac8b17d9bfa2629776043c616e48de6 [file] [log] [blame]
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package task
import (
"context"
"fmt"
"testing"
"github.com/google/go-github/v48/github"
"golang.org/x/build/internal/workflow"
)
func TestLatestVersion(t *testing.T) {
testcases := []struct {
name string
input []string
filters []func(semversion) bool
want semversion
}{
{
name: "choose the latest version v2.1.0",
input: []string{"v1.0.0", "v2.0.0", "v2.1.0"},
want: semversion{Major: 2, Minor: 1, Patch: 0},
},
{
name: "choose the latest version v2.2.0-pre.1",
input: []string{"v1.0.0", "v2.0.0", "v2.1.0", "v2.2.0-pre.1"},
want: semversion{Major: 2, Minor: 2, Patch: 0, Pre: "pre.1"},
},
{
name: "choose the latest pre-release version v2.2.0-pre.1",
input: []string{"v1.0.0", "v2.0.0", "v2.1.0", "v2.2.0-pre.1", "v2.3.0"},
filters: []func(semversion) bool{isPrereleaseVersion},
want: semversion{Major: 2, Minor: 2, Patch: 0, Pre: "pre.1"},
},
{
name: "choose the latest release version v2.1.0",
input: []string{"v1.0.0", "v2.0.0", "v2.1.0", "v2.2.0-pre.1"},
filters: []func(semversion) bool{isReleaseVersion},
want: semversion{Major: 2, Minor: 1, Patch: 0},
},
{
name: "choose the latest version among v2.2.0",
input: []string{"v1.0.0", "v2.0.0", "v2.1.0", "v2.2.0-pre.3", "v2.2.0-pre.2", "v2.2.0-pre.1", "v2.3.0"},
filters: []func(semversion) bool{isSameMajorMinorPatch(semversion{Major: 2, Minor: 2, Patch: 0})},
want: semversion{Major: 2, Minor: 2, Patch: 0, Pre: "pre.3"},
},
{
name: "release version is consider newer than prerelease version",
input: []string{"v1.0.0", "v2.0.0", "v2.1.0", "v2.2.0", "v2.2.0-pre.2", "v2.2.0-pre.3", "v2.2.0-pre.1", "v2.3.0"},
filters: []func(semversion) bool{isSameMajorMinorPatch(semversion{Major: 2, Minor: 2, Patch: 0})},
want: semversion{Major: 2, Minor: 2, Patch: 0},
},
{
name: "choose the latest pre-release version among v2.2.0",
input: []string{"v1.0.0", "v2.0.0", "v2.1.0", "v2.2.0", "v2.2.0-pre.2", "v2.2.0-pre.3", "v2.2.0-pre.1", "v2.3.0"},
filters: []func(semversion) bool{isPrereleaseVersion, isSameMajorMinorPatch(semversion{Major: 2, Minor: 2, Patch: 0})},
want: semversion{Major: 2, Minor: 2, Patch: 0, Pre: "pre.3"},
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
got := latestVersion(tc.input, tc.filters...)
if got != tc.want {
t.Errorf("latestVersion() = %v, want %v", got, tc.want)
}
})
}
}
func TestCreateReleaseMilestoneAndIssue(t *testing.T) {
testcases := []struct {
name string
version string
fakeGithub FakeGitHub
wantIssue int
wantMilestone int
}{
{
name: "flow should create a milestone and create an issue under the milestone",
version: "v0.45.0-rc.1",
fakeGithub: FakeGitHub{}, // no issues and no milestones.
wantIssue: 1,
wantMilestone: 1,
},
{
name: "flow should create an issue under the existing milestone",
version: "v0.48.0-rc.1",
fakeGithub: FakeGitHub{
Milestones: map[int]string{999: "v0.48.0", 998: "v0.46.0"},
},
wantIssue: 1,
wantMilestone: 999,
},
{
name: "flow should reuse the existing release issue",
version: "v0.48.0-rc.1",
fakeGithub: FakeGitHub{
Milestones: map[int]string{999: "v0.48.0", 998: "Release v0.46.0"},
Issues: map[int]*github.Issue{1000: {Number: github.Int(1000), Title: github.String("Release v0.48.0"), Milestone: &github.Milestone{ID: github.Int64(999)}}},
},
wantIssue: 1000,
wantMilestone: 999,
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
tasks := &ReleaseVSCodeGoTasks{
GitHub: &tc.fakeGithub,
}
semv, ok := parseSemver(tc.version)
if !ok {
t.Fatalf("parseSemver(%q) should success", tc.version)
}
issueNumber, err := tasks.createReleaseMilestoneAndIssue(&workflow.TaskContext{Context: context.Background(), Logger: &testLogger{t, ""}}, semv)
if err != nil {
t.Fatal(err)
}
issue, ok := tc.fakeGithub.Issues[issueNumber]
if !ok {
t.Errorf("release issue with number %v does not exist", issueNumber)
}
if *issue.Number != tc.wantIssue {
t.Errorf("createReleaseMilestoneAndIssue() create an issue with number %v, but should create issue with number %v", issue.Number, tc.wantIssue)
}
if int(*issue.Milestone.ID) != tc.wantMilestone {
t.Errorf("release issue is created under milestone %v should under milestone %v", *issue.Milestone.ID, tc.wantMilestone)
}
})
}
}
func TestCreateReleaseBranch(t *testing.T) {
ctx := context.Background()
testcases := []struct {
name string
version string
existingBranch bool
wantErr bool
}{
{
name: "nil if the release branch does not exist for first rc in a minor release",
version: "v0.44.0-rc.1",
existingBranch: false,
wantErr: false,
},
{
name: "nil if the release branch already exist for non-initial rc in a minor release",
version: "v0.44.0-rc.4",
existingBranch: true,
wantErr: false,
},
{
name: "fail if the release branch does not exist for non-initial rc in a minor release",
version: "v0.44.0-rc.4",
existingBranch: false,
wantErr: true,
},
{
name: "nil if the release branch already exist for a patch version",
version: "v0.44.3-rc.3",
existingBranch: true,
wantErr: false,
},
{
name: "fail if the release branch does not exist for a patch version",
version: "v0.44.3-rc.3",
existingBranch: false,
wantErr: true,
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
semv, ok := parseSemver(tc.version)
if !ok {
t.Fatalf("failed to parse the want version: %q", tc.version)
}
vscodego := NewFakeRepo(t, "vscode-go")
commit := vscodego.Commit(map[string]string{
"go.mod": "module github.com/golang/vscode-go\n",
"go.sum": "\n",
})
if tc.existingBranch {
vscodego.Branch(fmt.Sprintf("release-v%v.%v", semv.Major, semv.Minor), commit)
}
gerrit := NewFakeGerrit(t, vscodego)
tasks := &ReleaseVSCodeGoTasks{
Gerrit: gerrit,
}
err := tasks.createReleaseBranch(&workflow.TaskContext{Context: ctx, Logger: &testLogger{t, ""}}, semv)
if tc.wantErr && err == nil {
t.Errorf("createReleaseBranch(%q) should return error but return nil", tc.version)
} else if !tc.wantErr && err != nil {
t.Errorf("createReleaseBranch(%q) should return nil but return err: %v", tc.version, err)
}
if !tc.wantErr {
if _, err := gerrit.ReadBranchHead(ctx, "vscode-go", fmt.Sprintf("release-v%v.%v", semv.Major, semv.Minor)); err != nil {
t.Errorf("createReleaseBranch(%q) should ensure the release branch creation: %v", tc.version, err)
}
}
})
}
}
func TestNextPrereleaseVersion(t *testing.T) {
tests := []struct {
name string
existingTags []string
versionRule string
wantVersion string
}{
{
name: "v0.44.0 have not released, have no release candidate",
existingTags: []string{"v0.44.0", "v0.43.0", "v0.42.0"},
versionRule: "next minor",
wantVersion: "v0.46.0-rc.1",
},
{
name: "v0.44.0 have not released but already have two release candidate",
existingTags: []string{"v0.44.0-rc.1", "v0.44.0-rc.2", "v0.43.0", "v0.42.0"},
versionRule: "next minor",
wantVersion: "v0.44.0-rc.3",
},
{
name: "v0.44.3 have not released, have no release candidate",
existingTags: []string{"v0.44.2-rc.1", "v0.44.2", "v0.44.1", "v0.44.1-rc.1"},
versionRule: "next patch",
wantVersion: "v0.44.3-rc.1",
},
{
name: "v0.44.3 have not released but already have one release candidate",
existingTags: []string{"v0.44.3-rc.1", "v0.44.2", "v0.44.2-rc.1", "v0.44.1", "v0.44.1-rc.1"},
versionRule: "next patch",
wantVersion: "v0.44.3-rc.2",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
vscodego := NewFakeRepo(t, "vscode-go")
commit := vscodego.Commit(map[string]string{
"go.mod": "module github.com/golang/vscode-go\n",
"go.sum": "\n",
})
for _, tag := range tc.existingTags {
vscodego.Tag(tag, commit)
}
gerrit := NewFakeGerrit(t, vscodego)
tasks := &ReleaseVSCodeGoTasks{
Gerrit: gerrit,
}
got, err := tasks.nextPrereleaseVersion(&workflow.TaskContext{Context: context.Background(), Logger: &testLogger{t, ""}}, tc.versionRule)
if err != nil {
t.Fatal(err)
}
want, ok := parseSemver(tc.wantVersion)
if !ok {
t.Fatalf("failed to parse the want version: %q", tc.wantVersion)
}
if want != got {
t.Errorf("nextPrereleaseVersion(%q) = %v but want %v", tc.versionRule, got, want)
}
})
}
}
func TestVSCodeGoActiveReleaseBranch(t *testing.T) {
testcases := []struct {
name string
existingBranches []string
want string
}{
{
name: "choose the largest release branch",
existingBranches: []string{"release-v0.42", "release-v0.44", "release-v0.46"},
want: "release-v0.46",
},
{
name: "ignore any insider version release branch (should never exist)",
existingBranches: []string{"release-v0.42", "release-v0.44", "release-v0.46", "release-v0.47"},
want: "release-v0.46",
},
{
name: "ignore any branch with wrong formatting",
existingBranches: []string{"release-v0.42", "release-v0.44", "release-v0.46", "v0.48", "release-0.48"},
want: "release-v0.46",
},
{
name: "fall back to branch release",
existingBranches: []string{"foo", "bar"},
want: "release",
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
vscodego := NewFakeRepo(t, "vscode-go")
commit := vscodego.Commit(map[string]string{
"go.mod": "module github.com/golang/vscode-go\n",
"go.sum": "\n",
})
for _, branch := range tc.existingBranches {
vscodego.Branch(branch, commit)
}
gerrit := NewFakeGerrit(t, vscodego)
ctx := &workflow.TaskContext{
Context: context.Background(),
Logger: &testLogger{t, ""},
}
got, err := vsCodeGoActiveReleaseBranch(ctx, gerrit)
if err != nil {
t.Fatal(err)
}
if tc.want != got {
t.Errorf("vsCodeGoActiveReleaseBranch() = %q, want %q", got, tc.want)
}
})
}
}