Repository: goreleaser/goreleaser
Pull request #4272 (2023-09-04 18:38:20)

refactor: --skip=item
Laying the ground work to allow skipping more pipes without adding new flags et al.


cloudflare-pages[bot]: ## Deploying with &nbsp;<a href="https://pages.dev"><img alt="Cloudflare Pages" src="https://user-images.githubusercontent.com/23264/106598434-9e719e00-654f-11eb-9e59-6167043cfa01.png" width="16"></a> &nbsp;Cloudflare Pages

<table><tr><td><strong>Latest commit:</strong> </td><td>
<code>ffe2773</code>
</td></tr>
<tr><td><strong>Status:</strong></td><td>⚡️&nbsp; Build in progress...</td></tr>
</table>

[View logs](https://dash.cloudflare.com/?to=/:account/pages/view/goreleaser/0d618b71-fad5-4a96-90c7-14993d5f097c)

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/goreleaser/goreleaser/pull/4272?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) Report
> Merging [#4272](https://app.codecov.io/gh/goreleaser/goreleaser/pull/4272?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) (5a590de) into [main](https://app.codecov.io/gh/goreleaser/goreleaser/commit/962429de067b3f6cde8d377beaf3194b3b258075?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) (962429d) will **decrease** coverage by `0.33%`.
> The diff coverage is `62.50%`.

```diff
@@            Coverage Diff             @@
##             main    #4272      +/-   ##
==========================================
- Coverage   84.10%   83.77%   -0.33%     
==========================================
  Files         132      133       +1     
  Lines       12523    12634     +111     
==========================================
+ Hits        10532    10584      +52     
- Misses       1586     1633      +47     
- Partials      405      417      +12     
```


| [Files Changed](https://app.codecov.io/gh/goreleaser/goreleaser/pull/4272?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) | Coverage Δ | |
|---|---|---|
| [cmd/release.go](https://app.codecov.io/gh/goreleaser/goreleaser/pull/4272?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-Y21kL3JlbGVhc2UuZ28=) | `77.43% <51.42%> (-19.79%)` | :arrow_down: |
| [cmd/build.go](https://app.codecov.io/gh/goreleaser/goreleaser/pull/4272?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-Y21kL2J1aWxkLmdv) | `76.92% <57.50%> (-5.18%)` | :arrow_down: |
| [internal/skips/skips.go](https://app.codecov.io/gh/goreleaser/goreleaser/pull/4272?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-aW50ZXJuYWwvc2tpcHMvc2tpcHMuZ28=) | `62.50% <62.50%> (ø)` | |
| [internal/pipe/announce/announce.go](https://app.codecov.io/gh/goreleaser/goreleaser/pull/4272?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-aW50ZXJuYWwvcGlwZS9hbm5vdW5jZS9hbm5vdW5jZS5nbw==) | `100.00% <100.00%> (ø)` | |
| [internal/pipe/before/before.go](https://app.codecov.io/gh/goreleaser/goreleaser/pull/4272?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-aW50ZXJuYWwvcGlwZS9iZWZvcmUvYmVmb3JlLmdv) | `100.00% <100.00%> (ø)` | |
| [internal/pipe/build/build.go](https://app.codecov.io/gh/goreleaser/goreleaser/pull/4272?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-aW50ZXJuYWwvcGlwZS9idWlsZC9idWlsZC5nbw==) | `89.71% <100.00%> (+0.05%)` | :arrow_up: |
| [internal/pipe/docker/docker.go](https://app.codecov.io/gh/goreleaser/goreleaser/pull/4272?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-aW50ZXJuYWwvcGlwZS9kb2NrZXIvZG9ja2VyLmdv) | `87.80% <100.00%> (+0.04%)` | :arrow_up: |
| [internal/pipe/docker/manifest.go](https://app.codecov.io/gh/goreleaser/goreleaser/pull/4272?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-aW50ZXJuYWwvcGlwZS9kb2NrZXIvbWFuaWZlc3QuZ28=) | `92.03% <100.00%> (ø)` | |
| [internal/pipe/env/env.go](https://app.codecov.io/gh/goreleaser/goreleaser/pull/4272?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-aW50ZXJuYWwvcGlwZS9lbnYvZW52Lmdv) | `97.60% <100.00%> (ø)` | |
| [internal/pipe/git/git.go](https://app.codecov.io/gh/goreleaser/goreleaser/pull/4272?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser#diff-aW50ZXJuYWwvcGlwZS9naXQvZ2l0Lmdv) | `86.83% <100.00%> (ø)` | |
| ... and [8 more](https://app.codecov.io/gh/goreleaser/goreleaser/pull/4272?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=goreleaser) | |



Patch:
diff --git a/.gitignore b/.gitignore
index cc30a3e7..f7d2880d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@ dist/
 bin/
 coverage.txt
 goreleaser
+gorelaser.exe
 debug.test
 snap.login
 site/
diff --git a/cmd/build.go b/cmd/build.go
index c98ec593..def126fd 100644
--- a/cmd/build.go
+++ b/cmd/build.go
@@ -5,6 +5,7 @@ import (
 	"os"
 	"path/filepath"
 	"runtime"
+	"sort"
 	"strings"
 	"time"
 
@@ -17,6 +18,7 @@ import (
 	"github.com/goreleaser/goreleaser/internal/middleware/logging"
 	"github.com/goreleaser/goreleaser/internal/middleware/skip"
 	"github.com/goreleaser/goreleaser/internal/pipeline"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/pkg/config"
 	"github.com/goreleaser/goreleaser/pkg/context"
 	"github.com/spf13/cobra"
@@ -28,21 +30,25 @@ type buildCmd struct {
 }
 
 type buildOpts struct {
-	config        string
-	ids           []string
-	snapshot      bool
-	skipValidate  bool
-	skipBefore    bool
-	skipPostHooks bool
-	clean         bool
-	deprecated    bool
-	parallelism   int
-	timeout       time.Duration
-	singleTarget  bool
-	output        string
+	config       string
+	ids          []string
+	snapshot     bool
+	clean        bool
+	deprecated   bool
+	parallelism  int
+	timeout      time.Duration
+	singleTarget bool
+	output       string
+	skips        []string
 
 	// Deprecated: use clean instead.
 	rmDist bool
+	// Deprecated: use skip instead.
+	skipValidate bool
+	// Deprecated: use skip instead.
+	skipBefore bool
+	// Deprecated: use skip instead.
+	skipPostHooks bool
 }
 
 func newBuildCmd() *buildCmd {
@@ -88,7 +94,8 @@ When using ` + "`--single-target`" + `, the ` + "`GOOS`" + ` and ` + "`GOARCH`"
 	_ = cmd.RegisterFlagCompletionFunc("timeout", cobra.NoFileCompletions)
 	cmd.Flags().BoolVar(&root.opts.singleTarget, "single-target", false, "Builds only for current GOOS and GOARCH, regardless of what's set in the configuration file")
 	cmd.Flags().StringArrayVar(&root.opts.ids, "id", nil, "Builds only the specified build ids")
-	_ = cmd.RegisterFlagCompletionFunc("id", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+	_ = cmd.RegisterFlagCompletionFunc("id", func(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
+		// TODO: improve this
 		cfg, err := loadConfig(root.opts.config)
 		if err != nil {
 			return nil, cobra.ShellCompDirectiveNoFileComp
@@ -105,6 +112,31 @@ When using ` + "`--single-target`" + `, the ` + "`GOOS`" + ` and ` + "`GOARCH`"
 	_ = cmd.Flags().MarkHidden("rm-dist")
 	_ = cmd.Flags().MarkHidden("deprecated")
 
+	for _, f := range []string{
+		"post-hooks",
+		"before",
+		"validate",
+	} {
+		_ = cmd.Flags().MarkHidden("skip-" + f)
+		_ = cmd.Flags().MarkDeprecated("skip-"+f, fmt.Sprintf("please use --skip=%s instead", f))
+	}
+	cmd.Flags().StringSliceVar(
+		&root.opts.skips,
+		"skip",
+		nil,
+		fmt.Sprintf("Skip the given options (valid options are %s)", skips.Build.String()),
+	)
+	_ = cmd.RegisterFlagCompletionFunc("skip", func(_ *cobra.Command, _ []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+		var result []string
+		for _, k := range skips.Build {
+			if strings.HasPrefix(string(k), strings.ToLower(toComplete)) {
+				result = append(result, string(k))
+			}
+		}
+		sort.Strings(result)
+		return result, cobra.ShellCompDirectiveDefault
+	})
+
 	root.cmd = cmd
 	return root
 }
@@ -150,16 +182,34 @@ func setupBuildContext(ctx *context.Context, options buildOpts) error {
 	}
 	log.Debugf("parallelism: %v", ctx.Parallelism)
 	ctx.Snapshot = options.snapshot
-	ctx.SkipValidate = ctx.Snapshot || options.skipValidate
-	ctx.SkipBefore = options.skipBefore
-	ctx.SkipPostBuildHooks = options.skipPostHooks
-	ctx.SkipTokenCheck = true
-	ctx.Clean = options.clean || options.rmDist
+	if err := skips.SetBuild(ctx, options.skips...); err != nil {
+		return err
+	}
+
+	if options.skipValidate {
+		skips.Set(ctx, skips.Validate)
+		deprecate.NoticeCustom(ctx, "-skip", "--skip-validate was deprecated in favor of --skip=validate, check {{ .URL }} for more details")
+	}
+	if options.skipBefore {
+		skips.Set(ctx, skips.Before)
+		deprecate.NoticeCustom(ctx, "-skip", "--skip-before was deprecated in favor of --skip=before, check {{ .URL }} for more details")
+	}
+	if options.skipPostHooks {
+		skips.Set(ctx, skips.PostBuildHooks)
+		deprecate.NoticeCustom(ctx, "-skip", "--skip-post-hooks was deprecated in favor of --skip=post-hooks, check {{ .URL }} for more details")
+	}
 
 	if options.rmDist {
 		deprecate.NoticeCustom(ctx, "-rm-dist", "--rm-dist was deprecated in favor of --clean, check {{ .URL }} for more details")
 	}
 
+	if ctx.Snapshot {
+		skips.Set(ctx, skips.Validate)
+	}
+
+	ctx.SkipTokenCheck = true
+	ctx.Clean = options.clean || options.rmDist
+
 	if options.singleTarget {
 		setupBuildSingleTarget(ctx)
 	}
diff --git a/cmd/release.go b/cmd/release.go
index 77fb7778..fdcca216 100644
--- a/cmd/release.go
+++ b/cmd/release.go
@@ -1,7 +1,10 @@
 package cmd
 
 import (
+	"fmt"
 	"runtime"
+	"sort"
+	"strings"
 	"time"
 
 	"github.com/caarlos0/ctrlc"
@@ -12,6 +15,7 @@ import (
 	"github.com/goreleaser/goreleaser/internal/middleware/skip"
 	"github.com/goreleaser/goreleaser/internal/pipe/git"
 	"github.com/goreleaser/goreleaser/internal/pipeline"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/pkg/context"
 	"github.com/spf13/cobra"
 )
@@ -22,31 +26,40 @@ type releaseCmd struct {
 }
 
 type releaseOpts struct {
-	config             string
-	releaseNotesFile   string
-	releaseNotesTmpl   string
-	releaseHeaderFile  string
-	releaseHeaderTmpl  string
-	releaseFooterFile  string
-	releaseFooterTmpl  string
-	autoSnapshot       bool
-	snapshot           bool
-	failFast           bool
-	skipPublish        bool
-	skipSign           bool
-	skipValidate       bool
-	skipAnnounce       bool
-	skipSBOMCataloging bool
-	skipDocker         bool
-	skipKo             bool
-	skipBefore         bool
-	clean              bool
-	deprecated         bool
-	parallelism        int
-	timeout            time.Duration
+	config            string
+	releaseNotesFile  string
+	releaseNotesTmpl  string
+	releaseHeaderFile string
+	releaseHeaderTmpl string
+	releaseFooterFile string
+	releaseFooterTmpl string
+	autoSnapshot      bool
+	snapshot          bool
+	failFast          bool
+	clean             bool
+	deprecated        bool
+	parallelism       int
+	timeout           time.Duration
+	skips             []string
 
 	// Deprecated: use clean instead.
 	rmDist bool
+	// Deprecated: use skips instead.
+	skipPublish bool
+	// Deprecated: use skips instead.
+	skipSign bool
+	// Deprecated: use skips instead.
+	skipValidate bool
+	// Deprecated: use skips instead.
+	skipAnnounce bool
+	// Deprecated: use skips instead.
+	skipSBOMCataloging bool
+	// Deprecated: use skips instead.
+	skipDocker bool
+	// Deprecated: use skips instead.
+	skipKo bool
+	// Deprecated: use skips instead.
+	skipBefore bool
 }
 
 func newReleaseCmd() *releaseCmd {
@@ -60,7 +73,7 @@ func newReleaseCmd() *releaseCmd {
 		SilenceErrors:     true,
 		Args:              cobra.NoArgs,
 		ValidArgsFunction: cobra.NoFileCompletions,
-		RunE: timedRunE("release", func(cmd *cobra.Command, args []string) error {
+		RunE: timedRunE("release", func(_ *cobra.Command, _ []string) error {
 			ctx, err := releaseProject(root.opts)
 			if err != nil {
 				return err
@@ -85,10 +98,10 @@ func newReleaseCmd() *releaseCmd {
 	cmd.Flags().StringVar(&root.opts.releaseFooterTmpl, "release-footer-tmpl", "", "Load custom release notes footer from a templated markdown file (overrides --release-footer)")
 	_ = cmd.MarkFlagFilename("release-footer-tmpl", "md", "mkd", "markdown")
 	cmd.Flags().BoolVar(&root.opts.autoSnapshot, "auto-snapshot", false, "Automatically sets --snapshot if the repository is dirty")
-	cmd.Flags().BoolVar(&root.opts.snapshot, "snapshot", false, "Generate an unversioned snapshot release, skipping all validations and without publishing any artifacts (implies --skip-publish, --skip-announce and --skip-validate)")
+	cmd.Flags().BoolVar(&root.opts.snapshot, "snapshot", false, "Generate an unversioned snapshot release, skipping all validations and without publishing any artifacts (implies --skip=announce,publish,validate)")
 	cmd.Flags().BoolVar(&root.opts.failFast, "fail-fast", false, "Whether to abort the release publishing on the first error")
-	cmd.Flags().BoolVar(&root.opts.skipPublish, "skip-publish", false, "Skips publishing artifacts (implies --skip-announce)")
-	cmd.Flags().BoolVar(&root.opts.skipAnnounce, "skip-announce", false, "Skips announcing releases (implies --skip-validate)")
+	cmd.Flags().BoolVar(&root.opts.skipPublish, "skip-publish", false, "Skips publishing artifacts (implies --skip=announce)")
+	cmd.Flags().BoolVar(&root.opts.skipAnnounce, "skip-announce", false, "Skips announcing releases (implies --skip=validate)")
 	cmd.Flags().BoolVar(&root.opts.skipSign, "skip-sign", false, "Skips signing artifacts")
 	cmd.Flags().BoolVar(&root.opts.skipSBOMCataloging, "skip-sbom", false, "Skips cataloging artifacts")
 	cmd.Flags().BoolVar(&root.opts.skipDocker, "skip-docker", false, "Skips Docker Images/Manifests builds")
@@ -105,6 +118,35 @@ func newReleaseCmd() *releaseCmd {
 	_ = cmd.Flags().MarkHidden("deprecated")
 	_ = cmd.Flags().MarkHidden("rm-dist")
 	_ = cmd.Flags().MarkDeprecated("rm-dist", "please use --clean instead")
+	for _, f := range []string{
+		"publish",
+		"announce",
+		"sign",
+		"sbom",
+		"docker",
+		"ko",
+		"before",
+		"validate",
+	} {
+		_ = cmd.Flags().MarkHidden("skip-" + f)
+		_ = cmd.Flags().MarkDeprecated("skip"+f, fmt.Sprintf("please use --skip=%s instead", f))
+	}
+	cmd.Flags().StringSliceVar(
+		&root.opts.skips,
+		"skip",
+		nil,
+		fmt.Sprintf("Skip the given options (valid options are %s)", skips.Release.String()),
+	)
+	_ = cmd.RegisterFlagCompletionFunc("skip", func(_ *cobra.Command, _ []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+		var result []string
+		for _, k := range skips.Release {
+			if strings.HasPrefix(string(k), strings.ToLower(toComplete)) {
+				result = append(result, string(k))
+			}
+		}
+		sort.Strings(result)
+		return result, cobra.ShellCompDirectiveDefault
+	})
 
 	root.cmd = cmd
 	return root
@@ -117,7 +159,9 @@ func releaseProject(options releaseOpts) (*context.Context, error) {
 	}
 	ctx, cancel := context.NewWithTimeout(cfg, options.timeout)
 	defer cancel()
-	setupReleaseContext(ctx, options)
+	if err := setupReleaseContext(ctx, options); err != nil {
+		return nil, err
+	}
 	return ctx, ctrlc.Default.Run(ctx, func() error {
 		for _, pipe := range pipeline.Pipeline {
 			if err := skip.Maybe(
@@ -134,7 +178,7 @@ func releaseProject(options releaseOpts) (*context.Context, error) {
 	})
 }
 
-func setupReleaseContext(ctx *context.Context, options releaseOpts) {
+func setupReleaseContext(ctx *context.Context, options releaseOpts) error {
 	ctx.Deprecated = options.deprecated // test only
 	ctx.Parallelism = runtime.GOMAXPROCS(0)
 	if options.parallelism > 0 {
@@ -149,21 +193,59 @@ func setupReleaseContext(ctx *context.Context, options releaseOpts) {
 	ctx.ReleaseFooterTmpl = options.releaseFooterTmpl
 	ctx.Snapshot = options.snapshot
 	ctx.FailFast = options.failFast
+	ctx.Clean = options.clean || options.rmDist
 	if options.autoSnapshot && git.CheckDirty(ctx) != nil {
 		log.Info("git repository is dirty and --auto-snapshot is set, implying --snapshot")
 		ctx.Snapshot = true
 	}
-	ctx.SkipPublish = ctx.Snapshot || options.skipPublish
-	ctx.SkipAnnounce = ctx.Snapshot || options.skipPublish || options.skipAnnounce
-	ctx.SkipValidate = ctx.Snapshot || options.skipValidate
-	ctx.SkipSign = options.skipSign
-	ctx.SkipSBOMCataloging = options.skipSBOMCataloging
-	ctx.SkipDocker = options.skipDocker
-	ctx.SkipKo = options.skipKo
-	ctx.SkipBefore = options.skipBefore
-	ctx.Clean = options.clean || options.rmDist
 
+	if err := skips.SetRelease(ctx, options.skips...); err != nil {
+		return err
+	}
+
+	// wire deprecated options
+	// XXX: remove soon
+	if options.skipPublish {
+		skips.Set(ctx, skips.Publish)
+		deprecate.NoticeCustom(ctx, "-skip", "--skip-publish was deprecated in favor of --skip=publish, check {{ .URL }} for more details")
+	}
+	if options.skipSign {
+		skips.Set(ctx, skips.Sign)
+		deprecate.NoticeCustom(ctx, "-skip", "--skip-sign was deprecated in favor of --skip=sign, check {{ .URL }} for more details")
+	}
+	if options.skipValidate {
+		skips.Set(ctx, skips.Validate)
+		deprecate.NoticeCustom(ctx, "-skip", "--skip-validate was deprecated in favor of --skip=validate, check {{ .URL }} for more details")
+	}
+	if options.skipAnnounce {
+		skips.Set(ctx, skips.Announce)
+		deprecate.NoticeCustom(ctx, "-skip", "--skip-announce was deprecated in favor of --skip=announce, check {{ .URL }} for more details")
+	}
+	if options.skipSBOMCataloging {
+		skips.Set(ctx, skips.SBOM)
+		deprecate.NoticeCustom(ctx, "-skip", "--skip-sbom was deprecated in favor of --skip=sbom, check {{ .URL }} for more details")
+	}
+	if options.skipDocker {
+		skips.Set(ctx, skips.Docker)
+		deprecate.NoticeCustom(ctx, "-skip", "--skip-docker was deprecated in favor of --skip=docker, check {{ .URL }} for more details")
+	}
+	if options.skipKo {
+		skips.Set(ctx, skips.Ko)
+		deprecate.NoticeCustom(ctx, "-skip", "--skip-ko was deprecated in favor of --skip=ko, check {{ .URL }} for more details")
+	}
+	if options.skipBefore {
+		skips.Set(ctx, skips.Before)
+		deprecate.NoticeCustom(ctx, "-skip", "--skip-before was deprecated in favor of --skip=before, check {{ .URL }} for more details")
+	}
 	if options.rmDist {
 		deprecate.NoticeCustom(ctx, "-rm-dist", "--rm-dist was deprecated in favor of --clean, check {{ .URL }} for more details")
 	}
+
+	if ctx.Snapshot {
+		skips.Set(ctx, skips.Publish, skips.Announce, skips.Validate)
+	}
+	if skips.Any(ctx, skips.Publish) {
+		skips.Set(ctx, skips.Announce)
+	}
+	return nil
 }
diff --git a/internal/pipe/announce/announce.go b/internal/pipe/announce/announce.go
index 1f7264da..af790793 100644
--- a/internal/pipe/announce/announce.go
+++ b/internal/pipe/announce/announce.go
@@ -19,6 +19,7 @@ import (
 	"github.com/goreleaser/goreleaser/internal/pipe/telegram"
 	"github.com/goreleaser/goreleaser/internal/pipe/twitter"
 	"github.com/goreleaser/goreleaser/internal/pipe/webhook"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/tmpl"
 	"github.com/goreleaser/goreleaser/pkg/context"
 )
@@ -52,7 +53,7 @@ type Pipe struct{}
 func (Pipe) String() string { return "announcing" }
 
 func (Pipe) Skip(ctx *context.Context) (bool, error) {
-	if ctx.SkipAnnounce {
+	if skips.Any(ctx, skips.Announce) {
 		return true, nil
 	}
 	return tmpl.New(ctx).Bool(ctx.Config.Announce.Skip)
diff --git a/internal/pipe/before/before.go b/internal/pipe/before/before.go
index 9f38ca38..a8fd3dd6 100644
--- a/internal/pipe/before/before.go
+++ b/internal/pipe/before/before.go
@@ -11,6 +11,7 @@ import (
 	"github.com/caarlos0/log"
 	"github.com/goreleaser/goreleaser/internal/gio"
 	"github.com/goreleaser/goreleaser/internal/logext"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/tmpl"
 	"github.com/goreleaser/goreleaser/pkg/context"
 )
@@ -19,8 +20,9 @@ import (
 type Pipe struct{}
 
 func (Pipe) String() string { return "running before hooks" }
+
 func (Pipe) Skip(ctx *context.Context) bool {
-	return len(ctx.Config.Before.Hooks) == 0 || ctx.SkipBefore
+	return len(ctx.Config.Before.Hooks) == 0 || skips.Any(ctx, skips.Before)
 }
 
 // Run executes the hooks.
diff --git a/internal/pipe/build/build.go b/internal/pipe/build/build.go
index 0dfe72fb..59032632 100644
--- a/internal/pipe/build/build.go
+++ b/internal/pipe/build/build.go
@@ -15,6 +15,7 @@ import (
 	"github.com/goreleaser/goreleaser/internal/ids"
 	"github.com/goreleaser/goreleaser/internal/semerrgroup"
 	"github.com/goreleaser/goreleaser/internal/shell"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/tmpl"
 	builders "github.com/goreleaser/goreleaser/pkg/build"
 	"github.com/goreleaser/goreleaser/pkg/config"
@@ -102,7 +103,7 @@ func runPipeOnBuild(ctx *context.Context, g semerrgroup.Group, build config.Buil
 			if err := doBuild(ctx, build, *opts); err != nil {
 				return err
 			}
-			if !ctx.SkipPostBuildHooks {
+			if !skips.Any(ctx, skips.PostBuildHooks) {
 				if err := runHook(ctx, *opts, build.Env, build.Hooks.Post); err != nil {
 					return fmt.Errorf("post hook failed: %w", err)
 				}
diff --git a/internal/pipe/chocolatey/chocolatey.go b/internal/pipe/chocolatey/chocolatey.go
index f2549792..115eb40b 100644
--- a/internal/pipe/chocolatey/chocolatey.go
+++ b/internal/pipe/chocolatey/chocolatey.go
@@ -199,7 +199,7 @@ func doPush(ctx *context.Context, art *artifact.Artifact) error {
 		choco.SourceRepo,
 		"--api-key",
 		key,
-		art.Path,
+		filepath.Clean(art.Path),
 	}
 
 	if out, err := cmd.Exec(ctx, "choco", args...); err != nil {
@@ -325,5 +325,8 @@ type stdCmd struct{}
 var _ cmder = &stdCmd{}
 
 func (stdCmd) Exec(ctx *context.Context, name string, args ...string) ([]byte, error) {
+	log.WithField("cmd", name).
+		WithField("args", args).
+		Debug("running")
 	return exec.CommandContext(ctx, name, args...).CombinedOutput()
 }
diff --git a/internal/pipe/docker/docker.go b/internal/pipe/docker/docker.go
index fd6ef378..fd2d3911 100644
--- a/internal/pipe/docker/docker.go
+++ b/internal/pipe/docker/docker.go
@@ -16,6 +16,7 @@ import (
 	"github.com/goreleaser/goreleaser/internal/ids"
 	"github.com/goreleaser/goreleaser/internal/pipe"
 	"github.com/goreleaser/goreleaser/internal/semerrgroup"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/tmpl"
 	"github.com/goreleaser/goreleaser/pkg/config"
 	"github.com/goreleaser/goreleaser/pkg/context"
@@ -31,8 +32,11 @@ const (
 // Pipe for docker.
 type Pipe struct{}
 
-func (Pipe) String() string                 { return "docker images" }
-func (Pipe) Skip(ctx *context.Context) bool { return len(ctx.Config.Dockers) == 0 || ctx.SkipDocker }
+func (Pipe) String() string { return "docker images" }
+
+func (Pipe) Skip(ctx *context.Context) bool {
+	return len(ctx.Config.Dockers) == 0 || skips.Any(ctx, skips.Docker)
+}
 
 func (Pipe) Dependencies(ctx *context.Context) []string {
 	var cmds []string
diff --git a/internal/pipe/docker/manifest.go b/internal/pipe/docker/manifest.go
index 63ce51d5..5de323a6 100644
--- a/internal/pipe/docker/manifest.go
+++ b/internal/pipe/docker/manifest.go
@@ -10,6 +10,7 @@ import (
 	"github.com/goreleaser/goreleaser/internal/ids"
 	"github.com/goreleaser/goreleaser/internal/pipe"
 	"github.com/goreleaser/goreleaser/internal/semerrgroup"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/tmpl"
 	"github.com/goreleaser/goreleaser/pkg/config"
 	"github.com/goreleaser/goreleaser/pkg/context"
@@ -20,8 +21,9 @@ import (
 type ManifestPipe struct{}
 
 func (ManifestPipe) String() string { return "docker manifests" }
+
 func (ManifestPipe) Skip(ctx *context.Context) bool {
-	return len(ctx.Config.DockerManifests) == 0 || ctx.SkipDocker
+	return len(ctx.Config.DockerManifests) == 0 || skips.Any(ctx, skips.Docker)
 }
 
 func (ManifestPipe) Dependencies(ctx *context.Context) []string {
diff --git a/internal/pipe/env/env.go b/internal/pipe/env/env.go
index edfce267..cbb157c4 100644
--- a/internal/pipe/env/env.go
+++ b/internal/pipe/env/env.go
@@ -12,6 +12,7 @@ import (
 
 	"github.com/caarlos0/log"
 	"github.com/goreleaser/goreleaser/internal/logext"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/tmpl"
 	"github.com/goreleaser/goreleaser/pkg/context"
 	homedir "github.com/mitchellh/go-homedir"
@@ -132,7 +133,7 @@ func (Pipe) Run(ctx *context.Context) error {
 }
 
 func checkErrors(ctx *context.Context, noTokens, noTokenErrs bool, gitlabTokenErr, githubTokenErr, giteaTokenErr error) error {
-	if ctx.SkipTokenCheck || ctx.SkipPublish {
+	if ctx.SkipTokenCheck || skips.Any(ctx, skips.Publish) {
 		return nil
 	}
 	if b, err := tmpl.New(ctx).Bool(ctx.Config.Release.Disable); err != nil || b {
diff --git a/internal/pipe/git/git.go b/internal/pipe/git/git.go
index 24b9ea21..2b055532 100644
--- a/internal/pipe/git/git.go
+++ b/internal/pipe/git/git.go
@@ -13,6 +13,7 @@ import (
 	"github.com/caarlos0/log"
 	"github.com/goreleaser/goreleaser/internal/git"
 	"github.com/goreleaser/goreleaser/internal/pipe"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/tmpl"
 	"github.com/goreleaser/goreleaser/pkg/context"
 )
@@ -191,7 +192,7 @@ func validate(ctx *context.Context) error {
 	if ctx.Snapshot {
 		return pipe.ErrSnapshotEnabled
 	}
-	if ctx.SkipValidate {
+	if skips.Any(ctx, skips.Validate) {
 		return pipe.ErrSkipValidateEnabled
 	}
 	if _, err := os.Stat(".git/shallow"); err == nil {
diff --git a/internal/pipe/ko/ko.go b/internal/pipe/ko/ko.go
index 58f5fff5..26e8f5a3 100644
--- a/internal/pipe/ko/ko.go
+++ b/internal/pipe/ko/ko.go
@@ -27,6 +27,7 @@ import (
 	"github.com/goreleaser/goreleaser/internal/artifact"
 	"github.com/goreleaser/goreleaser/internal/ids"
 	"github.com/goreleaser/goreleaser/internal/semerrgroup"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/tmpl"
 	"github.com/goreleaser/goreleaser/pkg/config"
 	"github.com/goreleaser/goreleaser/pkg/context"
@@ -55,7 +56,7 @@ type Pipe struct{}
 
 func (Pipe) String() string { return "ko" }
 func (Pipe) Skip(ctx *context.Context) bool {
-	return ctx.SkipKo || len(ctx.Config.Kos) == 0
+	return skips.Any(ctx, skips.Ko) || len(ctx.Config.Kos) == 0
 }
 
 // Default sets the Pipes defaults.
diff --git a/internal/pipe/nfpm/nfpm.go b/internal/pipe/nfpm/nfpm.go
index 0c89ca36..bc447885 100644
--- a/internal/pipe/nfpm/nfpm.go
+++ b/internal/pipe/nfpm/nfpm.go
@@ -15,6 +15,7 @@ import (
 	"github.com/goreleaser/goreleaser/internal/ids"
 	"github.com/goreleaser/goreleaser/internal/pipe"
 	"github.com/goreleaser/goreleaser/internal/semerrgroup"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/tmpl"
 	"github.com/goreleaser/goreleaser/pkg/config"
 	"github.com/goreleaser/goreleaser/pkg/context"
@@ -364,7 +365,7 @@ func create(ctx *context.Context, fpm config.NFPM, format string, binaries []*ar
 		},
 	}
 
-	if ctx.SkipSign {
+	if skips.Any(ctx, skips.Sign) {
 		info.APK.Signature = nfpm.APKSignature{}
 		info.RPM.Signature = nfpm.RPMSignature{}
 		info.Deb.Signature = nfpm.DebSignature{}
diff --git a/internal/pipe/publish/publish.go b/internal/pipe/publish/publish.go
index 8b57b15c..9496f2fa 100644
--- a/internal/pipe/publish/publish.go
+++ b/internal/pipe/publish/publish.go
@@ -24,6 +24,7 @@ import (
 	"github.com/goreleaser/goreleaser/internal/pipe/snapcraft"
 	"github.com/goreleaser/goreleaser/internal/pipe/upload"
 	"github.com/goreleaser/goreleaser/internal/pipe/winget"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/pkg/context"
 )
 
@@ -69,7 +70,7 @@ type Pipe struct {
 }
 
 func (Pipe) String() string                 { return "publishing" }
-func (Pipe) Skip(ctx *context.Context) bool { return ctx.SkipPublish }
+func (Pipe) Skip(ctx *context.Context) bool { return skips.Any(ctx, skips.Publish) }
 
 func (p Pipe) Run(ctx *context.Context) error {
 	memo := errhandler.Memo{}
diff --git a/internal/pipe/sbom/sbom.go b/internal/pipe/sbom/sbom.go
index bc631c28..33e9dc6b 100644
--- a/internal/pipe/sbom/sbom.go
+++ b/internal/pipe/sbom/sbom.go
@@ -15,6 +15,7 @@ import (
 	"github.com/goreleaser/goreleaser/internal/ids"
 	"github.com/goreleaser/goreleaser/internal/logext"
 	"github.com/goreleaser/goreleaser/internal/semerrgroup"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/tmpl"
 	"github.com/goreleaser/goreleaser/pkg/config"
 	"github.com/goreleaser/goreleaser/pkg/context"
@@ -28,7 +29,7 @@ type Pipe struct{}
 
 func (Pipe) String() string { return "cataloging artifacts" }
 func (Pipe) Skip(ctx *context.Context) bool {
-	return ctx.SkipSBOMCataloging || len(ctx.Config.SBOMs) == 0
+	return skips.Any(ctx, skips.SBOM) || len(ctx.Config.SBOMs) == 0
 }
 
 func (Pipe) Dependencies(ctx *context.Context) []string {
diff --git a/internal/pipe/sign/sign.go b/internal/pipe/sign/sign.go
index 51e5e6f5..01356960 100644
--- a/internal/pipe/sign/sign.go
+++ b/internal/pipe/sign/sign.go
@@ -17,6 +17,7 @@ import (
 	"github.com/goreleaser/goreleaser/internal/logext"
 	"github.com/goreleaser/goreleaser/internal/pipe"
 	"github.com/goreleaser/goreleaser/internal/semerrgroup"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/tmpl"
 	"github.com/goreleaser/goreleaser/pkg/config"
 	"github.com/goreleaser/goreleaser/pkg/context"
@@ -25,8 +26,11 @@ import (
 // Pipe that signs common artifacts.
 type Pipe struct{}
 
-func (Pipe) String() string                 { return "signing artifacts" }
-func (Pipe) Skip(ctx *context.Context) bool { return ctx.SkipSign || len(ctx.Config.Signs) == 0 }
+func (Pipe) String() string { return "signing artifacts" }
+
+func (Pipe) Skip(ctx *context.Context) bool {
+	return skips.Any(ctx, skips.Sign) || len(ctx.Config.Signs) == 0
+}
 
 func (Pipe) Dependencies(ctx *context.Context) []string {
 	var cmds []string
diff --git a/internal/pipe/sign/sign_docker.go b/internal/pipe/sign/sign_docker.go
index 0bb45ca2..eb50f987 100644
--- a/internal/pipe/sign/sign_docker.go
+++ b/internal/pipe/sign/sign_docker.go
@@ -7,6 +7,7 @@ import (
 	"github.com/goreleaser/goreleaser/internal/ids"
 	"github.com/goreleaser/goreleaser/internal/pipe"
 	"github.com/goreleaser/goreleaser/internal/semerrgroup"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/pkg/context"
 )
 
@@ -16,7 +17,7 @@ type DockerPipe struct{}
 func (DockerPipe) String() string { return "signing docker images" }
 
 func (DockerPipe) Skip(ctx *context.Context) bool {
-	return ctx.SkipSign || len(ctx.Config.DockerSigns) == 0
+	return skips.Any(ctx, skips.Sign) || len(ctx.Config.DockerSigns) == 0
 }
 
 func (DockerPipe) Dependencies(ctx *context.Context) []string {
diff --git a/internal/pipe/winget/template.go b/internal/pipe/winget/template.go
index 94c34e95..179837b2 100644
--- a/internal/pipe/winget/template.go
+++ b/internal/pipe/winget/template.go
@@ -48,10 +48,10 @@ func createYAML(ctx *context.Context, winget config.Winget, in any, tp artifact.
 }
 
 const (
-	manifestVersion         = "1.4.0"
-	versionLangServer       = "# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.4.0.schema.json"
-	installerLangServer     = "# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.4.0.schema.json"
-	defaultLocaleLangServer = "# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.4.0.schema.json"
+	manifestVersion         = "1.5.0"
+	versionLangServer       = "# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.5.0.schema.json"
+	installerLangServer     = "# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.5.0.schema.json"
+	defaultLocaleLangServer = "# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.5.0.schema.json"
 	defaultLocale           = "en-US"
 	generatedHeader         = `# This file was generated by GoReleaser. DO NOT EDIT.`
 )
diff --git a/internal/skips/skips.go b/internal/skips/skips.go
new file mode 100644
index 00000000..d094196d
--- /dev/null
+++ b/internal/skips/skips.go
@@ -0,0 +1,83 @@
+package skips
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/goreleaser/goreleaser/pkg/context"
+	"golang.org/x/exp/slices"
+)
+
+type Key string
+
+const (
+	PostBuildHooks Key = "post-hooks"
+	Publish        Key = "publish"
+	Announce       Key = "announce"
+	Sign           Key = "sign"
+	Validate       Key = "validate"
+	SBOM           Key = "sbom"
+	Ko             Key = "ko"
+	Docker         Key = "docker"
+	Before         Key = "before"
+)
+
+func Any(ctx *context.Context, keys ...Key) bool {
+	for _, key := range keys {
+		if ctx.Skips[string(key)] {
+			return true
+		}
+	}
+	return false
+}
+
+func Set(ctx *context.Context, keys ...Key) {
+	for _, key := range keys {
+		ctx.Skips[string(key)] = true
+	}
+}
+
+var (
+	SetRelease = set(Release)
+	SetBuild   = set(Build)
+)
+
+func set(allowed Keys) func(ctx *context.Context, keys ...string) error {
+	return func(ctx *context.Context, keys ...string) error {
+		for _, key := range keys {
+			if !slices.Contains(allowed, Key(key)) {
+				return fmt.Errorf("--skip=%s is not allowed. Valid options for skip are [%s]", key, allowed)
+			}
+			ctx.Skips[key] = true
+		}
+		return nil
+	}
+}
+
+type Keys []Key
+
+func (keys Keys) String() string {
+	ss := make([]string, len(keys))
+	for i, key := range keys {
+		ss[i] = string(key)
+	}
+	slices.Sort(ss)
+	return strings.Join(ss, ", ")
+}
+
+var Release = Keys{
+	Publish,
+	Announce,
+	Sign,
+	Validate,
+	SBOM,
+	Ko,
+	Docker,
+	Before,
+}
+
+var Build = Keys{
+	PostBuildHooks,
+	Validate,
+	Before,
+}
diff --git a/pkg/context/context.go b/pkg/context/context.go
index 6887290c..37033d40 100644
--- a/pkg/context/context.go
+++ b/pkg/context/context.go
@@ -72,41 +72,33 @@ const (
 // Context carries along some data through the pipes.
 type Context struct {
 	stdctx.Context
-	Config             config.Project
-	Env                Env
-	SkipTokenCheck     bool
-	Token              string
-	TokenType          TokenType
-	Git                GitInfo
-	Date               time.Time
-	Artifacts          *artifact.Artifacts
-	ReleaseURL         string
-	ReleaseNotes       string
-	ReleaseNotesFile   string
-	ReleaseNotesTmpl   string
-	ReleaseHeaderFile  string
-	ReleaseHeaderTmpl  string
-	ReleaseFooterFile  string
-	ReleaseFooterTmpl  string
-	Version            string
-	ModulePath         string
-	Snapshot           bool
-	FailFast           bool
-	SkipPostBuildHooks bool
-	SkipPublish        bool
-	SkipAnnounce       bool
-	SkipSign           bool
-	SkipValidate       bool
-	SkipSBOMCataloging bool
-	SkipKo             bool
-	SkipDocker         bool
-	SkipBefore         bool
-	Clean              bool
-	PreRelease         bool
-	Deprecated         bool
-	Parallelism        int
-	Semver             Semver
-	Runtime            Runtime
+	Config            config.Project
+	Env               Env
+	Token             string
+	TokenType         TokenType
+	Git               GitInfo
+	Date              time.Time
+	Artifacts         *artifact.Artifacts
+	ReleaseURL        string
+	ReleaseNotes      string
+	ReleaseNotesFile  string
+	ReleaseNotesTmpl  string
+	ReleaseHeaderFile string
+	ReleaseHeaderTmpl string
+	ReleaseFooterFile string
+	ReleaseFooterTmpl string
+	Version           string
+	ModulePath        string
+	Snapshot          bool
+	FailFast          bool
+	SkipTokenCheck    bool
+	Clean             bool
+	PreRelease        bool
+	Deprecated        bool
+	Parallelism       int
+	Semver            Semver
+	Runtime           Runtime
+	Skips             map[string]bool
 }
 
 type Runtime struct {
@@ -142,6 +134,7 @@ func Wrap(ctx stdctx.Context, config config.Project) *Context {
 		Parallelism: 4,
 		Artifacts:   artifact.New(),
 		Date:        time.Now(),
+		Skips:       map[string]bool{},
 		Runtime: Runtime{
 			Goos:   runtime.GOOS,
 			Goarch: runtime.GOARCH,
diff --git a/www/docs/ci/actions.md b/www/docs/ci/actions.md
index 72bb158e..6b04d769 100644
--- a/www/docs/ci/actions.md
+++ b/www/docs/ci/actions.md
@@ -13,13 +13,14 @@ configuration to `.github/workflows/release.yml`.
 Below is a simple snippet to use this action in your workflow:
 
 ```yaml
+# .github/workflows/release.yml
 name: goreleaser
 
 on:
   push:
     # run only against tags
     tags:
-      - '*'
+      - "*"
 
 permissions:
   contents: write
@@ -37,9 +38,9 @@ jobs:
       - uses: actions/setup-go@v4
         with:
           go-version: stable
-      # More assembly might be required: Docker logins, GPG, etc. It all depends
-      # on your needs.
-      - uses: goreleaser/goreleaser-action@v4
+      # More assembly might be required: Docker logins, GPG, etc.
+      # It all depends on your needs.
+      - uses: goreleaser/goreleaser-action@v5
         with:
           # either 'goreleaser' (default) or 'goreleaser-pro':
           distribution: goreleaser
@@ -53,6 +54,7 @@ jobs:
 ```
 
 !!! warning "Some things to look closely..."
+
     #### The action does not install, configure or authenticate into dependencies
     GoReleaser Action will not install nor setup any other software needed to
     release. It's the user's responsibility to install and configure Go, Docker,
@@ -71,6 +73,7 @@ jobs:
     [actions/checkout#290](https://github.com/actions/checkout/issues/290).
 
 !!! tip
+
     For detailed instructions please follow GitHub Actions [workflow syntax][syntax].
 
 ### Signing
@@ -79,69 +82,83 @@ If [signing is enabled][signing] in your GoReleaser configuration, you can use
 the [Import GPG][import-gpg] GitHub Action along with this one:
 
 ```yaml
-      -
-        name: Import GPG key
+# .github/workflows/release.yml
+jobs:
+  # ...
+  goreleaser:
+    # ...
+    steps:
+      # ...
+      - name: Import GPG key
         id: import_gpg
-        uses: crazy-max/ghaction-import-gpg@v4
+        uses: crazy-max/ghaction-import-gpg@v6
         with:
           gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
           passphrase: ${{ secrets.PASSPHRASE }}
-      -
-        name: Run GoReleaser
-        uses: goreleaser/goreleaser-action@v4
+      - name: Run GoReleaser
+        uses: goreleaser/goreleaser-action@v5
         with:
           version: latest
           args: release --clean
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
+      # ...
 ```
 
 And reference the fingerprint in your signing configuration using the
 `GPG_FINGERPRINT` environment variable:
 
 ```yaml
+# .goreleaser.yaml
 signs:
   - artifacts: checksum
-    args: ["--batch", "-u", "{{ .Env.GPG_FINGERPRINT }}", "--output", "${signature}", "--detach-sign", "${artifact}"]
+    cms: gpg2
+    args:
+      - "--batch"
+      - "-u"
+      - "{{ .Env.GPG_FINGERPRINT }}"
+      - "--output"
+      - "${signature}"
+      - "--detach-sign"
+      - "${artifact}"
 ```
 
 ## Customizing
 
-<!-- to format the tables, use: https://tabletomarkdown.com/format-markdown-table/ -->
-
 ### Inputs
 
 Following inputs can be used as `step.with` keys
 
-Name          |Type  |Default     |Description
---------------|------|------------|----------------------------------------------------------------
-`distribution`|String|`goreleaser`|GoReleaser distribution, either `goreleaser` or `goreleaser-pro`
-`version`[^1] |String|`latest`    |GoReleaser version
-`args`        |String|            |Arguments to pass to GoReleaser
-`workdir`     |String|`.`         |Working directory (below repository root)
-`install-only`|Bool  |`false`     |Just install GoReleaser
+| Name           | Type   | Default      | Description                                                      |
+| -------------- | ------ | ------------ | ---------------------------------------------------------------- |
+| `distribution` | String | `goreleaser` | GoReleaser distribution, either `goreleaser` or `goreleaser-pro` |
+| `version`[^1]  | String | `latest`     | GoReleaser version                                               |
+| `args`         | String |              | Arguments to pass to GoReleaser                                  |
+| `workdir`      | String | `.`          | Working directory (below repository root)                        |
+| `install-only` | Bool   | `false`      | Just install GoReleaser                                          |
 
-[^1]: Can be a fixed version like `v0.117.0` or a max satisfying SemVer one like
-  `~> 0.132`. In this case this will return `v0.132.1`.
+[^1]:
+    Can be a fixed version like `v0.117.0` or a max satisfying SemVer one like
+    `~> 0.132`. In this case this will return `v0.132.1`.
 
 ### Outputs
 
 Following outputs are available
 
-Name       |Type|Description
------------|----|----------------------
-`artifacts`|JSON|Build result artifacts
-`metadata` |JSON|Build result metadata
+| Name        | Type | Description            |
+| ----------- | ---- | ---------------------- |
+| `artifacts` | JSON | Build result artifacts |
+| `metadata`  | JSON | Build result metadata  |
 
 ### Environment Variables
 
 Following environment variables can be used as `step.env` keys
 
-Name            |Description
-----------------|---------------------------------------------------------------------------------------------------------------------------------------------------
-`GITHUB_TOKEN`  |[GITHUB_TOKEN](https://help.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token) as provided by `secrets`
-`GORELEASER_KEY`|Your [GoReleaser Pro](https://goreleaser.com/pro) License Key, in case you are using the `goreleaser-pro` distribution
+| Name             | Description                                                                                                                                         |
+| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `GITHUB_TOKEN`   | [GITHUB_TOKEN](https://help.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token) as provided by `secrets` |
+| `GORELEASER_KEY` | Your [GoReleaser Pro](https://goreleaser.com/pro) License Key, in case you are using the `goreleaser-pro` distribution                              |
 
 ## Token Permissions
 
@@ -149,15 +166,15 @@ The following
 [permissions](https://docs.github.com/en/actions/reference/authentication-in-a-workflow#permissions-for-the-github_token)
 are required by GoReleaser:
 
- - `contents: write` if you wish to
-    - [upload archives as GitHub Releases](/customization/release/), or
-    - publish to [Homebrew](/customization/homebrew/), or
-      [Scoop](/customization/scoop/) (assuming it's part of the same repository)
- - or just `contents: read` if you don't need any of the above
- - `packages: write` if you [push Docker images](/customization/docker/) to
-   GitHub
- - `issues: write` if you use [milestone closing
-   capability](/customization/milestone/)
+- `contents: write` if you wish to
+  - [upload archives as GitHub Releases](/customization/release/), or
+  - publish to [Homebrew](/customization/homebrew/), or
+    [Scoop](/customization/scoop/) (assuming it's part of the same repository)
+- or just `contents: read` if you don't need any of the above
+- `packages: write` if you [push Docker images](/customization/docker/) to
+  GitHub
+- `issues: write` if you use [milestone closing
+  capability](/customization/milestone/)
 
 `GITHUB_TOKEN` permissions [are limited to the repository][about-github-token]
 that contains your workflow.
@@ -168,14 +185,21 @@ secret in the repository][secrets]. If you create a secret named `GH_PAT`, the
 step will look like this:
 
 ```yaml
-      -
-        name: Run GoReleaser
-        uses: goreleaser/goreleaser-action@v4
+# .github/workflows/release.yml
+jobs:
+  # ...
+  goreleaser:
+    # ...
+    steps:
+      # ...
+      - name: Run GoReleaser
+        uses: goreleaser/goreleaser-action@v5
         with:
           version: latest
           args: release --clean
         env:
           GITHUB_TOKEN: ${{ secrets.GH_PAT }}
+      # ...
 ```
 
 You can also read the [GitHub documentation](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) about it.
diff --git a/www/docs/customization/chocolatey.md b/www/docs/customization/chocolatey.md
index e4a704d4..144055d4 100644
--- a/www/docs/customization/chocolatey.md
+++ b/www/docs/customization/chocolatey.md
@@ -29,7 +29,7 @@ chocolateys:
       - bar
 
     # Your app's owner.
-    # It basically means your.
+    # It basically means you.
     owners: Drum Roll Inc
 
     # The app's title.
diff --git a/www/docs/deprecations.md b/www/docs/deprecations.md
index 82d9547c..593cec14 100644
--- a/www/docs/deprecations.md
+++ b/www/docs/deprecations.md
@@ -37,6 +37,52 @@ Description.
 
 -->
 
+### `--skip`
+
+> since 2023-09-14
+
+The following `goreleaser release` flags were deprecated:
+
+- `--skip-announce`
+- `--skip-before`
+- `--skip-docker`
+- `--skip-ko`
+- `--skip-publish`
+- `--skip-sbom`
+- `--skip-sign`
+- `--skip-validate`
+
+By the same token, the following `goreleaser build` flags were deprecated:
+
+- `--skip-before`
+- `--skip-post-hooks`
+- `--skip-validate`
+
+All these flags are now under a single `--skip` flag, that accepts multiple
+values.
+
+=== "Before"
+
+    ```sh
+    goreleaser build --skip-before --skip-validate
+    goreleaser release --skip-validate --skip-publish
+    ```
+
+=== "After"
+
+    ```sh
+    goreleaser build --skip=before,validate
+    goreleaser release --skip=validate,publish
+
+    # or
+
+    goreleaser build --skip=before --skip=validate
+    goreleaser release --skip=validate --skip=publish
+    ```
+
+You can check `goreleaser build --help` and `goreleaser release --help` to see
+the valid options, and shell autocompletion should work properly as well.
+
 ### scoops.bucket
 
 > since 2023-06-13 (v1.19.0)


Test patch:
diff --git a/cmd/build_test.go b/cmd/build_test.go
index 1d6bb22a..7469b751 100644
--- a/cmd/build_test.go
+++ b/cmd/build_test.go
@@ -5,6 +5,7 @@ import (
 	"testing"
 
 	"github.com/goreleaser/goreleaser/internal/pipeline"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/testctx"
 	"github.com/goreleaser/goreleaser/pkg/config"
 	"github.com/goreleaser/goreleaser/pkg/context"
@@ -142,17 +143,27 @@ func TestBuildFlags(t *testing.T) {
 			snapshot: true,
 		})
 		require.True(t, ctx.Snapshot)
-		require.True(t, ctx.SkipValidate)
+		requireAll(t, ctx, skips.Validate)
 		require.True(t, ctx.SkipTokenCheck)
 	})
 
-	t.Run("skips", func(t *testing.T) {
+	t.Run("skips (old)", func(t *testing.T) {
 		ctx := setup(buildOpts{
 			skipValidate:  true,
 			skipPostHooks: true,
 		})
-		require.True(t, ctx.SkipValidate)
-		require.True(t, ctx.SkipPostBuildHooks)
+		requireAll(t, ctx, skips.Validate, skips.PostBuildHooks)
+		require.True(t, ctx.SkipTokenCheck)
+	})
+
+	t.Run("skips", func(t *testing.T) {
+		ctx := setup(buildOpts{
+			skips: []string{
+				string(skips.Validate),
+				string(skips.PostBuildHooks),
+			},
+		})
+		requireAll(t, ctx, skips.Validate, skips.PostBuildHooks)
 		require.True(t, ctx.SkipTokenCheck)
 	})
 
diff --git a/cmd/helper_test.go b/cmd/helper_test.go
new file mode 100644
index 00000000..c56c3fc9
--- /dev/null
+++ b/cmd/helper_test.go
@@ -0,0 +1,16 @@
+package cmd
+
+import (
+	"testing"
+
+	"github.com/goreleaser/goreleaser/internal/skips"
+	"github.com/goreleaser/goreleaser/pkg/context"
+	"github.com/stretchr/testify/require"
+)
+
+func requireAll(tb testing.TB, ctx *context.Context, keys ...skips.Key) {
+	tb.Helper()
+	for _, key := range keys {
+		require.True(tb, ctx.Skips[string(key)], "expected %q to be true, but was false", key)
+	}
+}
diff --git a/cmd/release_test.go b/cmd/release_test.go
index 6b7018fe..ad58b8ef 100644
--- a/cmd/release_test.go
+++ b/cmd/release_test.go
@@ -4,6 +4,7 @@ import (
 	"path/filepath"
 	"testing"
 
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/testctx"
 	"github.com/goreleaser/goreleaser/pkg/context"
 	"github.com/stretchr/testify/require"
@@ -66,21 +67,29 @@ func TestReleaseFlags(t *testing.T) {
 			snapshot: true,
 		})
 		require.True(t, ctx.Snapshot)
-		require.True(t, ctx.SkipPublish)
-		require.True(t, ctx.SkipValidate)
-		require.True(t, ctx.SkipAnnounce)
+		requireAll(t, ctx, skips.Publish, skips.Validate, skips.Announce)
 	})
 
-	t.Run("skips", func(t *testing.T) {
+	t.Run("skips (old)", func(t *testing.T) {
 		ctx := setup(t, releaseOpts{
 			skipPublish:  true,
 			skipSign:     true,
 			skipValidate: true,
 		})
-		require.True(t, ctx.SkipSign)
-		require.True(t, ctx.SkipPublish)
-		require.True(t, ctx.SkipValidate)
-		require.True(t, ctx.SkipAnnounce)
+
+		requireAll(t, ctx, skips.Sign, skips.Publish, skips.Validate, skips.Announce)
+	})
+
+	t.Run("skips", func(t *testing.T) {
+		ctx := setup(t, releaseOpts{
+			skips: []string{
+				string(skips.Publish),
+				string(skips.Sign),
+				string(skips.Validate),
+			},
+		})
+
+		requireAll(t, ctx, skips.Sign, skips.Publish, skips.Validate, skips.Announce)
 	})
 
 	t.Run("parallelism", func(t *testing.T) {
diff --git a/internal/pipe/announce/announce_test.go b/internal/pipe/announce/announce_test.go
index 6a74c2c3..270b6118 100644
--- a/internal/pipe/announce/announce_test.go
+++ b/internal/pipe/announce/announce_test.go
@@ -4,6 +4,7 @@ import (
 	"errors"
 	"testing"
 
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/testctx"
 	"github.com/goreleaser/goreleaser/pkg/config"
 	"github.com/hashicorp/go-multierror"
@@ -40,7 +41,7 @@ func TestAnnounceAllDisabled(t *testing.T) {
 
 func TestSkip(t *testing.T) {
 	t.Run("skip", func(t *testing.T) {
-		ctx := testctx.New(testctx.SkipAnnounce)
+		ctx := testctx.New(testctx.Skip(skips.Announce))
 		b, err := Pipe{}.Skip(ctx)
 		require.NoError(t, err)
 		require.True(t, b)
diff --git a/internal/pipe/before/before_test.go b/internal/pipe/before/before_test.go
index 4885386d..e0183f38 100644
--- a/internal/pipe/before/before_test.go
+++ b/internal/pipe/before/before_test.go
@@ -6,6 +6,7 @@ import (
 	"testing"
 
 	"github.com/caarlos0/log"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/testctx"
 	"github.com/goreleaser/goreleaser/internal/testlib"
 	"github.com/goreleaser/goreleaser/pkg/config"
@@ -103,8 +104,7 @@ func TestSkip(t *testing.T) {
 			Before: config.Before{
 				Hooks: []string{""},
 			},
-		})
-		ctx.SkipBefore = true
+		}, testctx.Skip(skips.Before))
 		require.True(t, Pipe{}.Skip(ctx))
 	})
 
diff --git a/internal/pipe/chocolatey/chocolatey_test.go b/internal/pipe/chocolatey/chocolatey_test.go
index d0a2bf87..f80821e4 100644
--- a/internal/pipe/chocolatey/chocolatey_test.go
+++ b/internal/pipe/chocolatey/chocolatey_test.go
@@ -53,7 +53,7 @@ func Test_doRun(t *testing.T) {
 	tests := []struct {
 		name      string
 		choco     config.Chocolatey
-		exec      func() ([]byte, error)
+		exec      func(cmd string, args ...string) ([]byte, error)
 		published int
 		err       string
 	}{
@@ -72,7 +72,7 @@ func Test_doRun(t *testing.T) {
 				Name:    "app",
 				Goamd64: "v1",
 			},
-			exec: func() ([]byte, error) {
+			exec: func(_ string, _ ...string) ([]byte, error) {
 				return nil, errors.New(`exec: "choco.exe": executable file not found in $PATH`)
 			},
 			err: `failed to generate chocolatey package: exec: "choco.exe": executable file not found in $PATH: `,
@@ -84,7 +84,8 @@ func Test_doRun(t *testing.T) {
 				Goamd64:     "v1",
 				SkipPublish: true,
 			},
-			exec: func() ([]byte, error) {
+			exec: func(cmd string, args ...string) ([]byte, error) {
+				checkPackCmd(t, cmd, args...)
 				return []byte("success"), nil
 			},
 		},
@@ -94,7 +95,8 @@ func Test_doRun(t *testing.T) {
 				Name:    "app",
 				Goamd64: "v1",
 			},
-			exec: func() ([]byte, error) {
+			exec: func(cmd string, args ...string) ([]byte, error) {
+				checkPackCmd(t, cmd, args...)
 				return []byte("success"), nil
 			},
 			published: 1,
@@ -213,10 +215,13 @@ func TestPublish(t *testing.T) {
 	file := filepath.Join(folder, "archive")
 	require.NoError(t, os.WriteFile(file, []byte("lorem ipsum"), 0o644))
 
+	fakenu := filepath.Join(t.TempDir(), "foo.nupkg")
+	require.NoError(t, os.WriteFile(fakenu, []byte("fake nupkg"), 0o644))
+
 	tests := []struct {
 		name      string
 		artifacts []artifact.Artifact
-		exec      func() ([]byte, error)
+		exec      func(cmd string, args ...string) ([]byte, error)
 		skip      bool
 		err       string
 	}{
@@ -250,7 +255,7 @@ func TestPublish(t *testing.T) {
 					},
 				},
 			},
-			exec: func() ([]byte, error) {
+			exec: func(cmd string, args ...string) ([]byte, error) {
 				return nil, errors.New(`unable to push`)
 			},
 			err: "failed to push chocolatey package: unable to push: ",
@@ -261,15 +266,18 @@ func TestPublish(t *testing.T) {
 				{
 					Type: artifact.PublishableChocolatey,
 					Name: "app.1.0.1.nupkg",
+					Path: fakenu,
 					Extra: map[string]interface{}{
 						artifact.ExtraFormat: nupkgFormat,
 						chocoConfigExtra: config.Chocolatey{
-							APIKey: "abcd",
+							APIKey:     "abcd",
+							SourceRepo: "abc",
 						},
 					},
 				},
 			},
-			exec: func() ([]byte, error) {
+			exec: func(cmd string, args ...string) ([]byte, error) {
+				checkPushCmd(t, cmd, args...)
 				return []byte("success"), nil
 			},
 		},
@@ -305,11 +313,28 @@ func TestDependencies(t *testing.T) {
 }
 
 type fakeCmd struct {
-	execFn func() ([]byte, error)
+	execFn func(cmd string, args ...string) ([]byte, error)
 }
 
 var _ cmder = fakeCmd{}
 
-func (f fakeCmd) Exec(_ *context.Context, _ string, _ ...string) ([]byte, error) {
-	return f.execFn()
+func (f fakeCmd) Exec(_ *context.Context, cmd string, args ...string) ([]byte, error) {
+	return f.execFn(cmd, args...)
+}
+
+func checkPushCmd(tb testing.TB, cmd string, args ...string) {
+	tb.Helper()
+	tb.Log("would have run:", cmd, args)
+	require.Len(tb, args, 6)
+	require.Equal(tb, cmd, "choco")
+	require.FileExists(tb, args[5])
+}
+
+func checkPackCmd(tb testing.TB, cmd string, args ...string) {
+	tb.Helper()
+	tb.Log("would have run:", cmd, args)
+	require.Len(tb, args, 4)
+	require.Equal(tb, cmd, "choco")
+	require.FileExists(tb, args[1])
+	require.DirExists(tb, args[3])
 }
diff --git a/internal/pipe/docker/docker_test.go b/internal/pipe/docker/docker_test.go
index bb1176c7..4c011281 100644
--- a/internal/pipe/docker/docker_test.go
+++ b/internal/pipe/docker/docker_test.go
@@ -10,6 +10,7 @@ import (
 
 	"github.com/goreleaser/goreleaser/internal/artifact"
 	"github.com/goreleaser/goreleaser/internal/pipe"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/testctx"
 	"github.com/goreleaser/goreleaser/internal/testlib"
 	"github.com/goreleaser/goreleaser/pkg/config"
@@ -1343,8 +1344,7 @@ func TestSkip(t *testing.T) {
 		t.Run("skip docker", func(t *testing.T) {
 			ctx := testctx.NewWithCfg(config.Project{
 				Dockers: []config.Docker{{}},
-			})
-			ctx.SkipDocker = true
+			}, testctx.Skip(skips.Docker))
 			require.True(t, Pipe{}.Skip(ctx))
 		})
 
@@ -1364,7 +1364,7 @@ func TestSkip(t *testing.T) {
 		t.Run("skip docker", func(t *testing.T) {
 			ctx := testctx.NewWithCfg(config.Project{
 				DockerManifests: []config.DockerManifest{{}},
-			}, testctx.SkipDocker)
+			}, testctx.Skip(skips.Docker))
 			require.True(t, ManifestPipe{}.Skip(ctx))
 		})
 
diff --git a/internal/pipe/env/env_test.go b/internal/pipe/env/env_test.go
index 0c6a4c6d..78c6fe21 100644
--- a/internal/pipe/env/env_test.go
+++ b/internal/pipe/env/env_test.go
@@ -6,6 +6,7 @@ import (
 	"syscall"
 	"testing"
 
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/testctx"
 	"github.com/goreleaser/goreleaser/internal/testlib"
 	"github.com/goreleaser/goreleaser/pkg/config"
@@ -220,7 +221,7 @@ func TestEmptyGiteaEnvFile(t *testing.T) {
 }
 
 func TestInvalidEnvChecksSkipped(t *testing.T) {
-	ctx := testctx.New(testctx.SkipPublish)
+	ctx := testctx.New(testctx.Skip(skips.Publish))
 	require.NoError(t, Pipe{}.Run(ctx))
 }
 
diff --git a/internal/pipe/git/git_test.go b/internal/pipe/git/git_test.go
index 15c8cdad..1f331267 100644
--- a/internal/pipe/git/git_test.go
+++ b/internal/pipe/git/git_test.go
@@ -6,6 +6,7 @@ import (
 	"path/filepath"
 	"testing"
 
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/testctx"
 	"github.com/goreleaser/goreleaser/internal/testlib"
 	"github.com/goreleaser/goreleaser/pkg/config"
@@ -112,7 +113,7 @@ func TestDirty(t *testing.T) {
 		require.Contains(t, err.Error(), "git is in a dirty state")
 	})
 	t.Run("skip validate is set", func(t *testing.T) {
-		ctx := testctx.New(testctx.SkipValidate)
+		ctx := testctx.New(testctx.Skip(skips.Validate))
 		testlib.AssertSkipped(t, Pipe{}.Run(ctx))
 		require.True(t, ctx.Git.Dirty)
 	})
@@ -162,7 +163,7 @@ func TestShallowClone(t *testing.T) {
 		require.NoError(t, Pipe{}.Run(testctx.New()))
 	})
 	t.Run("skip validate is set", func(t *testing.T) {
-		ctx := testctx.New(testctx.SkipValidate)
+		ctx := testctx.New(testctx.Skip(skips.Validate))
 		testlib.AssertSkipped(t, Pipe{}.Run(ctx))
 	})
 	t.Run("snapshot", func(t *testing.T) {
diff --git a/internal/pipe/ko/ko_test.go b/internal/pipe/ko/ko_test.go
index 48826043..43c83b6e 100644
--- a/internal/pipe/ko/ko_test.go
+++ b/internal/pipe/ko/ko_test.go
@@ -12,6 +12,7 @@ import (
 	"github.com/google/go-containerregistry/pkg/name"
 	"github.com/google/go-containerregistry/pkg/v1/remote"
 	"github.com/goreleaser/goreleaser/internal/artifact"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/testctx"
 	"github.com/goreleaser/goreleaser/internal/testlib"
 	"github.com/goreleaser/goreleaser/pkg/config"
@@ -88,8 +89,7 @@ func TestSkip(t *testing.T) {
 	t.Run("skip ko set", func(t *testing.T) {
 		ctx := testctx.NewWithCfg(config.Project{
 			Kos: []config.Ko{{}},
-		})
-		ctx.SkipKo = true
+		}, testctx.Skip(skips.Ko))
 		require.True(t, Pipe{}.Skip(ctx))
 	})
 	t.Run("skip no kos", func(t *testing.T) {
diff --git a/internal/pipe/nfpm/nfpm_test.go b/internal/pipe/nfpm/nfpm_test.go
index 5c86cab4..d5396a62 100644
--- a/internal/pipe/nfpm/nfpm_test.go
+++ b/internal/pipe/nfpm/nfpm_test.go
@@ -6,6 +6,7 @@ import (
 	"testing"
 
 	"github.com/goreleaser/goreleaser/internal/artifact"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/testctx"
 	"github.com/goreleaser/goreleaser/internal/testlib"
 	"github.com/goreleaser/goreleaser/pkg/config"
@@ -1327,7 +1328,7 @@ func TestSkipSign(t *testing.T) {
 	})
 
 	t.Run("skip sign set", func(t *testing.T) {
-		ctx.SkipSign = true
+		skips.Set(ctx, skips.Sign)
 		require.NoError(t, Pipe{}.Run(ctx))
 	})
 }
diff --git a/internal/pipe/publish/publish_test.go b/internal/pipe/publish/publish_test.go
index 3d4daa11..eb0798f3 100644
--- a/internal/pipe/publish/publish_test.go
+++ b/internal/pipe/publish/publish_test.go
@@ -5,6 +5,7 @@ import (
 	"testing"
 
 	"github.com/goreleaser/goreleaser/internal/pipe"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/testctx"
 	"github.com/goreleaser/goreleaser/pkg/config"
 	"github.com/goreleaser/goreleaser/pkg/context"
@@ -72,7 +73,7 @@ func TestPublishError(t *testing.T) {
 
 func TestSkip(t *testing.T) {
 	t.Run("skip", func(t *testing.T) {
-		ctx := testctx.New(testctx.SkipPublish)
+		ctx := testctx.New(testctx.Skip(skips.Publish))
 		require.True(t, Pipe{}.Skip(ctx))
 	})
 
diff --git a/internal/pipe/sbom/sbom_test.go b/internal/pipe/sbom/sbom_test.go
index e33dbebd..60643857 100644
--- a/internal/pipe/sbom/sbom_test.go
+++ b/internal/pipe/sbom/sbom_test.go
@@ -9,6 +9,7 @@ import (
 	"testing"
 
 	"github.com/goreleaser/goreleaser/internal/artifact"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/testctx"
 	"github.com/goreleaser/goreleaser/internal/testlib"
 	"github.com/goreleaser/goreleaser/internal/tmpl"
@@ -199,8 +200,7 @@ func TestSkipCataloging(t *testing.T) {
 					Artifacts: "all",
 				},
 			},
-		})
-		ctx.SkipSBOMCataloging = true
+		}, testctx.Skip(skips.SBOM))
 		require.True(t, Pipe{}.Skip(ctx))
 	})
 
diff --git a/internal/pipe/sign/sign_docker_test.go b/internal/pipe/sign/sign_docker_test.go
index 81eeef84..c89e0d4e 100644
--- a/internal/pipe/sign/sign_docker_test.go
+++ b/internal/pipe/sign/sign_docker_test.go
@@ -8,6 +8,7 @@ import (
 
 	"github.com/goreleaser/goreleaser/internal/artifact"
 	"github.com/goreleaser/goreleaser/internal/gio"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/testctx"
 	"github.com/goreleaser/goreleaser/internal/testlib"
 	"github.com/goreleaser/goreleaser/pkg/config"
@@ -215,7 +216,7 @@ func TestDockerSkip(t *testing.T) {
 	})
 
 	t.Run("skip sign", func(t *testing.T) {
-		ctx := testctx.New(testctx.SkipSign)
+		ctx := testctx.New(testctx.Skip(skips.Sign))
 		require.True(t, DockerPipe{}.Skip(ctx))
 	})
 
diff --git a/internal/pipe/sign/sign_test.go b/internal/pipe/sign/sign_test.go
index b9f40a7a..c8104fed 100644
--- a/internal/pipe/sign/sign_test.go
+++ b/internal/pipe/sign/sign_test.go
@@ -16,6 +16,7 @@ import (
 
 	"github.com/goreleaser/goreleaser/internal/artifact"
 	"github.com/goreleaser/goreleaser/internal/git"
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/internal/testctx"
 	"github.com/goreleaser/goreleaser/internal/testlib"
 	"github.com/goreleaser/goreleaser/internal/tmpl"
@@ -760,7 +761,7 @@ func TestSkip(t *testing.T) {
 	})
 
 	t.Run("skip sign", func(t *testing.T) {
-		ctx := testctx.New(testctx.SkipSign)
+		ctx := testctx.New(testctx.Skip(skips.Sign))
 		require.True(t, Pipe{}.Skip(ctx))
 	})
 
diff --git a/internal/pipe/winget/testdata/TestRunPipe/bad-commit-msg-tmpl/bad-commit-msg-tmpl.installer.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/bad-commit-msg-tmpl/bad-commit-msg-tmpl.installer.yaml.golden
index b8ed7adc..6c55a215 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/bad-commit-msg-tmpl/bad-commit-msg-tmpl.installer.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/bad-commit-msg-tmpl/bad-commit-msg-tmpl.installer.yaml.golden
@@ -1,5 +1,5 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.5.0.schema.json
 PackageIdentifier: Beckersoft.foo
 PackageVersion: 1.2.1
 InstallerLocale: en-US
@@ -31,4 +31,4 @@ Installers:
     InstallerSha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
     UpgradeBehavior: uninstallPrevious
 ManifestType: installer
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/bad-commit-msg-tmpl/bad-commit-msg-tmpl.locale.en-US.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/bad-commit-msg-tmpl/bad-commit-msg-tmpl.locale.en-US.yaml.golden
index c0a0c652..26c47d79 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/bad-commit-msg-tmpl/bad-commit-msg-tmpl.locale.en-US.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/bad-commit-msg-tmpl/bad-commit-msg-tmpl.locale.en-US.yaml.golden
@@ -1,5 +1,5 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.5.0.schema.json
 PackageIdentifier: Beckersoft.foo
 PackageVersion: 1.2.1
 PackageLocale: en-US
@@ -9,4 +9,4 @@ License: MIT
 ShortDescription: foo bar zaz
 Moniker: foo
 ManifestType: defaultLocale
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/bad-commit-msg-tmpl/bad-commit-msg-tmpl.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/bad-commit-msg-tmpl/bad-commit-msg-tmpl.yaml.golden
index 8aa2e833..f0b0cd9e 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/bad-commit-msg-tmpl/bad-commit-msg-tmpl.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/bad-commit-msg-tmpl/bad-commit-msg-tmpl.yaml.golden
@@ -1,7 +1,7 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.5.0.schema.json
 PackageIdentifier: Beckersoft.foo
 PackageVersion: 1.2.1
 DefaultLocale: en-US
 ManifestType: version
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/full/full.installer.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/full/full.installer.yaml.golden
index b8ed7adc..6c55a215 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/full/full.installer.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/full/full.installer.yaml.golden
@@ -1,5 +1,5 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.5.0.schema.json
 PackageIdentifier: Beckersoft.foo
 PackageVersion: 1.2.1
 InstallerLocale: en-US
@@ -31,4 +31,4 @@ Installers:
     InstallerSha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
     UpgradeBehavior: uninstallPrevious
 ManifestType: installer
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/full/full.locale.en-US.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/full/full.locale.en-US.yaml.golden
index 7a739a4f..75bfa3d6 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/full/full.locale.en-US.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/full/full.locale.en-US.yaml.golden
@@ -1,5 +1,5 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.5.0.schema.json
 PackageIdentifier: Beckersoft.foo
 PackageVersion: 1.2.1
 PackageLocale: en-US
@@ -27,4 +27,4 @@ Tags:
 ReleaseNotes: the changelog for this release...
 ReleaseNotesUrl: https://github.com/goreleaser/goreleaser/tags/v1.2.1
 ManifestType: defaultLocale
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/full/full.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/full/full.yaml.golden
index 8aa2e833..f0b0cd9e 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/full/full.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/full/full.yaml.golden
@@ -1,7 +1,7 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.5.0.schema.json
 PackageIdentifier: Beckersoft.foo
 PackageVersion: 1.2.1
 DefaultLocale: en-US
 ManifestType: version
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/minimal/minimal.installer.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/minimal/minimal.installer.yaml.golden
index 27406983..bfb70c95 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/minimal/minimal.installer.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/minimal/minimal.installer.yaml.golden
@@ -1,5 +1,5 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.5.0.schema.json
 PackageIdentifier: Foo.min
 PackageVersion: 1.2.1
 InstallerLocale: en-US
@@ -31,4 +31,4 @@ Installers:
     InstallerSha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
     UpgradeBehavior: uninstallPrevious
 ManifestType: installer
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/minimal/minimal.locale.en-US.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/minimal/minimal.locale.en-US.yaml.golden
index cd37a869..33128d98 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/minimal/minimal.locale.en-US.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/minimal/minimal.locale.en-US.yaml.golden
@@ -1,5 +1,5 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.5.0.schema.json
 PackageIdentifier: Foo.min
 PackageVersion: 1.2.1
 PackageLocale: en-US
@@ -9,4 +9,4 @@ License: MIT
 ShortDescription: foo bar zaz
 Moniker: min
 ManifestType: defaultLocale
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/minimal/minimal.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/minimal/minimal.yaml.golden
index c5d82b35..282ec8f3 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/minimal/minimal.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/minimal/minimal.yaml.golden
@@ -1,7 +1,7 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.5.0.schema.json
 PackageIdentifier: Foo.min
 PackageVersion: 1.2.1
 DefaultLocale: en-US
 ManifestType: version
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/open-pr/open-pr.installer.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/open-pr/open-pr.installer.yaml.golden
index b8ed7adc..6c55a215 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/open-pr/open-pr.installer.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/open-pr/open-pr.installer.yaml.golden
@@ -1,5 +1,5 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.5.0.schema.json
 PackageIdentifier: Beckersoft.foo
 PackageVersion: 1.2.1
 InstallerLocale: en-US
@@ -31,4 +31,4 @@ Installers:
     InstallerSha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
     UpgradeBehavior: uninstallPrevious
 ManifestType: installer
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/open-pr/open-pr.locale.en-US.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/open-pr/open-pr.locale.en-US.yaml.golden
index c54c40f8..569a9df7 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/open-pr/open-pr.locale.en-US.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/open-pr/open-pr.locale.en-US.yaml.golden
@@ -1,5 +1,5 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.5.0.schema.json
 PackageIdentifier: Beckersoft.foo
 PackageVersion: 1.2.1
 PackageLocale: en-US
@@ -11,4 +11,4 @@ ShortDescription: foo bar zaz
 Description: my test
 Moniker: foo
 ManifestType: defaultLocale
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/open-pr/open-pr.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/open-pr/open-pr.yaml.golden
index 8aa2e833..f0b0cd9e 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/open-pr/open-pr.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/open-pr/open-pr.yaml.golden
@@ -1,7 +1,7 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.5.0.schema.json
 PackageIdentifier: Beckersoft.foo
 PackageVersion: 1.2.1
 DefaultLocale: en-US
 ManifestType: version
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/partial/partial.installer.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/partial/partial.installer.yaml.golden
index b9479274..89b1023e 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/partial/partial.installer.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/partial/partial.installer.yaml.golden
@@ -1,5 +1,5 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.5.0.schema.json
 PackageIdentifier: Beckersoft.partial
 PackageVersion: 1.2.1
 InstallerLocale: en-US
@@ -15,4 +15,4 @@ Installers:
     InstallerSha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
     UpgradeBehavior: uninstallPrevious
 ManifestType: installer
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/partial/partial.locale.en-US.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/partial/partial.locale.en-US.yaml.golden
index 74ec0a99..40707b62 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/partial/partial.locale.en-US.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/partial/partial.locale.en-US.yaml.golden
@@ -1,5 +1,5 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.5.0.schema.json
 PackageIdentifier: Beckersoft.partial
 PackageVersion: 1.2.1
 PackageLocale: en-US
@@ -9,4 +9,4 @@ License: MIT
 ShortDescription: foo bar zaz
 Moniker: partial
 ManifestType: defaultLocale
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/partial/partial.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/partial/partial.yaml.golden
index 91b85b54..980e7ccd 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/partial/partial.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/partial/partial.yaml.golden
@@ -1,7 +1,7 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.5.0.schema.json
 PackageIdentifier: Beckersoft.partial
 PackageVersion: 1.2.1
 DefaultLocale: en-US
 ManifestType: version
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/skip-upload-auto/skip-upload-auto.installer.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/skip-upload-auto/skip-upload-auto.installer.yaml.golden
index 7bdb868a..4de4fe19 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/skip-upload-auto/skip-upload-auto.installer.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/skip-upload-auto/skip-upload-auto.installer.yaml.golden
@@ -1,5 +1,5 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.5.0.schema.json
 PackageIdentifier: Beckersoft.doesnotmatter
 PackageVersion: 1.2.1
 InstallerLocale: en-US
@@ -31,4 +31,4 @@ Installers:
     InstallerSha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
     UpgradeBehavior: uninstallPrevious
 ManifestType: installer
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/skip-upload-auto/skip-upload-auto.locale.en-US.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/skip-upload-auto/skip-upload-auto.locale.en-US.yaml.golden
index 17ab8ad7..ebfc94d3 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/skip-upload-auto/skip-upload-auto.locale.en-US.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/skip-upload-auto/skip-upload-auto.locale.en-US.yaml.golden
@@ -1,5 +1,5 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.5.0.schema.json
 PackageIdentifier: Beckersoft.doesnotmatter
 PackageVersion: 1.2.1
 PackageLocale: en-US
@@ -9,4 +9,4 @@ License: MIT
 ShortDescription: foo bar zaz
 Moniker: doesnotmatter
 ManifestType: defaultLocale
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/skip-upload-auto/skip-upload-auto.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/skip-upload-auto/skip-upload-auto.yaml.golden
index 8097a2e7..fefc701f 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/skip-upload-auto/skip-upload-auto.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/skip-upload-auto/skip-upload-auto.yaml.golden
@@ -1,7 +1,7 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.5.0.schema.json
 PackageIdentifier: Beckersoft.doesnotmatter
 PackageVersion: 1.2.1
 DefaultLocale: en-US
 ManifestType: version
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/skip-upload/skip-upload.installer.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/skip-upload/skip-upload.installer.yaml.golden
index 7bdb868a..4de4fe19 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/skip-upload/skip-upload.installer.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/skip-upload/skip-upload.installer.yaml.golden
@@ -1,5 +1,5 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.5.0.schema.json
 PackageIdentifier: Beckersoft.doesnotmatter
 PackageVersion: 1.2.1
 InstallerLocale: en-US
@@ -31,4 +31,4 @@ Installers:
     InstallerSha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
     UpgradeBehavior: uninstallPrevious
 ManifestType: installer
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/skip-upload/skip-upload.locale.en-US.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/skip-upload/skip-upload.locale.en-US.yaml.golden
index 17ab8ad7..ebfc94d3 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/skip-upload/skip-upload.locale.en-US.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/skip-upload/skip-upload.locale.en-US.yaml.golden
@@ -1,5 +1,5 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.5.0.schema.json
 PackageIdentifier: Beckersoft.doesnotmatter
 PackageVersion: 1.2.1
 PackageLocale: en-US
@@ -9,4 +9,4 @@ License: MIT
 ShortDescription: foo bar zaz
 Moniker: doesnotmatter
 ManifestType: defaultLocale
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/skip-upload/skip-upload.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/skip-upload/skip-upload.yaml.golden
index 8097a2e7..fefc701f 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/skip-upload/skip-upload.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/skip-upload/skip-upload.yaml.golden
@@ -1,7 +1,7 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.5.0.schema.json
 PackageIdentifier: Beckersoft.doesnotmatter
 PackageVersion: 1.2.1
 DefaultLocale: en-US
 ManifestType: version
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/wrapped-in-dir/wrapped-in-dir.installer.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/wrapped-in-dir/wrapped-in-dir.installer.yaml.golden
index 6ab0e982..a5f04202 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/wrapped-in-dir/wrapped-in-dir.installer.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/wrapped-in-dir/wrapped-in-dir.installer.yaml.golden
@@ -1,5 +1,5 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.5.0.schema.json
 PackageIdentifier: Beckersoft.wrapped-in-dir
 PackageVersion: 1.2.1
 InstallerLocale: en-US
@@ -31,4 +31,4 @@ Installers:
     InstallerSha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
     UpgradeBehavior: uninstallPrevious
 ManifestType: installer
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/wrapped-in-dir/wrapped-in-dir.locale.en-US.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/wrapped-in-dir/wrapped-in-dir.locale.en-US.yaml.golden
index e4dab58d..c356f096 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/wrapped-in-dir/wrapped-in-dir.locale.en-US.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/wrapped-in-dir/wrapped-in-dir.locale.en-US.yaml.golden
@@ -1,5 +1,5 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.5.0.schema.json
 PackageIdentifier: Beckersoft.wrapped-in-dir
 PackageVersion: 1.2.1
 PackageLocale: en-US
@@ -13,4 +13,4 @@ Description: my test
 Moniker: wrapped-in-dir
 ReleaseNotesUrl: https://github.com/goreleaser/goreleaser/tags/v1.2.1
 ManifestType: defaultLocale
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/pipe/winget/testdata/TestRunPipe/wrapped-in-dir/wrapped-in-dir.yaml.golden b/internal/pipe/winget/testdata/TestRunPipe/wrapped-in-dir/wrapped-in-dir.yaml.golden
index b765c5e3..a9c1591f 100644
--- a/internal/pipe/winget/testdata/TestRunPipe/wrapped-in-dir/wrapped-in-dir.yaml.golden
+++ b/internal/pipe/winget/testdata/TestRunPipe/wrapped-in-dir/wrapped-in-dir.yaml.golden
@@ -1,7 +1,7 @@
 # This file was generated by GoReleaser. DO NOT EDIT.
-# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.4.0.schema.json
+# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.5.0.schema.json
 PackageIdentifier: Beckersoft.wrapped-in-dir
 PackageVersion: 1.2.1
 DefaultLocale: en-US
 ManifestType: version
-ManifestVersion: 1.4.0
+ManifestVersion: 1.5.0
diff --git a/internal/testctx/testctx.go b/internal/testctx/testctx.go
index 0e695b5f..0fcf5984 100644
--- a/internal/testctx/testctx.go
+++ b/internal/testctx/testctx.go
@@ -4,6 +4,7 @@ package testctx
 import (
 	"time"
 
+	"github.com/goreleaser/goreleaser/internal/skips"
 	"github.com/goreleaser/goreleaser/pkg/config"
 	"github.com/goreleaser/goreleaser/pkg/context"
 )
@@ -105,30 +106,16 @@ func WithFakeRuntime(ctx *context.Context) {
 	}
 }
 
-func SkipPublish(ctx *context.Context) {
-	ctx.SkipPublish = true
-}
-
-func SkipAnnounce(ctx *context.Context) {
-	ctx.SkipAnnounce = true
-}
-
-func SkipDocker(ctx *context.Context) {
-	ctx.SkipDocker = true
-}
-
-func SkipValidate(ctx *context.Context) {
-	ctx.SkipValidate = true
+func Skip(keys ...skips.Key) Opt {
+	return func(ctx *context.Context) {
+		skips.Set(ctx, keys...)
+	}
 }
 
 func Snapshot(ctx *context.Context) {
 	ctx.Snapshot = true
 }
 
-func SkipSign(ctx *context.Context) {
-	ctx.SkipSign = true
-}
-
 func NewWithCfg(c config.Project, opts ...Opt) *context.Context {
 	ctx := context.New(c)
 	for _, opt := range opts {