Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8aa1179

Browse files
authored
Fix actions schedule update issue (#35767)
Fix#34472Add integration tests for actions schedule update.
1 parent39c08ce commit8aa1179

File tree

2 files changed

+304
-12
lines changed

2 files changed

+304
-12
lines changed

‎services/actions/notifier_helper.go‎

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -234,12 +234,12 @@ func notify(ctx context.Context, input *notifyInput) error {
234234
}
235235

236236
ifshouldDetectSchedules {
237-
iferr:=handleSchedules(ctx,schedules,commit,input,ref.String());err!=nil {
237+
iferr:=handleSchedules(ctx,schedules,commit,input,ref);err!=nil {
238238
returnerr
239239
}
240240
}
241241

242-
returnhandleWorkflows(ctx,detectedWorkflows,commit,input,ref.String())
242+
returnhandleWorkflows(ctx,detectedWorkflows,commit,input,ref)
243243
}
244244

245245
funcskipWorkflows(ctx context.Context,input*notifyInput,commit*git.Commit)bool {
@@ -291,7 +291,7 @@ func handleWorkflows(
291291
detectedWorkflows []*actions_module.DetectedWorkflow,
292292
commit*git.Commit,
293293
input*notifyInput,
294-
refstring,
294+
refgit.RefName,
295295
)error {
296296
iflen(detectedWorkflows)==0 {
297297
log.Trace("repo %s with commit %s couldn't find workflows",input.Repo.RelativePath(),commit.ID)
@@ -327,7 +327,7 @@ func handleWorkflows(
327327
WorkflowID:dwf.EntryName,
328328
TriggerUserID:input.Doer.ID,
329329
TriggerUser:input.Doer,
330-
Ref:ref,
330+
Ref:ref.String(),
331331
CommitSHA:commit.ID.String(),
332332
IsForkPullRequest:isForkPullRequest,
333333
Event:input.Event,
@@ -442,13 +442,9 @@ func handleSchedules(
442442
detectedWorkflows []*actions_module.DetectedWorkflow,
443443
commit*git.Commit,
444444
input*notifyInput,
445-
refstring,
445+
refgit.RefName,
446446
)error {
447-
branch,err:=commit.GetBranchName()
448-
iferr!=nil {
449-
returnerr
450-
}
451-
ifbranch!=input.Repo.DefaultBranch {
447+
ifref.BranchName()!=input.Repo.DefaultBranch {
452448
log.Trace("commit branch is not default branch in repo")
453449
returnnil
454450
}
@@ -494,7 +490,7 @@ func handleSchedules(
494490
WorkflowID:dwf.EntryName,
495491
TriggerUserID:user_model.ActionsUserID,
496492
TriggerUser:user_model.NewActionsUser(),
497-
Ref:ref,
493+
Ref:ref.String(),
498494
CommitSHA:commit.ID.String(),
499495
Event:input.Event,
500496
EventPayload:string(p),
@@ -538,5 +534,5 @@ func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository)
538534
// so we use action user as the Doer of the notifyInput
539535
notifyInput:=newNotifyInputForSchedules(repo)
540536

541-
returnhandleSchedules(ctx,scheduleWorkflows,commit,notifyInput,repo.DefaultBranch)
537+
returnhandleSchedules(ctx,scheduleWorkflows,commit,notifyInput,git.RefNameFromBranch(repo.DefaultBranch))
542538
}
Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package integration
5+
6+
import (
7+
"net/url"
8+
"strconv"
9+
"strings"
10+
"testing"
11+
12+
actions_model"code.gitea.io/gitea/models/actions"
13+
auth_model"code.gitea.io/gitea/models/auth"
14+
git_model"code.gitea.io/gitea/models/git"
15+
issues_model"code.gitea.io/gitea/models/issues"
16+
repo_model"code.gitea.io/gitea/models/repo"
17+
unit_model"code.gitea.io/gitea/models/unit"
18+
"code.gitea.io/gitea/models/unittest"
19+
user_model"code.gitea.io/gitea/models/user"
20+
"code.gitea.io/gitea/modules/migration"
21+
api"code.gitea.io/gitea/modules/structs"
22+
"code.gitea.io/gitea/modules/util"
23+
mirror_service"code.gitea.io/gitea/services/mirror"
24+
repo_service"code.gitea.io/gitea/services/repository"
25+
files_service"code.gitea.io/gitea/services/repository/files"
26+
27+
"github.com/stretchr/testify/assert"
28+
)
29+
30+
funcTestScheduleUpdate(t*testing.T) {
31+
t.Run("Push",testScheduleUpdatePush)
32+
t.Run("PullMerge",testScheduleUpdatePullMerge)
33+
t.Run("DisableAndEnableActionsUnit",testScheduleUpdateDisableAndEnableActionsUnit)
34+
t.Run("ArchiveAndUnarchive",testScheduleUpdateArchiveAndUnarchive)
35+
t.Run("MirrorSync",testScheduleUpdateMirrorSync)
36+
}
37+
38+
functestScheduleUpdatePush(t*testing.T) {
39+
doTestScheduleUpdate(t,func(t*testing.T,u*url.URL,testContextAPITestContext,user*user_model.User,repo*repo_model.Repository) (commitID,expectedSpecstring) {
40+
newCron:="30 5 * * 1,3"
41+
pushScheduleChange(t,u,repo,newCron)
42+
branch,err:=git_model.GetBranch(t.Context(),repo.ID,repo.DefaultBranch)
43+
assert.NoError(t,err)
44+
returnbranch.CommitID,newCron
45+
})
46+
}
47+
48+
functestScheduleUpdatePullMerge(t*testing.T) {
49+
newBranchName:="feat1"
50+
workflowTreePath:=".gitea/workflows/actions-schedule.yml"
51+
workflowContent:=`name: actions-schedule
52+
on:
53+
schedule:
54+
- cron: '@every 2m' # update to 2m
55+
jobs:
56+
job:
57+
runs-on: ubuntu-latest
58+
steps:
59+
- run: echo 'schedule workflow'
60+
`
61+
62+
mergeStyles:= []repo_model.MergeStyle{
63+
repo_model.MergeStyleMerge,
64+
repo_model.MergeStyleRebase,
65+
repo_model.MergeStyleRebaseMerge,
66+
repo_model.MergeStyleSquash,
67+
repo_model.MergeStyleFastForwardOnly,
68+
}
69+
70+
for_,mergeStyle:=rangemergeStyles {
71+
t.Run(string(mergeStyle),func(t*testing.T) {
72+
doTestScheduleUpdate(t,func(t*testing.T,u*url.URL,testContextAPITestContext,user*user_model.User,repo*repo_model.Repository) (commitID,expectedSpecstring) {
73+
// update workflow file
74+
_,err:=files_service.ChangeRepoFiles(t.Context(),repo,user,&files_service.ChangeRepoFilesOptions{
75+
NewBranch:newBranchName,
76+
Files: []*files_service.ChangeRepoFile{
77+
{
78+
Operation:"update",
79+
TreePath:workflowTreePath,
80+
ContentReader:strings.NewReader(workflowContent),
81+
},
82+
},
83+
Message:"update workflow schedule",
84+
})
85+
assert.NoError(t,err)
86+
87+
// create pull request
88+
apiPull,err:=doAPICreatePullRequest(testContext,repo.OwnerName,repo.Name,repo.DefaultBranch,newBranchName)(t)
89+
assert.NoError(t,err)
90+
91+
// merge pull request
92+
testPullMerge(t,testContext.Session,repo.OwnerName,repo.Name,strconv.FormatInt(apiPull.Index,10),MergeOptions{
93+
Style:mergeStyle,
94+
})
95+
96+
pull:=unittest.AssertExistsAndLoadBean(t,&issues_model.PullRequest{ID:apiPull.ID})
97+
returnpull.MergedCommitID,"@every 2m"
98+
})
99+
})
100+
}
101+
102+
t.Run(string(repo_model.MergeStyleManuallyMerged),func(t*testing.T) {
103+
doTestScheduleUpdate(t,func(t*testing.T,u*url.URL,testContextAPITestContext,user*user_model.User,repo*repo_model.Repository) (commitID,expectedSpecstring) {
104+
// enable manual-merge
105+
doAPIEditRepository(testContext,&api.EditRepoOption{
106+
HasPullRequests:util.ToPointer(true),
107+
AllowManualMerge:util.ToPointer(true),
108+
})(t)
109+
110+
// update workflow file
111+
fileResp,err:=files_service.ChangeRepoFiles(t.Context(),repo,user,&files_service.ChangeRepoFilesOptions{
112+
NewBranch:newBranchName,
113+
Files: []*files_service.ChangeRepoFile{
114+
{
115+
Operation:"update",
116+
TreePath:workflowTreePath,
117+
ContentReader:strings.NewReader(workflowContent),
118+
},
119+
},
120+
Message:"update workflow schedule",
121+
})
122+
assert.NoError(t,err)
123+
124+
// merge and push
125+
dstPath:=t.TempDir()
126+
u.Path=repo.FullName()+".git"
127+
u.User=url.UserPassword(repo.OwnerName,userPassword)
128+
doGitClone(dstPath,u)(t)
129+
doGitMerge(dstPath,"origin/"+newBranchName)(t)
130+
doGitPushTestRepository(dstPath,"origin",repo.DefaultBranch)(t)
131+
132+
// create pull request
133+
apiPull,err:=doAPICreatePullRequest(testContext,repo.OwnerName,repo.Name,repo.DefaultBranch,newBranchName)(t)
134+
assert.NoError(t,err)
135+
136+
// merge pull request manually
137+
doAPIManuallyMergePullRequest(testContext,repo.OwnerName,repo.Name,fileResp.Commit.SHA,apiPull.Index)(t)
138+
139+
pull:=unittest.AssertExistsAndLoadBean(t,&issues_model.PullRequest{ID:apiPull.ID})
140+
assert.Equal(t,issues_model.PullRequestStatusManuallyMerged,pull.Status)
141+
returnpull.MergedCommitID,"@every 2m"
142+
})
143+
})
144+
}
145+
146+
functestScheduleUpdateMirrorSync(t*testing.T) {
147+
doTestScheduleUpdate(t,func(t*testing.T,u*url.URL,testContextAPITestContext,user*user_model.User,repo*repo_model.Repository) (commitID,expectedSpecstring) {
148+
// create mirror repo
149+
opts:= migration.MigrateOptions{
150+
RepoName:"actions-schedule-mirror",
151+
Description:"Test mirror for actions-schedule",
152+
Private:false,
153+
Mirror:true,
154+
CloneAddr:repo.CloneLinkGeneral(t.Context()).HTTPS,
155+
}
156+
mirrorRepo,err:=repo_service.CreateRepositoryDirectly(t.Context(),user,user, repo_service.CreateRepoOptions{
157+
Name:opts.RepoName,
158+
Description:opts.Description,
159+
IsPrivate:opts.Private,
160+
IsMirror:opts.Mirror,
161+
DefaultBranch:repo.DefaultBranch,
162+
Status:repo_model.RepositoryBeingMigrated,
163+
},false)
164+
assert.NoError(t,err)
165+
assert.True(t,mirrorRepo.IsMirror)
166+
mirrorRepo,err=repo_service.MigrateRepositoryGitData(t.Context(),user,mirrorRepo,opts,nil)
167+
assert.NoError(t,err)
168+
mirrorContext:=NewAPITestContext(t,user.Name,mirrorRepo.Name,auth_model.AccessTokenScopeWriteRepository)
169+
170+
// enable actions unit for mirror repo
171+
assert.False(t,mirrorRepo.UnitEnabled(t.Context(),unit_model.TypeActions))
172+
doAPIEditRepository(mirrorContext,&api.EditRepoOption{
173+
HasActions:util.ToPointer(true),
174+
})(t)
175+
actionSchedule:=unittest.AssertExistsAndLoadBean(t,&actions_model.ActionSchedule{RepoID:mirrorRepo.ID})
176+
scheduleSpec:=unittest.AssertExistsAndLoadBean(t,&actions_model.ActionScheduleSpec{RepoID:mirrorRepo.ID,ScheduleID:actionSchedule.ID})
177+
assert.Equal(t,"@every 1m",scheduleSpec.Spec)
178+
179+
// update remote repo
180+
newCron:="30 5,17 * * 2,4"
181+
pushScheduleChange(t,u,repo,newCron)
182+
repoDefaultBranch,err:=git_model.GetBranch(t.Context(),repo.ID,repo.DefaultBranch)
183+
assert.NoError(t,err)
184+
185+
// sync
186+
ok:=mirror_service.SyncPullMirror(t.Context(),mirrorRepo.ID)
187+
assert.True(t,ok)
188+
mirrorRepoDefaultBranch,err:=git_model.GetBranch(t.Context(),mirrorRepo.ID,mirrorRepo.DefaultBranch)
189+
assert.NoError(t,err)
190+
assert.Equal(t,repoDefaultBranch.CommitID,mirrorRepoDefaultBranch.CommitID)
191+
192+
// check updated schedule
193+
actionSchedule=unittest.AssertExistsAndLoadBean(t,&actions_model.ActionSchedule{RepoID:mirrorRepo.ID})
194+
scheduleSpec=unittest.AssertExistsAndLoadBean(t,&actions_model.ActionScheduleSpec{RepoID:mirrorRepo.ID,ScheduleID:actionSchedule.ID})
195+
assert.Equal(t,newCron,scheduleSpec.Spec)
196+
197+
returnrepoDefaultBranch.CommitID,newCron
198+
})
199+
}
200+
201+
functestScheduleUpdateArchiveAndUnarchive(t*testing.T) {
202+
doTestScheduleUpdate(t,func(t*testing.T,u*url.URL,testContextAPITestContext,user*user_model.User,repo*repo_model.Repository) (commitID,expectedSpecstring) {
203+
doAPIEditRepository(testContext,&api.EditRepoOption{
204+
Archived:util.ToPointer(true),
205+
})(t)
206+
assert.Zero(t,unittest.GetCount(t,&actions_model.ActionSchedule{RepoID:repo.ID}))
207+
doAPIEditRepository(testContext,&api.EditRepoOption{
208+
Archived:util.ToPointer(false),
209+
})(t)
210+
branch,err:=git_model.GetBranch(t.Context(),repo.ID,repo.DefaultBranch)
211+
assert.NoError(t,err)
212+
returnbranch.CommitID,"@every 1m"
213+
})
214+
}
215+
216+
functestScheduleUpdateDisableAndEnableActionsUnit(t*testing.T) {
217+
doTestScheduleUpdate(t,func(t*testing.T,u*url.URL,testContextAPITestContext,user*user_model.User,repo*repo_model.Repository) (commitID,expectedSpecstring) {
218+
doAPIEditRepository(testContext,&api.EditRepoOption{
219+
HasActions:util.ToPointer(false),
220+
})(t)
221+
assert.Zero(t,unittest.GetCount(t,&actions_model.ActionSchedule{RepoID:repo.ID}))
222+
doAPIEditRepository(testContext,&api.EditRepoOption{
223+
HasActions:util.ToPointer(true),
224+
})(t)
225+
branch,err:=git_model.GetBranch(t.Context(),repo.ID,repo.DefaultBranch)
226+
assert.NoError(t,err)
227+
returnbranch.CommitID,"@every 1m"
228+
})
229+
}
230+
231+
typescheduleUpdateTriggerfunc(t*testing.T,u*url.URL,testContextAPITestContext,user*user_model.User,repo*repo_model.Repository) (commitID,expectedSpecstring)
232+
233+
funcdoTestScheduleUpdate(t*testing.T,updateTriggerscheduleUpdateTrigger) {
234+
onGiteaRun(t,func(t*testing.T,u*url.URL) {
235+
user2:=unittest.AssertExistsAndLoadBean(t,&user_model.User{ID:2})
236+
session:=loginUser(t,user2.Name)
237+
token:=getTokenForLoggedInUser(t,session,auth_model.AccessTokenScopeWriteRepository,auth_model.AccessTokenScopeWriteUser)
238+
239+
apiRepo:=createActionsTestRepo(t,token,"actions-schedule",false)
240+
repo:=unittest.AssertExistsAndLoadBean(t,&repo_model.Repository{ID:apiRepo.ID})
241+
assert.NoError(t,repo.LoadAttributes(t.Context()))
242+
httpContext:=NewAPITestContext(t,user2.Name,repo.Name,auth_model.AccessTokenScopeWriteRepository)
243+
deferdoAPIDeleteRepository(httpContext)(t)
244+
245+
wfTreePath:=".gitea/workflows/actions-schedule.yml"
246+
wfFileContent:=`name: actions-schedule
247+
on:
248+
schedule:
249+
- cron: '@every 1m'
250+
jobs:
251+
job:
252+
runs-on: ubuntu-latest
253+
steps:
254+
- run: echo 'schedule workflow'
255+
`
256+
257+
opts1:=getWorkflowCreateFileOptions(user2,repo.DefaultBranch,"create "+wfTreePath,wfFileContent)
258+
apiFileResp:=createWorkflowFile(t,token,user2.Name,repo.Name,wfTreePath,opts1)
259+
260+
actionSchedule:=unittest.AssertExistsAndLoadBean(t,&actions_model.ActionSchedule{RepoID:repo.ID,CommitSHA:apiFileResp.Commit.SHA})
261+
scheduleSpec:=unittest.AssertExistsAndLoadBean(t,&actions_model.ActionScheduleSpec{RepoID:repo.ID,ScheduleID:actionSchedule.ID})
262+
assert.Equal(t,"@every 1m",scheduleSpec.Spec)
263+
264+
commitID,expectedSpec:=updateTrigger(t,u,httpContext,user2,repo)
265+
266+
actionSchedule=unittest.AssertExistsAndLoadBean(t,&actions_model.ActionSchedule{RepoID:repo.ID,CommitSHA:commitID})
267+
scheduleSpec=unittest.AssertExistsAndLoadBean(t,&actions_model.ActionScheduleSpec{RepoID:repo.ID,ScheduleID:actionSchedule.ID})
268+
assert.Equal(t,expectedSpec,scheduleSpec.Spec)
269+
})
270+
}
271+
272+
funcpushScheduleChange(t*testing.T,u*url.URL,repo*repo_model.Repository,newCronstring) {
273+
workflowTreePath:=".gitea/workflows/actions-schedule.yml"
274+
workflowContent:=`name: actions-schedule
275+
on:
276+
schedule:
277+
- cron: '`+newCron+`'
278+
jobs:
279+
job:
280+
runs-on: ubuntu-latest
281+
steps:
282+
- run: echo 'schedule workflow'
283+
`
284+
285+
dstPath:=t.TempDir()
286+
u.Path=repo.FullName()+".git"
287+
u.User=url.UserPassword(repo.OwnerName,userPassword)
288+
doGitClone(dstPath,u)(t)
289+
doGitCheckoutWriteFileCommit(localGitAddCommitOptions{
290+
LocalRepoPath:dstPath,
291+
CheckoutBranch:repo.DefaultBranch,
292+
TreeFilePath:workflowTreePath,
293+
TreeFileContent:workflowContent,
294+
})(t)
295+
doGitPushTestRepository(dstPath,"origin",repo.DefaultBranch)(t)
296+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp