github.com/goreleaser/goreleaser@v1.25.1/cmd/release.go (about) 1 package cmd 2 3 import ( 4 "fmt" 5 "runtime" 6 "time" 7 8 "github.com/caarlos0/ctrlc" 9 "github.com/caarlos0/log" 10 "github.com/goreleaser/goreleaser/internal/deprecate" 11 "github.com/goreleaser/goreleaser/internal/logext" 12 "github.com/goreleaser/goreleaser/internal/middleware/errhandler" 13 "github.com/goreleaser/goreleaser/internal/middleware/logging" 14 "github.com/goreleaser/goreleaser/internal/middleware/skip" 15 "github.com/goreleaser/goreleaser/internal/pipe/git" 16 "github.com/goreleaser/goreleaser/internal/pipeline" 17 "github.com/goreleaser/goreleaser/internal/skips" 18 "github.com/goreleaser/goreleaser/pkg/context" 19 "github.com/spf13/cobra" 20 ) 21 22 type releaseCmd struct { 23 cmd *cobra.Command 24 opts releaseOpts 25 } 26 27 type releaseOpts struct { 28 config string 29 releaseNotesFile string 30 releaseNotesTmpl string 31 releaseHeaderFile string 32 releaseHeaderTmpl string 33 releaseFooterFile string 34 releaseFooterTmpl string 35 autoSnapshot bool 36 snapshot bool 37 failFast bool 38 clean bool 39 deprecated bool 40 parallelism int 41 timeout time.Duration 42 skips []string 43 44 // Deprecated: use clean instead. 45 rmDist bool 46 // Deprecated: use skips instead. 47 skipPublish bool 48 // Deprecated: use skips instead. 49 skipSign bool 50 // Deprecated: use skips instead. 51 skipValidate bool 52 // Deprecated: use skips instead. 53 skipAnnounce bool 54 // Deprecated: use skips instead. 55 skipSBOMCataloging bool 56 // Deprecated: use skips instead. 57 skipDocker bool 58 // Deprecated: use skips instead. 59 skipKo bool 60 // Deprecated: use skips instead. 61 skipBefore bool 62 } 63 64 func newReleaseCmd() *releaseCmd { 65 root := &releaseCmd{} 66 // nolint: dupl 67 cmd := &cobra.Command{ 68 Use: "release", 69 Aliases: []string{"r"}, 70 Short: "Releases the current project", 71 SilenceUsage: true, 72 SilenceErrors: true, 73 Args: cobra.NoArgs, 74 ValidArgsFunction: cobra.NoFileCompletions, 75 RunE: timedRunE("release", func(_ *cobra.Command, _ []string) error { 76 ctx, err := releaseProject(root.opts) 77 if err != nil { 78 return err 79 } 80 deprecateWarn(ctx) 81 return nil 82 }), 83 } 84 85 cmd.Flags().StringVarP(&root.opts.config, "config", "f", "", "Load configuration from file") 86 _ = cmd.MarkFlagFilename("config", "yaml", "yml") 87 cmd.Flags().StringVar(&root.opts.releaseNotesFile, "release-notes", "", "Load custom release notes from a markdown file (will skip GoReleaser changelog generation)") 88 _ = cmd.MarkFlagFilename("release-notes", "md", "mkd", "markdown") 89 cmd.Flags().StringVar(&root.opts.releaseHeaderFile, "release-header", "", "Load custom release notes header from a markdown file") 90 _ = cmd.MarkFlagFilename("release-header", "md", "mkd", "markdown") 91 cmd.Flags().StringVar(&root.opts.releaseFooterFile, "release-footer", "", "Load custom release notes footer from a markdown file") 92 _ = cmd.MarkFlagFilename("release-footer", "md", "mkd", "markdown") 93 cmd.Flags().StringVar(&root.opts.releaseNotesTmpl, "release-notes-tmpl", "", "Load custom release notes from a templated markdown file (overrides --release-notes)") 94 _ = cmd.MarkFlagFilename("release-notes-tmpl", "md", "mkd", "markdown") 95 cmd.Flags().StringVar(&root.opts.releaseHeaderTmpl, "release-header-tmpl", "", "Load custom release notes header from a templated markdown file (overrides --release-header)") 96 _ = cmd.MarkFlagFilename("release-header-tmpl", "md", "mkd", "markdown") 97 cmd.Flags().StringVar(&root.opts.releaseFooterTmpl, "release-footer-tmpl", "", "Load custom release notes footer from a templated markdown file (overrides --release-footer)") 98 _ = cmd.MarkFlagFilename("release-footer-tmpl", "md", "mkd", "markdown") 99 cmd.Flags().BoolVar(&root.opts.autoSnapshot, "auto-snapshot", false, "Automatically sets --snapshot if the repository is dirty") 100 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)") 101 cmd.Flags().BoolVar(&root.opts.failFast, "fail-fast", false, "Whether to abort the release publishing on the first error") 102 cmd.Flags().BoolVar(&root.opts.skipPublish, "skip-publish", false, "Skips publishing artifacts (implies --skip=announce)") 103 cmd.Flags().BoolVar(&root.opts.skipAnnounce, "skip-announce", false, "Skips announcing releases (implies --skip=validate)") 104 cmd.Flags().BoolVar(&root.opts.skipSign, "skip-sign", false, "Skips signing artifacts") 105 cmd.Flags().BoolVar(&root.opts.skipSBOMCataloging, "skip-sbom", false, "Skips cataloging artifacts") 106 cmd.Flags().BoolVar(&root.opts.skipDocker, "skip-docker", false, "Skips Docker Images/Manifests builds") 107 cmd.Flags().BoolVar(&root.opts.skipKo, "skip-ko", false, "Skips Ko builds") 108 cmd.Flags().BoolVar(&root.opts.skipBefore, "skip-before", false, "Skips global before hooks") 109 cmd.Flags().BoolVar(&root.opts.skipValidate, "skip-validate", false, "Skips git checks") 110 cmd.Flags().BoolVar(&root.opts.clean, "clean", false, "Removes the 'dist' directory") 111 cmd.Flags().BoolVar(&root.opts.rmDist, "rm-dist", false, "Removes the 'dist' directory") 112 cmd.Flags().IntVarP(&root.opts.parallelism, "parallelism", "p", 0, "Amount tasks to run concurrently (default: number of CPUs)") 113 _ = cmd.RegisterFlagCompletionFunc("parallelism", cobra.NoFileCompletions) 114 cmd.Flags().DurationVar(&root.opts.timeout, "timeout", 30*time.Minute, "Timeout to the entire release process") 115 _ = cmd.RegisterFlagCompletionFunc("timeout", cobra.NoFileCompletions) 116 cmd.Flags().BoolVar(&root.opts.deprecated, "deprecated", false, "Force print the deprecation message - tests only") 117 _ = cmd.Flags().MarkHidden("deprecated") 118 _ = cmd.Flags().MarkHidden("rm-dist") 119 _ = cmd.Flags().MarkDeprecated("rm-dist", "please use --clean instead") 120 for _, f := range []string{ 121 "publish", 122 "announce", 123 "sign", 124 "sbom", 125 "docker", 126 "ko", 127 "before", 128 "validate", 129 } { 130 _ = cmd.Flags().MarkHidden("skip-" + f) 131 _ = cmd.Flags().MarkDeprecated("skip"+f, fmt.Sprintf("please use --skip=%s instead", f)) 132 } 133 cmd.Flags().StringSliceVar( 134 &root.opts.skips, 135 "skip", 136 nil, 137 fmt.Sprintf("Skip the given options (valid options are %s)", skips.Release.String()), 138 ) 139 _ = cmd.RegisterFlagCompletionFunc("skip", func(_ *cobra.Command, _ []string, toComplete string) ([]string, cobra.ShellCompDirective) { 140 return skips.Release.Complete(toComplete), cobra.ShellCompDirectiveDefault 141 }) 142 143 root.cmd = cmd 144 return root 145 } 146 147 func releaseProject(options releaseOpts) (*context.Context, error) { 148 cfg, err := loadConfig(options.config) 149 if err != nil { 150 return nil, err 151 } 152 ctx, cancel := context.NewWithTimeout(cfg, options.timeout) 153 defer cancel() 154 if err := setupReleaseContext(ctx, options); err != nil { 155 return nil, err 156 } 157 return ctx, ctrlc.Default.Run(ctx, func() error { 158 for _, pipe := range pipeline.Pipeline { 159 if err := skip.Maybe( 160 pipe, 161 logging.Log( 162 pipe.String(), 163 errhandler.Handle(pipe.Run), 164 ), 165 )(ctx); err != nil { 166 return err 167 } 168 } 169 return nil 170 }) 171 } 172 173 func setupReleaseContext(ctx *context.Context, options releaseOpts) error { 174 ctx.Action = context.ActionRelease 175 ctx.Deprecated = options.deprecated // test only 176 ctx.Parallelism = runtime.GOMAXPROCS(0) 177 if options.parallelism > 0 { 178 ctx.Parallelism = options.parallelism 179 } 180 log.Debugf("parallelism: %v", ctx.Parallelism) 181 ctx.ReleaseNotesFile = options.releaseNotesFile 182 ctx.ReleaseNotesTmpl = options.releaseNotesTmpl 183 ctx.ReleaseHeaderFile = options.releaseHeaderFile 184 ctx.ReleaseHeaderTmpl = options.releaseHeaderTmpl 185 ctx.ReleaseFooterFile = options.releaseFooterFile 186 ctx.ReleaseFooterTmpl = options.releaseFooterTmpl 187 ctx.Snapshot = options.snapshot 188 ctx.FailFast = options.failFast 189 ctx.Clean = options.clean || options.rmDist 190 if options.autoSnapshot && git.CheckDirty(ctx) != nil { 191 log.Info("git repository is dirty and --auto-snapshot is set, implying --snapshot") 192 ctx.Snapshot = true 193 } 194 195 if err := skips.SetRelease(ctx, options.skips...); err != nil { 196 return err 197 } 198 199 // wire deprecated options 200 // XXX: remove soon 201 if options.skipPublish { 202 skips.Set(ctx, skips.Publish) 203 deprecate.NoticeCustom(ctx, "-skip", "--skip-publish was deprecated in favor of --skip=publish, check {{ .URL }} for more details") 204 } 205 if options.skipSign { 206 skips.Set(ctx, skips.Sign) 207 deprecate.NoticeCustom(ctx, "-skip", "--skip-sign was deprecated in favor of --skip=sign, check {{ .URL }} for more details") 208 } 209 if options.skipValidate { 210 skips.Set(ctx, skips.Validate) 211 deprecate.NoticeCustom(ctx, "-skip", "--skip-validate was deprecated in favor of --skip=validate, check {{ .URL }} for more details") 212 } 213 if options.skipAnnounce { 214 skips.Set(ctx, skips.Announce) 215 deprecate.NoticeCustom(ctx, "-skip", "--skip-announce was deprecated in favor of --skip=announce, check {{ .URL }} for more details") 216 } 217 if options.skipSBOMCataloging { 218 skips.Set(ctx, skips.SBOM) 219 deprecate.NoticeCustom(ctx, "-skip", "--skip-sbom was deprecated in favor of --skip=sbom, check {{ .URL }} for more details") 220 } 221 if options.skipDocker { 222 skips.Set(ctx, skips.Docker) 223 deprecate.NoticeCustom(ctx, "-skip", "--skip-docker was deprecated in favor of --skip=docker, check {{ .URL }} for more details") 224 } 225 if options.skipKo { 226 skips.Set(ctx, skips.Ko) 227 deprecate.NoticeCustom(ctx, "-skip", "--skip-ko was deprecated in favor of --skip=ko, check {{ .URL }} for more details") 228 } 229 if options.skipBefore { 230 skips.Set(ctx, skips.Before) 231 deprecate.NoticeCustom(ctx, "-skip", "--skip-before was deprecated in favor of --skip=before, check {{ .URL }} for more details") 232 } 233 if options.rmDist { 234 deprecate.NoticeCustom(ctx, "-rm-dist", "--rm-dist was deprecated in favor of --clean, check {{ .URL }} for more details") 235 } 236 237 if ctx.Snapshot { 238 skips.Set(ctx, skips.Publish, skips.Announce, skips.Validate) 239 } 240 if skips.Any(ctx, skips.Publish) { 241 skips.Set(ctx, skips.Announce) 242 } 243 244 if skips.Any(ctx, skips.Release...) { 245 log.Warnf( 246 logext.Warning("skipping %s..."), 247 skips.String(ctx), 248 ) 249 } 250 return nil 251 }