From 7fc2aaa0d950c48f32d180abc2b49ffc3f7d3bdd Mon Sep 17 00:00:00 2001 From: Charlie Moog Date: Sat, 7 Nov 2020 19:09:58 -0600 Subject: [PATCH 1/6] Add new image tags commands --- coder-sdk/tags.go | 68 +++++++++++++++ docs/coder.md | 1 + docs/coder_tags.md | 23 ++++++ docs/coder_tags_create.md | 33 ++++++++ docs/coder_tags_ls.md | 33 ++++++++ docs/coder_tags_rm.md | 32 ++++++++ internal/cmd/cmd.go | 1 + internal/cmd/tags.go | 168 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 359 insertions(+) create mode 100644 coder-sdk/tags.go create mode 100644 docs/coder_tags.md create mode 100644 docs/coder_tags_create.md create mode 100644 docs/coder_tags_ls.md create mode 100644 docs/coder_tags_rm.md create mode 100644 internal/cmd/tags.go diff --git a/coder-sdk/tags.go b/coder-sdk/tags.go new file mode 100644 index 00000000..8c7282a9 --- /dev/null +++ b/coder-sdk/tags.go @@ -0,0 +1,68 @@ +package coder + +import ( + "context" + "net/http" + "time" +) + +// ImageTag is a Docker image tag. +type ImageTag struct { + ImageID string `json:"image_id" table:"-"` + Tag string `json:"tag" table:"Tag"` + LatestHash string `json:"latest_hash" table:"-"` + HashLastUpdatedAt time.Time `json:"hash_last_updated_at" table:"-"` + OSRelease *OSRelease `json:"os_release" table:"OS"` + Environments []*Environment `json:"environments" table:"-"` + UpdatedAt time.Time `json:"updated_at" table:"UpdatedAt"` + CreatedAt time.Time `json:"created_at" table:"-"` +} + +// OSRelease is the marshalled /etc/os-release file. +type OSRelease struct { + ID string `json:"id"` + PrettyName string `json:"pretty_name"` + HomeURL string `json:"home_url"` +} + +func (o OSRelease) String() string { + return o.PrettyName +} + +// CreateImageTagReq defines the request parameters for creating a new image tag. +type CreateImageTagReq struct { + Tag string `json:"tag"` + Default bool `json:"default"` +} + +// CreateImageTag creates a new image tag resource. +func (c Client) CreateImageTag(ctx context.Context, imageID string, req CreateImageTagReq) (*ImageTag, error) { + var tag ImageTag + if err := c.requestBody(ctx, http.MethodPost, "/api/images/"+imageID+"/tags", req, tag); err != nil { + return nil, err + } + return &tag, nil +} + +// DeleteImageTag deletes an image tag resource. +func (c Client) DeleteImageTag(ctx context.Context, imageID, tag string) error { + return c.requestBody(ctx, http.MethodDelete, "/api/images/"+imageID+"/tags/"+tag, nil, nil) +} + +// ImageTags fetch all image tags. +func (c Client) ImageTags(ctx context.Context, imageID string) ([]ImageTag, error) { + var tags []ImageTag + if err := c.requestBody(ctx, http.MethodGet, "/api/images/"+imageID+"/tags", nil, &tags); err != nil { + return nil, err + } + return tags, nil +} + +// ImageTagByID fetch an image tag by ID. +func (c Client) ImageTagByID(ctx context.Context, imageID, tagID string) (*ImageTag, error) { + var tag ImageTag + if err := c.requestBody(ctx, http.MethodGet, "/api/images/"+imageID+"/tags/"+tagID, nil, &tag); err != nil { + return nil, err + } + return &tag, nil +} diff --git a/docs/coder.md b/docs/coder.md index e268d312..f9099719 100644 --- a/docs/coder.md +++ b/docs/coder.md @@ -18,6 +18,7 @@ coder provides a CLI for working with an existing Coder Enterprise installation * [coder logout](coder_logout.md) - Remove local authentication credentials if any exist * [coder sh](coder_sh.md) - Open a shell and execute commands in a Coder environment * [coder sync](coder_sync.md) - Establish a one way directory sync to a Coder environment +* [coder tags](coder_tags.md) - operate on Coder image tags * [coder urls](coder_urls.md) - Interact with environment DevURLs * [coder users](coder_users.md) - Interact with Coder user accounts diff --git a/docs/coder_tags.md b/docs/coder_tags.md new file mode 100644 index 00000000..5cf8ca00 --- /dev/null +++ b/docs/coder_tags.md @@ -0,0 +1,23 @@ +## coder tags + +operate on Coder image tags + +### Options + +``` + -h, --help help for tags +``` + +### Options inherited from parent commands + +``` + -v, --verbose show verbose output +``` + +### SEE ALSO + +* [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation +* [coder tags create](coder_tags_create.md) - +* [coder tags ls](coder_tags_ls.md) - +* [coder tags rm](coder_tags_rm.md) - + diff --git a/docs/coder_tags_create.md b/docs/coder_tags_create.md new file mode 100644 index 00000000..cc8ce253 --- /dev/null +++ b/docs/coder_tags_create.md @@ -0,0 +1,33 @@ +## coder tags create + + + +``` +coder tags create [tag] [flags] +``` + +### Examples + +``` +coder tags create latest --image ubuntu --org default +``` + +### Options + +``` + --default make this tag the default for its image + -h, --help help for create + --image string image name + --org string organization name +``` + +### Options inherited from parent commands + +``` + -v, --verbose show verbose output +``` + +### SEE ALSO + +* [coder tags](coder_tags.md) - operate on Coder image tags + diff --git a/docs/coder_tags_ls.md b/docs/coder_tags_ls.md new file mode 100644 index 00000000..423b136b --- /dev/null +++ b/docs/coder_tags_ls.md @@ -0,0 +1,33 @@ +## coder tags ls + + + +``` +coder tags ls [flags] +``` + +### Examples + +``` +coder tags ls --image ubuntu --org default --output json +``` + +### Options + +``` + -h, --help help for ls + -i, --image string image by name + --org string organization by name + --output string output format (human|json) (default "human") +``` + +### Options inherited from parent commands + +``` + -v, --verbose show verbose output +``` + +### SEE ALSO + +* [coder tags](coder_tags.md) - operate on Coder image tags + diff --git a/docs/coder_tags_rm.md b/docs/coder_tags_rm.md new file mode 100644 index 00000000..9d0b6ac6 --- /dev/null +++ b/docs/coder_tags_rm.md @@ -0,0 +1,32 @@ +## coder tags rm + + + +``` +coder tags rm [tag] [flags] +``` + +### Examples + +``` +coder tags rm latest --image ubuntu --org default +``` + +### Options + +``` + -h, --help help for rm + -i, --image string image by name + -o, --org string organization by name +``` + +### Options inherited from parent commands + +``` + -v, --verbose show verbose output +``` + +### SEE ALSO + +* [coder tags](coder_tags.md) - operate on Coder image tags + diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go index 937c0558..e7b8aa63 100644 --- a/internal/cmd/cmd.go +++ b/internal/cmd/cmd.go @@ -26,6 +26,7 @@ func Make() *cobra.Command { logoutCmd(), shCmd(), usersCmd(), + tagsCmd(), configSSHCmd(), secretsCmd(), envsCmd(), diff --git a/internal/cmd/tags.go b/internal/cmd/tags.go new file mode 100644 index 00000000..0317ba46 --- /dev/null +++ b/internal/cmd/tags.go @@ -0,0 +1,168 @@ +package cmd + +import ( + "encoding/json" + "os" + + "cdr.dev/coder-cli/coder-sdk" + "cdr.dev/coder-cli/pkg/clog" + "cdr.dev/coder-cli/pkg/tablewriter" + "github.com/spf13/cobra" + "golang.org/x/xerrors" +) + +func tagsCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "tags", + Short: "operate on Coder image tags", + } + + cmd.AddCommand( + tagsLsCmd(), + tagsCreateCmd(), + tagsRmCmd(), + ) + return cmd +} + +func tagsCreateCmd() *cobra.Command { + var ( + orgName string + imageName string + defaultTag bool + ) + cmd := &cobra.Command{ + Use: "create [tag]", + Example: `coder tags create latest --image ubuntu --org default`, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() + client, err := newClient(ctx) + if err != nil { + return err + } + img, err := findImg(ctx, client, findImgConf{ + orgName: orgName, + imgName: imageName, + email: coder.Me, + }) + if err != nil { + return xerrors.Errorf("find image: %w", err) + } + + _, err = client.CreateImageTag(ctx, img.ID, coder.CreateImageTagReq{ + Tag: args[0], + Default: defaultTag, + }) + if err != nil { + return xerrors.Errorf("create image tag: %w", err) + } + clog.LogSuccess("created new tag") + + return nil + }, + } + + cmd.Flags().StringVar(&imageName, "image", "", "image name") + cmd.Flags().StringVar(&orgName, "org", "", "organization name") + cmd.Flags().BoolVar(&defaultTag, "default", false, "make this tag the default for its image") + _ = cmd.MarkFlagRequired("org") + _ = cmd.MarkFlagRequired("image") + return cmd +} + +func tagsLsCmd() *cobra.Command { + var ( + orgName string + imageName string + outputFmt string + ) + cmd := &cobra.Command{ + Use: "ls", + Example: `coder tags ls --image ubuntu --org default --output json`, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() + client, err := newClient(ctx) + if err != nil { + return err + } + + img, err := findImg(ctx, client, findImgConf{ + email: coder.Me, + orgName: orgName, + imgName: imageName, + }) + if err != nil { + return err + } + + tags, err := client.ImageTags(ctx, img.ID) + if err != nil { + return err + } + + switch outputFmt { + case humanOutput: + err = tablewriter.WriteTable(len(tags), func(i int) interface{} { return tags[i] }) + if err != nil { + return err + } + case jsonOutput: + err := json.NewEncoder(os.Stdout).Encode(tags) + if err != nil { + return err + } + default: + return clog.Error("unknown --output value") + } + + return nil + }, + } + cmd.Flags().StringVar(&orgName, "org", "", "organization by name") + cmd.Flags().StringVarP(&imageName, "image", "i", "", "image by name") + cmd.Flags().StringVar(&outputFmt, "output", humanOutput, "output format (human|json)") + _ = cmd.MarkFlagRequired("image") + _ = cmd.MarkFlagRequired("org") + return cmd +} + +func tagsRmCmd() *cobra.Command { + var ( + imageName string + orgName string + ) + cmd := &cobra.Command{ + Use: "rm [tag]", + Example: `coder tags rm latest --image ubuntu --org default`, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() + client, err := newClient(ctx) + if err != nil { + return err + } + + img, err := findImg(ctx, client, findImgConf{ + email: coder.Me, + imgName: imageName, + orgName: orgName, + }) + if err != nil { + return err + } + + if err = client.DeleteImageTag(ctx, img.ID, args[0]); err != nil { + return err + } + clog.LogSuccess("removed tag") + + return nil + }, + } + cmd.Flags().StringVarP(&orgName, "org", "o", "", "organization by name") + cmd.Flags().StringVarP(&imageName, "image", "i", "", "image by name") + _ = cmd.MarkFlagRequired("image") + _ = cmd.MarkFlagRequired("org") + return cmd +} From 10eb0cca0ea1046b488e9c0489e80f445435c165 Mon Sep 17 00:00:00 2001 From: Charlie Moog Date: Sat, 7 Nov 2020 19:13:49 -0600 Subject: [PATCH 2/6] fixup! Add new image tags commands --- docs/coder_tags_create.md | 4 ++-- internal/cmd/tags.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/coder_tags_create.md b/docs/coder_tags_create.md index cc8ce253..e35ecf02 100644 --- a/docs/coder_tags_create.md +++ b/docs/coder_tags_create.md @@ -17,8 +17,8 @@ coder tags create latest --image ubuntu --org default ``` --default make this tag the default for its image -h, --help help for create - --image string image name - --org string organization name + -i, --image string image name + -o, --org string organization name ``` ### Options inherited from parent commands diff --git a/internal/cmd/tags.go b/internal/cmd/tags.go index 0317ba46..9b2325eb 100644 --- a/internal/cmd/tags.go +++ b/internal/cmd/tags.go @@ -63,8 +63,8 @@ func tagsCreateCmd() *cobra.Command { }, } - cmd.Flags().StringVar(&imageName, "image", "", "image name") - cmd.Flags().StringVar(&orgName, "org", "", "organization name") + cmd.Flags().StringVarP(&imageName, "image", "i", "", "image name") + cmd.Flags().StringVarP(&orgName, "org", "o", "", "organization name") cmd.Flags().BoolVar(&defaultTag, "default", false, "make this tag the default for its image") _ = cmd.MarkFlagRequired("org") _ = cmd.MarkFlagRequired("image") From 0caca7b698616c6f51ba6b54d09af2b94ae6d96d Mon Sep 17 00:00:00 2001 From: Charlie Moog Date: Sat, 7 Nov 2020 19:25:45 -0600 Subject: [PATCH 3/6] fixup! Add new image tags commands --- docs/coder_tags.md | 4 ++-- docs/coder_tags_create.md | 4 ++++ docs/coder_tags_rm.md | 2 +- internal/cmd/tags.go | 3 +++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/coder_tags.md b/docs/coder_tags.md index 5cf8ca00..663920e5 100644 --- a/docs/coder_tags.md +++ b/docs/coder_tags.md @@ -17,7 +17,7 @@ operate on Coder image tags ### SEE ALSO * [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation -* [coder tags create](coder_tags_create.md) - +* [coder tags create](coder_tags_create.md) - add an image tag * [coder tags ls](coder_tags_ls.md) - -* [coder tags rm](coder_tags_rm.md) - +* [coder tags rm](coder_tags_rm.md) - remove an image tag diff --git a/docs/coder_tags_create.md b/docs/coder_tags_create.md index e35ecf02..a4089d97 100644 --- a/docs/coder_tags_create.md +++ b/docs/coder_tags_create.md @@ -1,6 +1,10 @@ ## coder tags create +add an image tag +### Synopsis + +allow users to create environments with this image tag ``` coder tags create [tag] [flags] diff --git a/docs/coder_tags_rm.md b/docs/coder_tags_rm.md index 9d0b6ac6..c909f8df 100644 --- a/docs/coder_tags_rm.md +++ b/docs/coder_tags_rm.md @@ -1,6 +1,6 @@ ## coder tags rm - +remove an image tag ``` coder tags rm [tag] [flags] diff --git a/internal/cmd/tags.go b/internal/cmd/tags.go index 9b2325eb..7c9bbe52 100644 --- a/internal/cmd/tags.go +++ b/internal/cmd/tags.go @@ -33,6 +33,8 @@ func tagsCreateCmd() *cobra.Command { ) cmd := &cobra.Command{ Use: "create [tag]", + Short: "add an image tag", + Long: "allow users to create environments with this image tag", Example: `coder tags create latest --image ubuntu --org default`, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { @@ -134,6 +136,7 @@ func tagsRmCmd() *cobra.Command { ) cmd := &cobra.Command{ Use: "rm [tag]", + Short: "remove an image tag", Example: `coder tags rm latest --image ubuntu --org default`, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { From 1115494d774ffe387a7dd9decdbb15c47a4d5236 Mon Sep 17 00:00:00 2001 From: Charlie Moog Date: Sat, 7 Nov 2020 19:47:03 -0600 Subject: [PATCH 4/6] Add ls integration test --- ci/integration/tags_test.go | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 ci/integration/tags_test.go diff --git a/ci/integration/tags_test.go b/ci/integration/tags_test.go new file mode 100644 index 00000000..5f7c9aed --- /dev/null +++ b/ci/integration/tags_test.go @@ -0,0 +1,35 @@ +package integration + +import ( + "context" + "testing" + + "cdr.dev/coder-cli/coder-sdk" + "cdr.dev/coder-cli/pkg/tcli" + "cdr.dev/slog/sloggers/slogtest/assert" +) + +func TestTags(t *testing.T) { + t.Parallel() + run(t, "tags-cli-tests", func(t *testing.T, ctx context.Context, c *tcli.ContainerRunner) { + headlessLogin(ctx, t, c) + client := cleanupClient(ctx, t) + + ensureImageImported(ctx, t, client, "ubuntu") + + c.Run(ctx, "coder tags ls").Assert(t, + tcli.Error(), + ) + c.Run(ctx, "coder tags ls --image ubuntu --org default").Assert(t, + tcli.Success(), + ) + var tags []coder.ImageTag + c.Run(ctx, "coder tags ls --image ubuntu --org default --output json").Assert(t, + tcli.Success(), + tcli.StdoutJSONUnmarshal(&tags), + ) + assert.True(t, "> 0 tags", len(tags) > 0) + + // TODO(@cmoog) add create and rm integration tests + }) +} From 0484bd3839716e6432daaa3b1de1cb4e8725a7eb Mon Sep 17 00:00:00 2001 From: Charlie Moog Date: Sat, 7 Nov 2020 20:02:12 -0600 Subject: [PATCH 5/6] fixup! Add ls integration test --- ci/integration/tags_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/integration/tags_test.go b/ci/integration/tags_test.go index 5f7c9aed..2fb7dfe0 100644 --- a/ci/integration/tags_test.go +++ b/ci/integration/tags_test.go @@ -11,6 +11,7 @@ import ( func TestTags(t *testing.T) { t.Parallel() + t.Skip("wait for dedicated test cluster so we can create an org") run(t, "tags-cli-tests", func(t *testing.T, ctx context.Context, c *tcli.ContainerRunner) { headlessLogin(ctx, t, c) client := cleanupClient(ctx, t) From e0228262ebb8ca9a3f8ed2b1cfefd1397624ff20 Mon Sep 17 00:00:00 2001 From: Charlie Moog Date: Sat, 7 Nov 2020 20:30:07 -0600 Subject: [PATCH 6/6] Hide tags cmd --- docs/coder.md | 1 - docs/coder_tags.md | 23 ----------------------- docs/coder_tags_create.md | 37 ------------------------------------- docs/coder_tags_ls.md | 33 --------------------------------- docs/coder_tags_rm.md | 32 -------------------------------- internal/cmd/tags.go | 5 +++-- 6 files changed, 3 insertions(+), 128 deletions(-) delete mode 100644 docs/coder_tags.md delete mode 100644 docs/coder_tags_create.md delete mode 100644 docs/coder_tags_ls.md delete mode 100644 docs/coder_tags_rm.md diff --git a/docs/coder.md b/docs/coder.md index f9099719..e268d312 100644 --- a/docs/coder.md +++ b/docs/coder.md @@ -18,7 +18,6 @@ coder provides a CLI for working with an existing Coder Enterprise installation * [coder logout](coder_logout.md) - Remove local authentication credentials if any exist * [coder sh](coder_sh.md) - Open a shell and execute commands in a Coder environment * [coder sync](coder_sync.md) - Establish a one way directory sync to a Coder environment -* [coder tags](coder_tags.md) - operate on Coder image tags * [coder urls](coder_urls.md) - Interact with environment DevURLs * [coder users](coder_users.md) - Interact with Coder user accounts diff --git a/docs/coder_tags.md b/docs/coder_tags.md deleted file mode 100644 index 663920e5..00000000 --- a/docs/coder_tags.md +++ /dev/null @@ -1,23 +0,0 @@ -## coder tags - -operate on Coder image tags - -### Options - -``` - -h, --help help for tags -``` - -### Options inherited from parent commands - -``` - -v, --verbose show verbose output -``` - -### SEE ALSO - -* [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation -* [coder tags create](coder_tags_create.md) - add an image tag -* [coder tags ls](coder_tags_ls.md) - -* [coder tags rm](coder_tags_rm.md) - remove an image tag - diff --git a/docs/coder_tags_create.md b/docs/coder_tags_create.md deleted file mode 100644 index a4089d97..00000000 --- a/docs/coder_tags_create.md +++ /dev/null @@ -1,37 +0,0 @@ -## coder tags create - -add an image tag - -### Synopsis - -allow users to create environments with this image tag - -``` -coder tags create [tag] [flags] -``` - -### Examples - -``` -coder tags create latest --image ubuntu --org default -``` - -### Options - -``` - --default make this tag the default for its image - -h, --help help for create - -i, --image string image name - -o, --org string organization name -``` - -### Options inherited from parent commands - -``` - -v, --verbose show verbose output -``` - -### SEE ALSO - -* [coder tags](coder_tags.md) - operate on Coder image tags - diff --git a/docs/coder_tags_ls.md b/docs/coder_tags_ls.md deleted file mode 100644 index 423b136b..00000000 --- a/docs/coder_tags_ls.md +++ /dev/null @@ -1,33 +0,0 @@ -## coder tags ls - - - -``` -coder tags ls [flags] -``` - -### Examples - -``` -coder tags ls --image ubuntu --org default --output json -``` - -### Options - -``` - -h, --help help for ls - -i, --image string image by name - --org string organization by name - --output string output format (human|json) (default "human") -``` - -### Options inherited from parent commands - -``` - -v, --verbose show verbose output -``` - -### SEE ALSO - -* [coder tags](coder_tags.md) - operate on Coder image tags - diff --git a/docs/coder_tags_rm.md b/docs/coder_tags_rm.md deleted file mode 100644 index c909f8df..00000000 --- a/docs/coder_tags_rm.md +++ /dev/null @@ -1,32 +0,0 @@ -## coder tags rm - -remove an image tag - -``` -coder tags rm [tag] [flags] -``` - -### Examples - -``` -coder tags rm latest --image ubuntu --org default -``` - -### Options - -``` - -h, --help help for rm - -i, --image string image by name - -o, --org string organization by name -``` - -### Options inherited from parent commands - -``` - -v, --verbose show verbose output -``` - -### SEE ALSO - -* [coder tags](coder_tags.md) - operate on Coder image tags - diff --git a/internal/cmd/tags.go b/internal/cmd/tags.go index 7c9bbe52..ad77932d 100644 --- a/internal/cmd/tags.go +++ b/internal/cmd/tags.go @@ -13,8 +13,9 @@ import ( func tagsCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "tags", - Short: "operate on Coder image tags", + Use: "tags", + Hidden: true, + Short: "operate on Coder image tags", } cmd.AddCommand( pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy