Skip to content

Commit 5d8e949

Browse files
nnnkkk7t-kikuc
authored andcommitted
Create a new branch if makePullRequest is true in git config (#4395)
* add new branch flag when commit changes in eventwatcher Signed-off-by: nnnkkk7 <[email protected]> * add createPullRequest flag to event watcher config instead of git config Signed-off-by: nnnkkk7 <[email protected]> * fix test Signed-off-by: nnnkkk7 <[email protected]> * push commit if the branch is new in event watcher Signed-off-by: nnnkkk7 <[email protected]> * fix docs-v0.43.x Signed-off-by: nnnkkk7 <[email protected]> * fix docs Signed-off-by: nnnkkk7 <[email protected]> * replace createPullRequest with makePullRequest Signed-off-by: nnnkkk7 <[email protected]> * renamed getBranchName to makeBranchName Signed-off-by: nnnkkk7 <[email protected]> * remove makePullRequest from EventWatcherEvent Signed-off-by: nnnkkk7 <[email protected]> * retry push commits in execute func Signed-off-by: nnnkkk7 <[email protected]> * fix how to push new branch Signed-off-by: nnnkkk7 <[email protected]> * use map for branchname Signed-off-by: nnnkkk7 <[email protected]> * use branchHandledEvents map Signed-off-by: nnnkkk7 <[email protected]> * use errors.Join Signed-off-by: nnnkkk7 <[email protected]> * remove docs Signed-off-by: nnnkkk7 <[email protected]> * remove handledEvents Signed-off-by: nnnkkk7 <[email protected]> * avoid using '!' Signed-off-by: nnnkkk7 <[email protected]> * rearrange package Signed-off-by: nnnkkk7 <[email protected]> --------- Signed-off-by: nnnkkk7 <[email protected]>
1 parent d33f8c6 commit 5d8e949

File tree

4 files changed

+106
-47
lines changed

4 files changed

+106
-47
lines changed

docs/content/en/docs-dev/user-guide/configuration-reference.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,7 @@ Note: By default, the sum of traffic is rounded to 100. If both `primary` and `c
706706
| Field | Type | Description | Required |
707707
|-|-|-|-|
708708
| commitMessage | string | The commit message used to push after replacing values. Default message is used if not given. | No |
709+
| makePullRequest | bool | Whether to create a new branch or not when commit changes in event watcher. Default is `false`. | No |
709710
| replacements | [][EventWatcherReplacement](#eventwatcherreplacement) | List of places where will be replaced when the new event matches. | Yes |
710711

711712
## DriftDetection

pkg/app/piped/eventwatcher/eventwatcher.go

Lines changed: 66 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"text/template"
3131
"time"
3232

33+
"github.com/google/uuid"
3334
"go.uber.org/zap"
3435
"google.golang.org/grpc"
3536

@@ -329,11 +330,11 @@ func (w *watcher) execute(ctx context.Context, repo git.Repo, repoID string, eve
329330
firstRead = false
330331
}
331332
var (
332-
handledEvents = make([]*pipedservice.ReportEventStatusesRequest_Event, 0, len(eventCfgs))
333-
outDatedEvents = make([]*pipedservice.ReportEventStatusesRequest_Event, 0)
334-
maxTimestamp int64
335-
outDatedDuration = time.Hour
336-
gitUpdateEvent = false
333+
outDatedEvents = make([]*pipedservice.ReportEventStatusesRequest_Event, 0)
334+
maxTimestamp int64
335+
outDatedDuration = time.Hour
336+
gitUpdateEvent = false
337+
branchHandledEvents = make(map[string][]*pipedservice.ReportEventStatusesRequest_Event, len(eventCfgs))
337338
)
338339
for _, e := range eventCfgs {
339340
for _, cfg := range e.Configs {
@@ -383,23 +384,25 @@ func (w *watcher) execute(ctx context.Context, repo git.Repo, repoID string, eve
383384
})
384385
continue
385386
}
386-
387387
switch handler.Type {
388388
case config.EventWatcherHandlerTypeGitUpdate:
389-
if err := w.commitFiles(ctx, latestEvent.Data, matcher.Name, handler.Config.CommitMessage, e.GitPath, handler.Config.Replacements, tmpRepo); err != nil {
389+
branchName, err := w.commitFiles(ctx, latestEvent.Data, matcher.Name, handler.Config.CommitMessage, e.GitPath, handler.Config.Replacements, tmpRepo, handler.Config.MakePullRequest)
390+
if err != nil {
390391
w.logger.Error("failed to commit outdated files", zap.Error(err))
391-
handledEvents = append(handledEvents, &pipedservice.ReportEventStatusesRequest_Event{
392+
handledEvent := &pipedservice.ReportEventStatusesRequest_Event{
392393
Id: latestEvent.Id,
393394
Status: model.EventStatus_EVENT_FAILURE,
394395
StatusDescription: fmt.Sprintf("Failed to change files: %v", err),
395-
})
396+
}
397+
branchHandledEvents[branchName] = append(branchHandledEvents[branchName], handledEvent)
396398
continue
397399
}
398-
handledEvents = append(handledEvents, &pipedservice.ReportEventStatusesRequest_Event{
400+
handledEvent := &pipedservice.ReportEventStatusesRequest_Event{
399401
Id: latestEvent.Id,
400402
Status: model.EventStatus_EVENT_SUCCESS,
401403
StatusDescription: fmt.Sprintf("Successfully updated %d files in the %q repository", len(handler.Config.Replacements), repoID),
402-
})
404+
}
405+
branchHandledEvents[branchName] = append(branchHandledEvents[branchName], handledEvent)
403406
if latestEvent.CreatedAt > maxTimestamp {
404407
maxTimestamp = latestEvent.CreatedAt
405408
}
@@ -419,46 +422,51 @@ func (w *watcher) execute(ctx context.Context, repo git.Repo, repoID string, eve
419422
}
420423
w.logger.Info(fmt.Sprintf("successfully made %d events OUTDATED", len(outDatedEvents)))
421424
}
422-
if len(handledEvents) == 0 {
423-
return nil
424-
}
425425

426426
if !gitUpdateEvent {
427427
return nil
428428
}
429429

430+
var responseError error
430431
retry := backoff.NewRetry(retryPushNum, backoff.NewConstant(retryPushInterval))
431-
_, err = retry.Do(ctx, func() (interface{}, error) {
432-
err := tmpRepo.Push(ctx, tmpRepo.GetClonedBranch())
433-
return nil, err
434-
})
435-
if err == nil {
436-
if _, err := w.apiClient.ReportEventStatuses(ctx, &pipedservice.ReportEventStatusesRequest{Events: handledEvents}); err != nil {
437-
return fmt.Errorf("failed to report event statuses: %w", err)
438-
}
439-
w.executionMilestoneMap.Store(repoID, maxTimestamp)
440-
return nil
441-
}
432+
for branch, events := range branchHandledEvents {
433+
_, err = retry.Do(ctx, func() (interface{}, error) {
434+
err := tmpRepo.Push(ctx, branch)
435+
return nil, err
436+
})
442437

443-
// If push fails because the local branch was not fresh, exit to retry again in the next interval.
444-
if err == git.ErrBranchNotFresh {
445-
w.logger.Warn("failed to push commits", zap.Error(err))
446-
return nil
447-
}
438+
if err == nil {
439+
if _, err := w.apiClient.ReportEventStatuses(ctx, &pipedservice.ReportEventStatusesRequest{Events: events}); err != nil {
440+
w.logger.Error("failed to report event statuses", zap.Error(err))
441+
}
442+
w.executionMilestoneMap.Store(repoID, maxTimestamp)
443+
continue
444+
}
448445

449-
// If push fails because of the other reason, re-set all statuses to FAILURE.
450-
for i := range handledEvents {
451-
if handledEvents[i].Status == model.EventStatus_EVENT_FAILURE {
446+
// If push fails because the local branch was not fresh, exit to retry again in the next interval.
447+
if err == git.ErrBranchNotFresh {
448+
w.logger.Warn("failed to push commits", zap.Error(err))
452449
continue
453450
}
454-
handledEvents[i].Status = model.EventStatus_EVENT_FAILURE
455-
handledEvents[i].StatusDescription = fmt.Sprintf("Failed to push changed files: %v", err)
451+
452+
// If push fails because of the other reason, re-set all statuses to FAILURE.
453+
for i := range events {
454+
if events[i].Status == model.EventStatus_EVENT_FAILURE {
455+
continue
456+
}
457+
events[i].Status = model.EventStatus_EVENT_FAILURE
458+
events[i].StatusDescription = fmt.Sprintf("Failed to push changed files: %v", err)
459+
}
460+
if _, err := w.apiClient.ReportEventStatuses(ctx, &pipedservice.ReportEventStatusesRequest{Events: events}); err != nil {
461+
w.logger.Error("failed to report event statuses", zap.Error(err))
462+
}
463+
w.executionMilestoneMap.Store(repoID, maxTimestamp)
464+
responseError = errors.Join(responseError, err)
456465
}
457-
if _, err := w.apiClient.ReportEventStatuses(ctx, &pipedservice.ReportEventStatusesRequest{Events: handledEvents}); err != nil {
458-
return fmt.Errorf("failed to report event statuses: %w", err)
466+
if responseError != nil {
467+
return responseError
459468
}
460-
w.executionMilestoneMap.Store(repoID, maxTimestamp)
461-
return fmt.Errorf("failed to push commits: %w", err)
469+
return nil
462470
}
463471

464472
// updateValues inspects all Event-definition and pushes the changes to git repo if there is.
@@ -530,7 +538,8 @@ func (w *watcher) updateValues(ctx context.Context, repo git.Repo, repoID string
530538
})
531539
continue
532540
}
533-
if err := w.commitFiles(ctx, latestEvent.Data, e.Name, commitMsg, "", e.Replacements, tmpRepo); err != nil {
541+
_, err := w.commitFiles(ctx, latestEvent.Data, e.Name, commitMsg, "", e.Replacements, tmpRepo, false)
542+
if err != nil {
534543
w.logger.Error("failed to commit outdated files", zap.Error(err))
535544
handledEvents = append(handledEvents, &pipedservice.ReportEventStatusesRequest_Event{
536545
Id: latestEvent.Id,
@@ -593,7 +602,7 @@ func (w *watcher) updateValues(ctx context.Context, repo git.Repo, repoID string
593602
}
594603

595604
// commitFiles commits changes if the data in Git is different from the latest event.
596-
func (w *watcher) commitFiles(ctx context.Context, latestData, eventName, commitMsg, gitPath string, replacements []config.EventWatcherReplacement, repo git.Repo) error {
605+
func (w *watcher) commitFiles(ctx context.Context, latestData, eventName, commitMsg, gitPath string, replacements []config.EventWatcherReplacement, repo git.Repo, newBranch bool) (string, error) {
597606
// Determine files to be changed by comparing with the latest event.
598607
changes := make(map[string][]byte, len(replacements))
599608
for _, r := range replacements {
@@ -619,31 +628,32 @@ func (w *watcher) commitFiles(ctx context.Context, latestData, eventName, commit
619628
newContent, upToDate, err = modifyText(path, r.Regex, latestData)
620629
}
621630
if err != nil {
622-
return err
631+
return "", err
623632
}
624633
if upToDate {
625634
continue
626635
}
627636

628637
if err := os.WriteFile(path, newContent, os.ModePerm); err != nil {
629-
return fmt.Errorf("failed to write file: %w", err)
638+
return "", fmt.Errorf("failed to write file: %w", err)
630639
}
631640
changes[filePath] = newContent
632641
}
633642
if len(changes) == 0 {
634-
return nil
643+
return "", nil
635644
}
636645

637646
args := argsTemplate{
638647
Value: latestData,
639648
EventName: eventName,
640649
}
641650
commitMsg = parseCommitMsg(commitMsg, args)
642-
if err := repo.CommitChanges(ctx, repo.GetClonedBranch(), commitMsg, false, changes); err != nil {
643-
return fmt.Errorf("failed to perform git commit: %w", err)
651+
branch := makeBranchName(newBranch, eventName, repo.GetClonedBranch())
652+
if err := repo.CommitChanges(ctx, branch, commitMsg, newBranch, changes); err != nil {
653+
return "", fmt.Errorf("failed to perform git commit: %w", err)
644654
}
645655
w.logger.Info(fmt.Sprintf("event watcher will update values of Event %q", eventName))
646-
return nil
656+
return branch, nil
647657
}
648658

649659
// modifyYAML returns a new YAML content as a first returned value if the value of given
@@ -777,3 +787,12 @@ func parseCommitMsg(msg string, args argsTemplate) string {
777787
}
778788
return buf.String()
779789
}
790+
791+
// makeBranchName generates a new branch name in the format {eventName}-{uuid} if newBranch is true.
792+
// If newBranch is false, the function returns the existing branch name.
793+
func makeBranchName(newBranch bool, eventName, branch string) string {
794+
if newBranch {
795+
return fmt.Sprintf("%s-%s", eventName, uuid.New().String())
796+
}
797+
return branch
798+
}

pkg/app/piped/eventwatcher/eventwatcher_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,3 +242,40 @@ spec:
242242
})
243243
}
244244
}
245+
246+
func TestGetBranchName(t *testing.T) {
247+
t.Parallel()
248+
testcases := []struct {
249+
name string
250+
newBranch bool
251+
eventName string
252+
branch string
253+
want string
254+
}{
255+
{
256+
name: "create new branch",
257+
newBranch: true,
258+
eventName: "event",
259+
branch: "main",
260+
},
261+
{
262+
name: "return existing branch",
263+
newBranch: false,
264+
eventName: "event",
265+
branch: "main",
266+
want: "main",
267+
},
268+
}
269+
for _, tc := range testcases {
270+
tc := tc
271+
t.Run(tc.name, func(t *testing.T) {
272+
t.Parallel()
273+
got := makeBranchName(tc.newBranch, tc.eventName, tc.branch)
274+
if tc.newBranch {
275+
assert.NotEqual(t, tc.branch, got)
276+
} else {
277+
assert.Equal(t, tc.want, got)
278+
}
279+
})
280+
}
281+
}

pkg/config/event_watcher.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ type EventWatcherHandlerConfig struct {
6464
// The commit message used to push after replacing values.
6565
// Default message is used if not given.
6666
CommitMessage string `json:"commitMessage,omitempty"`
67+
// Whether to create a new branch or not when event watcher commits changes.
68+
MakePullRequest bool `json:"makePullRequest,omitempty"`
6769
// List of places where will be replaced when the new event matches.
6870
Replacements []EventWatcherReplacement `json:"replacements"`
6971
}

0 commit comments

Comments
 (0)