blob: d7ced014e6d63c9792650f78b0867bdd8395829d [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"
"io"
"regexp"
"testing"
"github.com/google/go-cmp/cmp"
"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(releaseVersion, string) bool
wantRelease releaseVersion
wantPrerelease string
}{
{
name: "choose the latest version v2.1.0",
input: []string{"v1.0.0", "v2.0.0", "v2.1.0"},
wantRelease: releaseVersion{Major: 2, Minor: 1, Patch: 0},
wantPrerelease: "",
},
{
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"},
wantRelease: releaseVersion{Major: 2, Minor: 2, Patch: 0},
wantPrerelease: "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(releaseVersion, string) bool{isPrereleaseVersion},
wantRelease: releaseVersion{Major: 2, Minor: 2, Patch: 0},
wantPrerelease: "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(releaseVersion, string) bool{isReleaseVersion},
wantRelease: releaseVersion{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(releaseVersion, string) bool{isSameReleaseVersion(releaseVersion{Major: 2, Minor: 2, Patch: 0})},
wantRelease: releaseVersion{Major: 2, Minor: 2, Patch: 0},
wantPrerelease: "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(releaseVersion, string) bool{isSameReleaseVersion(releaseVersion{Major: 2, Minor: 2, Patch: 0})},
wantRelease: releaseVersion{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(releaseVersion, string) bool{isPrereleaseVersion, isSameReleaseVersion(releaseVersion{Major: 2, Minor: 2, Patch: 0})},
wantRelease: releaseVersion{Major: 2, Minor: 2, Patch: 0},
wantPrerelease: "pre.3",
},
{
name: "choose the latest pre-release version matching pattern among v2.2.0",
input: []string{"v2.2.0-pre.2", "v2.2.0-pre.3"},
filters: []func(releaseVersion, string) bool{isPrereleaseMatchRegex(`^pre\.\d+$`), isSameReleaseVersion(releaseVersion{Major: 2, Minor: 2, Patch: 0})},
wantRelease: releaseVersion{Major: 2, Minor: 2, Patch: 0},
wantPrerelease: "pre.3",
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
gotRelease, gotPrerelease := latestVersion(tc.input, tc.filters...)
if gotRelease != tc.wantRelease {
t.Errorf("latestVersion() = %v, want %v", gotRelease, tc.wantRelease)
}
if gotPrerelease != tc.wantPrerelease {
t.Errorf("latestVersion() = %v, want %v", gotPrerelease, tc.wantPrerelease)
}
})
}
}
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,
}
release, _, ok := parseVersion(tc.version)
if !ok {
t.Fatalf("parseVersion(%q) failed", tc.version)
}
issueNumber, err := tasks.createReleaseMilestoneAndIssue(&workflow.TaskContext{Context: context.Background(), Logger: &testLogger{t, ""}}, release, []string{"gobot"})
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
wantBranch string
}{
{
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,
wantBranch: "release-v0.44",
},
{
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,
wantBranch: "release-v0.44",
},
{
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,
wantBranch: "release-v0.44",
},
{
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) {
release, prerelease, ok := parseVersion(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", release.Major, release.Minor), commit)
}
gerrit := NewFakeGerrit(t, vscodego)
tasks := &ReleaseVSCodeGoTasks{
Gerrit: gerrit,
}
got, err := tasks.createReleaseBranch(&workflow.TaskContext{Context: ctx, Logger: &testLogger{t, ""}}, release, prerelease)
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 got != tc.wantBranch {
t.Errorf("createReleaseBranch(%q) returns %q, want %q", tc.version, got, tc.wantBranch)
}
if !tc.wantErr {
if _, err := gerrit.ReadBranchHead(ctx, "vscode-go", tc.wantBranch); err != nil {
t.Errorf("createReleaseBranch(%q) should ensure the release branch creation: %v", tc.version, err)
}
}
})
}
}
func TestDetermineReleaseAndNextPrereleaseVersion(t *testing.T) {
ctx := workflow.TaskContext{Context: context.Background(), Logger: &testLogger{t, ""}}
tests := []struct {
name string
existingTags []string
versionRule string
wantRelease releaseVersion
wantPrerelease 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",
wantRelease: releaseVersion{Major: 0, Minor: 46, Patch: 0},
wantPrerelease: "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",
wantRelease: releaseVersion{Major: 0, Minor: 44, Patch: 0},
wantPrerelease: "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",
wantRelease: releaseVersion{Major: 0, Minor: 44, Patch: 3},
wantPrerelease: "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",
wantRelease: releaseVersion{Major: 0, Minor: 44, Patch: 3},
wantPrerelease: "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,
}
gotRelease, err := tasks.determineReleaseVersion(&ctx, tc.versionRule)
if err != nil || gotRelease != tc.wantRelease {
t.Errorf("determineReleaseVersion(%q) = (%v, %v), want (%v, nil)", tc.versionRule, gotRelease, err, tc.wantRelease)
}
gotPrerelease, err := tasks.nextPrereleaseVersion(&ctx, gotRelease)
if err != nil || tc.wantPrerelease != gotPrerelease {
t.Errorf("nextPrerelease(%v) = (%s, %v) but want (%s, nil)", gotRelease, gotPrerelease, err, tc.wantPrerelease)
}
})
}
}
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)
}
})
}
}
func TestVerifyTestResults(t *testing.T) {
mustHaveShell(t)
fakeScriptFmt := `#!/bin/bash -exu
case "$1" in
"testlocal")
echo "the testlocal return %v"
exit %v
;;
*)
echo unexpected command $@
exit 1
;;
esac
`
testcases := []struct {
name string
rc int
wantErr bool
}{
{
name: "test failed, return error",
rc: 1,
wantErr: true,
},
{
name: "test passed, return nil",
rc: 0,
wantErr: false,
},
}
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",
"build/all.bash": fmt.Sprintf(fakeScriptFmt, tc.rc, tc.rc),
})
// Overwrite the script to empty to make sure vscode-go flow will checkout
// the specific commit.
_ = vscodego.Commit(map[string]string{
"build/all.bash": "",
})
gerrit := NewFakeGerrit(t, vscodego)
ctx := &workflow.TaskContext{
Context: context.Background(),
Logger: &testLogger{t, ""},
}
tasks := &ReleaseVSCodeGoTasks{
Gerrit: gerrit,
CloudBuild: NewFakeCloudBuild(t, gerrit, "vscode-go", nil, FakeBinary{"chown", fakeEmptyBinary}, FakeBinary{"npm", fakeEmptyBinary}),
}
err := tasks.verifyTestResults(ctx, commit)
if tc.wantErr && err == nil {
t.Errorf("verifyTestResult() should return error but return nil")
} else if !tc.wantErr && err != nil {
t.Errorf("verifyTestResult() should return nil but return err: %v", err)
}
})
}
}
func TestGeneratePackageExtension(t *testing.T) {
mustHaveShell(t)
testcases := []struct {
name string
release releaseVersion
prerelease string
rc int
wantErr bool
}{
{
name: "test failed, return error",
release: releaseVersion{0, 1, 0},
prerelease: "rc-1",
rc: 1,
wantErr: true,
},
{
name: "test passed, return nil",
release: releaseVersion{0, 2, 3},
prerelease: "",
rc: 0,
wantErr: false,
},
}
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",
"extension/tools/release/release.go": "foo",
})
gerrit := NewFakeGerrit(t, vscodego)
ctx := &workflow.TaskContext{
Context: context.Background(),
Logger: &testLogger{t, ""},
}
version := tc.release.String()[1:]
if tc.prerelease != "" {
version += tc.prerelease
}
// fakeGo write "bar" content to go-${version}.vsix file and "foo" content
// to README.md when executed go run tools/release/release.go.
var fakeGo = fmt.Sprintf(`#!/bin/bash -exu
case "$1" in
"run")
echo "writing content to vsix and README.md"
echo -n "bar" > go-%s.vsix
echo -n "foo" > README.md
exit %v
;;
*)
echo unexpected command $@
exit 1
;;
esac
`, version, tc.rc)
cloudbuild := NewFakeCloudBuild(t, gerrit, "vscode-go", nil, FakeBinary{Name: "go", Implementation: fakeGo}, FakeBinary{"npm", fakeEmptyBinary})
tasks := &ReleaseVSCodeGoTasks{
Gerrit: gerrit,
CloudBuild: cloudbuild,
}
cb, err := tasks.generatePackageExtension(ctx, tc.release, tc.prerelease, commit)
if tc.wantErr && err == nil {
t.Errorf("generateArtifacts(%s, %s, %s) should return error but return nil", tc.release, tc.prerelease, commit)
} else if !tc.wantErr && err != nil {
t.Errorf("generateArtifacts(%s, %s, %s) should return nil but return err: %v", tc.release, tc.prerelease, commit, err)
}
if !tc.wantErr {
path := fmt.Sprintf("go-%s.vsix", version)
resultFS, err := cloudbuild.ResultFS(ctx, cb)
if err != nil {
t.Fatal(err)
}
f, err := resultFS.Open(path)
if err != nil {
t.Fatal(err)
}
defer f.Close()
got, err := io.ReadAll(f)
if err != nil {
t.Fatal(err)
}
if string(got) != "bar" {
t.Errorf("generateArtifacts(%s, %s, %s) write content %q to %s, want %q", tc.release, tc.prerelease, commit, got, path, "bar")
}
}
})
}
}
func TestDetermineInsiderVersion(t *testing.T) {
testcases := []struct {
name string
existingTags []string
want releaseVersion
}{
{
name: "pick v0.45.0 because there is no other v0.45.X",
existingTags: []string{"v0.44.0", "v0.44.1", "v0.44.2"},
want: releaseVersion{Major: 0, Minor: 45, Patch: 0},
},
{
name: "pick v0.45.3 because there is v0.45.2",
existingTags: []string{"v0.44.0", "v0.44.1", "v0.44.2", "v0.45.2"},
want: releaseVersion{Major: 0, Minor: 45, Patch: 3},
},
{
name: "pick v0.47.4 because there is v0.47.3",
existingTags: []string{"v0.44.0", "v0.45.2", "v0.46.0", "v0.47.3"},
want: releaseVersion{Major: 0, Minor: 47, Patch: 4},
},
}
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 _, tag := range tc.existingTags {
vscodego.Tag(tag, commit)
}
gerrit := NewFakeGerrit(t, vscodego)
ctx := &workflow.TaskContext{
Context: context.Background(),
Logger: &testLogger{t, ""},
}
tasks := &ReleaseVSCodeGoTasks{
Gerrit: gerrit,
}
got, err := tasks.determineInsiderVersion(ctx)
if err != nil || got != tc.want {
t.Errorf("determineInsiderVersion() = (%v, %v), want (%v, nil)", got, err, tc.want)
}
})
}
}
func TestVSCodeGoGitHubReleaseBody(t *testing.T) {
// changelog is the content of the CHANGELOG.md in vscode-go repo master
// branch. For testing purpose, this file contains the following versions.
// v0.42.0 - a stable minor version.
// v0.42.1 - a stable patch version.
// Unreleased - for next stable version.
changelog := `# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/).
## Unreleased
CHANGE FOR v0.44.0 LINE 1
#### Level 3 heading 1
CHANGE FOR v0.44.0 LINE 2
#### Level 3 heading 2
CHANGE FOR v0.44.0 LINE 3
## v0.42.1
CHANGE FOR v0.42.1 LINE 1
CHANGE FOR v0.42.1 LINE 2
## v0.42.0
CHANGE FOR v0.42.0 LINE 1
CHANGE FOR v0.42.0 LINE 2
`
testcases := []struct {
name string
release releaseVersion
prerelease string
wantContent string
}{
{
name: "next stable patch version",
release: releaseVersion{Major: 0, Minor: 42, Patch: 2},
prerelease: "",
wantContent: "vscode-go-next-stable-patch.md",
},
{
name: "rc of the next patch version",
release: releaseVersion{Major: 0, Minor: 42, Patch: 2},
prerelease: "rc.3",
wantContent: "vscode-go-rc-next-stable-patch.md",
},
{
name: "next stable minor version",
release: releaseVersion{Major: 0, Minor: 44, Patch: 0},
prerelease: "",
wantContent: "vscode-go-next-stable-minor.md",
},
{
name: "rc of next stable minor version",
release: releaseVersion{Major: 0, Minor: 44, Patch: 0},
prerelease: "rc.4",
wantContent: "vscode-go-rc-next-stable-minor.md",
},
{
name: "next insider minor version",
release: releaseVersion{Major: 0, Minor: 43, Patch: 0},
prerelease: "",
wantContent: "vscode-go-next-insider-minor.md",
},
{
name: "next insider patch version",
release: releaseVersion{Major: 0, Minor: 43, Patch: 4},
prerelease: "",
wantContent: "vscode-go-next-insider-patch.md",
},
}
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",
"CHANGELOG.md": changelog,
})
for _, tag := range []string{"v0.42.1", "v0.42.0", "v0.41.1", "v0.41.0"} {
vscodego.Tag(tag, commit)
}
gerrit := NewFakeGerrit(t, vscodego)
ctx := &workflow.TaskContext{
Context: context.Background(),
Logger: &testLogger{t, ""},
}
tasks := &ReleaseVSCodeGoTasks{
Gerrit: gerrit,
}
gotBody, err := tasks.vscodeGoGitHubReleaseBody(ctx, tc.release, tc.prerelease)
if err != nil {
t.Fatal(err)
}
re := regexp.MustCompile(`Date: (.*)\n`)
want := re.ReplaceAllString(testdataFile(t, tc.wantContent), "\n")
got := re.ReplaceAllString(string(gotBody), "\n")
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("body text mismatch (-want +got):\n%s", diff)
}
})
}
}
func TestUpdatePackageJSONVersionInMasterBranch(t *testing.T) {
mustHaveShell(t)
testcases := []struct {
name string
existingTags []string
wantPackageJSON string
wantPackageLockJSON string
}{
{
name: "package json should point 0.46.0-dev",
existingTags: []string{"v0.44.0", "v0.45.0"},
wantPackageJSON: "0.46.0-dev",
wantPackageLockJSON: "0.46.0-dev\n",
},
{
name: "package json should point 0.48.0-dev",
existingTags: []string{"v0.45.0", "v0.46.0", "v0.46.1", "v0.46.2"},
wantPackageJSON: "0.48.0-dev",
wantPackageLockJSON: "0.48.0-dev\n",
},
}
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",
"extension/package.json": "foo\n",
"extension/package-lock.json": "foo\n",
})
for _, tag := range tc.existingTags {
vscodego.Tag(tag, commit)
}
gerrit := NewFakeGerrit(t, vscodego)
ctx := &workflow.TaskContext{
Context: context.Background(),
Logger: &testLogger{t, ""},
}
// fakeNPX successfully executes only when called with the command
// "npx vsce package V".
// In this case, the value "V" is written to both "package.json" and
// "package-lock.json".
fakeNPX := `#!/bin/bash -exu
case "$1" in
"vsce")
if [[ "$1" == "vsce" && "$2" == "package" ]]; then
# Write the third argument to extension/package.json
echo "$3" > package.json
echo "$3" > package-lock.json
exit 0
fi
exit 1
;;
*)
echo unexpected command $@
exit 1
;;
esac
`
tasks := &ReleaseVSCodeGoTasks{
CloudBuild: NewFakeCloudBuild(t, gerrit, "", nil, FakeBinary{"npm", fakeEmptyBinary}, FakeBinary{"npx", fakeNPX}),
Gerrit: gerrit,
}
_, err := tasks.updatePackageJSONVersionInMasterBranch(ctx, nil)
if err != nil {
t.Fatal(err)
}
head, err := gerrit.ReadBranchHead(ctx, "vscode-go", "master")
if err != nil {
t.Fatal(err)
}
got, err := gerrit.ReadFile(ctx, "vscode-go", head, "extension/package.json")
if err != nil || string(got) != tc.wantPackageJSON {
t.Errorf("ReadFile(%q) = (%q, %v), want (%q, nil)", "extension/package.json", got, err, tc.wantPackageJSON)
}
got, err = gerrit.ReadFile(ctx, "vscode-go", head, "extension/package-lock.json")
if err != nil || string(got) != tc.wantPackageLockJSON {
t.Errorf("ReadFile(%q) = (%q, %v), want (%q, nil)", "extension/package-lock.json", got, err, tc.wantPackageLockJSON)
}
})
}
}
func TestUpdatePackageJSONVersionInReleaseBranch(t *testing.T) {
mustHaveShell(t)
testcases := []struct {
name string
release releaseVersion
wantPackageJSON string
wantPackageLockJSON string
}{
{
name: "version 0.44.0 should update branch release-v0.44 package.json pointing 0.44.0",
release: releaseVersion{Major: 0, Minor: 44, Patch: 0},
wantPackageJSON: "0.44.0",
wantPackageLockJSON: "0.44.0\n",
},
{
name: "version 0.46.2 should update branch release-v0.46 package.json pointing 0.46.2",
release: releaseVersion{Major: 0, Minor: 46, Patch: 2},
wantPackageJSON: "0.46.2",
wantPackageLockJSON: "0.46.2\n",
},
}
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",
"extension/package.json": "foo\n",
"extension/package-lock.json": "foo\n",
})
// Prepare the release branch so the commit can be made.
vscodego.Branch(vscodeGoReleaseBranch(tc.release), commit)
gerrit := NewFakeGerrit(t, vscodego)
ctx := &workflow.TaskContext{
Context: context.Background(),
Logger: &testLogger{t, ""},
}
// fakeNPX successfully executes only when called with the command
// "npx vsce package V".
// In this case, the value "V" is written to both "package.json" and
// "package-lock.json".
fakeNPX := `#!/bin/bash -exu
case "$1" in
"vsce")
if [[ "$1" == "vsce" && "$2" == "package" ]]; then
# Write the third argument to extension/package.json with a trailing new line.
echo "$3" > package.json
echo "$3" > package-lock.json
exit 0
fi
exit 1
;;
*)
echo unexpected command $@
exit 1
;;
esac
`
tasks := &ReleaseVSCodeGoTasks{
CloudBuild: NewFakeCloudBuild(t, gerrit, "", nil, FakeBinary{"npm", fakeEmptyBinary}, FakeBinary{"npx", fakeNPX}),
Gerrit: gerrit,
}
_, err := tasks.updatePackageJSONVersionInReleaseBranch(ctx, tc.release, nil)
if err != nil {
t.Fatal(err)
}
head, err := gerrit.ReadBranchHead(ctx, "vscode-go", vscodeGoReleaseBranch(tc.release))
if err != nil {
t.Fatal(err)
}
got, err := gerrit.ReadFile(ctx, "vscode-go", head, "extension/package.json")
if err != nil || string(got) != tc.wantPackageJSON {
t.Errorf("ReadFile(%q) = (%q, %v), want (%q, nil)", "extension/package.json", got, err, tc.wantPackageJSON)
}
got, err = gerrit.ReadFile(ctx, "vscode-go", head, "extension/package-lock.json")
if err != nil || string(got) != tc.wantPackageLockJSON {
t.Errorf("ReadFile(%q) = (%q, %v), want (%q, nil)", "extension/package-lock.json", got, err, tc.wantPackageLockJSON)
}
})
}
}
func TestAddChangeLog(t *testing.T) {
changelog := `# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/).
## Unreleased
CHANGE FOR v0.44.0
## v0.42.1
CHANGE FOR v0.42.1
`
testcases := []struct {
name string
release releaseVersion
wantChangeLog string
}{
{
name: "add v0.44.0 heading",
release: releaseVersion{Major: 0, Minor: 44, Patch: 0},
wantChangeLog: `# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/).
## Unreleased
## v0.44.0
Date: 2002-01-02
CHANGE FOR v0.44.0
## v0.42.1
CHANGE FOR v0.42.1
`,
},
{
name: "add v0.46.0 heading",
release: releaseVersion{Major: 0, Minor: 46, Patch: 0},
wantChangeLog: `# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/).
## Unreleased
## v0.46.0
Date: 2002-01-02
CHANGE FOR v0.44.0
## v0.42.1
CHANGE FOR v0.42.1
`,
},
{
name: "add v0.46.3 patch entry",
release: releaseVersion{Major: 0, Minor: 46, Patch: 3},
wantChangeLog: `# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/).
## Unreleased
CHANGE FOR v0.44.0
## v0.46.3
Date: 2002-01-02
**Full Changelog**: https://github.com/golang/vscode-go/compare/v0.46.2...v0.46.3
**Milestone**: https://github.com/golang/vscode-go/issues?q=milestone%3Av0.46.3
## v0.42.1
CHANGE FOR v0.42.1
`,
},
{
name: "add v0.43.0 insider minor entry",
release: releaseVersion{Major: 0, Minor: 43, Patch: 0},
wantChangeLog: `# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/).
## Unreleased
CHANGE FOR v0.44.0
## v0.43.0 (prerelease)
Date: 2002-01-02
This is the [pre-release version](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#prerelease-extensions) of v0.44.
**Full Changelog**: https://github.com/golang/vscode-go/compare/v0.42.0-rc.1...v0.43.0
**Milestone**: https://github.com/golang/vscode-go/issues?q=milestone%3Av0.44.0
## v0.42.1
CHANGE FOR v0.42.1
`,
},
{
name: "add v0.45.6 insider patch entry",
release: releaseVersion{Major: 0, Minor: 45, Patch: 6},
wantChangeLog: `# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/).
## Unreleased
CHANGE FOR v0.44.0
## v0.45.6 (prerelease)
Date: 2002-01-02
This is the [pre-release version](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#prerelease-extensions) of v0.46.
**Full Changelog**: https://github.com/golang/vscode-go/compare/v0.44.0-rc.1...v0.45.6
**Milestone**: https://github.com/golang/vscode-go/issues?q=milestone%3Av0.46.0
## v0.42.1
CHANGE FOR v0.42.1
`,
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
vscodego := NewFakeRepo(t, "vscode-go")
commit := vscodego.Commit(map[string]string{
"CHANGELOG.md": changelog,
})
if tc.release.Patch >= 1 {
vscodego.Tag(fmt.Sprintf("v%v.%v.%v", tc.release.Major, tc.release.Minor, tc.release.Patch-1), commit)
}
vscodego.Tag(fmt.Sprintf("v%v.%v.%v", tc.release.Major, tc.release.Minor-1, 0), commit)
gerrit := NewFakeGerrit(t, vscodego)
ctx := &workflow.TaskContext{
Context: context.Background(),
Logger: &testLogger{t, ""},
}
tasks := &ReleaseVSCodeGoTasks{
CloudBuild: NewFakeCloudBuild(t, gerrit, "", nil),
Gerrit: gerrit,
}
_, err := tasks.addChangeLog(ctx, tc.release, nil)
if err != nil {
t.Fatal(err)
}
head, err := gerrit.ReadBranchHead(ctx, "vscode-go", "master")
if err != nil {
t.Fatal(err)
}
gotFile, err := gerrit.ReadFile(ctx, "vscode-go", head, "CHANGELOG.md")
if err != nil {
t.Fatal(err)
}
re := regexp.MustCompile(`Date: (.*)\n`)
want := re.ReplaceAllString(tc.wantChangeLog, "\n")
got := re.ReplaceAllString(string(gotFile), "\n")
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("change log content mismatch (-want +got):\n%s", diff)
}
})
}
}