diff options
author | Daniel Baumann <daniel@debian.org> | 2024-10-18 20:33:49 +0200 |
---|---|---|
committer | Daniel Baumann <daniel@debian.org> | 2024-12-12 23:57:56 +0100 |
commit | e68b9d00a6e05b3a941f63ffb696f91e554ac5ec (patch) | |
tree | 97775d6c13b0f416af55314eb6a89ef792474615 /services/webhook/sourcehut | |
parent | Initial commit. (diff) | |
download | forgejo-e68b9d00a6e05b3a941f63ffb696f91e554ac5ec.tar.xz forgejo-e68b9d00a6e05b3a941f63ffb696f91e554ac5ec.zip |
Adding upstream version 9.0.3.
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to '')
16 files changed, 711 insertions, 0 deletions
diff --git a/services/webhook/sourcehut/builds.go b/services/webhook/sourcehut/builds.go new file mode 100644 index 0000000..7b7ace1 --- /dev/null +++ b/services/webhook/sourcehut/builds.go @@ -0,0 +1,301 @@ +// Copyright 2024 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package sourcehut + +import ( + "cmp" + "context" + "fmt" + "html/template" + "io/fs" + "net/http" + "strings" + + webhook_model "code.gitea.io/gitea/models/webhook" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/gitrepo" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" + gitea_context "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/forms" + "code.gitea.io/gitea/services/webhook/shared" + + "gitea.com/go-chi/binding" + "gopkg.in/yaml.v3" +) + +type BuildsHandler struct{} + +func (BuildsHandler) Type() webhook_module.HookType { return webhook_module.SOURCEHUT_BUILDS } +func (BuildsHandler) Metadata(w *webhook_model.Webhook) any { + s := &BuildsMeta{} + if err := json.Unmarshal([]byte(w.Meta), s); err != nil { + log.Error("sourcehut.BuildsHandler.Metadata(%d): %v", w.ID, err) + } + return s +} + +func (BuildsHandler) Icon(size int) template.HTML { + return shared.ImgIcon("sourcehut.svg", size) +} + +type buildsForm struct { + forms.WebhookCoreForm + PayloadURL string `binding:"Required;ValidUrl"` + ManifestPath string `binding:"Required"` + Visibility string `binding:"Required;In(PUBLIC,UNLISTED,PRIVATE)"` + Secrets bool + AccessToken string `binding:"Required"` +} + +var _ binding.Validator = &buildsForm{} + +// Validate implements binding.Validator. +func (f *buildsForm) Validate(req *http.Request, errs binding.Errors) binding.Errors { + ctx := gitea_context.GetWebContext(req) + if !fs.ValidPath(f.ManifestPath) { + errs = append(errs, binding.Error{ + FieldNames: []string{"ManifestPath"}, + Classification: "", + Message: ctx.Locale.TrString("repo.settings.add_webhook.invalid_path"), + }) + } + f.AuthorizationHeader = "Bearer " + strings.TrimSpace(f.AccessToken) + return errs +} + +func (BuildsHandler) UnmarshalForm(bind func(any)) forms.WebhookForm { + var form buildsForm + bind(&form) + + return forms.WebhookForm{ + WebhookCoreForm: form.WebhookCoreForm, + URL: form.PayloadURL, + ContentType: webhook_model.ContentTypeJSON, + Secret: "", + HTTPMethod: http.MethodPost, + Metadata: &BuildsMeta{ + ManifestPath: form.ManifestPath, + Visibility: form.Visibility, + Secrets: form.Secrets, + }, + } +} + +type ( + graphqlPayload[V any] struct { + Query string `json:"query,omitempty"` + Error string `json:"error,omitempty"` + Variables V `json:"variables,omitempty"` + } + // buildsVariables according to https://man.sr.ht/builds.sr.ht/graphql.md + buildsVariables struct { + Manifest string `json:"manifest"` + Tags []string `json:"tags"` + Note string `json:"note"` + Secrets bool `json:"secrets"` + Execute bool `json:"execute"` + Visibility string `json:"visibility"` + } + + // BuildsMeta contains the metadata for the webhook + BuildsMeta struct { + ManifestPath string `json:"manifest_path"` + Visibility string `json:"visibility"` + Secrets bool `json:"secrets"` + } +) + +type sourcehutConvertor struct { + ctx context.Context + meta BuildsMeta +} + +var _ shared.PayloadConvertor[graphqlPayload[buildsVariables]] = sourcehutConvertor{} + +func (BuildsHandler) NewRequest(ctx context.Context, w *webhook_model.Webhook, t *webhook_model.HookTask) (*http.Request, []byte, error) { + meta := BuildsMeta{} + if err := json.Unmarshal([]byte(w.Meta), &meta); err != nil { + return nil, nil, fmt.Errorf("newSourcehutRequest meta json: %w", err) + } + pc := sourcehutConvertor{ + ctx: ctx, + meta: meta, + } + return shared.NewJSONRequest(pc, w, t, false) +} + +// Create implements PayloadConvertor Create method +func (pc sourcehutConvertor) Create(p *api.CreatePayload) (graphqlPayload[buildsVariables], error) { + return pc.newPayload(p.Repo, p.Sha, p.Ref, p.RefType+" "+git.RefName(p.Ref).ShortName()+" created", true) +} + +// Delete implements PayloadConvertor Delete method +func (pc sourcehutConvertor) Delete(_ *api.DeletePayload) (graphqlPayload[buildsVariables], error) { + return graphqlPayload[buildsVariables]{}, shared.ErrPayloadTypeNotSupported +} + +// Fork implements PayloadConvertor Fork method +func (pc sourcehutConvertor) Fork(_ *api.ForkPayload) (graphqlPayload[buildsVariables], error) { + return graphqlPayload[buildsVariables]{}, shared.ErrPayloadTypeNotSupported +} + +// Push implements PayloadConvertor Push method +func (pc sourcehutConvertor) Push(p *api.PushPayload) (graphqlPayload[buildsVariables], error) { + return pc.newPayload(p.Repo, p.HeadCommit.ID, p.Ref, p.HeadCommit.Message, true) +} + +// Issue implements PayloadConvertor Issue method +func (pc sourcehutConvertor) Issue(_ *api.IssuePayload) (graphqlPayload[buildsVariables], error) { + return graphqlPayload[buildsVariables]{}, shared.ErrPayloadTypeNotSupported +} + +// IssueComment implements PayloadConvertor IssueComment method +func (pc sourcehutConvertor) IssueComment(_ *api.IssueCommentPayload) (graphqlPayload[buildsVariables], error) { + return graphqlPayload[buildsVariables]{}, shared.ErrPayloadTypeNotSupported +} + +// PullRequest implements PayloadConvertor PullRequest method +func (pc sourcehutConvertor) PullRequest(_ *api.PullRequestPayload) (graphqlPayload[buildsVariables], error) { + // TODO + return graphqlPayload[buildsVariables]{}, shared.ErrPayloadTypeNotSupported +} + +// Review implements PayloadConvertor Review method +func (pc sourcehutConvertor) Review(_ *api.PullRequestPayload, _ webhook_module.HookEventType) (graphqlPayload[buildsVariables], error) { + return graphqlPayload[buildsVariables]{}, shared.ErrPayloadTypeNotSupported +} + +// Repository implements PayloadConvertor Repository method +func (pc sourcehutConvertor) Repository(_ *api.RepositoryPayload) (graphqlPayload[buildsVariables], error) { + return graphqlPayload[buildsVariables]{}, shared.ErrPayloadTypeNotSupported +} + +// Wiki implements PayloadConvertor Wiki method +func (pc sourcehutConvertor) Wiki(_ *api.WikiPayload) (graphqlPayload[buildsVariables], error) { + return graphqlPayload[buildsVariables]{}, shared.ErrPayloadTypeNotSupported +} + +// Release implements PayloadConvertor Release method +func (pc sourcehutConvertor) Release(_ *api.ReleasePayload) (graphqlPayload[buildsVariables], error) { + return graphqlPayload[buildsVariables]{}, shared.ErrPayloadTypeNotSupported +} + +func (pc sourcehutConvertor) Package(_ *api.PackagePayload) (graphqlPayload[buildsVariables], error) { + return graphqlPayload[buildsVariables]{}, shared.ErrPayloadTypeNotSupported +} + +// mustBuildManifest adjusts the manifest to submit to the builds service +// +// in case of an error the Error field will be set, to be visible by the end-user under recent deliveries +func (pc sourcehutConvertor) newPayload(repo *api.Repository, commitID, ref, note string, trusted bool) (graphqlPayload[buildsVariables], error) { + manifest, err := pc.buildManifest(repo, commitID, ref) + if err != nil { + if len(manifest) == 0 { + return graphqlPayload[buildsVariables]{}, err + } + // the manifest contains an error for the user: log the actual error and construct the payload + // the error will be visible under the "recent deliveries" of the webhook settings. + log.Warn("sourcehut.builds: could not construct manifest for %s: %v", repo.FullName, err) + msg := fmt.Sprintf("%s:%s %s", repo.FullName, ref, manifest) + return graphqlPayload[buildsVariables]{ + Error: msg, + }, nil + } + + gitRef := git.RefName(ref) + return graphqlPayload[buildsVariables]{ + Query: `mutation ( + $manifest: String! + $tags: [String!] + $note: String! + $secrets: Boolean! + $execute: Boolean! + $visibility: Visibility! +) { + submit( + manifest: $manifest + tags: $tags + note: $note + secrets: $secrets + execute: $execute + visibility: $visibility + ) { + id + } +}`, Variables: buildsVariables{ + Manifest: string(manifest), + Tags: []string{repo.FullName, gitRef.RefType() + "/" + gitRef.ShortName(), pc.meta.ManifestPath}, + Note: note, + Secrets: pc.meta.Secrets && trusted, + Execute: trusted, + Visibility: cmp.Or(pc.meta.Visibility, "PRIVATE"), + }, + }, nil +} + +// buildManifest adjusts the manifest to submit to the builds service +// in case of an error the []byte might contain an error that can be displayed to the user +func (pc sourcehutConvertor) buildManifest(repo *api.Repository, commitID, gitRef string) ([]byte, error) { + gitRepo, err := gitrepo.OpenRepository(pc.ctx, repo) + if err != nil { + msg := "could not open repository" + return []byte(msg), fmt.Errorf(msg+": %w", err) + } + defer gitRepo.Close() + + commit, err := gitRepo.GetCommit(commitID) + if err != nil { + msg := fmt.Sprintf("could not get commit %q", commitID) + return []byte(msg), fmt.Errorf(msg+": %w", err) + } + entry, err := commit.GetTreeEntryByPath(pc.meta.ManifestPath) + if err != nil { + msg := fmt.Sprintf("could not open manifest %q", pc.meta.ManifestPath) + return []byte(msg), fmt.Errorf(msg+": %w", err) + } + r, err := entry.Blob().DataAsync() + if err != nil { + msg := fmt.Sprintf("could not read manifest %q", pc.meta.ManifestPath) + return []byte(msg), fmt.Errorf(msg+": %w", err) + } + defer r.Close() + + // reference: https://man.sr.ht/builds.sr.ht/manifest.md + var manifest struct { + Sources []string `yaml:"sources"` + Environment map[string]string `yaml:"environment"` + + Rest map[string]yaml.Node `yaml:",inline"` + } + if err := yaml.NewDecoder(r).Decode(&manifest); err != nil { + msg := fmt.Sprintf("could not decode manifest %q", pc.meta.ManifestPath) + return []byte(msg), fmt.Errorf(msg+": %w", err) + } + + if manifest.Environment == nil { + manifest.Environment = make(map[string]string) + } + manifest.Environment["BUILD_SUBMITTER"] = "forgejo" + manifest.Environment["BUILD_SUBMITTER_URL"] = setting.AppURL + manifest.Environment["GIT_REF"] = gitRef + + source := repo.CloneURL + "#" + commitID + found := false + for i, s := range manifest.Sources { + if s == repo.CloneURL { + manifest.Sources[i] = source + found = true + break + } + } + if !found { + manifest.Sources = append(manifest.Sources, source) + } + + return yaml.Marshal(manifest) +} diff --git a/services/webhook/sourcehut/builds_test.go b/services/webhook/sourcehut/builds_test.go new file mode 100644 index 0000000..1a37279 --- /dev/null +++ b/services/webhook/sourcehut/builds_test.go @@ -0,0 +1,386 @@ +// Copyright 2024 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package sourcehut + +import ( + "context" + "testing" + + 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" + "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())) + require.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, shared.ErrPayloadTypeNotSupported, err) + require.Equal(t, graphqlPayload[buildsVariables]{}, pl) + }) + + t.Run("Fork", func(t *testing.T) { + p := &api.ForkPayload{} + + pl, err := pc.Fork(p) + require.Equal(t, shared.ErrPayloadTypeNotSupported, err) + require.Equal(t, graphqlPayload[buildsVariables]{}, pl) + }) + + 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, shared.ErrPayloadTypeNotSupported, err) + require.Equal(t, graphqlPayload[buildsVariables]{}, pl) + + p.Action = api.HookIssueClosed + pl, err = pc.Issue(p) + require.Equal(t, shared.ErrPayloadTypeNotSupported, err) + require.Equal(t, graphqlPayload[buildsVariables]{}, pl) + }) + + t.Run("IssueComment", func(t *testing.T) { + p := &api.IssueCommentPayload{} + + pl, err := pc.IssueComment(p) + require.Equal(t, shared.ErrPayloadTypeNotSupported, err) + require.Equal(t, graphqlPayload[buildsVariables]{}, pl) + }) + + t.Run("PullRequest", func(t *testing.T) { + p := &api.PullRequestPayload{} + + pl, err := pc.PullRequest(p) + require.Equal(t, shared.ErrPayloadTypeNotSupported, err) + require.Equal(t, graphqlPayload[buildsVariables]{}, pl) + }) + + t.Run("PullRequestComment", func(t *testing.T) { + p := &api.IssueCommentPayload{ + IsPull: true, + } + + pl, err := pc.IssueComment(p) + require.Equal(t, shared.ErrPayloadTypeNotSupported, err) + require.Equal(t, graphqlPayload[buildsVariables]{}, pl) + }) + + 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, shared.ErrPayloadTypeNotSupported, err) + require.Equal(t, graphqlPayload[buildsVariables]{}, pl) + }) + + t.Run("Repository", func(t *testing.T) { + p := &api.RepositoryPayload{} + + pl, err := pc.Repository(p) + require.Equal(t, shared.ErrPayloadTypeNotSupported, err) + require.Equal(t, graphqlPayload[buildsVariables]{}, pl) + }) + + t.Run("Package", func(t *testing.T) { + p := &api.PackagePayload{} + + pl, err := pc.Package(p) + require.Equal(t, shared.ErrPayloadTypeNotSupported, err) + require.Equal(t, graphqlPayload[buildsVariables]{}, pl) + }) + + t.Run("Wiki", func(t *testing.T) { + p := &api.WikiPayload{} + + p.Action = api.HookWikiCreated + pl, err := pc.Wiki(p) + require.Equal(t, shared.ErrPayloadTypeNotSupported, err) + require.Equal(t, graphqlPayload[buildsVariables]{}, pl) + + p.Action = api.HookWikiEdited + pl, err = pc.Wiki(p) + require.Equal(t, shared.ErrPayloadTypeNotSupported, err) + require.Equal(t, graphqlPayload[buildsVariables]{}, pl) + + p.Action = api.HookWikiDeleted + pl, err = pc.Wiki(p) + require.Equal(t, shared.ErrPayloadTypeNotSupported, err) + require.Equal(t, graphqlPayload[buildsVariables]{}, pl) + }) + + t.Run("Release", func(t *testing.T) { + p := &api.ReleasePayload{} + + pl, err := pc.Release(p) + require.Equal(t, shared.ErrPayloadTypeNotSupported, err) + require.Equal(t, graphqlPayload[buildsVariables]{}, pl) + }) +} + +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) + require.NoError(t, err) + assert.Equal(t, "json test", body.Variables.Note) +} diff --git a/services/webhook/sourcehut/testdata/repo.git/HEAD b/services/webhook/sourcehut/testdata/repo.git/HEAD new file mode 100644 index 0000000..b870d82 --- /dev/null +++ b/services/webhook/sourcehut/testdata/repo.git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/main diff --git a/services/webhook/sourcehut/testdata/repo.git/config b/services/webhook/sourcehut/testdata/repo.git/config new file mode 100644 index 0000000..07d359d --- /dev/null +++ b/services/webhook/sourcehut/testdata/repo.git/config @@ -0,0 +1,4 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true diff --git a/services/webhook/sourcehut/testdata/repo.git/description b/services/webhook/sourcehut/testdata/repo.git/description new file mode 100644 index 0000000..498b267 --- /dev/null +++ b/services/webhook/sourcehut/testdata/repo.git/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/services/webhook/sourcehut/testdata/repo.git/info/exclude b/services/webhook/sourcehut/testdata/repo.git/info/exclude new file mode 100644 index 0000000..a5196d1 --- /dev/null +++ b/services/webhook/sourcehut/testdata/repo.git/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/services/webhook/sourcehut/testdata/repo.git/objects/3c/3d4b799b3933ba687b263eeef2034300a5315e b/services/webhook/sourcehut/testdata/repo.git/objects/3c/3d4b799b3933ba687b263eeef2034300a5315e Binary files differnew file mode 100644 index 0000000..f03b45d --- /dev/null +++ b/services/webhook/sourcehut/testdata/repo.git/objects/3c/3d4b799b3933ba687b263eeef2034300a5315e diff --git a/services/webhook/sourcehut/testdata/repo.git/objects/58/771003157b81abc6bf41df0c5db4147a3e3c83 b/services/webhook/sourcehut/testdata/repo.git/objects/58/771003157b81abc6bf41df0c5db4147a3e3c83 new file mode 100644 index 0000000..e9ff0d0 --- /dev/null +++ b/services/webhook/sourcehut/testdata/repo.git/objects/58/771003157b81abc6bf41df0c5db4147a3e3c83 @@ -0,0 +1,2 @@ +x=0D=+nBXhVk%?_Pm̔bC̠D{ +;F&qm<5e8|[/
O5 GYK)\iOKJ3PƝjU>VX܃絈7\p;
\ No newline at end of file diff --git a/services/webhook/sourcehut/testdata/repo.git/objects/69/b217caa89166a02b8cd368b64fb83a44720e14 b/services/webhook/sourcehut/testdata/repo.git/objects/69/b217caa89166a02b8cd368b64fb83a44720e14 new file mode 100644 index 0000000..1aed811 --- /dev/null +++ b/services/webhook/sourcehut/testdata/repo.git/objects/69/b217caa89166a02b8cd368b64fb83a44720e14 @@ -0,0 +1 @@ +x=n {)^Z,EUN}&TAy6aT=ŵĢ5O \m\uFTGF;NQ^[֓aQokiW~+ppuiha3J?:7([VK|͙TI7uİӑ>sP=C}ˢO
\ No newline at end of file diff --git a/services/webhook/sourcehut/testdata/repo.git/objects/99/fb389b232e5497f0dcdb1c1065eac1d10d3794 b/services/webhook/sourcehut/testdata/repo.git/objects/99/fb389b232e5497f0dcdb1c1065eac1d10d3794 Binary files differnew file mode 100644 index 0000000..43dd885 --- /dev/null +++ b/services/webhook/sourcehut/testdata/repo.git/objects/99/fb389b232e5497f0dcdb1c1065eac1d10d3794 diff --git a/services/webhook/sourcehut/testdata/repo.git/objects/9e/4b777f81b316a1c75a0797b33add68ee49b0d0 b/services/webhook/sourcehut/testdata/repo.git/objects/9e/4b777f81b316a1c75a0797b33add68ee49b0d0 Binary files differnew file mode 100644 index 0000000..081cfcd --- /dev/null +++ b/services/webhook/sourcehut/testdata/repo.git/objects/9e/4b777f81b316a1c75a0797b33add68ee49b0d0 diff --git a/services/webhook/sourcehut/testdata/repo.git/objects/a5/4082fdb8e55055382725f10a81bb4dc2b13029 b/services/webhook/sourcehut/testdata/repo.git/objects/a5/4082fdb8e55055382725f10a81bb4dc2b13029 new file mode 100644 index 0000000..071f79e --- /dev/null +++ b/services/webhook/sourcehut/testdata/repo.git/objects/a5/4082fdb8e55055382725f10a81bb4dc2b13029 @@ -0,0 +1,4 @@ +xUn0wk +l4z0 %fm~@Dc<(ŝ%
m]NjDR +A閌9Xxu{;Nȅ4(Gy:QO?/9lh|0cΌl8*$?dԻ**>7ȖXomUJItmKqrh8>)ҺڋF,77,8
{:0zZfya) +5 ʴ狉7ΑLܯ)z
yivoQ78J}臤
\ No newline at end of file diff --git a/services/webhook/sourcehut/testdata/repo.git/objects/aa/3905af404394f576f88f00e7f0919b4b97453f b/services/webhook/sourcehut/testdata/repo.git/objects/aa/3905af404394f576f88f00e7f0919b4b97453f Binary files differnew file mode 100644 index 0000000..cc96171 --- /dev/null +++ b/services/webhook/sourcehut/testdata/repo.git/objects/aa/3905af404394f576f88f00e7f0919b4b97453f diff --git a/services/webhook/sourcehut/testdata/repo.git/objects/b0/404943256a1f5a50c3726f4378756b4c1e5704 b/services/webhook/sourcehut/testdata/repo.git/objects/b0/404943256a1f5a50c3726f4378756b4c1e5704 Binary files differnew file mode 100644 index 0000000..a2cff63 --- /dev/null +++ b/services/webhook/sourcehut/testdata/repo.git/objects/b0/404943256a1f5a50c3726f4378756b4c1e5704 diff --git a/services/webhook/sourcehut/testdata/repo.git/objects/d2/e0862c8b8097ba4bdd72946c20479751d307a0 b/services/webhook/sourcehut/testdata/repo.git/objects/d2/e0862c8b8097ba4bdd72946c20479751d307a0 new file mode 100644 index 0000000..f57ab8a --- /dev/null +++ b/services/webhook/sourcehut/testdata/repo.git/objects/d2/e0862c8b8097ba4bdd72946c20479751d307a0 @@ -0,0 +1,4 @@ +xENIn0YD#ȁ ۍ, +"$\f9ئ9~,+L-㒶ɀ=og#&OUo߷jU!,꺮DGP +e>L狡t[ +#?C~z2!,qCtQZ<.@78\I
\ No newline at end of file diff --git a/services/webhook/sourcehut/testdata/repo.git/refs/heads/main b/services/webhook/sourcehut/testdata/repo.git/refs/heads/main new file mode 100644 index 0000000..a7ab419 --- /dev/null +++ b/services/webhook/sourcehut/testdata/repo.git/refs/heads/main @@ -0,0 +1 @@ +b0404943256a1f5a50c3726f4378756b4c1e5704 |