Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support skipping stages by path pattern or commit message prefix #4922

Merged
merged 51 commits into from
Jun 18, 2024

Conversation

t-kikuc
Copy link
Member

@t-kikuc t-kikuc commented May 22, 2024

What this PR does / why we need it:

This PR enables skipping stages (Analysis,WaitApproval,Wait,ScriptRun) when the commit matches
configured path patterns or commit message prefixes.

Which issue(s) this PR fixes:

Fixes #4899

Does this PR introduce a user-facing change?: N/A (only append)

  • How are users affected by this change: N/A
  • Is this breaking change: N/A
  • How to migrate (if breaking change): N/A

How to use

Configuration: add with.skipOn section in stages to skip.

  • paths: When ALL changes of the commit match them, the stage will be skipped.
  • commitMessagePrefixes: When the prefix of the commit's message matches ANY of them, the stage will be skipped.
  pipeline:
    stages:
      - name: ECS_TRAFFIC_ROUTING
        with:
          canary: 30
      - name: WAIT_APPROVAL
        with:
          skipOn:
            commitMessagePrefixes:
              - [skip-approval] # When the commit message starts with '[skip-approval]', this stage will be skipped
      - name: WAIT
        with:
          duration: 60s
          skipOn:
            paths:
              - "**/*.yaml" # Any yaml file under any directory
      - name: ANALYSIS
        with:
          duration: 60s
          skipOn:
            paths:
              - "**/app.pipecd.yaml" # Any app.pipecd.yaml under any directory
              - "**/*.md" # Any markdown file under any directory
      - name: ECS_TRAFFIC_ROUTING
        with:
          primary: 100

When all skipOn conditions of each stage passed, the deployment will be:
image

t-kikuc added 30 commits April 22, 2024 20:53
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
…stage

Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
s.logger.Error("failed to report stage status", zap.Error(err))
return model.StageStatus_STAGE_FAILURE
}
lp.Infof("The stage was successfully skipped due to the skip configuration of the stage.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
lp.Infof("The stage was successfully skipped due to the skip configuration of the stage.")
lp.Info("The stage was successfully skipped due to the skip configuration of the stage.")

nits. There is no need to use formater here 👀

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I fixed it now. e2e35f4

t-kikuc added 4 commits May 30, 2024 18:40
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
@t-kikuc
Copy link
Member Author

t-kikuc commented May 30, 2024

"should we separate the skipstage as a new package/module or just place it in scheduler code"

I quit separating skipstage package because I also think we don't need to separate package here.

@Warashi
Copy link
Contributor

Warashi commented May 31, 2024

IMO, I agree with khanhtc1202. Because we have no need to hide functions from other controller codes.

Copy link
Member

@ffjlabo ffjlabo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the late review 🙏 Added some comments.

Comment on lines 709 to 721
stageConfig := in.StageConfig
var skipOptions config.SkipOptions
switch stageConfig.Name {
case model.StageAnalysis:
skipOptions = stageConfig.AnalysisStageOptions.SkipOn
case model.StageWait:
skipOptions = stageConfig.WaitStageOptions.SkipOn
case model.StageWaitApproval:
skipOptions = stageConfig.WaitApprovalStageOptions.SkipOn
case model.StageScriptRun:
skipOptions = stageConfig.ScriptRunStageOptions.SkipOn
default:
return false, nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[imo] How about adding the func StageConfig.GetSkipConfig() in the config package?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the current one is enough because

  • StageConfig.GetSkipConfig() will be used only in skipstage package
  • adding the func to each stage model seems redundant

WDYT?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I got it 👍

Comment on lines 67 to 74
func commitMessageHasAnyPrefix(commitMessage string, prefixes []string) bool {
for _, prefix := range prefixes {
if strings.HasPrefix(commitMessage, prefix) {
return true
}
}
return false
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[imo] It might not be a func, just put it in the skipByCommitMessagePrefixes ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean we need to mock repo.ChangedFiles in skipByCommitMessagePrefixes?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel commitMessageHasAnyPrefix doesn't have much logic, so IMO, it would be nice to gather the logic to the skipByCommitMessagePrefixes.

You mean we need to mock repo.ChangedFiles in skipByCommitMessagePrefixes?

When testing, we might need to mock as you said.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ffjlabo thanks, I merged the func and used mock in tests.
TBH, I missed git.mock.go https://github.com/pipe-cd/pipecd/blob/master/pkg/git/gittest/git.mock.go

Comment on lines 90 to 103
func hasOnlyPathsToSkip(skipPatterns []string, changedFiles []string) (bool, error) {
matcher, err := filematcher.NewPatternMatcher(skipPatterns)
if err != nil {
return false, err
}

for _, changedFile := range changedFiles {
if !matcher.Matches(changedFile) {
return false, nil
}
}

return true, nil
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[imo] It might not be a func, just put it in the skipByPathPattern?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ffjlabo thanks, I merged the func and used mock in tests.

Comment on lines 27 to 32
// checkSkipStage checks whether the stage should be skipped or not.
func checkSkipStage(ctx context.Context, in executor.Input, opt config.SkipOptions) (skip bool, err error) {
if len(opt.Paths) == 0 && len(opt.CommitMessagePrefixes) == 0 {
// When no condition is specified.
return false, nil
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[imo] It might not be a func, just put it in the shouldSkipStage ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I did it here 8a96a8c

@ffjlabo
Copy link
Member

ffjlabo commented Jun 7, 2024

Sorry to be late. I agree with it.
#4922 (review)

should we separate the skipstage as a new package/module or just place it in scheduler code" is left. IMO, we should place it in the scheduler.go code. Happy to hear other thoughts here 👀

Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
@t-kikuc t-kikuc requested a review from Warashi as a code owner June 10, 2024 00:39
t-kikuc and others added 4 commits June 10, 2024 18:03
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
Signed-off-by: t-kikuc <tkikuchi07f@gmail.com>
@t-kikuc t-kikuc requested review from khanhtc1202 and ffjlabo June 10, 2024 12:21
Copy link
Contributor

@Warashi Warashi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I push several commits at once, this PR's code seems to process only the last commit.
I think all pushed commits should be handled the same way as the last commit. What do you think?

@t-kikuc
Copy link
Member Author

t-kikuc commented Jun 12, 2024

@Warashi

Thank you, that's important.

a. Path Pattern:

This PR already checks ALL changes from the running commit to the latest commit as below.

changedFiles, err := repo.ChangedFiles(ctx, runningRev, targetRev)

b. Commit Message:

As you said, only the latest commit is checked.

Cases when the latest commit matches the condition but not all commits match it would be:

  • Commit&merge frequently
  • Not using a squash merge

cf. commitMatcher only checks the triggered commit.

if pipelineRegex.MatchString(in.Trigger.Commit.Message) {

@peaceiris What do you think? Should ALL commits match the condition?

@peaceiris
Copy link
Contributor

Only the latest commit is good enough for my use case 👍

@t-kikuc
Copy link
Member Author

t-kikuc commented Jun 12, 2024

@peaceiris I got it, thank you so much!

@khanhtc1202
Copy link
Member

I think the same way, we should only treat the last commit message 👍

Copy link
Member

@khanhtc1202 khanhtc1202 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, can't wait for this in action 👍

Copy link
Contributor

@Warashi Warashi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. There is a consensus to see only the last commit message, so LGTM.

@t-kikuc t-kikuc merged commit e978760 into master Jun 18, 2024
16 of 18 checks passed
@t-kikuc t-kikuc deleted the skip-stage branch June 18, 2024 01:11
@github-actions github-actions bot mentioned this pull request Jul 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/go kind/enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[feat] Skip stages when the commit is not important (Analysis,WaitApproval,Wait,ScriptRun)
5 participants