forgejo/services/webhook/sourcehut/builds_test.go

455 lines
13 KiB
Go

// Copyright 2024 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package sourcehut
import (
"context"
"testing"
"time"
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
webhook_model "code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
webhook_module "code.gitea.io/gitea/modules/webhook"
repo_service "code.gitea.io/gitea/services/repository"
files_service "code.gitea.io/gitea/services/repository/files"
"code.gitea.io/gitea/services/webhook/shared"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func gitInit(t testing.TB) {
if setting.Git.HomePath != "" {
return
}
t.Cleanup(test.MockVariableValue(&setting.Git.HomePath, t.TempDir()))
assert.NoError(t, git.InitSimple(context.Background()))
}
func TestSourcehutBuildsPayload(t *testing.T) {
gitInit(t)
defer test.MockVariableValue(&setting.RepoRootPath, ".")()
defer test.MockVariableValue(&setting.AppURL, "https://example.forgejo.org/")()
repo := &api.Repository{
HTMLURL: "http://localhost:3000/testdata/repo",
Name: "repo",
FullName: "testdata/repo",
Owner: &api.User{
UserName: "testdata",
},
CloneURL: "http://localhost:3000/testdata/repo.git",
}
pc := sourcehutConvertor{
ctx: git.DefaultContext,
meta: BuildsMeta{
ManifestPath: "adjust me in each test",
Visibility: "UNLISTED",
Secrets: true,
},
}
t.Run("Create/branch", func(t *testing.T) {
p := &api.CreatePayload{
Sha: "58771003157b81abc6bf41df0c5db4147a3e3c83",
Ref: "refs/heads/test",
RefType: "branch",
Repo: repo,
}
pc.meta.ManifestPath = "simple.yml"
pl, err := pc.Create(p)
require.NoError(t, err)
assert.Equal(t, `sources:
- http://localhost:3000/testdata/repo.git#58771003157b81abc6bf41df0c5db4147a3e3c83
environment:
BUILD_SUBMITTER: forgejo
BUILD_SUBMITTER_URL: https://example.forgejo.org/
GIT_REF: refs/heads/test
image: alpine/edge
tasks:
- say-hello: |
echo hello
- say-world: echo world
`, pl.Variables.Manifest)
assert.Equal(t, buildsVariables{
Manifest: pl.Variables.Manifest, // the manifest correctness is checked above, for nicer diff on error
Note: "branch test created",
Tags: []string{"testdata/repo", "branch/test", "simple.yml"},
Secrets: true,
Execute: true,
Visibility: "UNLISTED",
}, pl.Variables)
})
t.Run("Create/tag", func(t *testing.T) {
p := &api.CreatePayload{
Sha: "58771003157b81abc6bf41df0c5db4147a3e3c83",
Ref: "refs/tags/v1.0.0",
RefType: "tag",
Repo: repo,
}
pc.meta.ManifestPath = "simple.yml"
pl, err := pc.Create(p)
require.NoError(t, err)
assert.Equal(t, `sources:
- http://localhost:3000/testdata/repo.git#58771003157b81abc6bf41df0c5db4147a3e3c83
environment:
BUILD_SUBMITTER: forgejo
BUILD_SUBMITTER_URL: https://example.forgejo.org/
GIT_REF: refs/tags/v1.0.0
image: alpine/edge
tasks:
- say-hello: |
echo hello
- say-world: echo world
`, pl.Variables.Manifest)
assert.Equal(t, buildsVariables{
Manifest: pl.Variables.Manifest, // the manifest correctness is checked above, for nicer diff on error
Note: "tag v1.0.0 created",
Tags: []string{"testdata/repo", "tag/v1.0.0", "simple.yml"},
Secrets: true,
Execute: true,
Visibility: "UNLISTED",
}, pl.Variables)
})
t.Run("Delete", func(t *testing.T) {
p := &api.DeletePayload{}
pl, err := pc.Delete(p)
require.Equal(t, err, shared.ErrPayloadTypeNotSupported)
require.Equal(t, pl, graphqlPayload[buildsVariables]{})
})
t.Run("Fork", func(t *testing.T) {
p := &api.ForkPayload{}
pl, err := pc.Fork(p)
require.Equal(t, err, shared.ErrPayloadTypeNotSupported)
require.Equal(t, pl, graphqlPayload[buildsVariables]{})
})
t.Run("Push/simple", func(t *testing.T) {
p := &api.PushPayload{
Ref: "refs/heads/main",
HeadCommit: &api.PayloadCommit{
ID: "58771003157b81abc6bf41df0c5db4147a3e3c83",
Message: "add simple",
},
Repo: repo,
}
pc.meta.ManifestPath = "simple.yml"
pl, err := pc.Push(p)
require.NoError(t, err)
assert.Equal(t, `sources:
- http://localhost:3000/testdata/repo.git#58771003157b81abc6bf41df0c5db4147a3e3c83
environment:
BUILD_SUBMITTER: forgejo
BUILD_SUBMITTER_URL: https://example.forgejo.org/
GIT_REF: refs/heads/main
image: alpine/edge
tasks:
- say-hello: |
echo hello
- say-world: echo world
`, pl.Variables.Manifest)
assert.Equal(t, buildsVariables{
Manifest: pl.Variables.Manifest, // the manifest correctness is checked above, for nicer diff on error
Note: "add simple",
Tags: []string{"testdata/repo", "branch/main", "simple.yml"},
Secrets: true,
Execute: true,
Visibility: "UNLISTED",
}, pl.Variables)
})
t.Run("Push/complex", func(t *testing.T) {
p := &api.PushPayload{
Ref: "refs/heads/main",
HeadCommit: &api.PayloadCommit{
ID: "b0404943256a1f5a50c3726f4378756b4c1e5704",
Message: "replace simple with complex",
},
Repo: repo,
}
pc.meta.ManifestPath = "complex.yaml"
pc.meta.Visibility = "PRIVATE"
pc.meta.Secrets = false
pl, err := pc.Push(p)
require.NoError(t, err)
assert.Equal(t, `sources:
- http://localhost:3000/testdata/repo.git#b0404943256a1f5a50c3726f4378756b4c1e5704
environment:
BUILD_SUBMITTER: forgejo
BUILD_SUBMITTER_URL: https://example.forgejo.org/
GIT_REF: refs/heads/main
deploy: synapse@synapse-bt.org
image: archlinux
packages:
- nodejs
- npm
- rsync
secrets:
- 7ebab768-e5e4-4c9d-ba57-ec41a72c5665
tasks: []
triggers:
- condition: failure
action: email
to: Jim Jimson <jim@example.org>
# report back the status
- condition: always
action: webhook
url: https://hook.example.org
`, pl.Variables.Manifest)
assert.Equal(t, buildsVariables{
Manifest: pl.Variables.Manifest, // the manifest correctness is checked above, for nicer diff on error
Note: "replace simple with complex",
Tags: []string{"testdata/repo", "branch/main", "complex.yaml"},
Secrets: false,
Execute: true,
Visibility: "PRIVATE",
}, pl.Variables)
})
t.Run("Push/error", func(t *testing.T) {
p := &api.PushPayload{
Ref: "refs/heads/main",
HeadCommit: &api.PayloadCommit{
ID: "58771003157b81abc6bf41df0c5db4147a3e3c83",
Message: "add simple",
},
Repo: repo,
}
pc.meta.ManifestPath = "non-existing.yml"
pl, err := pc.Push(p)
require.NoError(t, err)
assert.Equal(t, graphqlPayload[buildsVariables]{
Error: "testdata/repo:refs/heads/main could not open manifest \"non-existing.yml\"",
}, pl)
})
t.Run("Issue", func(t *testing.T) {
p := &api.IssuePayload{}
p.Action = api.HookIssueOpened
pl, err := pc.Issue(p)
require.Equal(t, err, shared.ErrPayloadTypeNotSupported)
require.Equal(t, pl, graphqlPayload[buildsVariables]{})
p.Action = api.HookIssueClosed
pl, err = pc.Issue(p)
require.Equal(t, err, shared.ErrPayloadTypeNotSupported)
require.Equal(t, pl, graphqlPayload[buildsVariables]{})
})
t.Run("IssueComment", func(t *testing.T) {
p := &api.IssueCommentPayload{}
pl, err := pc.IssueComment(p)
require.Equal(t, err, shared.ErrPayloadTypeNotSupported)
require.Equal(t, pl, graphqlPayload[buildsVariables]{})
})
t.Run("PullRequest", func(t *testing.T) {
p := &api.PullRequestPayload{}
pl, err := pc.PullRequest(p)
require.Equal(t, err, shared.ErrPayloadTypeNotSupported)
require.Equal(t, pl, graphqlPayload[buildsVariables]{})
})
t.Run("PullRequestComment", func(t *testing.T) {
p := &api.IssueCommentPayload{
IsPull: true,
}
pl, err := pc.IssueComment(p)
require.Equal(t, err, shared.ErrPayloadTypeNotSupported)
require.Equal(t, pl, graphqlPayload[buildsVariables]{})
})
t.Run("Review", func(t *testing.T) {
p := &api.PullRequestPayload{}
p.Action = api.HookIssueReviewed
pl, err := pc.Review(p, webhook_module.HookEventPullRequestReviewApproved)
require.Equal(t, err, shared.ErrPayloadTypeNotSupported)
require.Equal(t, pl, graphqlPayload[buildsVariables]{})
})
t.Run("Repository", func(t *testing.T) {
p := &api.RepositoryPayload{}
pl, err := pc.Repository(p)
require.Equal(t, err, shared.ErrPayloadTypeNotSupported)
require.Equal(t, pl, graphqlPayload[buildsVariables]{})
})
t.Run("Package", func(t *testing.T) {
p := &api.PackagePayload{}
pl, err := pc.Package(p)
require.Equal(t, err, shared.ErrPayloadTypeNotSupported)
require.Equal(t, pl, graphqlPayload[buildsVariables]{})
})
t.Run("Wiki", func(t *testing.T) {
p := &api.WikiPayload{}
p.Action = api.HookWikiCreated
pl, err := pc.Wiki(p)
require.Equal(t, err, shared.ErrPayloadTypeNotSupported)
require.Equal(t, pl, graphqlPayload[buildsVariables]{})
p.Action = api.HookWikiEdited
pl, err = pc.Wiki(p)
require.Equal(t, err, shared.ErrPayloadTypeNotSupported)
require.Equal(t, pl, graphqlPayload[buildsVariables]{})
p.Action = api.HookWikiDeleted
pl, err = pc.Wiki(p)
require.Equal(t, err, shared.ErrPayloadTypeNotSupported)
require.Equal(t, pl, graphqlPayload[buildsVariables]{})
})
t.Run("Release", func(t *testing.T) {
p := &api.ReleasePayload{}
pl, err := pc.Release(p)
require.Equal(t, err, shared.ErrPayloadTypeNotSupported)
require.Equal(t, pl, graphqlPayload[buildsVariables]{})
})
}
func TestSourcehutJSONPayload(t *testing.T) {
gitInit(t)
defer test.MockVariableValue(&setting.RepoRootPath, ".")()
defer test.MockVariableValue(&setting.AppURL, "https://example.forgejo.org/")()
repo := &api.Repository{
HTMLURL: "http://localhost:3000/testdata/repo",
Name: "repo",
FullName: "testdata/repo",
Owner: &api.User{
UserName: "testdata",
},
CloneURL: "http://localhost:3000/testdata/repo.git",
}
p := &api.PushPayload{
Ref: "refs/heads/main",
HeadCommit: &api.PayloadCommit{
ID: "58771003157b81abc6bf41df0c5db4147a3e3c83",
Message: "json test",
},
Repo: repo,
}
data, err := p.JSONPayload()
require.NoError(t, err)
hook := &webhook_model.Webhook{
RepoID: 3,
IsActive: true,
Type: webhook_module.MATRIX,
URL: "https://sourcehut.example.com/api/jobs",
Meta: `{"manifest_path":"simple.yml"}`,
}
task := &webhook_model.HookTask{
HookID: hook.ID,
EventType: webhook_module.HookEventPush,
PayloadContent: string(data),
PayloadVersion: 2,
}
req, reqBody, err := BuildsHandler{}.NewRequest(context.Background(), hook, task)
require.NoError(t, err)
require.NotNil(t, req)
require.NotNil(t, reqBody)
assert.Equal(t, "POST", req.Method)
assert.Equal(t, "/api/jobs", req.URL.Path)
assert.Equal(t, "application/json", req.Header.Get("Content-Type"))
var body graphqlPayload[buildsVariables]
err = json.NewDecoder(req.Body).Decode(&body)
assert.NoError(t, err)
assert.Equal(t, "json test", body.Variables.Note)
}
func CreateDeclarativeRepo(t *testing.T, owner *user_model.User, name string, enabledUnits, disabledUnits []unit_model.Type, files []*files_service.ChangeRepoFile) (*repo_model.Repository, string) {
t.Helper()
// Create a new repository
repo, err := repo_service.CreateRepository(db.DefaultContext, owner, owner, repo_service.CreateRepoOptions{
Name: name,
Description: "Temporary Repo",
AutoInit: true,
Gitignores: "",
License: "WTFPL",
Readme: "Default",
DefaultBranch: "main",
})
assert.NoError(t, err)
assert.NotEmpty(t, repo)
t.Cleanup(func() {
repo_service.DeleteRepository(db.DefaultContext, owner, repo, false)
})
if enabledUnits != nil || disabledUnits != nil {
units := make([]repo_model.RepoUnit, len(enabledUnits))
for i, unitType := range enabledUnits {
units[i] = repo_model.RepoUnit{
RepoID: repo.ID,
Type: unitType,
}
}
err := repo_service.UpdateRepositoryUnits(db.DefaultContext, repo, units, disabledUnits)
assert.NoError(t, err)
}
var sha string
if len(files) > 0 {
resp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, owner, &files_service.ChangeRepoFilesOptions{
Files: files,
Message: "add files",
OldBranch: "main",
NewBranch: "main",
Author: &files_service.IdentityOptions{
Name: owner.Name,
Email: owner.Email,
},
Committer: &files_service.IdentityOptions{
Name: owner.Name,
Email: owner.Email,
},
Dates: &files_service.CommitDateOptions{
Author: time.Now(),
Committer: time.Now(),
},
})
assert.NoError(t, err)
assert.NotEmpty(t, resp)
sha = resp.Commit.SHA
}
return repo, sha
}