Update golangci-lint to v2.12.2 with canonical config
All checks were successful
Check / check (pull_request) Successful in 3m22s
All checks were successful
Check / check (pull_request) Successful in 3m22s
Bump golangci-lint from v2.10.1 to v2.12.2 in the Dockerfile lint stage (tag+digest pin) and script/bootstrap release-archive pins (linux amd64/arm64 sha256s). Replace .golangci.yml with the canonical v2-layout config so linter settings (lll 88, funlen 80/50, cyclop 15, dupl 100) actually apply. Fix all findings surfaced by the new linter and config: - noctx: use httptest.NewRequestWithContext in all tests - gosec G710/G703: route app redirects through a path-escaping redirectToApp helper; annotate internal log path usage - goconst: introduce shared constants for template/JSON keys and repeated test literals - lll: wrap lines to the 88-column limit - dupl: extract shared helpers (generic findAllByAppID in models, deleteAppResource in handlers, parsePush in webhook payloads, table-driven/helper-based test dedup) - nolintlint: drop nolint directives made obsolete by the new limits Record the change in TODO.md; make check is green.
This commit is contained in:
@@ -98,88 +98,77 @@ type GitLabPushPayload struct {
|
||||
func ParsePushPayload(source Source, payload []byte) (*PushEvent, error) {
|
||||
switch source {
|
||||
case SourceGitHub:
|
||||
return parseGitHubPush(payload)
|
||||
return parsePush(payload, githubPushEvent)
|
||||
case SourceGitLab:
|
||||
return parseGitLabPush(payload)
|
||||
return parsePush(payload, gitlabPushEvent)
|
||||
case SourceGitea, SourceUnknown:
|
||||
// Gitea and unknown both use Gitea format for backward compatibility.
|
||||
return parseGiteaPush(payload)
|
||||
return parsePush(payload, giteaPushEvent)
|
||||
}
|
||||
|
||||
// Unreachable for known source values, but satisfies exhaustive checker.
|
||||
return parseGiteaPush(payload)
|
||||
return parsePush(payload, giteaPushEvent)
|
||||
}
|
||||
|
||||
func parseGiteaPush(payload []byte) (*PushEvent, error) {
|
||||
var p GiteaPushPayload
|
||||
// parsePush unmarshals payload into P and converts it into a normalized
|
||||
// PushEvent via build.
|
||||
func parsePush[P any](payload []byte, build func(P) *PushEvent) (*PushEvent, error) {
|
||||
var p P
|
||||
|
||||
unmarshalErr := json.Unmarshal(payload, &p)
|
||||
if unmarshalErr != nil {
|
||||
return nil, unmarshalErr
|
||||
}
|
||||
|
||||
commitURL := extractGiteaCommitURL(p)
|
||||
|
||||
return &PushEvent{
|
||||
Source: SourceGitea,
|
||||
Ref: p.Ref,
|
||||
Before: p.Before,
|
||||
After: p.After,
|
||||
Branch: extractBranch(p.Ref),
|
||||
RepoName: p.Repository.FullName,
|
||||
CloneURL: p.Repository.CloneURL,
|
||||
HTMLURL: p.Repository.HTMLURL,
|
||||
CommitURL: commitURL,
|
||||
Pusher: p.Pusher.Username,
|
||||
}, nil
|
||||
return build(p), nil
|
||||
}
|
||||
|
||||
func parseGitHubPush(payload []byte) (*PushEvent, error) {
|
||||
var p GitHubPushPayload
|
||||
|
||||
unmarshalErr := json.Unmarshal(payload, &p)
|
||||
if unmarshalErr != nil {
|
||||
return nil, unmarshalErr
|
||||
}
|
||||
|
||||
commitURL := extractGitHubCommitURL(p)
|
||||
|
||||
// basePushEvent builds a PushEvent populated with the fields shared by all
|
||||
// webhook sources.
|
||||
func basePushEvent(source Source, ref, before, after string) *PushEvent {
|
||||
return &PushEvent{
|
||||
Source: SourceGitHub,
|
||||
Ref: p.Ref,
|
||||
Before: p.Before,
|
||||
After: p.After,
|
||||
Branch: extractBranch(p.Ref),
|
||||
RepoName: p.Repository.FullName,
|
||||
CloneURL: p.Repository.CloneURL,
|
||||
HTMLURL: p.Repository.HTMLURL,
|
||||
CommitURL: commitURL,
|
||||
Pusher: p.Pusher.Name,
|
||||
}, nil
|
||||
Source: source,
|
||||
Ref: ref,
|
||||
Before: before,
|
||||
After: after,
|
||||
Branch: extractBranch(ref),
|
||||
}
|
||||
}
|
||||
|
||||
func parseGitLabPush(payload []byte) (*PushEvent, error) {
|
||||
var p GitLabPushPayload
|
||||
// giteaPushEvent converts a Gitea push payload to a normalized PushEvent.
|
||||
func giteaPushEvent(p GiteaPushPayload) *PushEvent {
|
||||
event := basePushEvent(SourceGitea, p.Ref, p.Before, p.After)
|
||||
event.RepoName = p.Repository.FullName
|
||||
event.CloneURL = p.Repository.CloneURL
|
||||
event.HTMLURL = p.Repository.HTMLURL
|
||||
event.CommitURL = extractGiteaCommitURL(p)
|
||||
event.Pusher = p.Pusher.Username
|
||||
|
||||
unmarshalErr := json.Unmarshal(payload, &p)
|
||||
if unmarshalErr != nil {
|
||||
return nil, unmarshalErr
|
||||
}
|
||||
return event
|
||||
}
|
||||
|
||||
commitURL := extractGitLabCommitURL(p)
|
||||
// gitlabPushEvent converts a GitLab push payload to a normalized PushEvent.
|
||||
func gitlabPushEvent(p GitLabPushPayload) *PushEvent {
|
||||
event := basePushEvent(SourceGitLab, p.Ref, p.Before, p.After)
|
||||
event.RepoName = p.Project.PathWithNamespace
|
||||
event.CloneURL = p.Project.GitHTTPURL
|
||||
event.HTMLURL = p.Project.WebURL
|
||||
event.CommitURL = extractGitLabCommitURL(p)
|
||||
event.Pusher = p.UserName
|
||||
|
||||
return &PushEvent{
|
||||
Source: SourceGitLab,
|
||||
Ref: p.Ref,
|
||||
Before: p.Before,
|
||||
After: p.After,
|
||||
Branch: extractBranch(p.Ref),
|
||||
RepoName: p.Project.PathWithNamespace,
|
||||
CloneURL: p.Project.GitHTTPURL,
|
||||
HTMLURL: p.Project.WebURL,
|
||||
CommitURL: commitURL,
|
||||
Pusher: p.UserName,
|
||||
}, nil
|
||||
return event
|
||||
}
|
||||
|
||||
// githubPushEvent converts a GitHub push payload to a normalized PushEvent.
|
||||
func githubPushEvent(p GitHubPushPayload) *PushEvent {
|
||||
event := basePushEvent(SourceGitHub, p.Ref, p.Before, p.After)
|
||||
event.RepoName = p.Repository.FullName
|
||||
event.CloneURL = p.Repository.CloneURL
|
||||
event.HTMLURL = p.Repository.HTMLURL
|
||||
event.CommitURL = extractGitHubCommitURL(p)
|
||||
event.Pusher = p.Pusher.Name
|
||||
|
||||
return event
|
||||
}
|
||||
|
||||
// extractBranch extracts the branch name from a git ref.
|
||||
|
||||
@@ -24,6 +24,18 @@ import (
|
||||
"sneak.berlin/go/upaas/internal/service/webhook"
|
||||
)
|
||||
|
||||
const (
|
||||
giteaEventHeader = "X-Gitea-Event"
|
||||
githubEventHeader = "X-GitHub-Event"
|
||||
gitlabEventHeader = "X-Gitlab-Event"
|
||||
gitlabPushHook = "Push Hook"
|
||||
pushEventType = "push"
|
||||
branchMain = "main"
|
||||
refMain = "refs/heads/main"
|
||||
testCommitSHA = "abc123def456789"
|
||||
testPusher = "developer"
|
||||
)
|
||||
|
||||
type testDeps struct {
|
||||
logger *logger.Logger
|
||||
config *config.Config
|
||||
@@ -45,9 +57,14 @@ func setupTestDeps(t *testing.T) *testDeps {
|
||||
loggerInst, err := logger.New(fx.Lifecycle(nil), logger.Params{Globals: globalsInst})
|
||||
require.NoError(t, err)
|
||||
|
||||
cfg := &config.Config{Port: 8080, DataDir: tmpDir, SessionSecret: "test-secret-key-at-least-32-chars"}
|
||||
cfg := &config.Config{
|
||||
Port: 8080, DataDir: tmpDir,
|
||||
SessionSecret: "test-secret-key-at-least-32-chars",
|
||||
}
|
||||
|
||||
dbInst, err := database.New(fx.Lifecycle(nil), database.Params{Logger: loggerInst, Config: cfg})
|
||||
dbInst, err := database.New(
|
||||
fx.Lifecycle(nil), database.Params{Logger: loggerInst, Config: cfg},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
return &testDeps{logger: loggerInst, config: cfg, db: dbInst, tmpDir: tmpDir}
|
||||
@@ -58,14 +75,19 @@ func setupTestService(t *testing.T) (*webhook.Service, *database.Database, func(
|
||||
|
||||
deps := setupTestDeps(t)
|
||||
|
||||
dockerClient, err := docker.New(fx.Lifecycle(nil), docker.Params{Logger: deps.logger, Config: deps.config})
|
||||
dockerClient, err := docker.New(
|
||||
fx.Lifecycle(nil), docker.Params{Logger: deps.logger, Config: deps.config},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
notifySvc, err := notify.New(fx.Lifecycle(nil), notify.ServiceParams{Logger: deps.logger})
|
||||
notifySvc, err := notify.New(
|
||||
fx.Lifecycle(nil), notify.ServiceParams{Logger: deps.logger},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
deploySvc, err := deploy.New(fx.Lifecycle(nil), deploy.ServiceParams{
|
||||
Logger: deps.logger, Config: deps.config, Database: deps.db, Docker: dockerClient, Notify: notifySvc,
|
||||
Logger: deps.logger, Config: deps.config, Database: deps.db,
|
||||
Docker: dockerClient, Notify: notifySvc,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -104,8 +126,6 @@ func createTestApp(
|
||||
}
|
||||
|
||||
// TestDetectWebhookSource tests auto-detection of webhook source from HTTP headers.
|
||||
//
|
||||
//nolint:funlen // table-driven test with comprehensive test cases
|
||||
func TestDetectWebhookSource(testingT *testing.T) {
|
||||
testingT.Parallel()
|
||||
|
||||
@@ -116,17 +136,17 @@ func TestDetectWebhookSource(testingT *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "detects Gitea from X-Gitea-Event header",
|
||||
headers: map[string]string{"X-Gitea-Event": "push"},
|
||||
headers: map[string]string{giteaEventHeader: pushEventType},
|
||||
expected: webhook.SourceGitea,
|
||||
},
|
||||
{
|
||||
name: "detects GitHub from X-GitHub-Event header",
|
||||
headers: map[string]string{"X-GitHub-Event": "push"},
|
||||
headers: map[string]string{githubEventHeader: pushEventType},
|
||||
expected: webhook.SourceGitHub,
|
||||
},
|
||||
{
|
||||
name: "detects GitLab from X-Gitlab-Event header",
|
||||
headers: map[string]string{"X-Gitlab-Event": "Push Hook"},
|
||||
headers: map[string]string{gitlabEventHeader: gitlabPushHook},
|
||||
expected: webhook.SourceGitLab,
|
||||
},
|
||||
{
|
||||
@@ -142,16 +162,16 @@ func TestDetectWebhookSource(testingT *testing.T) {
|
||||
{
|
||||
name: "Gitea takes precedence over GitHub",
|
||||
headers: map[string]string{
|
||||
"X-Gitea-Event": "push",
|
||||
"X-GitHub-Event": "push",
|
||||
giteaEventHeader: pushEventType,
|
||||
githubEventHeader: pushEventType,
|
||||
},
|
||||
expected: webhook.SourceGitea,
|
||||
},
|
||||
{
|
||||
name: "GitHub takes precedence over GitLab",
|
||||
headers: map[string]string{
|
||||
"X-GitHub-Event": "push",
|
||||
"X-Gitlab-Event": "Push Hook",
|
||||
githubEventHeader: pushEventType,
|
||||
gitlabEventHeader: gitlabPushHook,
|
||||
},
|
||||
expected: webhook.SourceGitHub,
|
||||
},
|
||||
@@ -184,33 +204,33 @@ func TestDetectEventType(testingT *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "extracts Gitea event type",
|
||||
headers: map[string]string{"X-Gitea-Event": "push"},
|
||||
headers: map[string]string{giteaEventHeader: pushEventType},
|
||||
source: webhook.SourceGitea,
|
||||
expected: "push",
|
||||
expected: pushEventType,
|
||||
},
|
||||
{
|
||||
name: "extracts GitHub event type",
|
||||
headers: map[string]string{"X-GitHub-Event": "push"},
|
||||
headers: map[string]string{githubEventHeader: pushEventType},
|
||||
source: webhook.SourceGitHub,
|
||||
expected: "push",
|
||||
expected: pushEventType,
|
||||
},
|
||||
{
|
||||
name: "extracts GitLab event type",
|
||||
headers: map[string]string{"X-Gitlab-Event": "Push Hook"},
|
||||
headers: map[string]string{gitlabEventHeader: gitlabPushHook},
|
||||
source: webhook.SourceGitLab,
|
||||
expected: "Push Hook",
|
||||
expected: gitlabPushHook,
|
||||
},
|
||||
{
|
||||
name: "returns push for unknown source",
|
||||
headers: map[string]string{},
|
||||
source: webhook.SourceUnknown,
|
||||
expected: "push",
|
||||
expected: pushEventType,
|
||||
},
|
||||
{
|
||||
name: "returns push when header missing for source",
|
||||
headers: map[string]string{},
|
||||
source: webhook.SourceGitea,
|
||||
expected: "push",
|
||||
expected: pushEventType,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -250,11 +270,54 @@ func TestUnparsedURLString(t *testing.T) {
|
||||
assert.Empty(t, empty.String())
|
||||
}
|
||||
|
||||
// TestParsePushPayloadGitea tests parsing of Gitea push payloads.
|
||||
func TestParsePushPayloadGitea(t *testing.T) {
|
||||
t.Parallel()
|
||||
// pushEventExpectation describes the expected normalized fields of a parsed
|
||||
// push payload.
|
||||
type pushEventExpectation struct {
|
||||
source webhook.Source
|
||||
ref string
|
||||
branch string
|
||||
after string
|
||||
repoName string
|
||||
cloneURL webhook.UnparsedURL
|
||||
htmlURL webhook.UnparsedURL
|
||||
commitURL webhook.UnparsedURL
|
||||
pusher string
|
||||
}
|
||||
|
||||
payload := []byte(`{
|
||||
// assertPushEvent parses payload for want.source and asserts every
|
||||
// normalized PushEvent field matches want.
|
||||
func assertPushEvent(t *testing.T, payload []byte, want pushEventExpectation) {
|
||||
t.Helper()
|
||||
|
||||
event, err := webhook.ParsePushPayload(want.source, payload)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, want.source, event.Source)
|
||||
assert.Equal(t, want.ref, event.Ref)
|
||||
assert.Equal(t, want.branch, event.Branch)
|
||||
assert.Equal(t, want.after, event.After)
|
||||
|
||||
assertPushEventOrigin(t, event, want)
|
||||
}
|
||||
|
||||
// assertPushEventOrigin asserts the repository and pusher fields of event.
|
||||
func assertPushEventOrigin(
|
||||
t *testing.T,
|
||||
event *webhook.PushEvent,
|
||||
want pushEventExpectation,
|
||||
) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, want.repoName, event.RepoName)
|
||||
assert.Equal(t, want.cloneURL, event.CloneURL)
|
||||
assert.Equal(t, want.htmlURL, event.HTMLURL)
|
||||
assert.Equal(t, want.commitURL, event.CommitURL)
|
||||
assert.Equal(t, want.pusher, event.Pusher)
|
||||
}
|
||||
|
||||
// giteaPushJSON returns a realistic Gitea push webhook payload.
|
||||
func giteaPushJSON() []byte {
|
||||
return []byte(`{
|
||||
"ref": "refs/heads/main",
|
||||
"before": "0000000000000000000000000000000000000000",
|
||||
"after": "abc123def456789",
|
||||
@@ -275,29 +338,11 @@ func TestParsePushPayloadGitea(t *testing.T) {
|
||||
}
|
||||
]
|
||||
}`)
|
||||
|
||||
event, err := webhook.ParsePushPayload(webhook.SourceGitea, payload)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, webhook.SourceGitea, event.Source)
|
||||
assert.Equal(t, "refs/heads/main", event.Ref)
|
||||
assert.Equal(t, "main", event.Branch)
|
||||
assert.Equal(t, "abc123def456789", event.After)
|
||||
assert.Equal(t, "myorg/myrepo", event.RepoName)
|
||||
assert.Equal(t, webhook.UnparsedURL("https://gitea.example.com/myorg/myrepo.git"), event.CloneURL)
|
||||
assert.Equal(t, webhook.UnparsedURL("https://gitea.example.com/myorg/myrepo"), event.HTMLURL)
|
||||
assert.Equal(t,
|
||||
webhook.UnparsedURL("https://gitea.example.com/myorg/myrepo/commit/abc123def456789"),
|
||||
event.CommitURL,
|
||||
)
|
||||
assert.Equal(t, "developer", event.Pusher)
|
||||
}
|
||||
|
||||
// TestParsePushPayloadGitHub tests parsing of GitHub push payloads.
|
||||
func TestParsePushPayloadGitHub(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
payload := []byte(`{
|
||||
// githubPushJSON returns a realistic GitHub push webhook payload.
|
||||
func githubPushJSON() []byte {
|
||||
return []byte(`{
|
||||
"ref": "refs/heads/main",
|
||||
"before": "0000000000000000000000000000000000000000",
|
||||
"after": "abc123def456789",
|
||||
@@ -323,29 +368,11 @@ func TestParsePushPayloadGitHub(t *testing.T) {
|
||||
}
|
||||
]
|
||||
}`)
|
||||
|
||||
event, err := webhook.ParsePushPayload(webhook.SourceGitHub, payload)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, webhook.SourceGitHub, event.Source)
|
||||
assert.Equal(t, "refs/heads/main", event.Ref)
|
||||
assert.Equal(t, "main", event.Branch)
|
||||
assert.Equal(t, "abc123def456789", event.After)
|
||||
assert.Equal(t, "myorg/myrepo", event.RepoName)
|
||||
assert.Equal(t, webhook.UnparsedURL("https://github.com/myorg/myrepo.git"), event.CloneURL)
|
||||
assert.Equal(t, webhook.UnparsedURL("https://github.com/myorg/myrepo"), event.HTMLURL)
|
||||
assert.Equal(t,
|
||||
webhook.UnparsedURL("https://github.com/myorg/myrepo/commit/abc123def456789"),
|
||||
event.CommitURL,
|
||||
)
|
||||
assert.Equal(t, "developer", event.Pusher)
|
||||
}
|
||||
|
||||
// TestParsePushPayloadGitLab tests parsing of GitLab push payloads.
|
||||
func TestParsePushPayloadGitLab(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
payload := []byte(`{
|
||||
// gitlabPushJSON returns a realistic GitLab push webhook payload.
|
||||
func gitlabPushJSON() []byte {
|
||||
return []byte(`{
|
||||
"ref": "refs/heads/develop",
|
||||
"before": "0000000000000000000000000000000000000000",
|
||||
"after": "abc123def456789",
|
||||
@@ -366,25 +393,78 @@ func TestParsePushPayloadGitLab(t *testing.T) {
|
||||
}
|
||||
]
|
||||
}`)
|
||||
|
||||
event, err := webhook.ParsePushPayload(webhook.SourceGitLab, payload)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, webhook.SourceGitLab, event.Source)
|
||||
assert.Equal(t, "refs/heads/develop", event.Ref)
|
||||
assert.Equal(t, "develop", event.Branch)
|
||||
assert.Equal(t, "abc123def456789", event.After)
|
||||
assert.Equal(t, "mygroup/myproject", event.RepoName)
|
||||
assert.Equal(t, webhook.UnparsedURL("https://gitlab.com/mygroup/myproject.git"), event.CloneURL)
|
||||
assert.Equal(t, webhook.UnparsedURL("https://gitlab.com/mygroup/myproject"), event.HTMLURL)
|
||||
assert.Equal(t,
|
||||
webhook.UnparsedURL("https://gitlab.com/mygroup/myproject/-/commit/abc123def456789"),
|
||||
event.CommitURL,
|
||||
)
|
||||
assert.Equal(t, "developer", event.Pusher)
|
||||
}
|
||||
|
||||
// TestParsePushPayloadUnknownFallsBackToGitea tests that unknown source uses Gitea parser.
|
||||
// pushPayloadJSON returns the push payload fixture for source.
|
||||
func pushPayloadJSON(t *testing.T, source webhook.Source) []byte {
|
||||
t.Helper()
|
||||
|
||||
switch source {
|
||||
case webhook.SourceGitHub:
|
||||
return githubPushJSON()
|
||||
case webhook.SourceGitLab:
|
||||
return gitlabPushJSON()
|
||||
case webhook.SourceGitea, webhook.SourceUnknown:
|
||||
return giteaPushJSON()
|
||||
}
|
||||
|
||||
t.Fatalf("no push payload fixture for source %v", source)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TestParsePushPayload tests parsing of Gitea, GitHub, and GitLab push
|
||||
// payloads into normalized PushEvents.
|
||||
func TestParsePushPayload(testingT *testing.T) {
|
||||
testingT.Parallel()
|
||||
|
||||
tests := []pushEventExpectation{
|
||||
{
|
||||
source: webhook.SourceGitea,
|
||||
ref: refMain,
|
||||
branch: branchMain,
|
||||
after: testCommitSHA,
|
||||
repoName: "myorg/myrepo",
|
||||
cloneURL: "https://gitea.example.com/myorg/myrepo.git",
|
||||
htmlURL: "https://gitea.example.com/myorg/myrepo",
|
||||
commitURL: "https://gitea.example.com/myorg/myrepo/commit/abc123def456789",
|
||||
pusher: testPusher,
|
||||
},
|
||||
{
|
||||
source: webhook.SourceGitHub,
|
||||
ref: refMain,
|
||||
branch: branchMain,
|
||||
after: testCommitSHA,
|
||||
repoName: "myorg/myrepo",
|
||||
cloneURL: "https://github.com/myorg/myrepo.git",
|
||||
htmlURL: "https://github.com/myorg/myrepo",
|
||||
commitURL: "https://github.com/myorg/myrepo/commit/abc123def456789",
|
||||
pusher: testPusher,
|
||||
},
|
||||
{
|
||||
source: webhook.SourceGitLab,
|
||||
ref: "refs/heads/develop",
|
||||
branch: "develop",
|
||||
after: testCommitSHA,
|
||||
repoName: "mygroup/myproject",
|
||||
cloneURL: "https://gitlab.com/mygroup/myproject.git",
|
||||
htmlURL: "https://gitlab.com/mygroup/myproject",
|
||||
commitURL: "https://gitlab.com/mygroup/myproject/-/commit/abc123def456789",
|
||||
pusher: testPusher,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range tests {
|
||||
testingT.Run(testCase.source.String(), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assertPushEvent(t, pushPayloadJSON(t, testCase.source), testCase)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestParsePushPayloadUnknownFallsBackToGitea tests that unknown source
|
||||
// uses the Gitea parser.
|
||||
func TestParsePushPayloadUnknownFallsBackToGitea(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -399,7 +479,7 @@ func TestParsePushPayloadUnknownFallsBackToGitea(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, webhook.SourceGitea, event.Source)
|
||||
assert.Equal(t, "main", event.Branch)
|
||||
assert.Equal(t, branchMain, event.Branch)
|
||||
assert.Equal(t, "abc123", event.After)
|
||||
}
|
||||
|
||||
@@ -462,7 +542,10 @@ func TestGitHubCommitURLFallback(t *testing.T) {
|
||||
|
||||
event, err := webhook.ParsePushPayload(webhook.SourceGitHub, payload)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, webhook.UnparsedURL("https://github.com/u/r/commit/abc123"), event.CommitURL)
|
||||
assert.Equal(t,
|
||||
webhook.UnparsedURL("https://github.com/u/r/commit/abc123"),
|
||||
event.CommitURL,
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("falls back to commits list", func(t *testing.T) {
|
||||
@@ -477,7 +560,10 @@ func TestGitHubCommitURLFallback(t *testing.T) {
|
||||
|
||||
event, err := webhook.ParsePushPayload(webhook.SourceGitHub, payload)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, webhook.UnparsedURL("https://github.com/u/r/commit/abc123"), event.CommitURL)
|
||||
assert.Equal(t,
|
||||
webhook.UnparsedURL("https://github.com/u/r/commit/abc123"),
|
||||
event.CommitURL,
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("constructs URL from repo HTML URL", func(t *testing.T) {
|
||||
@@ -491,7 +577,10 @@ func TestGitHubCommitURLFallback(t *testing.T) {
|
||||
|
||||
event, err := webhook.ParsePushPayload(webhook.SourceGitHub, payload)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, webhook.UnparsedURL("https://github.com/u/r/commit/abc123"), event.CommitURL)
|
||||
assert.Equal(t,
|
||||
webhook.UnparsedURL("https://github.com/u/r/commit/abc123"),
|
||||
event.CommitURL,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -511,7 +600,10 @@ func TestGitLabCommitURLFallback(t *testing.T) {
|
||||
|
||||
event, err := webhook.ParsePushPayload(webhook.SourceGitLab, payload)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, webhook.UnparsedURL("https://gitlab.com/g/p/-/commit/abc123"), event.CommitURL)
|
||||
assert.Equal(t,
|
||||
webhook.UnparsedURL("https://gitlab.com/g/p/-/commit/abc123"),
|
||||
event.CommitURL,
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("constructs URL from project web URL", func(t *testing.T) {
|
||||
@@ -525,7 +617,10 @@ func TestGitLabCommitURLFallback(t *testing.T) {
|
||||
|
||||
event, err := webhook.ParsePushPayload(webhook.SourceGitLab, payload)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, webhook.UnparsedURL("https://gitlab.com/g/p/-/commit/abc123"), event.CommitURL)
|
||||
assert.Equal(t,
|
||||
webhook.UnparsedURL("https://gitlab.com/g/p/-/commit/abc123"),
|
||||
event.CommitURL,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -588,7 +683,8 @@ func TestGiteaPushPayloadParsing(testingT *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestGitHubPushPayloadParsing tests direct deserialization of the GitHub payload struct.
|
||||
// TestGitHubPushPayloadParsing tests deserialization of the GitHub payload
|
||||
// struct.
|
||||
func TestGitHubPushPayloadParsing(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -633,7 +729,8 @@ func TestGitHubPushPayloadParsing(t *testing.T) {
|
||||
assert.Len(t, p.Commits, 1)
|
||||
}
|
||||
|
||||
// TestGitLabPushPayloadParsing tests direct deserialization of the GitLab payload struct.
|
||||
// TestGitLabPushPayloadParsing tests deserialization of the GitLab payload
|
||||
// struct.
|
||||
func TestGitLabPushPayloadParsing(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -671,9 +768,8 @@ func TestGitLabPushPayloadParsing(t *testing.T) {
|
||||
assert.Len(t, p.Commits, 1)
|
||||
}
|
||||
|
||||
// TestExtractBranch tests branch extraction via HandleWebhook integration (extractBranch is unexported).
|
||||
//
|
||||
//nolint:funlen // table-driven test with comprehensive test cases
|
||||
// TestExtractBranch tests branch extraction via HandleWebhook integration
|
||||
// (extractBranch is unexported).
|
||||
func TestExtractBranch(testingT *testing.T) {
|
||||
testingT.Parallel()
|
||||
|
||||
@@ -684,8 +780,8 @@ func TestExtractBranch(testingT *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "extracts main branch",
|
||||
ref: "refs/heads/main",
|
||||
expected: "main",
|
||||
ref: refMain,
|
||||
expected: branchMain,
|
||||
},
|
||||
{
|
||||
name: "extracts feature branch",
|
||||
@@ -699,8 +795,8 @@ func TestExtractBranch(testingT *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "returns raw ref if no prefix",
|
||||
ref: "main",
|
||||
expected: "main",
|
||||
ref: branchMain,
|
||||
expected: branchMain,
|
||||
},
|
||||
{
|
||||
name: "handles empty ref",
|
||||
@@ -728,7 +824,7 @@ func TestExtractBranch(testingT *testing.T) {
|
||||
payload := []byte(`{"ref": "` + testCase.ref + `"}`)
|
||||
|
||||
err := svc.HandleWebhook(
|
||||
context.Background(), app, webhook.SourceGitea, "push", payload,
|
||||
context.Background(), app, webhook.SourceGitea, pushEventType, payload,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -750,7 +846,7 @@ func TestHandleWebhookMatchingBranch(t *testing.T) {
|
||||
svc, dbInst, cleanup := setupTestService(t)
|
||||
defer cleanup()
|
||||
|
||||
app := createTestApp(t, dbInst, "main")
|
||||
app := createTestApp(t, dbInst, branchMain)
|
||||
|
||||
payload := []byte(`{
|
||||
"ref": "refs/heads/main",
|
||||
@@ -767,7 +863,7 @@ func TestHandleWebhookMatchingBranch(t *testing.T) {
|
||||
}`)
|
||||
|
||||
err := svc.HandleWebhook(
|
||||
context.Background(), app, webhook.SourceGitea, "push", payload,
|
||||
context.Background(), app, webhook.SourceGitea, pushEventType, payload,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -779,8 +875,8 @@ func TestHandleWebhookMatchingBranch(t *testing.T) {
|
||||
require.Len(t, events, 1)
|
||||
|
||||
event := events[0]
|
||||
assert.Equal(t, "push", event.EventType)
|
||||
assert.Equal(t, "main", event.Branch)
|
||||
assert.Equal(t, pushEventType, event.EventType)
|
||||
assert.Equal(t, branchMain, event.Branch)
|
||||
assert.True(t, event.Matched)
|
||||
assert.Equal(t, "abc123def456", event.CommitSHA.String)
|
||||
}
|
||||
@@ -791,12 +887,12 @@ func TestHandleWebhookNonMatchingBranch(t *testing.T) {
|
||||
svc, dbInst, cleanup := setupTestService(t)
|
||||
defer cleanup()
|
||||
|
||||
app := createTestApp(t, dbInst, "main")
|
||||
app := createTestApp(t, dbInst, branchMain)
|
||||
|
||||
payload := []byte(`{"ref": "refs/heads/develop", "after": "def789ghi012"}`)
|
||||
|
||||
err := svc.HandleWebhook(
|
||||
context.Background(), app, webhook.SourceGitea, "push", payload,
|
||||
context.Background(), app, webhook.SourceGitea, pushEventType, payload,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -814,10 +910,11 @@ func TestHandleWebhookInvalidJSON(t *testing.T) {
|
||||
svc, dbInst, cleanup := setupTestService(t)
|
||||
defer cleanup()
|
||||
|
||||
app := createTestApp(t, dbInst, "main")
|
||||
app := createTestApp(t, dbInst, branchMain)
|
||||
|
||||
err := svc.HandleWebhook(
|
||||
context.Background(), app, webhook.SourceGitea, "push", []byte(`{invalid json}`),
|
||||
context.Background(), app, webhook.SourceGitea, pushEventType,
|
||||
[]byte(`{invalid json}`),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -832,10 +929,10 @@ func TestHandleWebhookEmptyPayload(t *testing.T) {
|
||||
svc, dbInst, cleanup := setupTestService(t)
|
||||
defer cleanup()
|
||||
|
||||
app := createTestApp(t, dbInst, "main")
|
||||
app := createTestApp(t, dbInst, branchMain)
|
||||
|
||||
err := svc.HandleWebhook(
|
||||
context.Background(), app, webhook.SourceGitea, "push", []byte(`{}`),
|
||||
context.Background(), app, webhook.SourceGitea, pushEventType, []byte(`{}`),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -845,14 +942,43 @@ func TestHandleWebhookEmptyPayload(t *testing.T) {
|
||||
assert.False(t, events[0].Matched)
|
||||
}
|
||||
|
||||
// TestHandleWebhookGitHubSource tests HandleWebhook with a GitHub push payload.
|
||||
func TestHandleWebhookGitHubSource(t *testing.T) {
|
||||
t.Parallel()
|
||||
// assertHandleWebhookDeploys runs HandleWebhook for payload against a fresh
|
||||
// app on branchMain and asserts the recorded event matched with the given
|
||||
// commit SHA and commit URL.
|
||||
func assertHandleWebhookDeploys(
|
||||
t *testing.T,
|
||||
source webhook.Source,
|
||||
payload []byte,
|
||||
wantSHA string,
|
||||
wantCommitURL string,
|
||||
) {
|
||||
t.Helper()
|
||||
|
||||
svc, dbInst, cleanup := setupTestService(t)
|
||||
defer cleanup()
|
||||
|
||||
app := createTestApp(t, dbInst, "main")
|
||||
app := createTestApp(t, dbInst, branchMain)
|
||||
|
||||
err := svc.HandleWebhook(context.Background(), app, source, pushEventType, payload)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Allow async deployment goroutine to complete before test cleanup
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
events, err := app.GetWebhookEvents(context.Background(), 10)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, events, 1)
|
||||
|
||||
event := events[0]
|
||||
assert.Equal(t, branchMain, event.Branch)
|
||||
assert.True(t, event.Matched)
|
||||
assert.Equal(t, wantSHA, event.CommitSHA.String)
|
||||
assert.Equal(t, wantCommitURL, event.CommitURL.String)
|
||||
}
|
||||
|
||||
// TestHandleWebhookGitHubSource tests HandleWebhook with a GitHub push payload.
|
||||
func TestHandleWebhookGitHubSource(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
payload := []byte(`{
|
||||
"ref": "refs/heads/main",
|
||||
@@ -870,34 +996,16 @@ func TestHandleWebhookGitHubSource(t *testing.T) {
|
||||
}
|
||||
}`)
|
||||
|
||||
err := svc.HandleWebhook(
|
||||
context.Background(), app, webhook.SourceGitHub, "push", payload,
|
||||
assertHandleWebhookDeploys(
|
||||
t, webhook.SourceGitHub, payload,
|
||||
"github123", "https://github.com/org/repo/commit/github123",
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Allow async deployment goroutine to complete before test cleanup
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
events, err := app.GetWebhookEvents(context.Background(), 10)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, events, 1)
|
||||
|
||||
event := events[0]
|
||||
assert.Equal(t, "main", event.Branch)
|
||||
assert.True(t, event.Matched)
|
||||
assert.Equal(t, "github123", event.CommitSHA.String)
|
||||
assert.Equal(t, "https://github.com/org/repo/commit/github123", event.CommitURL.String)
|
||||
}
|
||||
|
||||
// TestHandleWebhookGitLabSource tests HandleWebhook with a GitLab push payload.
|
||||
func TestHandleWebhookGitLabSource(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
svc, dbInst, cleanup := setupTestService(t)
|
||||
defer cleanup()
|
||||
|
||||
app := createTestApp(t, dbInst, "main")
|
||||
|
||||
payload := []byte(`{
|
||||
"ref": "refs/heads/main",
|
||||
"after": "gitlab456",
|
||||
@@ -917,23 +1025,10 @@ func TestHandleWebhookGitLabSource(t *testing.T) {
|
||||
]
|
||||
}`)
|
||||
|
||||
err := svc.HandleWebhook(
|
||||
context.Background(), app, webhook.SourceGitLab, "push", payload,
|
||||
assertHandleWebhookDeploys(
|
||||
t, webhook.SourceGitLab, payload,
|
||||
"gitlab456", "https://gitlab.com/group/project/-/commit/gitlab456",
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Allow async deployment goroutine to complete before test cleanup
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
events, err := app.GetWebhookEvents(context.Background(), 10)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, events, 1)
|
||||
|
||||
event := events[0]
|
||||
assert.Equal(t, "main", event.Branch)
|
||||
assert.True(t, event.Matched)
|
||||
assert.Equal(t, "gitlab456", event.CommitSHA.String)
|
||||
assert.Equal(t, "https://gitlab.com/group/project/-/commit/gitlab456", event.CommitURL.String)
|
||||
}
|
||||
|
||||
// TestSetupTestService verifies the test helper creates a working test service.
|
||||
@@ -962,10 +1057,10 @@ func TestPushEventConstruction(t *testing.T) {
|
||||
|
||||
event := webhook.PushEvent{
|
||||
Source: webhook.SourceGitHub,
|
||||
Ref: "refs/heads/main",
|
||||
Ref: refMain,
|
||||
Before: "000",
|
||||
After: "abc",
|
||||
Branch: "main",
|
||||
Branch: branchMain,
|
||||
RepoName: "org/repo",
|
||||
CloneURL: webhook.UnparsedURL("https://github.com/org/repo.git"),
|
||||
HTMLURL: webhook.UnparsedURL("https://github.com/org/repo"),
|
||||
@@ -973,7 +1068,7 @@ func TestPushEventConstruction(t *testing.T) {
|
||||
Pusher: "user",
|
||||
}
|
||||
|
||||
assert.Equal(t, "main", event.Branch)
|
||||
assert.Equal(t, branchMain, event.Branch)
|
||||
assert.Equal(t, webhook.SourceGitHub, event.Source)
|
||||
assert.Equal(t, "abc", event.After)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user