Skip to content
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Make sure to check out [#migrating](#migrating) to learn more.
| `labels` | No | `["bug", "enhancement"]` | The labels on the PR. The pipeline will only trigger on pull requests having at least one of the specified labels. |
| `disable_git_lfs` | No | `true` | Disable Git LFS, skipping an attempt to convert pointers of files tracked into their corresponding objects when checked out into a working copy. |
| `states` | No | `["OPEN", "MERGED"]` | The PR states to select (`OPEN`, `MERGED` or `CLOSED`). The pipeline will only trigger on pull requests matching one of the specified states. Default is ["OPEN"]. |
| `track_non_commit_changes` | No | `false` | Will cause a new version of the resource to be created on every pull request update. Changes that do not create new commits, such as adding a label, will trigger the pipeline.

Notes:
- If `v3_endpoint` is set, `v4_endpoint` must also be set (and the other way around).
Expand All @@ -48,15 +49,15 @@ Notes:

#### `check`

Produces new versions for all commits (after the last version) ordered by the committed date.
By default produces new versions for all commits (after the last version) ordered by the committed date. If `track_non_commit_changes` is set to true in the source will produce new versions every time the pull request is updated, ordered by the time of the updates.
A version is represented as follows:

- `pr`: The pull request number.
- `commit`: The commit SHA.
- `committed`: Timestamp of when the commit was committed. Used to filter subsequent checks.
- `change_time`: Timestamp of when the last change was made. Used to filter subsequent checks.
- `approved_review_count`: The number of reviews approving of the PR.

If several commits are pushed to a given PR at the same time, the last commit will be the new version.
If several commits/updates are pushed to a given PR at the same time, the last commit/update will be the new version.

**Note on webhooks:**
This resource does not implement any caching, so it should work well with webhooks (should be subscribed to `push` and `pull_request` events).
Expand Down
4 changes: 2 additions & 2 deletions check.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Loop:
}

// Filter out commits that are too old.
if !p.UpdatedDate().Time.After(request.Version.CommittedDate) {
if !p.ChangeTime().Time.After(request.Version.ChangeTime) {
continue
}

Expand Down Expand Up @@ -207,7 +207,7 @@ func (r CheckResponse) Len() int {
}

func (r CheckResponse) Less(i, j int) bool {
return r[j].CommittedDate.After(r[i].CommittedDate)
return r[j].ChangeTime.After(r[i].ChangeTime)
}

func (r CheckResponse) Swap(i, j int) {
Expand Down
27 changes: 15 additions & 12 deletions github.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ type Github interface {

// GithubClient for handling requests to the Github V3 and V4 APIs.
type GithubClient struct {
V3 *github.Client
V4 *githubv4.Client
Repository string
Owner string
V3 *github.Client
V4 *githubv4.Client
Repository string
Owner string
TrackNonCommitChanges bool
}

// NewGithubClient ...
Expand Down Expand Up @@ -90,10 +91,11 @@ func NewGithubClient(s *Source) (*GithubClient, error) {
}

return &GithubClient{
V3: v3,
V4: v4,
Owner: owner,
Repository: repository,
V3: v3,
V4: v4,
Owner: owner,
Repository: repository,
TrackNonCommitChanges: s.TrackNonCommitChanges,
}, nil
}

Expand Down Expand Up @@ -156,10 +158,11 @@ func (m *GithubClient) ListPullRequests(prStates []githubv4.PullRequestState) ([

for _, c := range p.Node.Commits.Edges {
response = append(response, &PullRequest{
PullRequestObject: p.Node.PullRequestObject,
Tip: c.Node.Commit,
ApprovedReviewCount: p.Node.Reviews.TotalCount,
Labels: labels,
PullRequestObject: p.Node.PullRequestObject,
Tip: c.Node.Commit,
ApprovedReviewCount: p.Node.Reviews.TotalCount,
Labels: labels,
TrackNonCommitChanges: m.TrackNonCommitChanges,
})
}
}
Expand Down
31 changes: 16 additions & 15 deletions in_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ func TestGet(t *testing.T) {
version: resource.Version{
PR: "pr1",
Commit: "commit1",
CommittedDate: time.Time{},
ChangeTime: time.Time{},
ApprovedReviewCount: "0",
State: githubv4.PullRequestStateOpen,
},
parameters: resource.GetParameters{},
pullRequest: createTestPR(1, "master", false, false, 0, nil, false, githubv4.PullRequestStateOpen),
versionString: `{"pr":"pr1","commit":"commit1","committed":"0001-01-01T00:00:00Z","approved_review_count":"0","state":"OPEN"}`,
versionString: `{"pr":"pr1","commit":"commit1","change_time":"0001-01-01T00:00:00Z","approved_review_count":"0","state":"OPEN"}`,
metadataString: `[{"name":"pr","value":"1"},{"name":"title","value":"pr1 title"},{"name":"url","value":"pr1 url"},{"name":"head_name","value":"pr1"},{"name":"head_sha","value":"oid1"},{"name":"base_name","value":"master"},{"name":"base_sha","value":"sha"},{"name":"message","value":"commit message1"},{"name":"author","value":"login1"},{"name":"author_email","value":"user@example.com"},{"name":"state","value":"OPEN"}]`,
},
{
Expand All @@ -56,13 +56,13 @@ func TestGet(t *testing.T) {
version: resource.Version{
PR: "pr1",
Commit: "commit1",
CommittedDate: time.Time{},
ChangeTime: time.Time{},
ApprovedReviewCount: "0",
State: githubv4.PullRequestStateOpen,
},
parameters: resource.GetParameters{},
pullRequest: createTestPR(1, "master", false, false, 0, nil, false, githubv4.PullRequestStateOpen),
versionString: `{"pr":"pr1","commit":"commit1","committed":"0001-01-01T00:00:00Z","approved_review_count":"0","state":"OPEN"}`,
versionString: `{"pr":"pr1","commit":"commit1","change_time":"0001-01-01T00:00:00Z","approved_review_count":"0","state":"OPEN"}`,
metadataString: `[{"name":"pr","value":"1"},{"name":"title","value":"pr1 title"},{"name":"url","value":"pr1 url"},{"name":"head_name","value":"pr1"},{"name":"head_sha","value":"oid1"},{"name":"base_name","value":"master"},{"name":"base_sha","value":"sha"},{"name":"message","value":"commit message1"},{"name":"author","value":"login1"},{"name":"author_email","value":"user@example.com"},{"name":"state","value":"OPEN"}]`,
},
{
Expand All @@ -74,15 +74,15 @@ func TestGet(t *testing.T) {
version: resource.Version{
PR: "pr1",
Commit: "commit1",
CommittedDate: time.Time{},
ChangeTime: time.Time{},
ApprovedReviewCount: "0",
State: githubv4.PullRequestStateOpen,
},
parameters: resource.GetParameters{
IntegrationTool: "rebase",
},
pullRequest: createTestPR(1, "master", false, false, 0, nil, false, githubv4.PullRequestStateOpen),
versionString: `{"pr":"pr1","commit":"commit1","committed":"0001-01-01T00:00:00Z","approved_review_count":"0","state":"OPEN"}`,
versionString: `{"pr":"pr1","commit":"commit1","change_time":"0001-01-01T00:00:00Z","approved_review_count":"0","state":"OPEN"}`,
metadataString: `[{"name":"pr","value":"1"},{"name":"title","value":"pr1 title"},{"name":"url","value":"pr1 url"},{"name":"head_name","value":"pr1"},{"name":"head_sha","value":"oid1"},{"name":"base_name","value":"master"},{"name":"base_sha","value":"sha"},{"name":"message","value":"commit message1"},{"name":"author","value":"login1"},{"name":"author_email","value":"user@example.com"},{"name":"state","value":"OPEN"}]`,
},
{
Expand All @@ -94,15 +94,15 @@ func TestGet(t *testing.T) {
version: resource.Version{
PR: "pr1",
Commit: "commit1",
CommittedDate: time.Time{},
ChangeTime: time.Time{},
ApprovedReviewCount: "0",
State: githubv4.PullRequestStateOpen,
},
parameters: resource.GetParameters{
IntegrationTool: "checkout",
},
pullRequest: createTestPR(1, "master", false, false, 0, nil, false, githubv4.PullRequestStateOpen),
versionString: `{"pr":"pr1","commit":"commit1","committed":"0001-01-01T00:00:00Z","approved_review_count":"0","state":"OPEN"}`,
versionString: `{"pr":"pr1","commit":"commit1","change_time":"0001-01-01T00:00:00Z","approved_review_count":"0","state":"OPEN"}`,
metadataString: `[{"name":"pr","value":"1"},{"name":"title","value":"pr1 title"},{"name":"url","value":"pr1 url"},{"name":"head_name","value":"pr1"},{"name":"head_sha","value":"oid1"},{"name":"base_name","value":"master"},{"name":"base_sha","value":"sha"},{"name":"message","value":"commit message1"},{"name":"author","value":"login1"},{"name":"author_email","value":"user@example.com"},{"name":"state","value":"OPEN"}]`,
},
{
Expand All @@ -114,15 +114,15 @@ func TestGet(t *testing.T) {
version: resource.Version{
PR: "pr1",
Commit: "commit1",
CommittedDate: time.Time{},
ChangeTime: time.Time{},
ApprovedReviewCount: "0",
State: githubv4.PullRequestStateOpen,
},
parameters: resource.GetParameters{
GitDepth: 2,
},
pullRequest: createTestPR(1, "master", false, false, 0, nil, false, githubv4.PullRequestStateOpen),
versionString: `{"pr":"pr1","commit":"commit1","committed":"0001-01-01T00:00:00Z","approved_review_count":"0","state":"OPEN"}`,
versionString: `{"pr":"pr1","commit":"commit1","change_time":"0001-01-01T00:00:00Z","approved_review_count":"0","state":"OPEN"}`,
metadataString: `[{"name":"pr","value":"1"},{"name":"title","value":"pr1 title"},{"name":"url","value":"pr1 url"},{"name":"head_name","value":"pr1"},{"name":"head_sha","value":"oid1"},{"name":"base_name","value":"master"},{"name":"base_sha","value":"sha"},{"name":"message","value":"commit message1"},{"name":"author","value":"login1"},{"name":"author_email","value":"user@example.com"},{"name":"state","value":"OPEN"}]`,
},
{
Expand All @@ -134,7 +134,7 @@ func TestGet(t *testing.T) {
version: resource.Version{
PR: "pr1",
Commit: "commit1",
CommittedDate: time.Time{},
ChangeTime: time.Time{},
ApprovedReviewCount: "0",
State: githubv4.PullRequestStateOpen,
},
Expand All @@ -150,7 +150,7 @@ func TestGet(t *testing.T) {
Path: "Other.md",
},
},
versionString: `{"pr":"pr1","commit":"commit1","committed":"0001-01-01T00:00:00Z","approved_review_count":"0","state":"OPEN"}`,
versionString: `{"pr":"pr1","commit":"commit1","change_time":"0001-01-01T00:00:00Z","approved_review_count":"0","state":"OPEN"}`,
metadataString: `[{"name":"pr","value":"1"},{"name":"title","value":"pr1 title"},{"name":"url","value":"pr1 url"},{"name":"head_name","value":"pr1"},{"name":"head_sha","value":"oid1"},{"name":"base_name","value":"master"},{"name":"base_sha","value":"sha"},{"name":"message","value":"commit message1"},{"name":"author","value":"login1"},{"name":"author_email","value":"user@example.com"},{"name":"state","value":"OPEN"}]`,
filesString: "README.md\nOther.md\n",
},
Expand Down Expand Up @@ -292,9 +292,9 @@ func TestGetSkipDownload(t *testing.T) {
AccessToken: "oauthtoken",
},
version: resource.Version{
PR: "pr1",
Commit: "commit1",
CommittedDate: time.Time{},
PR: "pr1",
Commit: "commit1",
ChangeTime: time.Time{},
},
parameters: resource.GetParameters{SkipDownload: true},
},
Expand Down Expand Up @@ -361,6 +361,7 @@ func createTestPR(
State: state,
ClosedAt: githubv4.DateTime{Time: time.Now()},
MergedAt: githubv4.DateTime{Time: time.Now()},
UpdatedAt: githubv4.DateTime{Time: time.Now()},
},
Tip: resource.CommitObject{
ID: fmt.Sprintf("commit%s", n),
Expand Down
27 changes: 19 additions & 8 deletions models.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type Source struct {
RequiredReviewApprovals int `json:"required_review_approvals"`
Labels []string `json:"labels"`
States []githubv4.PullRequestState `json:"states"`
TrackNonCommitChanges bool `json:"track_non_commit_changes"`
}

// Validate the source configuration.
Expand Down Expand Up @@ -73,7 +74,7 @@ type MetadataField struct {
type Version struct {
PR string `json:"pr"`
Commit string `json:"commit"`
CommittedDate time.Time `json:"committed,omitempty"`
ChangeTime time.Time `json:"change_time,omitempty"`
ApprovedReviewCount string `json:"approved_review_count"`
State githubv4.PullRequestState `json:"state"`
}
Expand All @@ -83,7 +84,7 @@ func NewVersion(p *PullRequest) Version {
return Version{
PR: strconv.Itoa(p.Number),
Commit: p.Tip.OID,
CommittedDate: p.UpdatedDate().Time,
ChangeTime: p.ChangeTime().Time,
ApprovedReviewCount: strconv.Itoa(p.ApprovedReviewCount),
State: p.State,
}
Expand All @@ -92,9 +93,10 @@ func NewVersion(p *PullRequest) Version {
// PullRequest represents a pull request and includes the tip (commit).
type PullRequest struct {
PullRequestObject
Tip CommitObject
ApprovedReviewCount int
Labels []LabelObject
Tip CommitObject
ApprovedReviewCount int
Labels []LabelObject
TrackNonCommitChanges bool
}

// PullRequestObject represents the GraphQL commit node.
Expand All @@ -114,11 +116,20 @@ type PullRequestObject struct {
State githubv4.PullRequestState
ClosedAt githubv4.DateTime
MergedAt githubv4.DateTime
UpdatedAt githubv4.DateTime
}

// UpdatedDate returns the last time a PR was updated, either by commit
// or being closed/merged.
func (p *PullRequest) UpdatedDate() githubv4.DateTime {
// ChangeTime returns the last time a PR was updated.
// If track_non_commit_changes the time is the most recent of committed_date and updated_at.
// Otherwise, time is either by commit or close/merge.
func (p *PullRequest) ChangeTime() githubv4.DateTime {
if p.TrackNonCommitChanges {
if p.Tip.CommittedDate.Time.After(p.UpdatedAt.Time) {
return p.Tip.CommittedDate
}
return p.UpdatedAt
}

date := p.Tip.CommittedDate
switch p.State {
case githubv4.PullRequestStateClosed:
Expand Down
Loading