diff --git a/README.md b/README.md index d46077ff..30f2ee95 100644 --- a/README.md +++ b/README.md @@ -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). @@ -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). diff --git a/check.go b/check.go index 64df9e24..50babbbc 100644 --- a/check.go +++ b/check.go @@ -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 } @@ -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) { diff --git a/github.go b/github.go index ab10cbdc..55549d1a 100644 --- a/github.go +++ b/github.go @@ -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 ... @@ -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 } @@ -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, }) } } diff --git a/in_test.go b/in_test.go index 17e7abfc..31c8d205 100644 --- a/in_test.go +++ b/in_test.go @@ -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"}]`, }, { @@ -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"}]`, }, { @@ -74,7 +74,7 @@ func TestGet(t *testing.T) { version: resource.Version{ PR: "pr1", Commit: "commit1", - CommittedDate: time.Time{}, + ChangeTime: time.Time{}, ApprovedReviewCount: "0", State: githubv4.PullRequestStateOpen, }, @@ -82,7 +82,7 @@ func TestGet(t *testing.T) { 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"}]`, }, { @@ -94,7 +94,7 @@ func TestGet(t *testing.T) { version: resource.Version{ PR: "pr1", Commit: "commit1", - CommittedDate: time.Time{}, + ChangeTime: time.Time{}, ApprovedReviewCount: "0", State: githubv4.PullRequestStateOpen, }, @@ -102,7 +102,7 @@ func TestGet(t *testing.T) { 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"}]`, }, { @@ -114,7 +114,7 @@ func TestGet(t *testing.T) { version: resource.Version{ PR: "pr1", Commit: "commit1", - CommittedDate: time.Time{}, + ChangeTime: time.Time{}, ApprovedReviewCount: "0", State: githubv4.PullRequestStateOpen, }, @@ -122,7 +122,7 @@ func TestGet(t *testing.T) { 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"}]`, }, { @@ -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, }, @@ -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", }, @@ -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}, }, @@ -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), diff --git a/models.go b/models.go index 9e4e7b1c..70ea7b0a 100644 --- a/models.go +++ b/models.go @@ -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. @@ -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"` } @@ -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, } @@ -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. @@ -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: diff --git a/out_test.go b/out_test.go index 4d430c7b..22dc1bbf 100644 --- a/out_test.go +++ b/out_test.go @@ -29,9 +29,9 @@ func TestPut(t *testing.T) { AccessToken: "oauthtoken", }, version: resource.Version{ - PR: "pr1", - Commit: "commit1", - CommittedDate: time.Time{}, + PR: "pr1", + Commit: "commit1", + ChangeTime: time.Time{}, }, parameters: resource.PutParameters{}, pullRequest: createTestPR(1, "master", false, false, 0, nil, false, githubv4.PullRequestStateOpen), @@ -44,9 +44,9 @@ func TestPut(t *testing.T) { AccessToken: "oauthtoken", }, version: resource.Version{ - PR: "pr1", - Commit: "commit1", - CommittedDate: time.Time{}, + PR: "pr1", + Commit: "commit1", + ChangeTime: time.Time{}, }, parameters: resource.PutParameters{ Status: "success", @@ -61,9 +61,9 @@ func TestPut(t *testing.T) { AccessToken: "oauthtoken", }, version: resource.Version{ - PR: "pr1", - Commit: "commit1", - CommittedDate: time.Time{}, + PR: "pr1", + Commit: "commit1", + ChangeTime: time.Time{}, }, parameters: resource.PutParameters{ Status: "failure", @@ -79,9 +79,9 @@ func TestPut(t *testing.T) { AccessToken: "oauthtoken", }, version: resource.Version{ - PR: "pr1", - Commit: "commit1", - CommittedDate: time.Time{}, + PR: "pr1", + Commit: "commit1", + ChangeTime: time.Time{}, }, parameters: resource.PutParameters{ Status: "failure", @@ -98,9 +98,9 @@ func TestPut(t *testing.T) { AccessToken: "oauthtoken", }, version: resource.Version{ - PR: "pr1", - Commit: "commit1", - CommittedDate: time.Time{}, + PR: "pr1", + Commit: "commit1", + ChangeTime: time.Time{}, }, parameters: resource.PutParameters{ Status: "failure", @@ -116,9 +116,9 @@ func TestPut(t *testing.T) { AccessToken: "oauthtoken", }, version: resource.Version{ - PR: "pr1", - Commit: "commit1", - CommittedDate: time.Time{}, + PR: "pr1", + Commit: "commit1", + ChangeTime: time.Time{}, }, parameters: resource.PutParameters{ Status: "failure", @@ -134,9 +134,9 @@ func TestPut(t *testing.T) { AccessToken: "oauthtoken", }, version: resource.Version{ - PR: "pr1", - Commit: "commit1", - CommittedDate: time.Time{}, + PR: "pr1", + Commit: "commit1", + ChangeTime: time.Time{}, }, parameters: resource.PutParameters{ Comment: "comment", @@ -151,9 +151,9 @@ func TestPut(t *testing.T) { AccessToken: "oauthtoken", }, version: resource.Version{ - PR: "pr1", - Commit: "commit1", - CommittedDate: time.Time{}, + PR: "pr1", + Commit: "commit1", + ChangeTime: time.Time{}, }, parameters: resource.PutParameters{ DeletePreviousComments: true, @@ -243,9 +243,9 @@ func TestVariableSubstitution(t *testing.T) { AccessToken: "oauthtoken", }, version: resource.Version{ - PR: "pr1", - Commit: "commit1", - CommittedDate: time.Time{}, + PR: "pr1", + Commit: "commit1", + ChangeTime: time.Time{}, }, parameters: resource.PutParameters{ Comment: fmt.Sprintf("$%s", variableName), @@ -261,9 +261,9 @@ func TestVariableSubstitution(t *testing.T) { AccessToken: "oauthtoken", }, version: resource.Version{ - PR: "pr1", - Commit: "commit1", - CommittedDate: time.Time{}, + PR: "pr1", + Commit: "commit1", + ChangeTime: time.Time{}, }, parameters: resource.PutParameters{ Status: "failure", @@ -280,9 +280,9 @@ func TestVariableSubstitution(t *testing.T) { AccessToken: "oauthtoken", }, version: resource.Version{ - PR: "pr1", - Commit: "commit1", - CommittedDate: time.Time{}, + PR: "pr1", + Commit: "commit1", + ChangeTime: time.Time{}, }, parameters: resource.PutParameters{ Comment: "$THIS_IS_NOT_SUBSTITUTED",