2023-06-26 08:33:18 +02:00
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package integration
import (
2023-11-18 12:37:08 +01:00
"fmt"
2023-06-26 08:33:18 +02:00
"net/url"
2023-07-18 20:14:47 +02:00
"strings"
2023-06-26 08:33:18 +02:00
"testing"
"time"
actions_model "code.gitea.io/gitea/models/actions"
2024-03-19 08:23:40 +01:00
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
2023-06-26 08:33:18 +02:00
issues_model "code.gitea.io/gitea/models/issues"
2024-03-19 08:23:40 +01:00
repo_model "code.gitea.io/gitea/models/repo"
2023-06-26 08:33:18 +02:00
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"
2024-03-19 08:23:40 +01:00
"code.gitea.io/gitea/modules/gitrepo"
2023-11-18 12:37:08 +01:00
"code.gitea.io/gitea/modules/setting"
2024-03-14 04:18:04 +01:00
"code.gitea.io/gitea/modules/test"
2024-02-11 14:06:54 +01:00
webhook_module "code.gitea.io/gitea/modules/webhook"
actions_service "code.gitea.io/gitea/services/actions"
2023-06-26 08:33:18 +02:00
pull_service "code.gitea.io/gitea/services/pull"
2024-03-19 08:23:40 +01:00
release_service "code.gitea.io/gitea/services/release"
2023-06-26 08:33:18 +02:00
repo_service "code.gitea.io/gitea/services/repository"
files_service "code.gitea.io/gitea/services/repository/files"
"github.com/stretchr/testify/assert"
)
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
2023-09-14 04:59:53 +02:00
org3 := unittest . AssertExistsAndLoadBean ( t , & user_model . User { ID : 3 } ) // owner of the forked repo
2023-06-26 08:33:18 +02:00
// create the base repo
2024-01-12 11:53:14 +01:00
baseRepo , _ , f := CreateDeclarativeRepo ( t , user2 , "repo-pull-request-target" ,
[ ] unit_model . Type { unit_model . TypeActions } , nil , nil ,
)
defer f ( )
2023-06-26 08:33:18 +02:00
// create the forked repo
2023-09-14 04:59:53 +02:00
forkedRepo , err := repo_service . ForkRepository ( git . DefaultContext , user2 , org3 , repo_service . ForkRepoOptions {
2023-06-26 08:33:18 +02:00
BaseRepo : baseRepo ,
Name : "forked-repo-pull-request-target" ,
Description : "test pull-request-target event" ,
} )
assert . 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 {
{
2023-07-18 20:14:47 +02:00
Operation : "create" ,
TreePath : ".gitea/workflows/pr.yml" ,
2023-08-05 08:26:06 +02:00
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" ) ,
2023-06-26 08:33:18 +02:00
} ,
} ,
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 ( ) ,
} ,
} )
assert . NoError ( t , err )
assert . NotEmpty ( t , addWorkflowToBaseResp )
// add a new file to the forked repo
2023-09-14 04:59:53 +02:00
addFileToForkedResp , err := files_service . ChangeRepoFiles ( git . DefaultContext , forkedRepo , org3 , & files_service . ChangeRepoFilesOptions {
2023-06-26 08:33:18 +02:00
Files : [ ] * files_service . ChangeRepoFile {
{
2023-07-18 20:14:47 +02:00
Operation : "create" ,
TreePath : "file_1.txt" ,
ContentReader : strings . NewReader ( "file1" ) ,
2023-06-26 08:33:18 +02:00
} ,
} ,
Message : "add file1" ,
OldBranch : "main" ,
NewBranch : "fork-branch-1" ,
Author : & files_service . IdentityOptions {
2023-09-14 04:59:53 +02:00
Name : org3 . Name ,
Email : org3 . Email ,
2023-06-26 08:33:18 +02:00
} ,
Committer : & files_service . IdentityOptions {
2023-09-14 04:59:53 +02:00
Name : org3 . Name ,
Email : org3 . Email ,
2023-06-26 08:33:18 +02:00
} ,
Dates : & files_service . CommitDateOptions {
Author : time . Now ( ) ,
Committer : time . Now ( ) ,
} ,
} )
assert . NoError ( t , err )
assert . NotEmpty ( t , addFileToForkedResp )
// create Pull
pullIssue := & issues_model . Issue {
RepoID : baseRepo . ID ,
Title : "Test pull-request-target-event" ,
2023-09-14 04:59:53 +02:00
PosterID : org3 . ID ,
Poster : org3 ,
2023-06-26 08:33:18 +02:00
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 )
assert . NoError ( t , err )
2024-02-11 14:06:54 +01:00
// 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 ) )
2023-06-26 08:33:18 +02:00
// load and compare ActionRun
2023-08-05 08:26:06 +02:00
assert . Equal ( t , 1 , unittest . GetCount ( t , & actions_model . ActionRun { RepoID : baseRepo . ID } ) )
2023-06-26 08:33:18 +02:00
actionRun := unittest . AssertExistsAndLoadBean ( t , & actions_model . ActionRun { RepoID : baseRepo . ID } )
2023-07-07 21:22:03 +02:00
assert . Equal ( t , addFileToForkedResp . Commit . SHA , actionRun . CommitSHA )
2023-06-26 08:33:18 +02:00
assert . Equal ( t , actions_module . GithubEventPullRequestTarget , actionRun . TriggerEvent )
2023-08-05 08:26:06 +02:00
// add another file whose name cannot match the specified path
2023-09-14 04:59:53 +02:00
addFileToForkedResp , err = files_service . ChangeRepoFiles ( git . DefaultContext , forkedRepo , org3 , & files_service . ChangeRepoFilesOptions {
2023-08-05 08:26:06 +02:00
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 {
2023-09-14 04:59:53 +02:00
Name : org3 . Name ,
Email : org3 . Email ,
2023-08-05 08:26:06 +02:00
} ,
Committer : & files_service . IdentityOptions {
2023-09-14 04:59:53 +02:00
Name : org3 . Name ,
Email : org3 . Email ,
2023-08-05 08:26:06 +02:00
} ,
Dates : & files_service . CommitDateOptions {
Author : time . Now ( ) ,
Committer : time . Now ( ) ,
} ,
} )
assert . 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" ,
2023-09-14 04:59:53 +02:00
PosterID : org3 . ID ,
Poster : org3 ,
2023-08-05 08:26:06 +02:00
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 )
assert . 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 } ) )
2023-06-26 08:33:18 +02:00
} )
}
2023-11-18 12:37:08 +01:00
func TestSkipCI ( t * testing . T ) {
onGiteaRun ( t , func ( t * testing . T , u * url . URL ) {
2024-03-14 04:18:04 +01:00
session := loginUser ( t , "user2" )
2023-11-18 12:37:08 +01:00
user2 := unittest . AssertExistsAndLoadBean ( t , & user_model . User { ID : 2 } )
// create the repo
2024-01-12 11:53:14 +01:00
repo , _ , f := CreateDeclarativeRepo ( t , user2 , "skip-ci" ,
[ ] unit_model . Type { unit_model . TypeActions } , nil ,
[ ] * files_service . ChangeRepoFile {
2023-11-18 12:37:08 +01:00
{
Operation : "create" ,
TreePath : ".gitea/workflows/pr.yml" ,
2024-03-14 04:18:04 +01:00
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" ) ,
2023-11-18 12:37:08 +01:00
} ,
} ,
2024-01-12 11:53:14 +01:00
)
defer f ( )
2023-11-18 12:37:08 +01:00
// 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 ( ) ,
} ,
} )
assert . 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 } ) )
2024-03-14 04:18:04 +01:00
// 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 ( ) ,
} ,
} )
assert . 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 } ) )
2023-11-18 12:37:08 +01:00
} )
}
2024-03-19 08:23:40 +01:00
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 ,
} )
assert . 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 )
assert . 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 ( ) ,
} ,
} )
assert . NoError ( t , err )
assert . NotEmpty ( t , addWorkflowToBaseResp )
// Get the commit ID of the default branch
gitRepo , err := gitrepo . OpenRepository ( git . DefaultContext , repo )
assert . NoError ( t , err )
defer gitRepo . Close ( )
branch , err := git_model . GetBranch ( db . DefaultContext , repo . ID , repo . DefaultBranch )
assert . NoError ( t , err )
// create a branch
err = repo_service . CreateNewBranchFromCommit ( db . DefaultContext , user2 , repo , gitRepo , branch . CommitID , "test-create-branch" )
assert . 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" )
assert . 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" )
assert . NoError ( t , err )
run = unittest . AssertExistsAndLoadBean ( t , & actions_model . ActionRun {
Title : "add workflow" ,
RepoID : repo . ID ,
Event : "delete" ,
Ref : "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" )
assert . NoError ( t , err )
err = release_service . DeleteReleaseByID ( db . DefaultContext , repo , tag , user2 , true )
assert . NoError ( t , err )
run = unittest . AssertExistsAndLoadBean ( t , & actions_model . ActionRun {
Title : "add workflow" ,
RepoID : repo . ID ,
Event : "delete" ,
Ref : "main" ,
WorkflowID : "createdelete.yml" ,
CommitSHA : branch . CommitID ,
} )
assert . NotNil ( t , run )
} )
}
2024-06-28 07:17:11 +02:00
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 := 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 )
assert . NoError ( t , err )
defer gitRepo . Close ( )
workflow , err := actions_service . GetWorkflowFromCommit ( gitRepo , sha , "dispatch.yml" )
assert . NoError ( t , err )
inputGetter := func ( key string ) string {
return ""
}
err = workflow . Dispatch ( db . DefaultContext , inputGetter , repo , user2 )
assert . NoError ( t , err )
assert . Equal ( t , 1 , unittest . GetCount ( t , & actions_model . ActionRun { RepoID : repo . ID } ) )
} )
}