diff --git a/docs/client/errors.go b/docs/client/errors.go index e02b0f73..adb909d1 100644 --- a/docs/client/errors.go +++ b/docs/client/errors.go @@ -112,3 +112,10 @@ func parseHTTPErrorResponse(response *http.Response) error { } return &errors } + +func handleErrorResponse(resp *http.Response) error { + if resp.StatusCode >= 400 && resp.StatusCode < 500 { + return parseHTTPErrorResponse(resp) + } + return &UnexpectedHTTPStatusError{Status: resp.Status} +} diff --git a/docs/client/layer_upload.go b/docs/client/layer_upload.go index ce0794c2..02cc5162 100644 --- a/docs/client/layer_upload.go +++ b/docs/client/layer_upload.go @@ -26,14 +26,10 @@ type httpLayerUpload struct { } func (hlu *httpLayerUpload) handleErrorResponse(resp *http.Response) error { - switch { - case resp.StatusCode == http.StatusNotFound: + if resp.StatusCode == http.StatusNotFound { return &BlobUploadNotFoundError{Location: hlu.location} - case resp.StatusCode >= 400 && resp.StatusCode < 500: - return parseHTTPErrorResponse(resp) - default: - return &UnexpectedHTTPStatusError{Status: resp.Status} } + return handleErrorResponse(resp) } func (hlu *httpLayerUpload) ReadFrom(r io.Reader) (n int64, err error) { diff --git a/docs/client/repository.go b/docs/client/repository.go index 0cda0d83..c79c306b 100644 --- a/docs/client/repository.go +++ b/docs/client/repository.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "io/ioutil" "net/http" "net/url" "strconv" @@ -90,7 +91,36 @@ type manifests struct { } func (ms *manifests) Tags() ([]string, error) { - panic("not implemented") + u, err := ms.ub.BuildTagsURL(ms.name) + if err != nil { + return nil, err + } + + resp, err := ms.client.Get(u) + if err != nil { + return nil, err + } + + switch { + case resp.StatusCode == http.StatusOK: + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + tagsResponse := struct { + Tags []string `json:"tags"` + }{} + if err := json.Unmarshal(b, &tagsResponse); err != nil { + return nil, err + } + + return tagsResponse.Tags, nil + case resp.StatusCode == http.StatusNotFound: + return nil, nil + default: + return nil, handleErrorResponse(resp) + } } func (ms *manifests) Exists(dgst digest.Digest) (bool, error) { @@ -113,10 +143,8 @@ func (ms *manifests) ExistsByTag(tag string) (bool, error) { return true, nil case resp.StatusCode == http.StatusNotFound: return false, nil - case resp.StatusCode >= 400 && resp.StatusCode < 500: - return false, parseHTTPErrorResponse(resp) default: - return false, &UnexpectedHTTPStatusError{Status: resp.Status} + return false, handleErrorResponse(resp) } } @@ -146,10 +174,8 @@ func (ms *manifests) GetByTag(tag string) (*manifest.SignedManifest, error) { } return &sm, nil - case resp.StatusCode >= 400 && resp.StatusCode < 500: - return nil, parseHTTPErrorResponse(resp) default: - return nil, &UnexpectedHTTPStatusError{Status: resp.Status} + return nil, handleErrorResponse(resp) } } @@ -174,10 +200,8 @@ func (ms *manifests) Put(m *manifest.SignedManifest) error { case resp.StatusCode == http.StatusAccepted: // TODO(dmcgowan): Use or check digest header return nil - case resp.StatusCode >= 400 && resp.StatusCode < 500: - return parseHTTPErrorResponse(resp) default: - return &UnexpectedHTTPStatusError{Status: resp.Status} + return handleErrorResponse(resp) } } @@ -200,10 +224,8 @@ func (ms *manifests) Delete(dgst digest.Digest) error { switch { case resp.StatusCode == http.StatusOK: return nil - case resp.StatusCode >= 400 && resp.StatusCode < 500: - return parseHTTPErrorResponse(resp) default: - return &UnexpectedHTTPStatusError{Status: resp.Status} + return handleErrorResponse(resp) } } @@ -275,10 +297,8 @@ func (ls *layers) Upload() (distribution.LayerUpload, error) { startedAt: time.Now(), location: location, }, nil - case resp.StatusCode >= 400 && resp.StatusCode < 500: - return nil, parseHTTPErrorResponse(resp) default: - return nil, &UnexpectedHTTPStatusError{Status: resp.Status} + return nil, handleErrorResponse(resp) } } @@ -327,9 +347,7 @@ func (ls *layers) fetchLayer(dgst digest.Digest) (distribution.Layer, error) { BlobSum: dgst, }, } - case resp.StatusCode >= 400 && resp.StatusCode < 500: - return nil, parseHTTPErrorResponse(resp) default: - return nil, &UnexpectedHTTPStatusError{Status: resp.Status} + return nil, handleErrorResponse(resp) } } diff --git a/docs/client/repository_test.go b/docs/client/repository_test.go index f53112dc..fe8ffeb7 100644 --- a/docs/client/repository_test.go +++ b/docs/client/repository_test.go @@ -9,6 +9,7 @@ import ( "log" "net/http" "net/http/httptest" + "strings" "testing" "time" @@ -602,3 +603,54 @@ func TestManifestPut(t *testing.T) { // TODO(dmcgowan): Check for error cases } + +func TestManifestTags(t *testing.T) { + repo := "test.example.com/repo/tags/list" + tagsList := []byte(strings.TrimSpace(` +{ + "name": "test.example.com/repo/tags/list", + "tags": [ + "tag1", + "tag2", + "funtag" + ] +} + `)) + var m testutil.RequestResponseMap + addPing(&m) + m = append(m, testutil.RequestResponseMapping{ + Request: testutil.Request{ + Method: "GET", + Route: "/v2/" + repo + "/tags/list", + }, + Response: testutil.Response{ + StatusCode: http.StatusOK, + Body: tagsList, + Headers: http.Header(map[string][]string{ + "Content-Length": {fmt.Sprint(len(tagsList))}, + "Last-Modified": {time.Now().Add(-1 * time.Second).Format(time.ANSIC)}, + }), + }, + }) + + e, c := testServer(m) + defer c() + + r, err := NewRepository(context.Background(), repo, e, &RepositoryConfig{}) + if err != nil { + t.Fatal(err) + } + + ms := r.Manifests() + tags, err := ms.Tags() + if err != nil { + t.Fatal(err) + } + + if len(tags) != 3 { + t.Fatalf("Wrong number of tags returned: %d, expected 3", len(tags)) + } + // TODO(dmcgowan): Check array + + // TODO(dmcgowan): Check for error cases +}