Skip to content

Commit 22869cb

Browse files
CollinShoopCollin Shoopandrewsomething
authored
registry: Add support for ListRepositoriesV2 and ListManifests commands. (#1069)
* registry: Add support for ListRepositoriesV2 and ListManifests commands. * registry: hide `list` to promote `list-v2` Co-authored-by: Andrew Starr-Bochicchio <[email protected]> Co-authored-by: Collin Shoop <[email protected]> Co-authored-by: Andrew Starr-Bochicchio <[email protected]>
1 parent b1f1b24 commit 22869cb

15 files changed

+847
-4
lines changed

commands/displayers/registry.go

+103
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,61 @@ func (r *Repository) KV() []map[string]interface{} {
104104
return out
105105
}
106106

107+
type RepositoryV2 struct {
108+
Repositories []do.RepositoryV2
109+
}
110+
111+
var _ Displayable = &Repository{}
112+
113+
func (r *RepositoryV2) JSON(out io.Writer) error {
114+
return writeJSON(r.Repositories, out)
115+
}
116+
117+
func (r *RepositoryV2) Cols() []string {
118+
return []string{
119+
"Name",
120+
"LatestManifest",
121+
"LatestTag",
122+
"TagCount",
123+
"ManifestCount",
124+
"UpdatedAt",
125+
}
126+
}
127+
128+
func (r *RepositoryV2) ColMap() map[string]string {
129+
return map[string]string{
130+
"Name": "Name",
131+
"LatestManifest": "Latest Manifest",
132+
"LatestTag": "Latest Tag",
133+
"TagCount": "Tag Count",
134+
"ManifestCount": "Manifest Count",
135+
"UpdatedAt": "Updated At",
136+
}
137+
}
138+
139+
func (r *RepositoryV2) KV() []map[string]interface{} {
140+
out := make([]map[string]interface{}, 0, len(r.Repositories))
141+
142+
for _, reg := range r.Repositories {
143+
latestTag := "<none>" // default when latest manifest has no tags
144+
if len(reg.LatestManifest.Tags) > 0 {
145+
latestTag = reg.LatestManifest.Tags[0]
146+
}
147+
m := map[string]interface{}{
148+
"Name": reg.Name,
149+
"LatestManifest": reg.LatestManifest.Digest,
150+
"LatestTag": latestTag,
151+
"TagCount": reg.TagCount,
152+
"ManifestCount": reg.ManifestCount,
153+
"UpdatedAt": reg.LatestManifest.UpdatedAt,
154+
}
155+
156+
out = append(out, m)
157+
}
158+
159+
return out
160+
}
161+
107162
type RepositoryTag struct {
108163
Tags []do.RepositoryTag
109164
}
@@ -149,6 +204,54 @@ func (r *RepositoryTag) KV() []map[string]interface{} {
149204
return out
150205
}
151206

207+
type RepositoryManifest struct {
208+
Manifests []do.RepositoryManifest
209+
}
210+
211+
var _ Displayable = &RepositoryManifest{}
212+
213+
func (r *RepositoryManifest) JSON(out io.Writer) error {
214+
return writeJSON(r.Manifests, out)
215+
}
216+
217+
func (r *RepositoryManifest) Cols() []string {
218+
return []string{
219+
"Digest",
220+
"CompressedSizeBytes",
221+
"SizeBytes",
222+
"UpdatedAt",
223+
"Tags",
224+
}
225+
}
226+
227+
func (r *RepositoryManifest) ColMap() map[string]string {
228+
return map[string]string{
229+
"Digest": "Manifest Digest",
230+
"CompressedSizeBytes": "Compressed Size",
231+
"SizeBytes": "Uncompressed Size",
232+
"UpdatedAt": "Updated At",
233+
"Tags": "Tags",
234+
}
235+
}
236+
237+
func (r *RepositoryManifest) KV() []map[string]interface{} {
238+
out := make([]map[string]interface{}, 0, len(r.Manifests))
239+
240+
for _, manifest := range r.Manifests {
241+
m := map[string]interface{}{
242+
"Digest": manifest.Digest,
243+
"CompressedSizeBytes": BytesToHumanReadableUnit(manifest.CompressedSizeBytes),
244+
"SizeBytes": BytesToHumanReadableUnit(manifest.SizeBytes),
245+
"UpdatedAt": manifest.UpdatedAt,
246+
"Tags": manifest.Tags,
247+
}
248+
249+
out = append(out, m)
250+
}
251+
252+
return out
253+
}
254+
152255
type GarbageCollection struct {
153256
GarbageCollections []do.GarbageCollection
154257
}

commands/registry.go

+80
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,22 @@ func Repository() *Command {
142142
RunListRepositories, "list",
143143
"List repositories for a container registry", listRepositoriesDesc,
144144
Writer, aliasOpt("ls"), displayerType(&displayers.Repository{}),
145+
hiddenCmd(),
146+
)
147+
148+
listRepositoriesV2Desc := `This command retrieves information about repositories in a registry, including:
149+
- The repository name
150+
- The latest manifest of the repository
151+
- The latest manifest's latest tag, if any
152+
- The number of tags in the repository
153+
- The number of manifests in the repository
154+
`
155+
156+
CmdBuilder(
157+
cmd,
158+
RunListRepositoriesV2, "list-v2",
159+
"List repositories for a container registry", listRepositoriesV2Desc,
160+
Writer, aliasOpt("ls2"), displayerType(&displayers.Repository{}),
145161
)
146162

147163
listRepositoryTagsDesc := `This command retrieves information about tags in a repository, including:
@@ -169,6 +185,21 @@ func Repository() *Command {
169185
)
170186
AddBoolFlag(cmdRunRepositoryDeleteTag, doctl.ArgForce, doctl.ArgShortForce, false, "Force tag deletion")
171187

188+
listRepositoryManifests := `This command retrieves information about manifests in a repository, including:
189+
- The manifest digest
190+
- The compressed size
191+
- The uncompressed size
192+
- The last updated timestamp
193+
- The manifest tags
194+
- The manifest blobs (available in detailed output only)
195+
`
196+
CmdBuilder(
197+
cmd,
198+
RunListRepositoryManifests, "list-manifests <repository>",
199+
"List manifests for a repository in a container registry", listRepositoryManifests,
200+
Writer, aliasOpt("lm"), displayerType(&displayers.RepositoryManifest{}),
201+
)
202+
172203
deleteManifestDesc := "This command permanently deletes one or more repository manifests by digest."
173204
cmdRunRepositoryDeleteManifest := CmdBuilder(
174205
cmd,
@@ -537,6 +568,21 @@ func RunListRepositories(c *CmdConfig) error {
537568
return displayRepositories(c, repositories...)
538569
}
539570

571+
// RunListRepositoriesV2 lists repositories for the registry
572+
func RunListRepositoriesV2(c *CmdConfig) error {
573+
registry, err := c.Registry().Get()
574+
if err != nil {
575+
return fmt.Errorf("failed to get registry: %w", err)
576+
}
577+
578+
repositories, err := c.Registry().ListRepositoriesV2(registry.Name)
579+
if err != nil {
580+
return err
581+
}
582+
583+
return displayRepositoriesV2(c, repositories...)
584+
}
585+
540586
// RunListRepositoryTags lists tags for the repository in a registry
541587
func RunListRepositoryTags(c *CmdConfig) error {
542588
err := ensureOneArg(c)
@@ -557,6 +603,26 @@ func RunListRepositoryTags(c *CmdConfig) error {
557603
return displayRepositoryTags(c, tags...)
558604
}
559605

606+
// RunListRepositoryManifests lists manifests for the repository in a registry
607+
func RunListRepositoryManifests(c *CmdConfig) error {
608+
err := ensureOneArg(c)
609+
if err != nil {
610+
return err
611+
}
612+
613+
registry, err := c.Registry().Get()
614+
if err != nil {
615+
return fmt.Errorf("failed to get registry: %w", err)
616+
}
617+
618+
manifests, err := c.Registry().ListRepositoryManifests(registry.Name, c.Args[0])
619+
if err != nil {
620+
return err
621+
}
622+
623+
return displayRepositoryManifests(c, manifests...)
624+
}
625+
560626
// RunRepositoryDeleteTag deletes one or more repository tags
561627
func RunRepositoryDeleteTag(c *CmdConfig) error {
562628
force, err := c.Doit.GetBool(c.NS, doctl.ArgForce)
@@ -645,13 +711,27 @@ func displayRepositories(c *CmdConfig, repositories ...do.Repository) error {
645711
return c.Display(item)
646712
}
647713

714+
func displayRepositoriesV2(c *CmdConfig, repositories ...do.RepositoryV2) error {
715+
item := &displayers.RepositoryV2{
716+
Repositories: repositories,
717+
}
718+
return c.Display(item)
719+
}
720+
648721
func displayRepositoryTags(c *CmdConfig, tags ...do.RepositoryTag) error {
649722
item := &displayers.RepositoryTag{
650723
Tags: tags,
651724
}
652725
return c.Display(item)
653726
}
654727

728+
func displayRepositoryManifests(c *CmdConfig, manifests ...do.RepositoryManifest) error {
729+
item := &displayers.RepositoryManifest{
730+
Manifests: manifests,
731+
}
732+
return c.Display(item)
733+
}
734+
655735
// Garbage Collection run commands
656736

657737
// RunStartGarbageCollection starts a garbage collection for the specified

0 commit comments

Comments
 (0)