Skip to content

Commit

Permalink
Convert age matcher to use a duration config (#159)
Browse files Browse the repository at this point in the history
* 🚀 Allow age with at-least/at-most options

Marks the old `age: 2d` option as deprecated but keeps it for backward compatability
  • Loading branch information
himynameisdave authored Nov 22, 2024
1 parent a8cc9f9 commit fe4b1c7
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 20 deletions.
37 changes: 23 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Please consider [sponsoring the project](https://github.com/sponsors/srvaroa) if
### How to trigger action

To trigger the action on events, add a file `.github/workflows/main.yml`
to your repository:
to your repository:

```yaml
name: Label PRs
Expand Down Expand Up @@ -294,7 +294,7 @@ With this config, the behaviour changes:

## Conditions

Below are the conditions currently supported in label matchers, in
Below are the conditions currently supported in label matchers, in
alphabetical order. Some important considerations:

* Conditions evaluate only when they are explicitly added in
Expand All @@ -308,20 +308,29 @@ alphabetical order. Some important considerations:

### Age (PRs and Issues) <a name="age" />

This condition is satisfied when the age of the PR or Issue are larger than
the given one. The age is calculated from the creation date.
This condition evaluates the creation date of the PR or Issue.

If you're looking to evaluate on the modification date of the issue or PR,
If you're looking to evaluate on the modification date of the issue or PR,
check on <a href="#last-modified" ></a>

This condition is best used when with a <a href="#schedule">schedule trigger</a>.

Example:
Examples:

```yaml
age-range:
at-most: 1d
```

Will label PRs or issues that were created at most one day ago.

```yaml
age: 1d
age-range:
at-least: 1w
```

Will label PRs or issues that were created at least one week ago.

The syntax for values is based on a number, followed by a suffix:

* s: seconds
Expand Down Expand Up @@ -412,7 +421,7 @@ This condition is satisfied when any of the PR files matches on the
given regexs.

```yaml
files:
files:
- "cmd\\/.*_tests.go"
- ".*\\/subfolder\\/.*\\.md"
```
Expand All @@ -425,9 +434,9 @@ and therefore must be escaped itself to appear as a literal in the regex.

### Last Modified (PRs and Issues) <a name="last-modified" />

This condition evaluates the modification date of the PR or Issue.
This condition evaluates the modification date of the PR or Issue.

If you're looking to evaluate on the creation date of the issue or PR,
If you're looking to evaluate on the creation date of the issue or PR,
check on <a href="#age" ></a>

This condition is best used when with a <a href="#schedule">schedule trigger</a>.
Expand Down Expand Up @@ -462,19 +471,19 @@ For example, `2d` means 2 days, `4w` means 4 weeks, and so on.

This condition is satisfied when the [mergeable
state](https://developer.github.com/v3/pulls/#response-1) matches that
of the PR.
of the PR.

```yaml
mergeable: True
```

Will match if the label is mergeable.
Will match if the label is mergeable.

```yaml
mergeable: False
```

Will match if the label is not mergeable.
Will match if the label is not mergeable.

### Size (PRs only) <a name="size" />

Expand Down Expand Up @@ -518,7 +527,7 @@ file or a Regex expression:
size:
exclude-files: ["yarn.lock", "\\/root\\/.+\\/test.md"]
above: 100
```
```

This condition will apply the `L` label if the diff is above 100 lines,
but NOT taking into account changes in `yarn.lock`, or any `test.md`
Expand Down
43 changes: 38 additions & 5 deletions pkg/condition_age.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,35 @@ func AgeCondition(l *Labeler) Condition {
return target.ghIssue != nil || target.ghPR != nil
},
Evaluate: func(target *Target, matcher LabelMatcher) (bool, error) {
// Parse the age from the configuration
ageDuration, err := parseExtendedDuration(matcher.Age)
if err != nil {
return false, fmt.Errorf("failed to parse age parameter in configuration: %v", err)
// Backward compatibility: If "age" is provided as a string, treat it as "at-least"
var atLeastDuration, atMostDuration time.Duration
var err error

// If they have specified a legacy "age" field, use that
// and treat it is as "at-least"
if matcher.Age != "" {
atLeastDuration, err = parseExtendedDuration(matcher.Age)
if err != nil {
return false, fmt.Errorf("failed to parse age parameter in configuration: %v", err)
}
} else if matcher.AgeRange != nil {
// Parse "at-least" if specified
if matcher.AgeRange.AtLeast != "" {
atLeastDuration, err = parseExtendedDuration(matcher.AgeRange.AtLeast)
if err != nil {
return false, fmt.Errorf("failed to parse `age.at-least` parameter in configuration: %v", err)
}
}

// Parse "at-most" if specified
if matcher.AgeRange.AtMost != "" {
atMostDuration, err = parseExtendedDuration(matcher.AgeRange.AtMost)
if err != nil {
return false, fmt.Errorf("failed to parse `age.at-most` parameter in configuration: %v", err)
}
}
} else {
return false, fmt.Errorf("no age conditions are set in config")
}

// Determine the creation time of the issue or PR
Expand All @@ -30,7 +55,15 @@ func AgeCondition(l *Labeler) Condition {

age := time.Since(createdAt)

return age > ageDuration, nil
// Check if the age of the issue/PR is within the specified range
if atLeastDuration != 0 && age < atLeastDuration {
return false, nil
}
if atMostDuration != 0 && age > atMostDuration {
return false, nil
}

return true, nil
},
}
}
3 changes: 2 additions & 1 deletion pkg/labeler.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ type SizeConfig struct {
}

type LabelMatcher struct {
Age string
Age string `yaml:"age,omitempty"` // Deprecated age config.
AgeRange *DurationConfig `yaml:"age-range,omitempty"`
AuthorCanMerge string `yaml:"author-can-merge"`
Authors []string
AuthorInTeam string `yaml:"author-in-team"`
Expand Down
26 changes: 26 additions & 0 deletions pkg/labeler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,32 @@ func TestHandleEvent(t *testing.T) {
initialLabels: []string{},
expectedLabels: []string{"ThisIsOld"},
},
// Test the AgeRange configuration
{
event: "pull_request",
payloads: []string{"create_pr"},
name: "Age of a PR in the past",
config: LabelerConfigV1{
Version: 1,
Labels: []LabelMatcher{
{
Label: "Getting Old",
AgeRange: &DurationConfig{
AtLeast: "7d",
AtMost: "14d",
},
},
{
Label: "Getting Ancient",
AgeRange: &DurationConfig{
AtLeast: "14d",
},
},
},
},
initialLabels: []string{},
expectedLabels: []string{"Getting Ancient"},
},
{
event: "pull_request",
payloads: []string{"create_draft_pr"},
Expand Down

0 comments on commit fe4b1c7

Please sign in to comment.