2020-04-28 02:42:44 +02:00
package cmd
import (
2023-09-16 22:01:20 +02:00
"fmt"
2021-01-13 19:21:04 +02:00
"runtime"
2020-04-28 02:42:44 +02:00
"time"
"github.com/caarlos0/ctrlc"
2022-06-22 02:11:15 +02:00
"github.com/caarlos0/log"
2023-01-29 05:24:11 +02:00
"github.com/goreleaser/goreleaser/internal/deprecate"
2023-09-20 17:03:15 +02:00
"github.com/goreleaser/goreleaser/internal/logext"
2021-09-18 15:21:29 +02:00
"github.com/goreleaser/goreleaser/internal/middleware/errhandler"
"github.com/goreleaser/goreleaser/internal/middleware/logging"
"github.com/goreleaser/goreleaser/internal/middleware/skip"
2021-06-05 04:09:12 +02:00
"github.com/goreleaser/goreleaser/internal/pipe/git"
2020-04-28 02:42:44 +02:00
"github.com/goreleaser/goreleaser/internal/pipeline"
2023-09-16 22:01:20 +02:00
"github.com/goreleaser/goreleaser/internal/skips"
2020-04-28 02:42:44 +02:00
"github.com/goreleaser/goreleaser/pkg/context"
2022-05-07 01:38:50 +02:00
"github.com/spf13/cobra"
2020-04-28 02:42:44 +02:00
)
type releaseCmd struct {
2022-05-07 01:38:50 +02:00
cmd * cobra . Command
2020-04-28 02:42:44 +02:00
opts releaseOpts
}
type releaseOpts struct {
2023-09-16 22:01:20 +02:00
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
2023-08-04 16:47:54 +02:00
// Deprecated: use clean instead.
rmDist bool
2023-09-16 22:01:20 +02:00
// 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
2020-04-28 02:42:44 +02:00
}
func newReleaseCmd ( ) * releaseCmd {
2021-04-22 15:45:36 +02:00
root := & releaseCmd { }
2020-05-15 16:19:20 +02:00
// nolint: dupl
2022-05-07 01:38:50 +02:00
cmd := & cobra . Command {
2023-06-06 05:21:17 +02:00
Use : "release" ,
Aliases : [ ] string { "r" } ,
Short : "Releases the current project" ,
SilenceUsage : true ,
SilenceErrors : true ,
Args : cobra . NoArgs ,
ValidArgsFunction : cobra . NoFileCompletions ,
2023-09-16 22:01:20 +02:00
RunE : timedRunE ( "release" , func ( _ * cobra . Command , _ [ ] string ) error {
2020-04-28 02:42:44 +02:00
ctx , err := releaseProject ( root . opts )
if err != nil {
2022-06-22 06:48:11 +02:00
return err
2020-04-28 02:42:44 +02:00
}
2022-06-22 06:48:11 +02:00
deprecateWarn ( ctx )
2020-04-28 02:42:44 +02:00
return nil
2022-06-22 06:48:11 +02:00
} ) ,
2020-04-28 02:42:44 +02:00
}
cmd . Flags ( ) . StringVarP ( & root . opts . config , "config" , "f" , "" , "Load configuration from file" )
2023-06-06 05:21:17 +02:00
_ = cmd . MarkFlagFilename ( "config" , "yaml" , "yml" )
2022-01-30 16:28:00 +02:00
cmd . Flags ( ) . StringVar ( & root . opts . releaseNotesFile , "release-notes" , "" , "Load custom release notes from a markdown file (will skip GoReleaser changelog generation)" )
2023-06-06 05:21:17 +02:00
_ = cmd . MarkFlagFilename ( "release-notes" , "md" , "mkd" , "markdown" )
2021-05-22 02:07:47 +02:00
cmd . Flags ( ) . StringVar ( & root . opts . releaseHeaderFile , "release-header" , "" , "Load custom release notes header from a markdown file" )
2023-06-06 05:21:17 +02:00
_ = cmd . MarkFlagFilename ( "release-header" , "md" , "mkd" , "markdown" )
2021-05-22 02:07:47 +02:00
cmd . Flags ( ) . StringVar ( & root . opts . releaseFooterFile , "release-footer" , "" , "Load custom release notes footer from a markdown file" )
2023-06-06 05:21:17 +02:00
_ = cmd . MarkFlagFilename ( "release-footer" , "md" , "mkd" , "markdown" )
2021-05-22 02:07:47 +02:00
cmd . Flags ( ) . StringVar ( & root . opts . releaseNotesTmpl , "release-notes-tmpl" , "" , "Load custom release notes from a templated markdown file (overrides --release-notes)" )
2023-06-06 05:21:17 +02:00
_ = cmd . MarkFlagFilename ( "release-notes-tmpl" , "md" , "mkd" , "markdown" )
2021-05-22 02:07:47 +02:00
cmd . Flags ( ) . StringVar ( & root . opts . releaseHeaderTmpl , "release-header-tmpl" , "" , "Load custom release notes header from a templated markdown file (overrides --release-header)" )
2023-06-06 05:21:17 +02:00
_ = cmd . MarkFlagFilename ( "release-header-tmpl" , "md" , "mkd" , "markdown" )
2021-05-22 02:07:47 +02:00
cmd . Flags ( ) . StringVar ( & root . opts . releaseFooterTmpl , "release-footer-tmpl" , "" , "Load custom release notes footer from a templated markdown file (overrides --release-footer)" )
2023-06-06 05:21:17 +02:00
_ = cmd . MarkFlagFilename ( "release-footer-tmpl" , "md" , "mkd" , "markdown" )
2022-12-29 15:41:59 +02:00
cmd . Flags ( ) . BoolVar ( & root . opts . autoSnapshot , "auto-snapshot" , false , "Automatically sets --snapshot if the repository is dirty" )
2023-09-16 22:01:20 +02:00
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)" )
2023-06-20 14:33:59 +02:00
cmd . Flags ( ) . BoolVar ( & root . opts . failFast , "fail-fast" , false , "Whether to abort the release publishing on the first error" )
2023-09-16 22:01:20 +02:00
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)" )
2021-09-23 05:39:28 +02:00
cmd . Flags ( ) . BoolVar ( & root . opts . skipSign , "skip-sign" , false , "Skips signing artifacts" )
2021-12-12 05:21:51 +02:00
cmd . Flags ( ) . BoolVar ( & root . opts . skipSBOMCataloging , "skip-sbom" , false , "Skips cataloging artifacts" )
2022-06-23 02:39:20 +02:00
cmd . Flags ( ) . BoolVar ( & root . opts . skipDocker , "skip-docker" , false , "Skips Docker Images/Manifests builds" )
2023-01-17 03:34:49 +02:00
cmd . Flags ( ) . BoolVar ( & root . opts . skipKo , "skip-ko" , false , "Skips Ko builds" )
2022-06-23 02:56:53 +02:00
cmd . Flags ( ) . BoolVar ( & root . opts . skipBefore , "skip-before" , false , "Skips global before hooks" )
2021-09-23 05:39:28 +02:00
cmd . Flags ( ) . BoolVar ( & root . opts . skipValidate , "skip-validate" , false , "Skips git checks" )
2023-01-21 04:47:08 +02:00
cmd . Flags ( ) . BoolVar ( & root . opts . clean , "clean" , false , "Removes the dist folder" )
2023-01-29 05:24:11 +02:00
cmd . Flags ( ) . BoolVar ( & root . opts . rmDist , "rm-dist" , false , "Removes the dist folder" )
2021-04-22 15:45:36 +02:00
cmd . Flags ( ) . IntVarP ( & root . opts . parallelism , "parallelism" , "p" , 0 , "Amount tasks to run concurrently (default: number of CPUs)" )
2023-06-06 05:21:17 +02:00
_ = cmd . RegisterFlagCompletionFunc ( "parallelism" , cobra . NoFileCompletions )
2020-04-28 02:42:44 +02:00
cmd . Flags ( ) . DurationVar ( & root . opts . timeout , "timeout" , 30 * time . Minute , "Timeout to the entire release process" )
2023-06-06 05:21:17 +02:00
_ = cmd . RegisterFlagCompletionFunc ( "timeout" , cobra . NoFileCompletions )
2020-04-28 02:42:44 +02:00
cmd . Flags ( ) . BoolVar ( & root . opts . deprecated , "deprecated" , false , "Force print the deprecation message - tests only" )
_ = cmd . Flags ( ) . MarkHidden ( "deprecated" )
2023-01-21 04:47:08 +02:00
_ = cmd . Flags ( ) . MarkHidden ( "rm-dist" )
_ = cmd . Flags ( ) . MarkDeprecated ( "rm-dist" , "please use --clean instead" )
2023-09-16 22:01:20 +02:00
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 ) {
2023-09-17 05:00:15 +02:00
return skips . Release . Complete ( toComplete ) , cobra . ShellCompDirectiveDefault
2023-09-16 22:01:20 +02:00
} )
2020-04-28 02:42:44 +02:00
root . cmd = cmd
return root
}
func releaseProject ( options releaseOpts ) ( * context . Context , error ) {
cfg , err := loadConfig ( options . config )
if err != nil {
return nil , err
}
ctx , cancel := context . NewWithTimeout ( cfg , options . timeout )
defer cancel ( )
2023-09-16 22:01:20 +02:00
if err := setupReleaseContext ( ctx , options ) ; err != nil {
return nil , err
}
2020-04-28 02:42:44 +02:00
return ctx , ctrlc . Default . Run ( ctx , func ( ) error {
for _ , pipe := range pipeline . Pipeline {
2021-09-18 15:21:29 +02:00
if err := skip . Maybe (
pipe ,
logging . Log (
pipe . String ( ) ,
errhandler . Handle ( pipe . Run ) ,
) ,
2020-04-28 02:42:44 +02:00
) ( ctx ) ; err != nil {
return err
}
}
return nil
} )
}
2023-09-16 22:01:20 +02:00
func setupReleaseContext ( ctx * context . Context , options releaseOpts ) error {
2023-12-29 20:22:03 +02:00
ctx . Action = context . ActionRelease
2023-01-29 05:24:11 +02:00
ctx . Deprecated = options . deprecated // test only
fix: set parallelism to match Linux container CPU (#3901)
<!--
Hi, thanks for contributing!
Please make sure you read our CONTRIBUTING guide.
Also, add tests and the respective documentation changes as well.
-->
Currently Goreleaser uses `runtime.NumCPU()` as the default value if
`--parallelism` is not set.
However, this will get the number of CPUs on the host even when
Goreleaser is run in a container with a limit on the maximum number of
CPUs that can be used (typically in a Kubernetes pod).
Actually, `docker run --cpus=1 goreleaser/goreleaser --debug` shows
`parallelism: 4` on my machine.
This behavior causes CPU throttling, which increases execution time and,
in the worst case, terminates with an error.
I ran into this problem with Jenkins where the agent runs on pod
([Kubernetes plugin for
Jenkins](https://plugins.jenkins.io/kubernetes/)).
This commit introduces
[automaxprocs](https://github.com/uber-go/automaxprocs) to fix this
issue.
This library sets `GOMAXPROCS` to match Linux container CPU quota.
I have also looked for a library that can get CPU quota more directly,
but this seems to be the best I could find.
The reason it is set in a different notation from the automaxprocs
README is to prevent logs from being displayed
([comment](https://github.com/uber-go/automaxprocs/issues/18#issuecomment-511330567)).
I would have liked to write a test, but this change is dependent on the
number of CPUs in the execution environment, so I could not.
Instead, I wrote a Dockerfile for testing
```Dockerfile
FROM golang:1.20.2
WORKDIR /go/app
RUN sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin
COPY . .
RUN task build
```
and confirmed built binary shows expected parallelism by following
commands:
```sh
docker build --file Dockerfile.test . -t test-goreleaser
docker run --cpus=1 test-goreleaser ./goreleaser build --snapshot --debug # parallelism: 1
docker run test-goreleaser ./goreleaser build --snapshot --debug # parallelism: 4
```
I also ran the built binary on my Macbook and it was fine.
2023-04-02 22:16:41 +02:00
ctx . Parallelism = runtime . GOMAXPROCS ( 0 )
2021-04-22 15:45:36 +02:00
if options . parallelism > 0 {
ctx . Parallelism = options . parallelism
}
2020-04-28 02:42:44 +02:00
log . Debugf ( "parallelism: %v" , ctx . Parallelism )
2021-05-22 02:07:47 +02:00
ctx . ReleaseNotesFile = options . releaseNotesFile
ctx . ReleaseNotesTmpl = options . releaseNotesTmpl
ctx . ReleaseHeaderFile = options . releaseHeaderFile
ctx . ReleaseHeaderTmpl = options . releaseHeaderTmpl
ctx . ReleaseFooterFile = options . releaseFooterFile
ctx . ReleaseFooterTmpl = options . releaseFooterTmpl
2020-04-28 02:42:44 +02:00
ctx . Snapshot = options . snapshot
2023-06-20 14:33:59 +02:00
ctx . FailFast = options . failFast
2023-09-16 22:01:20 +02:00
ctx . Clean = options . clean || options . rmDist
2022-04-12 13:35:19 +02:00
if options . autoSnapshot && git . CheckDirty ( ctx ) != nil {
2022-12-29 15:41:59 +02:00
log . Info ( "git repository is dirty and --auto-snapshot is set, implying --snapshot" )
2021-06-05 04:09:12 +02:00
ctx . Snapshot = true
}
2020-04-28 02:42:44 +02:00
2023-09-16 22:01:20 +02:00
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" )
}
2023-01-29 05:24:11 +02:00
if options . rmDist {
deprecate . NoticeCustom ( ctx , "-rm-dist" , "--rm-dist was deprecated in favor of --clean, check {{ .URL }} for more details" )
}
2023-09-16 22:01:20 +02:00
if ctx . Snapshot {
skips . Set ( ctx , skips . Publish , skips . Announce , skips . Validate )
}
if skips . Any ( ctx , skips . Publish ) {
skips . Set ( ctx , skips . Announce )
}
2023-09-20 17:03:15 +02:00
2023-09-23 06:28:03 +02:00
if skips . Any ( ctx , skips . Release ... ) {
log . Warnf (
logext . Warning ( "skipping %s..." ) ,
skips . String ( ctx ) ,
)
}
2023-09-16 22:01:20 +02:00
return nil
2020-04-28 02:42:44 +02:00
}