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 last-modified #149

Merged
merged 1 commit into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
version: 1

labels:
# Type: Recent changes
- label: "@type/new"
last-modified:
at-most: 1d

# Type: Old changes
- label: "@type/old"
last-modified:
at-least: 30d

# Type: Build-related changes
- label: "@type/build"
title: '^build(?:\(.+\))?\!?:'
Expand Down
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,9 @@ alphabetical order. Some important considerations:
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.

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:
Expand Down Expand Up @@ -407,6 +410,41 @@ regular expressions (Regex). Special characters need to be escaped with double
backslashes. This is because the backslash in Go strings is an escape character
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.

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>.

Examples:

```yaml
last-modified:
at-most: 1d
```
Will label PRs or issues that were last modified at most one day ago

```yaml
last-modified:
at-least: 1d
```

Will label PRs or issues that were last modified at least one day ago

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

* s: seconds
* m: minutes
* h: hours
* d: days
* w: weeks
* y: years

For example, `2d` means 2 days, `4w` means 4 weeks, and so on.

### Mergeable status (PRs only) <a name="mergeable" />

This condition is satisfied when the [mergeable
Expand Down
25 changes: 0 additions & 25 deletions pkg/condition_age.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package labeler

import (
"fmt"
"strconv"
"strings"
"time"
)

Expand Down Expand Up @@ -36,26 +34,3 @@ func AgeCondition(l *Labeler) Condition {
},
}
}

func parseExtendedDuration(s string) (time.Duration, error) {
multiplier := time.Hour * 24 // default to days

if strings.HasSuffix(s, "w") {
multiplier = time.Hour * 24 * 7 // weeks
s = strings.TrimSuffix(s, "w")
} else if strings.HasSuffix(s, "y") {
multiplier = time.Hour * 24 * 365 // years
s = strings.TrimSuffix(s, "y")
} else if strings.HasSuffix(s, "d") {
s = strings.TrimSuffix(s, "d") // days
} else {
return time.ParseDuration(s) // default to time.ParseDuration for hours, minutes, seconds
}

value, err := strconv.Atoi(s)
if err != nil {
return 0, err
}

return time.Duration(value) * multiplier, nil
}
53 changes: 53 additions & 0 deletions pkg/condition_last_modified.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package labeler

import (
"fmt"
"time"

"github.com/google/go-github/v50/github"
)

func LastModifiedCondition(l *Labeler) Condition {
return Condition{
GetName: func() string {
return "Last modification of issue/PR"
},
CanEvaluate: func(target *Target) bool {
return target.ghIssue != nil || target.ghPR != nil
},
Evaluate: func(target *Target, matcher LabelMatcher) (bool, error) {
if matcher.LastModified == nil {
return false, fmt.Errorf("no last modified conditions are set in config")
}
// Determine the last modification time of the issue or PR
var lastModifiedAt *github.Timestamp
if target.ghIssue != nil {
lastModifiedAt = target.ghIssue.UpdatedAt
} else if target.ghPR != nil {
lastModifiedAt = target.ghPR.UpdatedAt
} else {
return false, fmt.Errorf("no issue or PR found in target")
}
duration := time.Since(lastModifiedAt.Time)

if matcher.LastModified.AtMost != "" {
maxDuration, err := parseExtendedDuration(matcher.LastModified.AtMost)
if err != nil {
return false, fmt.Errorf("failed to parse `last-modified.at-most` parameter in configuration: %v", err)
}
return duration <= maxDuration, nil
}

if matcher.LastModified.AtLeast != "" {
minDuration, err := parseExtendedDuration(matcher.LastModified.AtLeast)
if err != nil {
return false, fmt.Errorf("failed to parse `last-modified.at-least` parameter in configuration: %v", err)
}
return duration >= minDuration, nil
}

return false, fmt.Errorf("no last modified conditions are set in config")

},
}
}
7 changes: 7 additions & 0 deletions pkg/labeler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import (
gh "github.com/google/go-github/v50/github"
)

type DurationConfig struct {
AtLeast string `yaml:"at-least"`
AtMost string `yaml:"at-most"`
}

type SizeConfig struct {
ExcludeFiles []string `yaml:"exclude-files"`
Above string
Expand All @@ -23,6 +28,7 @@ type LabelMatcher struct {
Draft string
Files []string
Label string
LastModified *DurationConfig `yaml:"last-modified"`
Mergeable string
Negate bool
Size *SizeConfig
Expand Down Expand Up @@ -223,6 +229,7 @@ func (l *Labeler) findMatches(target *Target, config *LabelerConfigV1) (LabelUpd
BodyCondition(),
BranchCondition(),
FilesCondition(l),
LastModifiedCondition(l),
IsDraftCondition(),
IsMergeableCondition(),
SizeCondition(l),
Expand Down
18 changes: 18 additions & 0 deletions pkg/labeler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,24 @@ func TestHandleEvent(t *testing.T) {
initialLabels: []string{"Meh"},
expectedLabels: []string{"Meh", "Test"},
},
{
event: "pull_request",
payloads: []string{"create_pr"},
name: "Add a label to pull request when last-modified.at-least matches",
config: LabelerConfigV1{
Version: 1,
Labels: []LabelMatcher{
{
Label: "Test",
LastModified: &DurationConfig{
AtLeast: "1d",
},
},
},
},
initialLabels: []string{"Meh"},
expectedLabels: []string{"Meh", "Test"},
},
}

for _, tc := range testCases {
Expand Down
30 changes: 30 additions & 0 deletions pkg/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package labeler

import (
"strconv"
"strings"
"time"
)

func parseExtendedDuration(s string) (time.Duration, error) {
multiplier := time.Hour * 24 // default to days

if strings.HasSuffix(s, "w") {
multiplier = time.Hour * 24 * 7 // weeks
s = strings.TrimSuffix(s, "w")
} else if strings.HasSuffix(s, "y") {
multiplier = time.Hour * 24 * 365 // years
s = strings.TrimSuffix(s, "y")
} else if strings.HasSuffix(s, "d") {
s = strings.TrimSuffix(s, "d") // days
} else {
return time.ParseDuration(s) // default to time.ParseDuration for hours, minutes, seconds
}

value, err := strconv.Atoi(s)
if err != nil {
return 0, err
}

return time.Duration(value) * multiplier, nil
}
File renamed without changes.
Loading