From b8355e05ebb6f8cba3c72f2fe8ebe6f3465e40cd Mon Sep 17 00:00:00 2001 From: thelovekesh Date: Mon, 15 Jun 2026 18:06:57 +0530 Subject: [PATCH 1/7] Add client method to set dist tag --- pkg/pm/registry/client.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pkg/pm/registry/client.go b/pkg/pm/registry/client.go index 3593177..0e21e32 100644 --- a/pkg/pm/registry/client.go +++ b/pkg/pm/registry/client.go @@ -32,6 +32,7 @@ type Client interface { DownloadTarball(ctx context.Context, url string) (io.ReadCloser, error) PutPackage(ctx context.Context, data *manifest.Package, tarball io.Reader) error GetPackageManifest(ctx context.Context, packageName, versionOrTag string, force bool) (*manifest.Package, error) + AddDistTag(ctx context.Context, packageName, tag, version string) error } var _ Client = &client{} @@ -91,6 +92,26 @@ func (c *client) PutPackage(ctx context.Context, data *manifest.Package, tarball ) } +type distTagRequest struct { + Version string `json:"version"` +} + +// AddDistTag adds sets a tag for a specific version of a package in the registry +func (c *client) AddDistTag(ctx context.Context, packageName, tag, version string) error { + body, err := json.Marshal(distTagRequest{Version: version}) + if err != nil { + return err + } + + return c.restClient.DoWithContext( + ctx, + http.MethodPut, + "/-/dist-tags/"+packageName+"/"+tag, + bytes.NewReader(body), + nil, + ) +} + // GetPackageManifest retrieves a package manifest from the registry func (c *client) GetPackageManifest(ctx context.Context, packageName, versionOrTag string, force bool) (*manifest.Package, error) { var pkg *manifest.Package From e23fd06f46ef5a25c09132fe65221bff27330c89 Mon Sep 17 00:00:00 2001 From: thelovekesh Date: Mon, 15 Jun 2026 18:45:29 +0530 Subject: [PATCH 2/7] Update dist tag autocomp func --- cli/command/completion/functions.go | 6 +++--- cli/command/publish/publish.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/command/completion/functions.go b/cli/command/completion/functions.go index 8a6fe7f..77a771b 100644 --- a/cli/command/completion/functions.go +++ b/cli/command/completion/functions.go @@ -80,9 +80,9 @@ func PackageVisibility() cobra.CompletionFunc { ) } -// PublishTags suggests a non-exhaustive list of common dist-tags for -// `wpm publish --tag`. -func PublishTags() cobra.CompletionFunc { +// DistTags suggests a non-exhaustive list of common distribution tags, used by +// `wpm publish --tag` and `wpm dist-tag add`. +func DistTags() cobra.CompletionFunc { return func(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) { return []string{"latest", "next", "beta", "alpha"}, cobra.ShellCompDirectiveNoFileComp } diff --git a/cli/command/publish/publish.go b/cli/command/publish/publish.go index 43d3162..97fa921 100644 --- a/cli/command/publish/publish.go +++ b/cli/command/publish/publish.go @@ -59,7 +59,7 @@ func NewPublishCommand(wpmCli command.Cli) *cobra.Command { flags.StringVarP(&opts.access, "access", "a", "private", "Set the package access level to either public or private") flags.BoolVar(&opts.dryRun, "dry-run", false, "Perform a publish operation without actually publishing the package") - _ = cmd.RegisterFlagCompletionFunc("tag", completion.PublishTags()) + _ = cmd.RegisterFlagCompletionFunc("tag", completion.DistTags()) _ = cmd.RegisterFlagCompletionFunc("access", completion.PackageVisibility()) return cmd From 3827b79c533d0ffd5c6ed639e49a38af67a69576 Mon Sep 17 00:00:00 2001 From: thelovekesh Date: Mon, 15 Jun 2026 18:46:20 +0530 Subject: [PATCH 3/7] Add dist tag command --- cli/command/commands/commands.go | 2 ++ cli/command/disttag/cmd.go | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 cli/command/disttag/cmd.go diff --git a/cli/command/commands/commands.go b/cli/command/commands/commands.go index cdefeea..102e06a 100644 --- a/cli/command/commands/commands.go +++ b/cli/command/commands/commands.go @@ -5,6 +5,7 @@ import ( "go.wpm.so/cli/cli/command" "go.wpm.so/cli/cli/command/auth" + "go.wpm.so/cli/cli/command/disttag" pmInit "go.wpm.so/cli/cli/command/init" "go.wpm.so/cli/cli/command/install" "go.wpm.so/cli/cli/command/ls" @@ -22,6 +23,7 @@ func AddCommands(cmd *cobra.Command, wpmCli command.Cli) { auth.NewAuthCommand(wpmCli), pmInit.NewInitCommand(wpmCli), whoami.NewWhoamiCommand(wpmCli), + disttag.NewDistTagCommand(wpmCli), publish.NewPublishCommand(wpmCli), install.NewInstallCommand(wpmCli), outdated.NewOutdatedCommand(wpmCli), diff --git a/cli/command/disttag/cmd.go b/cli/command/disttag/cmd.go new file mode 100644 index 0000000..5f0ac1c --- /dev/null +++ b/cli/command/disttag/cmd.go @@ -0,0 +1,26 @@ +package disttag + +import ( + "github.com/spf13/cobra" + + "go.wpm.so/cli/cli" + "go.wpm.so/cli/cli/command" +) + +func NewDistTagCommand(wpmCli command.Cli) *cobra.Command { + cmd := &cobra.Command{ + Use: "dist-tag", + Short: "Manage package distribution tags", + Aliases: []string{"dist-tags"}, + Args: cli.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + cmd.SetOut(wpmCli.Out()) + cmd.HelpFunc()(cmd, args) + return nil + }, + } + + cmd.AddCommand(newAddCommand(wpmCli)) + + return cmd +} From 1d4715394d55889870233feac3a33db48e25ad6d Mon Sep 17 00:00:00 2001 From: thelovekesh Date: Mon, 15 Jun 2026 18:46:30 +0530 Subject: [PATCH 4/7] Add dist tag command docs --- docs/reference/cli/dist-tag.md | 33 +++++++++++++++++++++++++++++++++ docs/reference/cli/wpm.md | 1 + 2 files changed, 34 insertions(+) create mode 100644 docs/reference/cli/dist-tag.md diff --git a/docs/reference/cli/dist-tag.md b/docs/reference/cli/dist-tag.md new file mode 100644 index 0000000..5f2b245 --- /dev/null +++ b/docs/reference/cli/dist-tag.md @@ -0,0 +1,33 @@ +# wpm dist-tag + + + +Manage package distribution tags + +### Aliases + +`wpm dist-tag`, `wpm dist-tags` + +### Subcommands + +| Name | Description | +|:-------------------------|:--------------------------------------| +| [`add`](dist-tag_add.md) | Point a dist tag at a package version | + + + + + + +## Description + +`wpm dist-tag` groups the subcommands that manage a package's distribution tags. + +A distribution tag is a human-friendly label, such as `latest` or `beta`, that +points at a specific published version. Tags give consumers a stable name to +install against instead of pinning an exact version: `wpm install acme-blocks` +resolves through the `latest` tag to whatever version it currently points at. + +The `latest` tag is special and it is what `wpm install ` uses when no +version or tag is requested. Any other tag (`beta`, `next`, `canary`, …) is a +convention you define for your own release workflow. diff --git a/docs/reference/cli/wpm.md b/docs/reference/cli/wpm.md index 9304eee..db7c0ee 100644 --- a/docs/reference/cli/wpm.md +++ b/docs/reference/cli/wpm.md @@ -9,6 +9,7 @@ Package Manager for WordPress ecosystem | Name | Description | |:----------------------------|:-------------------------------------------------------------------| | [`auth`](auth.md) | Authenticate with the wpm registry | +| [`dist-tag`](dist-tag.md) | Manage package distribution tags | | [`init`](init.md) | Initialize a new WordPress package or init wpm in existing project | | [`install`](install.md) | Install project dependencies and add new packages | | [`ls`](ls.md) | List installed dependencies | From 6b35fddd225691f7b045bb7d729d7c7f5daa7b82 Mon Sep 17 00:00:00 2001 From: thelovekesh Date: Mon, 15 Jun 2026 19:11:18 +0530 Subject: [PATCH 5/7] Add dist-tag add sub command --- cli/command/disttag/add.go | 101 +++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 cli/command/disttag/add.go diff --git a/cli/command/disttag/add.go b/cli/command/disttag/add.go new file mode 100644 index 0000000..394ea5f --- /dev/null +++ b/cli/command/disttag/add.go @@ -0,0 +1,101 @@ +package disttag + +import ( + "context" + "errors" + "fmt" + "strings" + + "github.com/spf13/cobra" + + "go.wpm.so/cli/cli" + "go.wpm.so/cli/cli/command" + "go.wpm.so/cli/cli/command/completion" + "go.wpm.so/cli/pkg/pm/wpmjson/validator" +) + +const defaultDistTag = "latest" + +func newAddCommand(wpmCli command.Cli) *cobra.Command { + cmd := &cobra.Command{ + Use: "add PACKAGE@VERSION [TAG]", + Short: "Point a dist tag at a package version", + Args: cli.RequiresRangeArgs(1, 2), + RunE: func(cmd *cobra.Command, args []string) error { + return runAdd(cmd.Context(), wpmCli, args) + }, + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) == 1 { + return completion.DistTags()(cmd, args, toComplete) + } + return nil, cobra.ShellCompDirectiveNoFileComp + }, + } + + return cmd +} + +func runAdd(ctx context.Context, wpmCli command.Cli, args []string) error { + name, version, err := parsePackageVersion(args[0]) + if err != nil { + return err + } + + tag := defaultDistTag + if len(args) == 2 { + tag = args[1] + } + + if err := validator.IsValidDistTag(tag); err != nil { + return fmt.Errorf("invalid dist tag %q: %w", tag, err) + } + + if err := validateAuth(wpmCli); err != nil { + return err + } + + client, err := wpmCli.RegistryClient() + if err != nil { + return err + } + + if err := wpmCli.Progress().RunWithProgress( + "", + func() error { return client.AddDistTag(ctx, name, tag, version) }, + wpmCli.Err(), + ); err != nil { + return err + } + + wpmCli.Out().WriteString(fmt.Sprintf("+%s: %s@%s\n", tag, name, version)) + + return nil +} + +func validateAuth(wpmCli command.Cli) error { + cfg := wpmCli.ConfigFile() + if cfg.DefaultUser == "" || cfg.AuthToken == "" { + return errors.New("user must be logged in to perform this action") + } + return nil +} + +func parsePackageVersion(arg string) (name, version string, err error) { + lastAt := strings.LastIndex(arg, "@") + if lastAt <= 0 { + return "", "", fmt.Errorf("invalid package spec %q: expected @", arg) + } + + name = arg[:lastAt] + version = arg[lastAt+1:] + + if err := validator.IsValidPackageName(name); err != nil { + return "", "", fmt.Errorf("invalid package name %q: %w", name, err) + } + + if err := validator.IsValidVersion(version); err != nil { + return "", "", fmt.Errorf("invalid version %q: %w", version, err) + } + + return name, version, nil +} From 95b2398eb0593065b1a42ee6eeda89af0523b370 Mon Sep 17 00:00:00 2001 From: thelovekesh Date: Mon, 15 Jun 2026 19:11:28 +0530 Subject: [PATCH 6/7] Add dist-tag add subcommand docs --- docs/reference/cli/dist-tag_add.md | 45 ++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 docs/reference/cli/dist-tag_add.md diff --git a/docs/reference/cli/dist-tag_add.md b/docs/reference/cli/dist-tag_add.md new file mode 100644 index 0000000..207ee55 --- /dev/null +++ b/docs/reference/cli/dist-tag_add.md @@ -0,0 +1,45 @@ +# wpm dist-tag add + + + +Point a dist tag at a package version + + + + + +## Description + +Point a distribution tag at an already-published version of a package. + +The spec is `@`, where the version must be a concrete semantic +version that already exists in the registry and the tag always resolves to an +exact release, never to another tag. If you omit the tag, it defaults to +`latest`. + +You must be logged in (`wpm auth login`) or have `WPM_TOKEN` set, and you need +write access to the package. On success wpm prints a one-line summary: + +```console +$ wpm dist-tag add acme-blocks@1.4.0 beta ++beta: acme-blocks@1.4.0 +``` + +Moving an existing tag is the same operation as creating one: re-run `add` with +a different version and the tag is re-pointed. + +## Examples + +### Tag a version as `latest` + +```console +$ wpm dist-tag add acme-blocks@1.4.0 ++latest: acme-blocks@1.4.0 +``` + +### Create a pre-release tag + +```console +$ wpm dist-tag add acme-blocks@2.0.0-beta.1 beta ++beta: acme-blocks@2.0.0-beta.1 +``` From 9bab4ae917566c8e847d5cfc1cc180ad1562f324 Mon Sep 17 00:00:00 2001 From: thelovekesh Date: Mon, 15 Jun 2026 19:29:48 +0530 Subject: [PATCH 7/7] Update AddDistTag func comment --- pkg/pm/registry/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/pm/registry/client.go b/pkg/pm/registry/client.go index 0e21e32..5262ee6 100644 --- a/pkg/pm/registry/client.go +++ b/pkg/pm/registry/client.go @@ -96,7 +96,7 @@ type distTagRequest struct { Version string `json:"version"` } -// AddDistTag adds sets a tag for a specific version of a package in the registry +// AddDistTag sets a distribution tag to point at a specific package version in the registry. func (c *client) AddDistTag(ctx context.Context, packageName, tag, version string) error { body, err := json.Marshal(distTagRequest{Version: version}) if err != nil {