Skip to content

Commit

Permalink
Include tag in resolved references
Browse files Browse the repository at this point in the history
If a single tag is explicitly set (i.e. it's not "latest"), include that
in the reference that gets rendered in the yaml.

This is really useful for tracking releases.
  • Loading branch information
jonjohnsonjr committed Nov 7, 2019
1 parent 4833bb4 commit e980071
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 12 deletions.
36 changes: 24 additions & 12 deletions pkg/publish/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,30 +97,42 @@ func (d *defalt) Publish(img v1.Image, s string) (name.Reference, error) {
// https://github.com/google/go-containerregistry/issues/212
s = strings.ToLower(s)

for _, tagName := range d.tags {
ro := []remote.Option{remote.WithAuth(d.auth), remote.WithTransport(d.t)}
no := []name.Option{}
if d.insecure {
no = append(no, name.Insecure)
}

var os []name.Option
if d.insecure {
os = []name.Option{name.Insecure}
}
tag, err := name.NewTag(fmt.Sprintf("%s/%s:%s", d.base, d.namer(s), tagName), os...)
for i, tagName := range d.tags {
tag, err := name.NewTag(fmt.Sprintf("%s/%s:%s", d.base, d.namer(s), tagName), no...)
if err != nil {
return nil, err
}

log.Printf("Publishing %v", tag)
// TODO: This is slow because we have to load the image multiple times.
// Figure out some way to publish the manifest with another tag.
if err := remote.Write(tag, img, remote.WithAuth(d.auth), remote.WithTransport(d.t)); err != nil {
return nil, err
if i == 0 {
log.Printf("Publishing %v", tag)
if err := remote.Write(tag, img, ro...); err != nil {
return nil, err
}
} else {
log.Printf("Tagging %v", tag)
if err := remote.Tag(tag, img, ro...); err != nil {
return nil, err
}
}
}

h, err := img.Digest()
if err != nil {
return nil, err
}
dig, err := name.NewDigest(fmt.Sprintf("%s/%s@%s", d.base, d.namer(s), h))
ref := fmt.Sprintf("%s/%s@%s", d.base, d.namer(s), h)
if len(d.tags) == 1 && d.tags[0] != defaultTags[0] {
// If a single tag is explicitly set (not latest), then this
// is probably a release, so include the tag in the reference.
ref = fmt.Sprintf("%s/%s:%s@%s", d.base, d.namer(s), d.tags[0], h)
}
dig, err := name.NewDigest(ref)
if err != nil {
return nil, err
}
Expand Down
71 changes: 71 additions & 0 deletions pkg/publish/default_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,3 +221,74 @@ func TestDefaultWithTags(t *testing.T) {
t.Errorf("Tag v1.2.3 was not created.")
}
}

func TestDefaultWithReleaseTag(t *testing.T) {
img, err := random.Image(1024, 1)
if err != nil {
t.Fatalf("random.Image() = %v", err)
}
base := "blah"
releaseTag := "v1.2.3"
importpath := "github.com/Google/go-containerregistry/cmd/crane"
expectedRepo := fmt.Sprintf("%s/%s", base, strings.ToLower(importpath))
headPathPrefix := fmt.Sprintf("/v2/%s/blobs/", expectedRepo)
initiatePath := fmt.Sprintf("/v2/%s/blobs/uploads/", expectedRepo)
manifestPath := fmt.Sprintf("/v2/%s/manifests/", expectedRepo)

createdTags := make(map[string]struct{})

server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodHead && strings.HasPrefix(r.URL.Path, headPathPrefix) && r.URL.Path != initiatePath {
http.Error(w, "NotFound", http.StatusNotFound)
return
}
switch {
case r.URL.Path == "/v2/":
w.WriteHeader(http.StatusOK)
case r.URL.Path == initiatePath:
if r.Method != http.MethodPost {
t.Errorf("Method; got %v, want %v", r.Method, http.MethodPost)
}
http.Error(w, "Mounted", http.StatusCreated)
case strings.HasPrefix(r.URL.Path, manifestPath):
if r.Method != http.MethodPut {
t.Errorf("Method; got %v, want %v", r.Method, http.MethodPut)
}

createdTags[strings.TrimPrefix(r.URL.Path, manifestPath)] = struct{}{}

http.Error(w, "Created", http.StatusCreated)
default:
t.Fatalf("Unexpected path: %v", r.URL.Path)
}
}))
defer server.Close()
u, err := url.Parse(server.URL)
if err != nil {
t.Fatalf("url.Parse(%v) = %v", server.URL, err)
}
tag, err := name.NewTag(fmt.Sprintf("%s/%s:notLatest", u.Host, expectedRepo))
if err != nil {
t.Fatalf("NewTag() = %v", err)
}

repoName := fmt.Sprintf("%s/%s", u.Host, base)

def, err := NewDefault(repoName, WithTags([]string{releaseTag}))
if err != nil {
t.Errorf("NewDefault() = %v", err)
}
if d, err := def.Publish(img, importpath); err != nil {
t.Errorf("Publish() = %v", err)
} else if !strings.HasPrefix(d.String(), repoName) {
t.Errorf("Publish() = %v, wanted prefix %v", d, tag.Repository)
} else if !strings.HasSuffix(d.Context().String(), strings.ToLower(importpath)) {
t.Errorf("Publish() = %v, wanted suffix %v", d.Context(), md5Hash(importpath))
} else if !strings.Contains(d.String(), releaseTag) {
t.Errorf("Publish() = %v, wanted tag included: %v", d.String(), releaseTag)
}

if _, ok := createdTags["v1.2.3"]; !ok {
t.Errorf("Tag v1.2.3 was not created.")
}
}

0 comments on commit e980071

Please sign in to comment.