Skip to content

Commit 02bffdf

Browse files
authored
test(e2e): verify simple releases (#344)
1 parent 784cf11 commit 02bffdf

File tree

4 files changed

+211
-7
lines changed

4 files changed

+211
-7
lines changed

test/e2e/forge.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,21 @@ package e2e
33
import (
44
"context"
55
"testing"
6+
7+
"github.com/go-git/go-git/v5/plumbing/transport"
8+
9+
"github.com/apricote/releaser-pleaser/internal/git"
610
)
711

812
type TestForge interface {
913
Init(ctx context.Context, runID string) error
1014
CreateRepo(t *testing.T, opts CreateRepoOpts) (*Repository, error)
15+
CloneURL(t *testing.T, repo *Repository) string
16+
GitAuth(t *testing.T) transport.AuthMethod
17+
18+
ListOpenPRs(t *testing.T, repo *Repository) ([]*git.PullRequest, error)
19+
MergePR(t *testing.T, repo *Repository, pr *git.PullRequest) error
20+
ListTags(t *testing.T, repo *Repository) ([]*git.Tag, error)
1121

1222
RunArguments() []string
1323
}

test/e2e/forgejo/forge.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ import (
99
"testing"
1010

1111
"codeberg.org/mvdkleijn/forgejo-sdk/forgejo/v2"
12+
"github.com/go-git/go-git/v5/plumbing/transport"
13+
"github.com/go-git/go-git/v5/plumbing/transport/http"
14+
"github.com/stretchr/testify/require"
1215

16+
"github.com/apricote/releaser-pleaser/internal/git"
1317
"github.com/apricote/releaser-pleaser/test/e2e"
1418
)
1519

@@ -103,6 +107,67 @@ func (f *TestForge) CreateRepo(t *testing.T, opts e2e.CreateRepoOpts) (*e2e.Repo
103107
}, nil
104108
}
105109

110+
func (f *TestForge) CloneURL(t *testing.T, repo *e2e.Repository) string {
111+
t.Helper()
112+
113+
return fmt.Sprintf("%s/%s/%s.git", TestAPIURL, f.username, repo.Name)
114+
}
115+
116+
func (f *TestForge) GitAuth(t *testing.T) transport.AuthMethod {
117+
t.Helper()
118+
119+
return &http.BasicAuth{
120+
Username: f.username,
121+
Password: f.token,
122+
}
123+
}
124+
125+
func (f *TestForge) ListOpenPRs(t *testing.T, repo *e2e.Repository) ([]*git.PullRequest, error) {
126+
t.Helper()
127+
128+
fPRs, _, err := f.client.ListRepoPullRequests(f.username, repo.Name, forgejo.ListPullRequestsOptions{
129+
State: forgejo.StateOpen,
130+
})
131+
if err != nil {
132+
return nil, err
133+
}
134+
135+
prs := make([]*git.PullRequest, 0, len(fPRs))
136+
for _, pr := range fPRs {
137+
prs = append(prs, forgejoPRToPullRequest(pr))
138+
}
139+
140+
return prs, nil
141+
}
142+
143+
func (f *TestForge) MergePR(t *testing.T, repo *e2e.Repository, pr *git.PullRequest) error {
144+
t.Helper()
145+
146+
ok, _, err := f.client.MergePullRequest(f.username, repo.Name, pr.ID, forgejo.MergePullRequestOption{Style: forgejo.MergeStyleSquash})
147+
if err != nil {
148+
return err
149+
}
150+
if !ok {
151+
return fmt.Errorf("merging pull request #%d failed", pr.ID)
152+
}
153+
154+
return nil
155+
}
156+
157+
func (f *TestForge) ListTags(t *testing.T, repo *e2e.Repository) ([]*git.Tag, error) {
158+
t.Helper()
159+
160+
fTags, _, err := f.client.ListRepoTags(f.username, repo.Name, forgejo.ListRepoTagsOptions{})
161+
require.NoError(t, err)
162+
163+
tags := make([]*git.Tag, 0, len(fTags))
164+
for _, tag := range fTags {
165+
tags = append(tags, forgejoTagToTag(tag))
166+
}
167+
168+
return tags, nil
169+
}
170+
106171
func (f *TestForge) RunArguments() []string {
107172
return []string{"--forge=forgejo",
108173
fmt.Sprintf("--owner=%s", f.username),
@@ -111,3 +176,18 @@ func (f *TestForge) RunArguments() []string {
111176
fmt.Sprintf("--username=%s", f.username),
112177
}
113178
}
179+
180+
func forgejoPRToPullRequest(pr *forgejo.PullRequest) *git.PullRequest {
181+
return &git.PullRequest{
182+
ID: pr.Index,
183+
Title: pr.Title,
184+
Description: pr.Body,
185+
}
186+
}
187+
188+
func forgejoTagToTag(tag *forgejo.Tag) *git.Tag {
189+
return &git.Tag{
190+
Hash: tag.Commit.SHA,
191+
Name: tag.Name,
192+
}
193+
}

test/e2e/forgejo/forgejo_test.go

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,21 @@ import (
1010

1111
"github.com/stretchr/testify/require"
1212

13+
"github.com/apricote/releaser-pleaser/internal/git"
1314
"github.com/apricote/releaser-pleaser/test/e2e"
1415
)
1516

1617
var (
1718
f *e2e.Framework
1819
)
1920

21+
var (
22+
TestAuthor = git.Author{
23+
Name: "Peter Parker",
24+
Email: "parker@example.com",
25+
}
26+
)
27+
2028
func TestMain(m *testing.M) {
2129
ctx := context.Background()
2230

@@ -33,7 +41,56 @@ func TestCreateRepository(t *testing.T) {
3341
_ = f.NewRepository(t, t.Name())
3442
}
3543

36-
func TestRun(t *testing.T) {
44+
func TestEmptyRun(t *testing.T) {
3745
repo := f.NewRepository(t, t.Name())
3846
require.NoError(t, f.Run(t, repo, []string{}))
3947
}
48+
49+
func TestRunMultipleSimpleReleases(t *testing.T) {
50+
repo := f.NewRepository(t, t.Name())
51+
52+
// First release
53+
{
54+
clonedRepo := f.CloneRepo(t, repo)
55+
56+
clonedRepo.UpdateFile(t.Context(), "README.md", true, func(_ string) (string, error) {
57+
return "# Hello World", nil
58+
})
59+
60+
_, err := clonedRepo.Commit(t.Context(), "feat: cool new thing", TestAuthor)
61+
require.NoError(t, err)
62+
63+
clonedRepo.ForcePush(t.Context(), e2e.TestDefaultBranch)
64+
65+
require.NoError(t, f.Run(t, repo, []string{}))
66+
67+
pr := f.HasReleasePR(t, repo, "v0.1.0")
68+
f.MergeReleasePR(t, repo, pr)
69+
70+
require.NoError(t, f.Run(t, repo, []string{}))
71+
f.HasTag(t, repo, "v0.1.0")
72+
}
73+
74+
// Second release
75+
{
76+
clonedRepo := f.CloneRepo(t, repo)
77+
78+
clonedRepo.UpdateFile(t.Context(), "README.md", true, func(_ string) (string, error) {
79+
return "# Goodbye", nil
80+
})
81+
82+
_, err := clonedRepo.Commit(t.Context(), "fix: readme was broken", TestAuthor)
83+
require.NoError(t, err)
84+
85+
clonedRepo.ForcePush(t.Context(), e2e.TestDefaultBranch)
86+
87+
require.NoError(t, f.Run(t, repo, []string{}))
88+
89+
pr := f.HasReleasePR(t, repo, "v0.1.1")
90+
f.MergeReleasePR(t, repo, pr)
91+
92+
require.NoError(t, f.Run(t, repo, []string{}))
93+
f.HasTag(t, repo, "v0.1.1")
94+
}
95+
96+
}

test/e2e/framework.go

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@ import (
66
"crypto/rand"
77
"encoding/hex"
88
"fmt"
9+
"log/slog"
10+
"os"
11+
"slices"
912
"strings"
1013
"testing"
1114

1215
"github.com/stretchr/testify/require"
1316

1417
"github.com/apricote/releaser-pleaser/cmd/rp/cmd"
18+
"github.com/apricote/releaser-pleaser/internal/git"
1519
)
1620

1721
const (
@@ -27,14 +31,16 @@ func randomString() string {
2731
}
2832

2933
type Framework struct {
30-
runID string
31-
forge TestForge
34+
runID string
35+
forge TestForge
36+
logger *slog.Logger
3237
}
3338

3439
func NewFramework(ctx context.Context, forge TestForge) (*Framework, error) {
3540
f := &Framework{
36-
runID: randomString(),
37-
forge: forge,
41+
runID: randomString(),
42+
forge: forge,
43+
logger: slog.New(slog.NewTextHandler(os.Stderr, nil)),
3844
}
3945

4046
err := forge.Init(ctx, f.runID)
@@ -67,6 +73,17 @@ func (f *Framework) NewRepository(t *testing.T, name string) *Repository {
6773
return r
6874
}
6975

76+
func (f *Framework) CloneRepo(t *testing.T, r *Repository) *git.Repository {
77+
// TODO: Is this too low-level?
78+
t.Helper()
79+
80+
repo, err := git.CloneRepo(t.Context(), f.logger, f.forge.CloneURL(t, r), TestDefaultBranch, f.forge.GitAuth(t))
81+
require.NoError(t, err)
82+
require.NotNil(t, repo)
83+
84+
return repo
85+
}
86+
7087
func (f *Framework) Run(t *testing.T, r *Repository, extraFiles []string) error {
7188
t.Helper()
7289

@@ -89,8 +106,48 @@ func (f *Framework) Run(t *testing.T, r *Repository, extraFiles []string) error
89106
stdoutString := stdout.String()
90107
stderrString := stderr.String()
91108

92-
t.Log(stdoutString)
93-
t.Log(stderrString)
109+
if stdoutString != "" {
110+
t.Log("STDOUT: \n", stdoutString)
111+
}
112+
if stderrString != "" {
113+
t.Log("STDERR: \n", stderrString)
114+
}
94115

95116
return err
96117
}
118+
119+
func (f *Framework) HasReleasePR(t *testing.T, r *Repository, version string) *git.PullRequest {
120+
t.Helper()
121+
122+
prs, err := f.forge.ListOpenPRs(t, r)
123+
require.NoError(t, err)
124+
125+
expectedTitle := fmt.Sprintf("chore(main): release %s", version)
126+
index := slices.IndexFunc(prs, func(pr *git.PullRequest) bool {
127+
return pr.Title == expectedTitle
128+
})
129+
require.GreaterOrEqualf(t, index, 0, "release pull request for version %q does not exist", version)
130+
131+
return prs[index]
132+
}
133+
134+
func (f *Framework) MergeReleasePR(t *testing.T, r *Repository, pr *git.PullRequest) {
135+
t.Helper()
136+
137+
err := f.forge.MergePR(t, r, pr)
138+
require.NoError(t, err)
139+
}
140+
141+
func (f *Framework) HasTag(t *testing.T, r *Repository, version string) (tag *git.Tag) {
142+
t.Helper()
143+
144+
tags, err := f.forge.ListTags(t, r)
145+
require.NoError(t, err)
146+
147+
index := slices.IndexFunc(tags, func(tag *git.Tag) bool {
148+
return tag.Name == version
149+
})
150+
require.GreaterOrEqualf(t, index, 0, "tag %q does not exist", version)
151+
152+
return tags[index]
153+
}

0 commit comments

Comments
 (0)