code.gitea.io/gitea@v1.22.3/tests/integration/actions_trigger_test.go (about) 1 // Copyright 2023 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package integration 5 6 import ( 7 "fmt" 8 "net/url" 9 "strings" 10 "testing" 11 "time" 12 13 actions_model "code.gitea.io/gitea/models/actions" 14 auth_model "code.gitea.io/gitea/models/auth" 15 "code.gitea.io/gitea/models/db" 16 git_model "code.gitea.io/gitea/models/git" 17 issues_model "code.gitea.io/gitea/models/issues" 18 "code.gitea.io/gitea/models/perm" 19 repo_model "code.gitea.io/gitea/models/repo" 20 unit_model "code.gitea.io/gitea/models/unit" 21 "code.gitea.io/gitea/models/unittest" 22 user_model "code.gitea.io/gitea/models/user" 23 actions_module "code.gitea.io/gitea/modules/actions" 24 "code.gitea.io/gitea/modules/git" 25 "code.gitea.io/gitea/modules/gitrepo" 26 "code.gitea.io/gitea/modules/setting" 27 "code.gitea.io/gitea/modules/test" 28 pull_service "code.gitea.io/gitea/services/pull" 29 release_service "code.gitea.io/gitea/services/release" 30 repo_service "code.gitea.io/gitea/services/repository" 31 files_service "code.gitea.io/gitea/services/repository/files" 32 33 "github.com/stretchr/testify/assert" 34 ) 35 36 func TestPullRequestTargetEvent(t *testing.T) { 37 onGiteaRun(t, func(t *testing.T, u *url.URL) { 38 user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the base repo 39 user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of the forked repo 40 41 // create the base repo 42 baseRepo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{ 43 Name: "repo-pull-request-target", 44 Description: "test pull-request-target event", 45 AutoInit: true, 46 Gitignores: "Go", 47 License: "MIT", 48 Readme: "Default", 49 DefaultBranch: "main", 50 IsPrivate: false, 51 }) 52 assert.NoError(t, err) 53 assert.NotEmpty(t, baseRepo) 54 55 // enable actions 56 err = repo_service.UpdateRepositoryUnits(db.DefaultContext, baseRepo, []repo_model.RepoUnit{{ 57 RepoID: baseRepo.ID, 58 Type: unit_model.TypeActions, 59 }}, nil) 60 assert.NoError(t, err) 61 62 // add user4 as the collaborator 63 ctx := NewAPITestContext(t, baseRepo.OwnerName, baseRepo.Name, auth_model.AccessTokenScopeWriteRepository) 64 t.Run("AddUser4AsCollaboratorWithReadAccess", doAPIAddCollaborator(ctx, "user4", perm.AccessModeRead)) 65 66 // create the forked repo 67 forkedRepo, err := repo_service.ForkRepository(git.DefaultContext, user2, user4, repo_service.ForkRepoOptions{ 68 BaseRepo: baseRepo, 69 Name: "forked-repo-pull-request-target", 70 Description: "test pull-request-target event", 71 }) 72 assert.NoError(t, err) 73 assert.NotEmpty(t, forkedRepo) 74 75 // add workflow file to the base repo 76 addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, baseRepo, user2, &files_service.ChangeRepoFilesOptions{ 77 Files: []*files_service.ChangeRepoFile{ 78 { 79 Operation: "create", 80 TreePath: ".gitea/workflows/pr.yml", 81 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"), 82 }, 83 }, 84 Message: "add workflow", 85 OldBranch: "main", 86 NewBranch: "main", 87 Author: &files_service.IdentityOptions{ 88 Name: user2.Name, 89 Email: user2.Email, 90 }, 91 Committer: &files_service.IdentityOptions{ 92 Name: user2.Name, 93 Email: user2.Email, 94 }, 95 Dates: &files_service.CommitDateOptions{ 96 Author: time.Now(), 97 Committer: time.Now(), 98 }, 99 }) 100 assert.NoError(t, err) 101 assert.NotEmpty(t, addWorkflowToBaseResp) 102 103 // add a new file to the forked repo 104 addFileToForkedResp, err := files_service.ChangeRepoFiles(git.DefaultContext, forkedRepo, user4, &files_service.ChangeRepoFilesOptions{ 105 Files: []*files_service.ChangeRepoFile{ 106 { 107 Operation: "create", 108 TreePath: "file_1.txt", 109 ContentReader: strings.NewReader("file1"), 110 }, 111 }, 112 Message: "add file1", 113 OldBranch: "main", 114 NewBranch: "fork-branch-1", 115 Author: &files_service.IdentityOptions{ 116 Name: user4.Name, 117 Email: user4.Email, 118 }, 119 Committer: &files_service.IdentityOptions{ 120 Name: user4.Name, 121 Email: user4.Email, 122 }, 123 Dates: &files_service.CommitDateOptions{ 124 Author: time.Now(), 125 Committer: time.Now(), 126 }, 127 }) 128 assert.NoError(t, err) 129 assert.NotEmpty(t, addFileToForkedResp) 130 131 // create Pull 132 pullIssue := &issues_model.Issue{ 133 RepoID: baseRepo.ID, 134 Title: "Test pull-request-target-event", 135 PosterID: user4.ID, 136 Poster: user4, 137 IsPull: true, 138 } 139 pullRequest := &issues_model.PullRequest{ 140 HeadRepoID: forkedRepo.ID, 141 BaseRepoID: baseRepo.ID, 142 HeadBranch: "fork-branch-1", 143 BaseBranch: "main", 144 HeadRepo: forkedRepo, 145 BaseRepo: baseRepo, 146 Type: issues_model.PullRequestGitea, 147 } 148 err = pull_service.NewPullRequest(git.DefaultContext, baseRepo, pullIssue, nil, nil, pullRequest, nil) 149 assert.NoError(t, err) 150 151 // load and compare ActionRun 152 assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: baseRepo.ID})) 153 actionRun := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{RepoID: baseRepo.ID}) 154 assert.Equal(t, addFileToForkedResp.Commit.SHA, actionRun.CommitSHA) 155 assert.Equal(t, actions_module.GithubEventPullRequestTarget, actionRun.TriggerEvent) 156 157 // add another file whose name cannot match the specified path 158 addFileToForkedResp, err = files_service.ChangeRepoFiles(git.DefaultContext, forkedRepo, user4, &files_service.ChangeRepoFilesOptions{ 159 Files: []*files_service.ChangeRepoFile{ 160 { 161 Operation: "create", 162 TreePath: "foo.txt", 163 ContentReader: strings.NewReader("foo"), 164 }, 165 }, 166 Message: "add foo.txt", 167 OldBranch: "main", 168 NewBranch: "fork-branch-2", 169 Author: &files_service.IdentityOptions{ 170 Name: user4.Name, 171 Email: user4.Email, 172 }, 173 Committer: &files_service.IdentityOptions{ 174 Name: user4.Name, 175 Email: user4.Email, 176 }, 177 Dates: &files_service.CommitDateOptions{ 178 Author: time.Now(), 179 Committer: time.Now(), 180 }, 181 }) 182 assert.NoError(t, err) 183 assert.NotEmpty(t, addFileToForkedResp) 184 185 // create Pull 186 pullIssue = &issues_model.Issue{ 187 RepoID: baseRepo.ID, 188 Title: "A mismatched path cannot trigger pull-request-target-event", 189 PosterID: user4.ID, 190 Poster: user4, 191 IsPull: true, 192 } 193 pullRequest = &issues_model.PullRequest{ 194 HeadRepoID: forkedRepo.ID, 195 BaseRepoID: baseRepo.ID, 196 HeadBranch: "fork-branch-2", 197 BaseBranch: "main", 198 HeadRepo: forkedRepo, 199 BaseRepo: baseRepo, 200 Type: issues_model.PullRequestGitea, 201 } 202 err = pull_service.NewPullRequest(git.DefaultContext, baseRepo, pullIssue, nil, nil, pullRequest, nil) 203 assert.NoError(t, err) 204 205 // the new pull request cannot trigger actions, so there is still only 1 record 206 assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: baseRepo.ID})) 207 }) 208 } 209 210 func TestSkipCI(t *testing.T) { 211 onGiteaRun(t, func(t *testing.T, u *url.URL) { 212 session := loginUser(t, "user2") 213 user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) 214 215 // create the repo 216 repo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{ 217 Name: "skip-ci", 218 Description: "test skip ci functionality", 219 AutoInit: true, 220 Gitignores: "Go", 221 License: "MIT", 222 Readme: "Default", 223 DefaultBranch: "master", 224 IsPrivate: false, 225 }) 226 assert.NoError(t, err) 227 assert.NotEmpty(t, repo) 228 229 // enable actions 230 err = repo_service.UpdateRepositoryUnits(db.DefaultContext, repo, []repo_model.RepoUnit{{ 231 RepoID: repo.ID, 232 Type: unit_model.TypeActions, 233 }}, nil) 234 assert.NoError(t, err) 235 236 // add workflow file to the repo 237 addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{ 238 Files: []*files_service.ChangeRepoFile{ 239 { 240 Operation: "create", 241 TreePath: ".gitea/workflows/pr.yml", 242 ContentReader: strings.NewReader("name: test\non:\n push:\n branches: [master]\n pull_request:\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - run: echo helloworld\n"), 243 }, 244 }, 245 Message: "add workflow", 246 OldBranch: "master", 247 NewBranch: "master", 248 Author: &files_service.IdentityOptions{ 249 Name: user2.Name, 250 Email: user2.Email, 251 }, 252 Committer: &files_service.IdentityOptions{ 253 Name: user2.Name, 254 Email: user2.Email, 255 }, 256 Dates: &files_service.CommitDateOptions{ 257 Author: time.Now(), 258 Committer: time.Now(), 259 }, 260 }) 261 assert.NoError(t, err) 262 assert.NotEmpty(t, addWorkflowToBaseResp) 263 264 // a run has been created 265 assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID})) 266 267 // add a file with a configured skip-ci string in commit message 268 addFileResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{ 269 Files: []*files_service.ChangeRepoFile{ 270 { 271 Operation: "create", 272 TreePath: "bar.txt", 273 ContentReader: strings.NewReader("bar"), 274 }, 275 }, 276 Message: fmt.Sprintf("%s add bar", setting.Actions.SkipWorkflowStrings[0]), 277 OldBranch: "master", 278 NewBranch: "master", 279 Author: &files_service.IdentityOptions{ 280 Name: user2.Name, 281 Email: user2.Email, 282 }, 283 Committer: &files_service.IdentityOptions{ 284 Name: user2.Name, 285 Email: user2.Email, 286 }, 287 Dates: &files_service.CommitDateOptions{ 288 Author: time.Now(), 289 Committer: time.Now(), 290 }, 291 }) 292 assert.NoError(t, err) 293 assert.NotEmpty(t, addFileResp) 294 295 // the commit message contains a configured skip-ci string, so there is still only 1 record 296 assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID})) 297 298 // add file to new branch 299 addFileToBranchResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{ 300 Files: []*files_service.ChangeRepoFile{ 301 { 302 Operation: "create", 303 TreePath: "test-skip-ci", 304 ContentReader: strings.NewReader("test-skip-ci"), 305 }, 306 }, 307 Message: "add test file", 308 OldBranch: "master", 309 NewBranch: "test-skip-ci", 310 Author: &files_service.IdentityOptions{ 311 Name: user2.Name, 312 Email: user2.Email, 313 }, 314 Committer: &files_service.IdentityOptions{ 315 Name: user2.Name, 316 Email: user2.Email, 317 }, 318 Dates: &files_service.CommitDateOptions{ 319 Author: time.Now(), 320 Committer: time.Now(), 321 }, 322 }) 323 assert.NoError(t, err) 324 assert.NotEmpty(t, addFileToBranchResp) 325 326 resp := testPullCreate(t, session, "user2", "skip-ci", true, "master", "test-skip-ci", "[skip ci] test-skip-ci") 327 328 // check the redirected URL 329 url := test.RedirectURL(resp) 330 assert.Regexp(t, "^/user2/skip-ci/pulls/[0-9]*$", url) 331 332 // the pr title contains a configured skip-ci string, so there is still only 1 record 333 assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID})) 334 }) 335 } 336 337 func TestCreateDeleteRefEvent(t *testing.T) { 338 onGiteaRun(t, func(t *testing.T, u *url.URL) { 339 user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) 340 341 // create the repo 342 repo, err := repo_service.CreateRepository(db.DefaultContext, user2, user2, repo_service.CreateRepoOptions{ 343 Name: "create-delete-ref-event", 344 Description: "test create delete ref ci event", 345 AutoInit: true, 346 Gitignores: "Go", 347 License: "MIT", 348 Readme: "Default", 349 DefaultBranch: "main", 350 IsPrivate: false, 351 }) 352 assert.NoError(t, err) 353 assert.NotEmpty(t, repo) 354 355 // enable actions 356 err = repo_service.UpdateRepositoryUnits(db.DefaultContext, repo, []repo_model.RepoUnit{{ 357 RepoID: repo.ID, 358 Type: unit_model.TypeActions, 359 }}, nil) 360 assert.NoError(t, err) 361 362 // add workflow file to the repo 363 addWorkflowToBaseResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{ 364 Files: []*files_service.ChangeRepoFile{ 365 { 366 Operation: "create", 367 TreePath: ".gitea/workflows/createdelete.yml", 368 ContentReader: strings.NewReader("name: test\non:\n [create,delete]\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - run: echo helloworld\n"), 369 }, 370 }, 371 Message: "add workflow", 372 OldBranch: "main", 373 NewBranch: "main", 374 Author: &files_service.IdentityOptions{ 375 Name: user2.Name, 376 Email: user2.Email, 377 }, 378 Committer: &files_service.IdentityOptions{ 379 Name: user2.Name, 380 Email: user2.Email, 381 }, 382 Dates: &files_service.CommitDateOptions{ 383 Author: time.Now(), 384 Committer: time.Now(), 385 }, 386 }) 387 assert.NoError(t, err) 388 assert.NotEmpty(t, addWorkflowToBaseResp) 389 390 // Get the commit ID of the default branch 391 gitRepo, err := gitrepo.OpenRepository(git.DefaultContext, repo) 392 assert.NoError(t, err) 393 defer gitRepo.Close() 394 branch, err := git_model.GetBranch(db.DefaultContext, repo.ID, repo.DefaultBranch) 395 assert.NoError(t, err) 396 397 // create a branch 398 err = repo_service.CreateNewBranchFromCommit(db.DefaultContext, user2, repo, gitRepo, branch.CommitID, "test-create-branch") 399 assert.NoError(t, err) 400 run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ 401 Title: "add workflow", 402 RepoID: repo.ID, 403 Event: "create", 404 Ref: "refs/heads/test-create-branch", 405 WorkflowID: "createdelete.yml", 406 CommitSHA: branch.CommitID, 407 }) 408 assert.NotNil(t, run) 409 410 // create a tag 411 err = release_service.CreateNewTag(db.DefaultContext, user2, repo, branch.CommitID, "test-create-tag", "test create tag event") 412 assert.NoError(t, err) 413 run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ 414 Title: "add workflow", 415 RepoID: repo.ID, 416 Event: "create", 417 Ref: "refs/tags/test-create-tag", 418 WorkflowID: "createdelete.yml", 419 CommitSHA: branch.CommitID, 420 }) 421 assert.NotNil(t, run) 422 423 // delete the branch 424 err = repo_service.DeleteBranch(db.DefaultContext, user2, repo, gitRepo, "test-create-branch") 425 assert.NoError(t, err) 426 run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ 427 Title: "add workflow", 428 RepoID: repo.ID, 429 Event: "delete", 430 Ref: "refs/heads/main", 431 WorkflowID: "createdelete.yml", 432 CommitSHA: branch.CommitID, 433 }) 434 assert.NotNil(t, run) 435 436 // delete the tag 437 tag, err := repo_model.GetRelease(db.DefaultContext, repo.ID, "test-create-tag") 438 assert.NoError(t, err) 439 err = release_service.DeleteReleaseByID(db.DefaultContext, repo, tag, user2, true) 440 assert.NoError(t, err) 441 run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ 442 Title: "add workflow", 443 RepoID: repo.ID, 444 Event: "delete", 445 Ref: "refs/heads/main", 446 WorkflowID: "createdelete.yml", 447 CommitSHA: branch.CommitID, 448 }) 449 assert.NotNil(t, run) 450 }) 451 }