diff --git a/fakes/fake_git_hub.go b/fakes/fake_git_hub.go index a4c21e8..3f9b929 100644 --- a/fakes/fake_git_hub.go +++ b/fakes/fake_git_hub.go @@ -109,6 +109,15 @@ type FakeGitHub struct { result1 *url.URL result2 error } + GetRefStub func(tag string) (*github.Reference, error) + getRefMutex sync.RWMutex + getRefArgsForCall []struct { + tag string + } + getRefReturns struct { + result1 *github.Reference + result2 error + } } func (fake *FakeGitHub) ListReleases() ([]*github.RepositoryRelease, error) { @@ -466,4 +475,37 @@ func (fake *FakeGitHub) GetZipballLinkReturns(result1 *url.URL, result2 error) { }{result1, result2} } +func (fake *FakeGitHub) GetRef(tag string) (*github.Reference, error) { + fake.getRefMutex.Lock() + fake.getRefArgsForCall = append(fake.getRefArgsForCall, struct { + tag string + }{tag}) + fake.getRefMutex.Unlock() + if fake.GetRefStub != nil { + return fake.GetRefStub(tag) + } else { + return fake.getRefReturns.result1, fake.getRefReturns.result2 + } +} + +func (fake *FakeGitHub) GetRefCallCount() int { + fake.getRefMutex.RLock() + defer fake.getRefMutex.RUnlock() + return len(fake.getRefArgsForCall) +} + +func (fake *FakeGitHub) GetRefArgsForCall(i int) string { + fake.getRefMutex.RLock() + defer fake.getRefMutex.RUnlock() + return fake.getRefArgsForCall[i].tag +} + +func (fake *FakeGitHub) GetRefReturns(result1 *github.Reference, result2 error) { + fake.GetRefStub = nil + fake.getRefReturns = struct { + result1 *github.Reference + result2 error + }{result1, result2} +} + var _ resource.GitHub = new(FakeGitHub) diff --git a/github.go b/github.go index a8e7195..71151c3 100644 --- a/github.go +++ b/github.go @@ -31,6 +31,7 @@ type GitHub interface { GetTarballLink(tag string) (*url.URL, error) GetZipballLink(tag string) (*url.URL, error) + GetRef(tag string) (*github.Reference, error) } type GitHubClient struct { @@ -247,6 +248,15 @@ func (g *GitHubClient) GetZipballLink(tag string) (*url.URL, error) { return u, nil } +func (g *GitHubClient) GetRef(tag string) (*github.Reference, error) { + ref, res, err := g.client.Git.GetRef(context.TODO(), g.owner, g.repository, "tags/"+tag) + if err != nil { + return nil, err + } + res.Body.Close() + return ref, nil +} + func oauthClient(ctx context.Context, source Source) (*http.Client, error) { ts := oauth2.StaticTokenSource(&oauth2.Token{ AccessToken: source.AccessToken, diff --git a/github_test.go b/github_test.go index 1bad6bd..18b10d0 100644 --- a/github_test.go +++ b/github_test.go @@ -189,4 +189,40 @@ var _ = Describe("GitHub Client", func() { }) }) }) + + Describe("GetRef", func() { + BeforeEach(func() { + source = Source{ + Owner: "concourse", + Repository: "concourse", + } + }) + Context("When GitHub's rate limit has been exceeded", func() { + BeforeEach(func() { + rateLimitResponse := `{ + "message": "API rate limit exceeded for 127.0.0.1. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)", + "documentation_url": "https://developer.github.com/v3/#rate-limiting" + }` + + rateLimitHeaders := http.Header(map[string][]string{ + "X-RateLimit-Limit": {"60"}, + "X-RateLimit-Remaining": {"0"}, + "X-RateLimit-Reset": {"1377013266"}, + }) + + server.AppendHandlers( + ghttp.CombineHandlers( + ghttp.VerifyRequest("GET", "/repos/concourse/concourse/git/refs/tags/some-tag"), + ghttp.RespondWith(403, rateLimitResponse, rateLimitHeaders), + ), + ) + }) + + It("Returns an appropriate error", func() { + _, err := client.GetRef("some-tag") + Expect(err).ToNot(BeNil()) + Expect(err.Error()).To(ContainSubstring("API rate limit exceeded for 127.0.0.1. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)")) + }) + }) + }) }) diff --git a/in_command_test.go b/in_command_test.go index a0818a9..e1b0760 100644 --- a/in_command_test.go +++ b/in_command_test.go @@ -86,10 +86,23 @@ var _ = Describe("In Command", func() { } } + buildTagRef := func(tagRef, commitSHA string) *github.Reference { + return &github.Reference{ + Ref: github.String(tagRef), + URL: github.String("https://example.com"), + Object: &github.GitObject{ + Type: github.String("commit"), + SHA: github.String(commitSHA), + URL: github.String("https://example.com"), + }, + } + } + Context("when there is a tagged release", func() { Context("when a present version is specified", func() { BeforeEach(func() { githubClient.GetReleaseByTagReturns(buildRelease(1, "v0.35.0", false), nil) + githubClient.GetRefReturns(buildTagRef("v0.35.0", "f28085a4a8f744da83411f5e09fd7b1709149eee"), nil) githubClient.ListReleaseAssetsReturns([]*github.ReleaseAsset{ buildAsset(0, "example.txt"), @@ -129,6 +142,7 @@ var _ = Describe("In Command", func() { resource.MetadataPair{Name: "name", Value: "release-name", URL: "http://google.com"}, resource.MetadataPair{Name: "body", Value: "*markdown*", Markdown: true}, resource.MetadataPair{Name: "tag", Value: "v0.35.0"}, + resource.MetadataPair{Name: "commit_sha", Value: "f28085a4a8f744da83411f5e09fd7b1709149eee"}, )) }) @@ -157,6 +171,10 @@ var _ = Describe("In Command", func() { Ω(err).ShouldNot(HaveOccurred()) Ω(string(contents)).Should(Equal("0.35.0")) + contents, err = ioutil.ReadFile(path.Join(destDir, "commit_sha")) + Ω(err).ShouldNot(HaveOccurred()) + Ω(string(contents)).Should(Equal("f28085a4a8f744da83411f5e09fd7b1709149eee")) + contents, err = ioutil.ReadFile(path.Join(destDir, "body")) Ω(err).ShouldNot(HaveOccurred()) Ω(string(contents)).Should(Equal("*markdown*")) @@ -343,6 +361,7 @@ var _ = Describe("In Command", func() { resource.MetadataPair{Name: "name", Value: "release-name", URL: "http://google.com"}, resource.MetadataPair{Name: "body", Value: "*markdown*", Markdown: true}, resource.MetadataPair{Name: "tag", Value: "v0.35.0"}, + resource.MetadataPair{Name: "commit_sha", Value: "f28085a4a8f744da83411f5e09fd7b1709149eee"}, )) }) @@ -416,6 +435,7 @@ var _ = Describe("In Command", func() { Context("which has a tag", func() { BeforeEach(func() { githubClient.GetReleaseReturns(buildRelease(1, "v0.35.0", true), nil) + githubClient.GetRefReturns(buildTagRef("v0.35.0", "f28085a4a8f744da83411f5e09fd7b1709149eee"), nil) inRequest.Version = &resource.Version{ID: "1"} inResponse, inErr = command.Run(destDir, inRequest) @@ -435,6 +455,7 @@ var _ = Describe("In Command", func() { resource.MetadataPair{Name: "name", Value: "release-name", URL: "http://google.com"}, resource.MetadataPair{Name: "body", Value: "*markdown*", Markdown: true}, resource.MetadataPair{Name: "tag", Value: "v0.35.0"}, + resource.MetadataPair{Name: "commit_sha", Value: "f28085a4a8f744da83411f5e09fd7b1709149eee"}, resource.MetadataPair{Name: "draft", Value: "true"}, )) }) @@ -479,6 +500,7 @@ var _ = Describe("In Command", func() { It("does not create the tag and version files", func() { Ω(path.Join(destDir, "tag")).ShouldNot(BeAnExistingFile()) Ω(path.Join(destDir, "version")).ShouldNot(BeAnExistingFile()) + Ω(path.Join(destDir, "commit_sha")).ShouldNot(BeAnExistingFile()) }) })