diff options
Diffstat (limited to '')
-rw-r--r-- | tests/integration/actions_trigger_test.go | 761 |
1 files changed, 761 insertions, 0 deletions
diff --git a/tests/integration/actions_trigger_test.go b/tests/integration/actions_trigger_test.go new file mode 100644 index 0000000..dfd1f75 --- /dev/null +++ b/tests/integration/actions_trigger_test.go @@ -0,0 +1,761 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package integration + +import ( + "fmt" + "net/http" + "net/url" + "strings" + "testing" + "time" + + actions_model "code.gitea.io/gitea/models/actions" + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + git_model "code.gitea.io/gitea/models/git" + issues_model "code.gitea.io/gitea/models/issues" + repo_model "code.gitea.io/gitea/models/repo" + unit_model "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + actions_module "code.gitea.io/gitea/modules/actions" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/gitrepo" + "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" + actions_service "code.gitea.io/gitea/services/actions" + issue_service "code.gitea.io/gitea/services/issue" + pull_service "code.gitea.io/gitea/services/pull" + release_service "code.gitea.io/gitea/services/release" + repo_service "code.gitea.io/gitea/services/repository" + files_service "code.gitea.io/gitea/services/repository/files" + "code.gitea.io/gitea/tests" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPullRequestCommitStatus(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the base repo + session := loginUser(t, "user2") + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue) + + // prepare the repository + files := make([]*files_service.ChangeRepoFile, 0, 10) + for _, onType := range []string{ + "opened", + "synchronize", + "labeled", + "unlabeled", + "assigned", + "unassigned", + "milestoned", + "demilestoned", + "closed", + "reopened", + } { + files = append(files, &files_service.ChangeRepoFile{ + Operation: "create", + TreePath: fmt.Sprintf(".forgejo/workflows/%s.yml", onType), + ContentReader: strings.NewReader(fmt.Sprintf(`name: %[1]s +on: + pull_request: + types: + - %[1]s +jobs: + %[1]s: + runs-on: docker + steps: + - run: true +`, onType)), + }) + } + baseRepo, _, f := tests.CreateDeclarativeRepo(t, user2, "repo-pull-request", + []unit_model.Type{unit_model.TypeActions}, nil, files) + defer f() + baseGitRepo, err := gitrepo.OpenRepository(db.DefaultContext, baseRepo) + require.NoError(t, err) + defer func() { + baseGitRepo.Close() + }() + + // prepare the repository labels + labelStr := "/api/v1/repos/user2/repo-pull-request/labels" + labelsCount := 2 + labels := make([]*api.Label, labelsCount) + for i := 0; i < labelsCount; i++ { + color := "abcdef" + req := NewRequestWithJSON(t, "POST", labelStr, &api.CreateLabelOption{ + Name: fmt.Sprintf("label%d", i), + Color: color, + }).AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusCreated) + labels[i] = new(api.Label) + DecodeJSON(t, resp, &labels[i]) + assert.Equal(t, color, labels[i].Color) + } + + // create the pull request + testEditFileToNewBranch(t, session, "user2", "repo-pull-request", "main", "wip-something", "README.md", "Hello, world 1") + testPullCreate(t, session, "user2", "repo-pull-request", true, "main", "wip-something", "Commit status PR") + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: baseRepo.ID}) + require.NoError(t, pr.LoadIssue(db.DefaultContext)) + + // prepare the assignees + issueURL := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%s", "user2", "repo-pull-request", fmt.Sprintf("%d", pr.Issue.Index)) + + // prepare the labels + labelURL := fmt.Sprintf("%s/labels", issueURL) + + // prepare the milestone + milestoneStr := "/api/v1/repos/user2/repo-pull-request/milestones" + req := NewRequestWithJSON(t, "POST", milestoneStr, &api.CreateMilestoneOption{ + Title: "mymilestone", + State: "open", + }).AddTokenAuth(token) + resp := MakeRequest(t, req, http.StatusCreated) + milestone := new(api.Milestone) + DecodeJSON(t, resp, &milestone) + + // check that one of the status associated with the commit sha matches both + // context & state + checkCommitStatus := func(sha, context string, state api.CommitStatusState) bool { + commitStatuses, _, err := git_model.GetLatestCommitStatus(db.DefaultContext, pr.BaseRepoID, sha, db.ListOptionsAll) + require.NoError(t, err) + for _, commitStatus := range commitStatuses { + if state == commitStatus.State && context == commitStatus.Context { + return true + } + } + return false + } + + assertActionRun := func(t *testing.T, sha, onType string, action api.HookIssueAction, actionRun *actions_model.ActionRun) { + assert.Equal(t, fmt.Sprintf("%s.yml", onType), actionRun.WorkflowID) + assert.Equal(t, sha, actionRun.CommitSHA) + assert.Equal(t, actions_module.GithubEventPullRequest, actionRun.TriggerEvent) + event, err := actionRun.GetPullRequestEventPayload() + require.NoError(t, err) + assert.Equal(t, action, event.Action) + } + + type assertType func(t *testing.T, sha, onType string, action api.HookIssueAction, actionRuns []*actions_model.ActionRun) + assertActionRuns := func(t *testing.T, sha, onType string, action api.HookIssueAction, actionRuns []*actions_model.ActionRun) { + require.Len(t, actionRuns, 1) + assertActionRun(t, sha, onType, action, actionRuns[0]) + } + + for _, testCase := range []struct { + onType string + jobID string + doSomething func() + actionRunCount int + action api.HookIssueAction + assert assertType + }{ + { + onType: "opened", + doSomething: func() {}, + actionRunCount: 1, + action: api.HookIssueOpened, + assert: assertActionRuns, + }, + { + onType: "synchronize", + doSomething: func() { + testEditFile(t, session, "user2", "repo-pull-request", "wip-something", "README.md", "Hello, world 2") + }, + actionRunCount: 1, + action: api.HookIssueSynchronized, + assert: assertActionRuns, + }, + { + onType: "labeled", + doSomething: func() { + req := NewRequestWithJSON(t, "POST", labelURL, &api.IssueLabelsOption{ + Labels: []any{labels[0].ID, labels[1].ID}, + }).AddTokenAuth(token) + MakeRequest(t, req, http.StatusOK) + }, + actionRunCount: 2, + action: api.HookIssueLabelUpdated, + assert: func(t *testing.T, sha, onType string, action api.HookIssueAction, actionRuns []*actions_model.ActionRun) { + assertActionRun(t, sha, onType, api.HookIssueLabelUpdated, actionRuns[0]) + assertActionRun(t, sha, onType, api.HookIssueLabelUpdated, actionRuns[1]) + }, + }, + { + onType: "unlabeled", + doSomething: func() { + req := NewRequestWithJSON(t, "PUT", labelURL, &api.IssueLabelsOption{ + Labels: []any{labels[0].ID}, + }).AddTokenAuth(token) + MakeRequest(t, req, http.StatusOK) + }, + actionRunCount: 3, + action: api.HookIssueLabelCleared, + assert: func(t *testing.T, sha, onType string, action api.HookIssueAction, actionRuns []*actions_model.ActionRun) { + foundPayloadWithLabels := false + knownLabels := []string{"label0", "label1"} + for _, actionRun := range actionRuns { + assert.Equal(t, sha, actionRun.CommitSHA) + assert.Equal(t, actions_module.GithubEventPullRequest, actionRun.TriggerEvent) + event, err := actionRun.GetPullRequestEventPayload() + require.NoError(t, err) + switch event.Action { + case api.HookIssueLabelUpdated: + assert.Equal(t, "labeled.yml", actionRun.WorkflowID) + assert.Equal(t, "label0", event.Label.Name) + require.Len(t, event.PullRequest.Labels, 1) + assert.Contains(t, "label0", event.PullRequest.Labels[0].Name) + case api.HookIssueLabelCleared: + assert.Equal(t, "unlabeled.yml", actionRun.WorkflowID) + assert.Contains(t, knownLabels, event.Label.Name) + if len(event.PullRequest.Labels) > 0 { + foundPayloadWithLabels = true + assert.Contains(t, knownLabels, event.PullRequest.Labels[0].Name) + } + default: + require.Fail(t, fmt.Sprintf("unexpected action '%s'", event.Action)) + } + } + assert.True(t, foundPayloadWithLabels, "expected at least one clear label payload with non empty labels") + }, + }, + { + onType: "assigned", + doSomething: func() { + req := NewRequestWithJSON(t, "PATCH", issueURL, &api.EditIssueOption{ + Assignees: []string{"user2"}, + }).AddTokenAuth(token) + MakeRequest(t, req, http.StatusCreated) + }, + actionRunCount: 1, + action: api.HookIssueAssigned, + assert: assertActionRuns, + }, + { + onType: "unassigned", + doSomething: func() { + req := NewRequestWithJSON(t, "PATCH", issueURL, &api.EditIssueOption{ + Assignees: []string{}, + }).AddTokenAuth(token) + MakeRequest(t, req, http.StatusCreated) + }, + actionRunCount: 1, + action: api.HookIssueUnassigned, + assert: assertActionRuns, + }, + { + onType: "milestoned", + doSomething: func() { + req := NewRequestWithJSON(t, "PATCH", issueURL, &api.EditIssueOption{ + Milestone: &milestone.ID, + }).AddTokenAuth(token) + MakeRequest(t, req, http.StatusCreated) + }, + actionRunCount: 1, + action: api.HookIssueMilestoned, + assert: assertActionRuns, + }, + { + onType: "demilestoned", + doSomething: func() { + var zero int64 + req := NewRequestWithJSON(t, "PATCH", issueURL, &api.EditIssueOption{ + Milestone: &zero, + }).AddTokenAuth(token) + MakeRequest(t, req, http.StatusCreated) + }, + actionRunCount: 1, + action: api.HookIssueDemilestoned, + assert: assertActionRuns, + }, + { + onType: "closed", + doSomething: func() { + sha, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName()) + require.NoError(t, err) + err = issue_service.ChangeStatus(db.DefaultContext, pr.Issue, user2, sha, true) + require.NoError(t, err) + }, + actionRunCount: 1, + action: api.HookIssueClosed, + assert: assertActionRuns, + }, + { + onType: "reopened", + doSomething: func() { + sha, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName()) + require.NoError(t, err) + err = issue_service.ChangeStatus(db.DefaultContext, pr.Issue, user2, sha, false) + require.NoError(t, err) + }, + actionRunCount: 1, + action: api.HookIssueReOpened, + assert: assertActionRuns, + }, + } { + t.Run(testCase.onType, func(t *testing.T) { + defer func() { + // cleanup leftovers, start from scratch + _, err = db.DeleteByBean(db.DefaultContext, actions_model.ActionRun{RepoID: baseRepo.ID}) + require.NoError(t, err) + _, err = db.DeleteByBean(db.DefaultContext, actions_model.ActionRunJob{RepoID: baseRepo.ID}) + require.NoError(t, err) + }() + + // trigger the onType event + testCase.doSomething() + count := testCase.actionRunCount + context := fmt.Sprintf("%[1]s / %[1]s (pull_request)", testCase.onType) + + var actionRuns []*actions_model.ActionRun + + // wait for ActionRun(s) to be created + require.Eventually(t, func() bool { + actionRuns = make([]*actions_model.ActionRun, 0) + require.NoError(t, db.GetEngine(db.DefaultContext).Where("repo_id=?", baseRepo.ID).Find(&actionRuns)) + return len(actionRuns) == count + }, 30*time.Second, 1*time.Second) + + // verify the expected ActionRuns were created + sha, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName()) + require.NoError(t, err) + // verify the commit status changes to CommitStatusSuccess when the job changes to StatusSuccess + require.Eventually(t, func() bool { + return checkCommitStatus(sha, context, api.CommitStatusPending) + }, 30*time.Second, 1*time.Second) + for _, actionRun := range actionRuns { + // verify the expected ActionRunJob was created and is StatusWaiting + job := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{RunID: actionRun.ID, CommitSHA: sha}) + assert.Equal(t, actions_model.StatusWaiting, job.Status) + + // change the state of the job to success + job.Status = actions_model.StatusSuccess + actions_service.CreateCommitStatus(db.DefaultContext, job) + } + // verify the commit status changed to CommitStatusSuccess because the job(s) changed to StatusSuccess + require.Eventually(t, func() bool { + return checkCommitStatus(sha, context, api.CommitStatusSuccess) + }, 30*time.Second, 1*time.Second) + + testCase.assert(t, sha, testCase.onType, testCase.action, actionRuns) + }) + } + }) +} + +func TestPullRequestTargetEvent(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the base repo + org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the forked repo + + // create the base repo + baseRepo, _, f := tests.CreateDeclarativeRepo(t, user2, "repo-pull-request-target", + []unit_model.Type{unit_model.TypeActions}, nil, nil, + ) + defer f() + + // create the forked repo + forkedRepo, err := repo_service.ForkRepositoryAndUpdates(git.DefaultContext, user2, org3, repo_service.ForkRepoOptions{ + BaseRepo: baseRepo, + Name: "forked-repo-pull-request-target", + Description: "test pull-request-target event", + }) + require.NoError(t, err) + assert.NotEmpty(t, forkedRepo) + + // add workflow file to the base repo + addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, baseRepo, user2, &files_service.ChangeRepoFilesOptions{ + Files: []*files_service.ChangeRepoFile{ + { + Operation: "create", + TreePath: ".gitea/workflows/pr.yml", + ContentReader: strings.NewReader("name: test\non:\n pull_request_target:\n paths:\n - 'file_*.txt'\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - run: echo helloworld\n"), + }, + }, + Message: "add workflow", + OldBranch: "main", + NewBranch: "main", + Author: &files_service.IdentityOptions{ + Name: user2.Name, + Email: user2.Email, + }, + Committer: &files_service.IdentityOptions{ + Name: user2.Name, + Email: user2.Email, + }, + Dates: &files_service.CommitDateOptions{ + Author: time.Now(), + Committer: time.Now(), + }, + }) + require.NoError(t, err) + assert.NotEmpty(t, addWorkflowToBaseResp) + + // add a new file to the forked repo + addFileToForkedResp, err := files_service.ChangeRepoFiles(git.DefaultContext, forkedRepo, org3, &files_service.ChangeRepoFilesOptions{ + Files: []*files_service.ChangeRepoFile{ + { + Operation: "create", + TreePath: "file_1.txt", + ContentReader: strings.NewReader("file1"), + }, + }, + Message: "add file1", + OldBranch: "main", + NewBranch: "fork-branch-1", + Author: &files_service.IdentityOptions{ + Name: org3.Name, + Email: org3.Email, + }, + Committer: &files_service.IdentityOptions{ + Name: org3.Name, + Email: org3.Email, + }, + Dates: &files_service.CommitDateOptions{ + Author: time.Now(), + Committer: time.Now(), + }, + }) + require.NoError(t, err) + assert.NotEmpty(t, addFileToForkedResp) + + // create Pull + pullIssue := &issues_model.Issue{ + RepoID: baseRepo.ID, + Title: "Test pull-request-target-event", + PosterID: org3.ID, + Poster: org3, + IsPull: true, + } + pullRequest := &issues_model.PullRequest{ + HeadRepoID: forkedRepo.ID, + BaseRepoID: baseRepo.ID, + HeadBranch: "fork-branch-1", + BaseBranch: "main", + HeadRepo: forkedRepo, + BaseRepo: baseRepo, + Type: issues_model.PullRequestGitea, + } + err = pull_service.NewPullRequest(git.DefaultContext, baseRepo, pullIssue, nil, nil, pullRequest, nil) + require.NoError(t, err) + // if a PR "synchronized" event races the "opened" event by having the same SHA, it must be skipped. See https://codeberg.org/forgejo/forgejo/issues/2009. + assert.True(t, actions_service.SkipPullRequestEvent(git.DefaultContext, webhook_module.HookEventPullRequestSync, baseRepo.ID, addFileToForkedResp.Commit.SHA)) + + // load and compare ActionRun + assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: baseRepo.ID})) + actionRun := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{RepoID: baseRepo.ID}) + assert.Equal(t, addFileToForkedResp.Commit.SHA, actionRun.CommitSHA) + assert.Equal(t, actions_module.GithubEventPullRequestTarget, actionRun.TriggerEvent) + + // add another file whose name cannot match the specified path + addFileToForkedResp, err = files_service.ChangeRepoFiles(git.DefaultContext, forkedRepo, org3, &files_service.ChangeRepoFilesOptions{ + Files: []*files_service.ChangeRepoFile{ + { + Operation: "create", + TreePath: "foo.txt", + ContentReader: strings.NewReader("foo"), + }, + }, + Message: "add foo.txt", + OldBranch: "main", + NewBranch: "fork-branch-2", + Author: &files_service.IdentityOptions{ + Name: org3.Name, + Email: org3.Email, + }, + Committer: &files_service.IdentityOptions{ + Name: org3.Name, + Email: org3.Email, + }, + Dates: &files_service.CommitDateOptions{ + Author: time.Now(), + Committer: time.Now(), + }, + }) + require.NoError(t, err) + assert.NotEmpty(t, addFileToForkedResp) + + // create Pull + pullIssue = &issues_model.Issue{ + RepoID: baseRepo.ID, + Title: "A mismatched path cannot trigger pull-request-target-event", + PosterID: org3.ID, + Poster: org3, + IsPull: true, + } + pullRequest = &issues_model.PullRequest{ + HeadRepoID: forkedRepo.ID, + BaseRepoID: baseRepo.ID, + HeadBranch: "fork-branch-2", + BaseBranch: "main", + HeadRepo: forkedRepo, + BaseRepo: baseRepo, + Type: issues_model.PullRequestGitea, + } + err = pull_service.NewPullRequest(git.DefaultContext, baseRepo, pullIssue, nil, nil, pullRequest, nil) + require.NoError(t, err) + + // the new pull request cannot trigger actions, so there is still only 1 record + assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: baseRepo.ID})) + }) +} + +func TestSkipCI(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + session := loginUser(t, "user2") + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + + // create the repo + repo, _, f := tests.CreateDeclarativeRepo(t, user2, "skip-ci", + []unit_model.Type{unit_model.TypeActions}, nil, + []*files_service.ChangeRepoFile{ + { + Operation: "create", + TreePath: ".gitea/workflows/pr.yml", + ContentReader: strings.NewReader("name: test\non:\n push:\n branches: [main]\n pull_request:\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - run: echo helloworld\n"), + }, + }, + ) + defer f() + + // a run has been created + assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID})) + + // add a file with a configured skip-ci string in commit message + addFileResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{ + Files: []*files_service.ChangeRepoFile{ + { + Operation: "create", + TreePath: "bar.txt", + ContentReader: strings.NewReader("bar"), + }, + }, + Message: fmt.Sprintf("%s add bar", setting.Actions.SkipWorkflowStrings[0]), + OldBranch: "main", + NewBranch: "main", + Author: &files_service.IdentityOptions{ + Name: user2.Name, + Email: user2.Email, + }, + Committer: &files_service.IdentityOptions{ + Name: user2.Name, + Email: user2.Email, + }, + Dates: &files_service.CommitDateOptions{ + Author: time.Now(), + Committer: time.Now(), + }, + }) + require.NoError(t, err) + assert.NotEmpty(t, addFileResp) + + // the commit message contains a configured skip-ci string, so there is still only 1 record + assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID})) + + // add file to new branch + addFileToBranchResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{ + Files: []*files_service.ChangeRepoFile{ + { + Operation: "create", + TreePath: "test-skip-ci", + ContentReader: strings.NewReader("test-skip-ci"), + }, + }, + Message: "add test file", + OldBranch: "main", + NewBranch: "test-skip-ci", + Author: &files_service.IdentityOptions{ + Name: user2.Name, + Email: user2.Email, + }, + Committer: &files_service.IdentityOptions{ + Name: user2.Name, + Email: user2.Email, + }, + Dates: &files_service.CommitDateOptions{ + Author: time.Now(), + Committer: time.Now(), + }, + }) + require.NoError(t, err) + assert.NotEmpty(t, addFileToBranchResp) + + resp := testPullCreate(t, session, "user2", "skip-ci", true, "main", "test-skip-ci", "[skip ci] test-skip-ci") + + // check the redirected URL + url := test.RedirectURL(resp) + assert.Regexp(t, "^/user2/skip-ci/pulls/[0-9]*$", url) + + // the pr title contains a configured skip-ci string, so there is still only 1 record + assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID})) + }) +} + +func TestCreateDeleteRefEvent(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + + // create the repo + repo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{ + Name: "create-delete-ref-event", + Description: "test create delete ref ci event", + AutoInit: true, + Gitignores: "Go", + License: "MIT", + Readme: "Default", + DefaultBranch: "main", + IsPrivate: false, + }) + require.NoError(t, err) + assert.NotEmpty(t, repo) + + // enable actions + err = repo_service.UpdateRepositoryUnits(db.DefaultContext, repo, []repo_model.RepoUnit{{ + RepoID: repo.ID, + Type: unit_model.TypeActions, + }}, nil) + require.NoError(t, err) + + // add workflow file to the repo + addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{ + Files: []*files_service.ChangeRepoFile{ + { + Operation: "create", + TreePath: ".gitea/workflows/createdelete.yml", + ContentReader: strings.NewReader("name: test\non:\n [create,delete]\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - run: echo helloworld\n"), + }, + }, + Message: "add workflow", + OldBranch: "main", + NewBranch: "main", + Author: &files_service.IdentityOptions{ + Name: user2.Name, + Email: user2.Email, + }, + Committer: &files_service.IdentityOptions{ + Name: user2.Name, + Email: user2.Email, + }, + Dates: &files_service.CommitDateOptions{ + Author: time.Now(), + Committer: time.Now(), + }, + }) + require.NoError(t, err) + assert.NotEmpty(t, addWorkflowToBaseResp) + + // Get the commit ID of the default branch + gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo) + require.NoError(t, err) + defer gitRepo.Close() + branch, err := git_model.GetBranch(db.DefaultContext, repo.ID, repo.DefaultBranch) + require.NoError(t, err) + + // create a branch + err = repo_service.CreateNewBranchFromCommit(db.DefaultContext, user2, repo, gitRepo, branch.CommitID, "test-create-branch") + require.NoError(t, err) + run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ + Title: "add workflow", + RepoID: repo.ID, + Event: "create", + Ref: "refs/heads/test-create-branch", + WorkflowID: "createdelete.yml", + CommitSHA: branch.CommitID, + }) + assert.NotNil(t, run) + + // create a tag + err = release_service.CreateNewTag(db.DefaultContext, user2, repo, branch.CommitID, "test-create-tag", "test create tag event") + require.NoError(t, err) + run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ + Title: "add workflow", + RepoID: repo.ID, + Event: "create", + Ref: "refs/tags/test-create-tag", + WorkflowID: "createdelete.yml", + CommitSHA: branch.CommitID, + }) + assert.NotNil(t, run) + + // delete the branch + err = repo_service.DeleteBranch(db.DefaultContext, user2, repo, gitRepo, "test-create-branch") + require.NoError(t, err) + run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ + Title: "add workflow", + RepoID: repo.ID, + Event: "delete", + Ref: "refs/heads/main", + WorkflowID: "createdelete.yml", + CommitSHA: branch.CommitID, + }) + assert.NotNil(t, run) + + // delete the tag + tag, err := repo_model.GetRelease(db.DefaultContext, repo.ID, "test-create-tag") + require.NoError(t, err) + err = release_service.DeleteReleaseByID(db.DefaultContext, repo, tag, user2, true) + require.NoError(t, err) + run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ + Title: "add workflow", + RepoID: repo.ID, + Event: "delete", + Ref: "refs/heads/main", + WorkflowID: "createdelete.yml", + CommitSHA: branch.CommitID, + }) + assert.NotNil(t, run) + }) +} + +func TestWorkflowDispatchEvent(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + + // create the repo + repo, sha, f := tests.CreateDeclarativeRepo(t, user2, "repo-workflow-dispatch", + []unit_model.Type{unit_model.TypeActions}, nil, + []*files_service.ChangeRepoFile{ + { + Operation: "create", + TreePath: ".gitea/workflows/dispatch.yml", + ContentReader: strings.NewReader( + "name: test\n" + + "on: [workflow_dispatch]\n" + + "jobs:\n" + + " test:\n" + + " runs-on: ubuntu-latest\n" + + " steps:\n" + + " - run: echo helloworld\n", + ), + }, + }, + ) + defer f() + + gitRepo, err := gitrepo.OpenRepository(db.DefaultContext, repo) + require.NoError(t, err) + defer gitRepo.Close() + + workflow, err := actions_service.GetWorkflowFromCommit(gitRepo, "main", "dispatch.yml") + require.NoError(t, err) + assert.Equal(t, "refs/heads/main", workflow.Ref) + assert.Equal(t, sha, workflow.Commit.ID.String()) + + inputGetter := func(key string) string { + return "" + } + + err = workflow.Dispatch(db.DefaultContext, inputGetter, repo, user2) + require.NoError(t, err) + + assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID})) + }) +} |