mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-02 13:23:30 +01:00
Backport #35767 by @Zettat123 Fix #34472 Add integration tests for actions schedule update. --------- Co-authored-by: Zettat123 <zettat123@gmail.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
parent
cf644d565d
commit
f85cd7aeb5
@ -236,12 +236,12 @@ func notify(ctx context.Context, input *notifyInput) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if shouldDetectSchedules {
|
if shouldDetectSchedules {
|
||||||
if err := handleSchedules(ctx, schedules, commit, input, ref.String()); err != nil {
|
if err := handleSchedules(ctx, schedules, commit, input, ref); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return handleWorkflows(ctx, detectedWorkflows, commit, input, ref.String())
|
return handleWorkflows(ctx, detectedWorkflows, commit, input, ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
func skipWorkflows(ctx context.Context, input *notifyInput, commit *git.Commit) bool {
|
func skipWorkflows(ctx context.Context, input *notifyInput, commit *git.Commit) bool {
|
||||||
@ -293,7 +293,7 @@ func handleWorkflows(
|
|||||||
detectedWorkflows []*actions_module.DetectedWorkflow,
|
detectedWorkflows []*actions_module.DetectedWorkflow,
|
||||||
commit *git.Commit,
|
commit *git.Commit,
|
||||||
input *notifyInput,
|
input *notifyInput,
|
||||||
ref string,
|
ref git.RefName,
|
||||||
) error {
|
) error {
|
||||||
if len(detectedWorkflows) == 0 {
|
if len(detectedWorkflows) == 0 {
|
||||||
log.Trace("repo %s with commit %s couldn't find workflows", input.Repo.RepoPath(), commit.ID)
|
log.Trace("repo %s with commit %s couldn't find workflows", input.Repo.RepoPath(), commit.ID)
|
||||||
@ -329,7 +329,7 @@ func handleWorkflows(
|
|||||||
WorkflowID: dwf.EntryName,
|
WorkflowID: dwf.EntryName,
|
||||||
TriggerUserID: input.Doer.ID,
|
TriggerUserID: input.Doer.ID,
|
||||||
TriggerUser: input.Doer,
|
TriggerUser: input.Doer,
|
||||||
Ref: ref,
|
Ref: ref.String(),
|
||||||
CommitSHA: commit.ID.String(),
|
CommitSHA: commit.ID.String(),
|
||||||
IsForkPullRequest: isForkPullRequest,
|
IsForkPullRequest: isForkPullRequest,
|
||||||
Event: input.Event,
|
Event: input.Event,
|
||||||
@ -500,13 +500,9 @@ func handleSchedules(
|
|||||||
detectedWorkflows []*actions_module.DetectedWorkflow,
|
detectedWorkflows []*actions_module.DetectedWorkflow,
|
||||||
commit *git.Commit,
|
commit *git.Commit,
|
||||||
input *notifyInput,
|
input *notifyInput,
|
||||||
ref string,
|
ref git.RefName,
|
||||||
) error {
|
) error {
|
||||||
branch, err := commit.GetBranchName()
|
if ref.BranchName() != input.Repo.DefaultBranch {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if branch != input.Repo.DefaultBranch {
|
|
||||||
log.Trace("commit branch is not default branch in repo")
|
log.Trace("commit branch is not default branch in repo")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -552,7 +548,7 @@ func handleSchedules(
|
|||||||
WorkflowID: dwf.EntryName,
|
WorkflowID: dwf.EntryName,
|
||||||
TriggerUserID: user_model.ActionsUserID,
|
TriggerUserID: user_model.ActionsUserID,
|
||||||
TriggerUser: user_model.NewActionsUser(),
|
TriggerUser: user_model.NewActionsUser(),
|
||||||
Ref: ref,
|
Ref: ref.String(),
|
||||||
CommitSHA: commit.ID.String(),
|
CommitSHA: commit.ID.String(),
|
||||||
Event: input.Event,
|
Event: input.Event,
|
||||||
EventPayload: string(p),
|
EventPayload: string(p),
|
||||||
@ -614,5 +610,5 @@ func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository)
|
|||||||
// so we use action user as the Doer of the notifyInput
|
// so we use action user as the Doer of the notifyInput
|
||||||
notifyInput := newNotifyInputForSchedules(repo)
|
notifyInput := newNotifyInputForSchedules(repo)
|
||||||
|
|
||||||
return handleSchedules(ctx, scheduleWorkflows, commit, notifyInput, repo.DefaultBranch)
|
return handleSchedules(ctx, scheduleWorkflows, commit, notifyInput, git.RefNameFromBranch(repo.DefaultBranch))
|
||||||
}
|
}
|
||||||
|
|||||||
294
tests/integration/actions_schedule_test.go
Normal file
294
tests/integration/actions_schedule_test.go
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
actions_model "code.gitea.io/gitea/models/actions"
|
||||||
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
|
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"
|
||||||
|
"code.gitea.io/gitea/modules/migration"
|
||||||
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
mirror_service "code.gitea.io/gitea/services/mirror"
|
||||||
|
repo_service "code.gitea.io/gitea/services/repository"
|
||||||
|
files_service "code.gitea.io/gitea/services/repository/files"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestScheduleUpdate(t *testing.T) {
|
||||||
|
t.Run("Push", testScheduleUpdatePush)
|
||||||
|
t.Run("PullMerge", testScheduleUpdatePullMerge)
|
||||||
|
t.Run("DisableAndEnableActionsUnit", testScheduleUpdateDisableAndEnableActionsUnit)
|
||||||
|
t.Run("ArchiveAndUnarchive", testScheduleUpdateArchiveAndUnarchive)
|
||||||
|
t.Run("MirrorSync", testScheduleUpdateMirrorSync)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testScheduleUpdatePush(t *testing.T) {
|
||||||
|
doTestScheduleUpdate(t, func(t *testing.T, u *url.URL, testContext APITestContext, user *user_model.User, repo *repo_model.Repository) (commitID, expectedSpec string) {
|
||||||
|
newCron := "30 5 * * 1,3"
|
||||||
|
pushScheduleChange(t, u, repo, newCron)
|
||||||
|
branch, err := git_model.GetBranch(t.Context(), repo.ID, repo.DefaultBranch)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
return branch.CommitID, newCron
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testScheduleUpdatePullMerge(t *testing.T) {
|
||||||
|
newBranchName := "feat1"
|
||||||
|
workflowTreePath := ".gitea/workflows/actions-schedule.yml"
|
||||||
|
workflowContent := `name: actions-schedule
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '@every 2m' # update to 2m
|
||||||
|
jobs:
|
||||||
|
job:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- run: echo 'schedule workflow'
|
||||||
|
`
|
||||||
|
|
||||||
|
mergeStyles := []repo_model.MergeStyle{
|
||||||
|
repo_model.MergeStyleMerge,
|
||||||
|
repo_model.MergeStyleRebase,
|
||||||
|
repo_model.MergeStyleRebaseMerge,
|
||||||
|
repo_model.MergeStyleSquash,
|
||||||
|
repo_model.MergeStyleFastForwardOnly,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, mergeStyle := range mergeStyles {
|
||||||
|
t.Run(string(mergeStyle), func(t *testing.T) {
|
||||||
|
doTestScheduleUpdate(t, func(t *testing.T, u *url.URL, testContext APITestContext, user *user_model.User, repo *repo_model.Repository) (commitID, expectedSpec string) {
|
||||||
|
// update workflow file
|
||||||
|
_, err := files_service.ChangeRepoFiles(t.Context(), repo, user, &files_service.ChangeRepoFilesOptions{
|
||||||
|
NewBranch: newBranchName,
|
||||||
|
Files: []*files_service.ChangeRepoFile{
|
||||||
|
{
|
||||||
|
Operation: "update",
|
||||||
|
TreePath: workflowTreePath,
|
||||||
|
ContentReader: strings.NewReader(workflowContent),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Message: "update workflow schedule",
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// create pull request
|
||||||
|
apiPull, err := doAPICreatePullRequest(testContext, repo.OwnerName, repo.Name, repo.DefaultBranch, newBranchName)(t)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// merge pull request
|
||||||
|
testPullMerge(t, testContext.Session, repo.OwnerName, repo.Name, strconv.FormatInt(apiPull.Index, 10), mergeStyle, false)
|
||||||
|
|
||||||
|
pull := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: apiPull.ID})
|
||||||
|
return pull.MergedCommitID, "@every 2m"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run(string(repo_model.MergeStyleManuallyMerged), func(t *testing.T) {
|
||||||
|
doTestScheduleUpdate(t, func(t *testing.T, u *url.URL, testContext APITestContext, user *user_model.User, repo *repo_model.Repository) (commitID, expectedSpec string) {
|
||||||
|
// enable manual-merge
|
||||||
|
doAPIEditRepository(testContext, &api.EditRepoOption{
|
||||||
|
HasPullRequests: util.ToPointer(true),
|
||||||
|
AllowManualMerge: util.ToPointer(true),
|
||||||
|
})(t)
|
||||||
|
|
||||||
|
// update workflow file
|
||||||
|
fileResp, err := files_service.ChangeRepoFiles(t.Context(), repo, user, &files_service.ChangeRepoFilesOptions{
|
||||||
|
NewBranch: newBranchName,
|
||||||
|
Files: []*files_service.ChangeRepoFile{
|
||||||
|
{
|
||||||
|
Operation: "update",
|
||||||
|
TreePath: workflowTreePath,
|
||||||
|
ContentReader: strings.NewReader(workflowContent),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Message: "update workflow schedule",
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// merge and push
|
||||||
|
dstPath := t.TempDir()
|
||||||
|
u.Path = repo.FullName() + ".git"
|
||||||
|
u.User = url.UserPassword(repo.OwnerName, userPassword)
|
||||||
|
doGitClone(dstPath, u)(t)
|
||||||
|
doGitMerge(dstPath, "origin/"+newBranchName)(t)
|
||||||
|
doGitPushTestRepository(dstPath, "origin", repo.DefaultBranch)(t)
|
||||||
|
|
||||||
|
// create pull request
|
||||||
|
apiPull, err := doAPICreatePullRequest(testContext, repo.OwnerName, repo.Name, repo.DefaultBranch, newBranchName)(t)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// merge pull request manually
|
||||||
|
doAPIManuallyMergePullRequest(testContext, repo.OwnerName, repo.Name, fileResp.Commit.SHA, apiPull.Index)(t)
|
||||||
|
|
||||||
|
pull := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: apiPull.ID})
|
||||||
|
assert.Equal(t, issues_model.PullRequestStatusManuallyMerged, pull.Status)
|
||||||
|
return pull.MergedCommitID, "@every 2m"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testScheduleUpdateMirrorSync(t *testing.T) {
|
||||||
|
doTestScheduleUpdate(t, func(t *testing.T, u *url.URL, testContext APITestContext, user *user_model.User, repo *repo_model.Repository) (commitID, expectedSpec string) {
|
||||||
|
// create mirror repo
|
||||||
|
opts := migration.MigrateOptions{
|
||||||
|
RepoName: "actions-schedule-mirror",
|
||||||
|
Description: "Test mirror for actions-schedule",
|
||||||
|
Private: false,
|
||||||
|
Mirror: true,
|
||||||
|
CloneAddr: repo.CloneLinkGeneral(t.Context()).HTTPS,
|
||||||
|
}
|
||||||
|
mirrorRepo, err := repo_service.CreateRepositoryDirectly(t.Context(), user, user, repo_service.CreateRepoOptions{
|
||||||
|
Name: opts.RepoName,
|
||||||
|
Description: opts.Description,
|
||||||
|
IsPrivate: opts.Private,
|
||||||
|
IsMirror: opts.Mirror,
|
||||||
|
DefaultBranch: repo.DefaultBranch,
|
||||||
|
Status: repo_model.RepositoryBeingMigrated,
|
||||||
|
}, false)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, mirrorRepo.IsMirror)
|
||||||
|
mirrorRepo, err = repo_service.MigrateRepositoryGitData(t.Context(), user, mirrorRepo, opts, nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
mirrorContext := NewAPITestContext(t, user.Name, mirrorRepo.Name, auth_model.AccessTokenScopeWriteRepository)
|
||||||
|
|
||||||
|
// enable actions unit for mirror repo
|
||||||
|
assert.False(t, mirrorRepo.UnitEnabled(t.Context(), unit_model.TypeActions))
|
||||||
|
doAPIEditRepository(mirrorContext, &api.EditRepoOption{
|
||||||
|
HasActions: util.ToPointer(true),
|
||||||
|
})(t)
|
||||||
|
actionSchedule := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionSchedule{RepoID: mirrorRepo.ID})
|
||||||
|
scheduleSpec := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionScheduleSpec{RepoID: mirrorRepo.ID, ScheduleID: actionSchedule.ID})
|
||||||
|
assert.Equal(t, "@every 1m", scheduleSpec.Spec)
|
||||||
|
|
||||||
|
// update remote repo
|
||||||
|
newCron := "30 5,17 * * 2,4"
|
||||||
|
pushScheduleChange(t, u, repo, newCron)
|
||||||
|
repoDefaultBranch, err := git_model.GetBranch(t.Context(), repo.ID, repo.DefaultBranch)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// sync
|
||||||
|
ok := mirror_service.SyncPullMirror(t.Context(), mirrorRepo.ID)
|
||||||
|
assert.True(t, ok)
|
||||||
|
mirrorRepoDefaultBranch, err := git_model.GetBranch(t.Context(), mirrorRepo.ID, mirrorRepo.DefaultBranch)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, repoDefaultBranch.CommitID, mirrorRepoDefaultBranch.CommitID)
|
||||||
|
|
||||||
|
// check updated schedule
|
||||||
|
actionSchedule = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionSchedule{RepoID: mirrorRepo.ID})
|
||||||
|
scheduleSpec = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionScheduleSpec{RepoID: mirrorRepo.ID, ScheduleID: actionSchedule.ID})
|
||||||
|
assert.Equal(t, newCron, scheduleSpec.Spec)
|
||||||
|
|
||||||
|
return repoDefaultBranch.CommitID, newCron
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testScheduleUpdateArchiveAndUnarchive(t *testing.T) {
|
||||||
|
doTestScheduleUpdate(t, func(t *testing.T, u *url.URL, testContext APITestContext, user *user_model.User, repo *repo_model.Repository) (commitID, expectedSpec string) {
|
||||||
|
doAPIEditRepository(testContext, &api.EditRepoOption{
|
||||||
|
Archived: util.ToPointer(true),
|
||||||
|
})(t)
|
||||||
|
assert.Zero(t, unittest.GetCount(t, &actions_model.ActionSchedule{RepoID: repo.ID}))
|
||||||
|
doAPIEditRepository(testContext, &api.EditRepoOption{
|
||||||
|
Archived: util.ToPointer(false),
|
||||||
|
})(t)
|
||||||
|
branch, err := git_model.GetBranch(t.Context(), repo.ID, repo.DefaultBranch)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
return branch.CommitID, "@every 1m"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testScheduleUpdateDisableAndEnableActionsUnit(t *testing.T) {
|
||||||
|
doTestScheduleUpdate(t, func(t *testing.T, u *url.URL, testContext APITestContext, user *user_model.User, repo *repo_model.Repository) (commitID, expectedSpec string) {
|
||||||
|
doAPIEditRepository(testContext, &api.EditRepoOption{
|
||||||
|
HasActions: util.ToPointer(false),
|
||||||
|
})(t)
|
||||||
|
assert.Zero(t, unittest.GetCount(t, &actions_model.ActionSchedule{RepoID: repo.ID}))
|
||||||
|
doAPIEditRepository(testContext, &api.EditRepoOption{
|
||||||
|
HasActions: util.ToPointer(true),
|
||||||
|
})(t)
|
||||||
|
branch, err := git_model.GetBranch(t.Context(), repo.ID, repo.DefaultBranch)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
return branch.CommitID, "@every 1m"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type scheduleUpdateTrigger func(t *testing.T, u *url.URL, testContext APITestContext, user *user_model.User, repo *repo_model.Repository) (commitID, expectedSpec string)
|
||||||
|
|
||||||
|
func doTestScheduleUpdate(t *testing.T, updateTrigger scheduleUpdateTrigger) {
|
||||||
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
|
session := loginUser(t, user2.Name)
|
||||||
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
|
||||||
|
|
||||||
|
apiRepo := createActionsTestRepo(t, token, "actions-schedule", false)
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiRepo.ID})
|
||||||
|
assert.NoError(t, repo.LoadAttributes(t.Context()))
|
||||||
|
httpContext := NewAPITestContext(t, user2.Name, repo.Name, auth_model.AccessTokenScopeWriteRepository)
|
||||||
|
defer doAPIDeleteRepository(httpContext)(t)
|
||||||
|
|
||||||
|
wfTreePath := ".gitea/workflows/actions-schedule.yml"
|
||||||
|
wfFileContent := `name: actions-schedule
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '@every 1m'
|
||||||
|
jobs:
|
||||||
|
job:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- run: echo 'schedule workflow'
|
||||||
|
`
|
||||||
|
|
||||||
|
opts1 := getWorkflowCreateFileOptions(user2, repo.DefaultBranch, "create "+wfTreePath, wfFileContent)
|
||||||
|
apiFileResp := createWorkflowFile(t, token, user2.Name, repo.Name, wfTreePath, opts1)
|
||||||
|
|
||||||
|
actionSchedule := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionSchedule{RepoID: repo.ID, CommitSHA: apiFileResp.Commit.SHA})
|
||||||
|
scheduleSpec := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionScheduleSpec{RepoID: repo.ID, ScheduleID: actionSchedule.ID})
|
||||||
|
assert.Equal(t, "@every 1m", scheduleSpec.Spec)
|
||||||
|
|
||||||
|
commitID, expectedSpec := updateTrigger(t, u, httpContext, user2, repo)
|
||||||
|
|
||||||
|
actionSchedule = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionSchedule{RepoID: repo.ID, CommitSHA: commitID})
|
||||||
|
scheduleSpec = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionScheduleSpec{RepoID: repo.ID, ScheduleID: actionSchedule.ID})
|
||||||
|
assert.Equal(t, expectedSpec, scheduleSpec.Spec)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func pushScheduleChange(t *testing.T, u *url.URL, repo *repo_model.Repository, newCron string) {
|
||||||
|
workflowTreePath := ".gitea/workflows/actions-schedule.yml"
|
||||||
|
workflowContent := `name: actions-schedule
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '` + newCron + `'
|
||||||
|
jobs:
|
||||||
|
job:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- run: echo 'schedule workflow'
|
||||||
|
`
|
||||||
|
|
||||||
|
dstPath := t.TempDir()
|
||||||
|
u.Path = repo.FullName() + ".git"
|
||||||
|
u.User = url.UserPassword(repo.OwnerName, userPassword)
|
||||||
|
doGitClone(dstPath, u)(t)
|
||||||
|
doGitCheckoutWriteFileCommit(localGitAddCommitOptions{
|
||||||
|
LocalRepoPath: dstPath,
|
||||||
|
CheckoutBranch: repo.DefaultBranch,
|
||||||
|
TreeFilePath: workflowTreePath,
|
||||||
|
TreeFileContent: workflowContent,
|
||||||
|
})(t)
|
||||||
|
doGitPushTestRepository(dstPath, "origin", repo.DefaultBranch)(t)
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user