Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improve cli documentation when using the --help flag #303

Merged
merged 3 commits into from
Jan 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions cmd/uplift/bump.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,28 @@ import (
)

const (
bumpDesc = `Bumps the semantic version within files in your git repository. The
version bump is based on the conventional commit message from the last commit.
Uplift can bump the version in any file using regex pattern matching`
bumpLongDesc = `Calculates the next semantic version based on the conventional commits since the
last release (or identifiable tag) and bumps (or patches) a configurable set of
files with said version. JSON Path or Regex Pattern matching is supported when
scanning files for an existing semantic version. Uplift automatically handles
the staging and pushing of modified files to the git remote, but this behavior
can be disabled, to manage this action manually.

Configuring a bump requires an Uplift configuration file to exist within the
root of your project:

https://upliftci.dev/bumping-files/`

bumpExamples = `
# Bump (patch) all configured files with the next calculated semantic version
uplift bump

# Append a prerelease suffix to the next calculated semantic version
uplift bump --prerelease beta.1

# Bump (patch) all configured files but do not stage or push any changes
# back to the git remote
uplift bump --no-stage`
)

type bumpOptions struct {
Expand All @@ -68,10 +87,11 @@ func newBumpCmd(gopts *globalOptions, out io.Writer) *bumpCommand {
}

cmd := &cobra.Command{
Use: "bump",
Short: "Bump the semantic version within files",
Long: bumpDesc,
Args: cobra.NoArgs,
Use: "bump",
Short: "Bump the semantic version within files",
Long: bumpLongDesc,
Example: bumpExamples,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return bumpFiles(bmpCmd.Opts, out)
},
Expand Down
49 changes: 40 additions & 9 deletions cmd/uplift/changelog.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,41 @@ import (
)

const (
chlogDesc = `Create or update an existing changelog with an entry for
the latest semantic release. For a first release, all commits
between the latest tag and trunk will be written to the
changelog. Subsequent entries will contain only commits between
release tags`
changelogLongDesc = `Scans the git log for the latest semantic release and generates a changelog
entry. If this is a first release, all commits between the last release (or
identifiable tag) and the repository trunk will be written to the changelog.
Any subsequent entry within the changelog will only contain commits between
the latest set of tags. Basic customization is supported. Optionally commits
can be explicitly included or excluded from the entry and sorted in ascending
or descending order. Uplift automatically handles the staging and pushing of
changes to the CHANGELOG.md file to the git remote, but this behavior can be
disabled, to manage this action manually.

Uplift bases its changelog format on the Keep a Changelog specification:

https://keepachangelog.com/en/1.0.0/`

changelogExamples = `
# Generate the next changelog entry for the latest semantic release
uplift changelog

# Generate a changelog for the entire history of the repository
uplift changelog --all

# Generate the next changelog entry and write it to stdout
uplift changelog --diff-only

# Generate the next changelog entry by exclude any conventional commits
# with the ci, chore or test prefixes
uplift changelog --exclude "^ci,^chore,^test"

# Generate the next changelog entry with commits that only include the
# following scope
uplift changelog --include "^.*\(scope\)"

# Generate the next changelog entry but do not stage or push any changes
# back to the git remote
uplift changelog --no-stage`
)

type changelogOptions struct {
Expand All @@ -74,10 +104,11 @@ func newChangelogCmd(gopts *globalOptions, out io.Writer) *changelogCommand {
}

cmd := &cobra.Command{
Use: "changelog",
Short: "Create or update a changelog with the latest semantic release",
Long: chlogDesc,
Args: cobra.NoArgs,
Use: "changelog",
Short: "Create or update a changelog with the latest semantic release",
Long: changelogLongDesc,
Example: changelogExamples,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
// Always lowercase sort
chglogCmd.Opts.Sort = strings.ToLower(chglogCmd.Opts.Sort)
Expand Down
48 changes: 38 additions & 10 deletions cmd/uplift/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,34 @@ import (
)

const (
releaseDesc = `Release the next semantic version of your git repository. A release
will automatically bump any files and tag the associated commit with
the required semantic version`
releaseLongDesc = `Release the next semantic version of your git repository. A release consists of
a three-stage process. First, all configured files will be bumped (patched) using
the next semantic version. Second, a changelog entry containing all commits for
the latest semantic release will be created. Finally, Uplift will tag the
repository. Uplift automatically handles the staging and pushing of modified
files and the tagging of the repository with two separate git pushes. But this
behavior can be disabled to manage these actions manually.

Parts of this release process can be disabled if needed.

https://upliftci.dev/first-release/`

releaseExamples = `
# Release the next semantic version
uplift release

# Release the next semantic version without bumping any files
uplift release --skip-bumps

# Release the next semantic version without generating a changelog
uplift release --skip-changelog

# Append a prerelease suffix to the next calculated semantic version
uplift release --prerelease beta.1

# Ensure any "v" prefix is stripped from the next calculated semantic
# version to explicitly adhere to the SemVer specification
uplift release --no-prefix`
)

type releaseOptions struct {
Expand All @@ -67,6 +92,7 @@ type releaseOptions struct {
SkipBumps bool
NoPrefix bool
Exclude []string
Include []string
Sort string
*globalOptions
}
Expand All @@ -84,10 +110,11 @@ func newReleaseCmd(gopts *globalOptions, out io.Writer) *releaseCommand {
}

cmd := &cobra.Command{
Use: "release",
Short: "Release the next semantic version of a repository",
Long: releaseDesc,
Args: cobra.NoArgs,
Use: "release",
Short: "Release the next semantic version of a repository",
Long: releaseLongDesc,
Example: releaseExamples,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
// Just check if uplift would trigger a release
if relCmd.Opts.Check {
Expand All @@ -105,7 +132,8 @@ func newReleaseCmd(gopts *globalOptions, out io.Writer) *releaseCommand {
f.BoolVar(&relCmd.Opts.SkipChangelog, "skip-changelog", false, "skips the creation or amendment of a changelog")
f.BoolVar(&relCmd.Opts.SkipBumps, "skip-bumps", false, "skips the bumping of any files")
f.BoolVar(&relCmd.Opts.NoPrefix, "no-prefix", false, "strip the default 'v' prefix from the next calculated semantic version")
f.StringSliceVar(&relCmd.Opts.Exclude, "exclude", []string{}, "a list of conventional commit prefixes to exclude from the changelog")
f.StringSliceVar(&relCmd.Opts.Exclude, "exclude", []string{}, "a list of regexes for excluding conventional commits from the changelog")
f.StringSliceVar(&relCmd.Opts.Include, "include", []string{}, "a list of regexes to cherry-pick conventional commits for the changelog")
f.StringVar(&relCmd.Opts.Sort, "sort", "", "the sort order of commits within each changelog entry")

relCmd.Cmd = cmd
Expand Down Expand Up @@ -171,8 +199,8 @@ func setupReleaseContext(opts releaseOptions, out io.Writer) (*context.Context,
ctx.Changelog.PreTag = true

// Merge config and command line arguments together
ctx.Changelog.Exclude = opts.Exclude
ctx.Changelog.Exclude = append(ctx.Changelog.Exclude, ctx.Config.Changelog.Exclude...)
ctx.Changelog.Include = append(opts.Include, ctx.Config.Changelog.Include...)
ctx.Changelog.Exclude = append(opts.Exclude, ctx.Config.Changelog.Exclude...)

// By default ensure the ci(uplift): commits are excluded also
ctx.Changelog.Exclude = append(ctx.Changelog.Exclude, "ci(uplift):")
Expand Down
20 changes: 19 additions & 1 deletion cmd/uplift/release_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ func TestRelease_WithExclude(t *testing.T) {
untaggedRepo(t, "feat: a new feat", "fix: a new fix", "ci: a ci task", "docs: some new docs")

relCmd := newReleaseCmd(noChangesPushed(), os.Stdout)
relCmd.Cmd.SetArgs([]string{"--exclude", "ci,docs"})
relCmd.Cmd.SetArgs([]string{"--exclude", "^ci,^docs"})

err := relCmd.Cmd.Execute()
require.NoError(t, err)
Expand All @@ -210,3 +210,21 @@ func TestRelease_WithExclude(t *testing.T) {
assert.NotContains(t, cl, "ci: a ci task")
assert.NotContains(t, cl, "docs: some new docs")
}

func TestRelease_WithInclude(t *testing.T) {
untaggedRepo(t, "feat: a new feat", "fix: a new fix", "ci: a ci task", "docs: some new docs")

relCmd := newReleaseCmd(noChangesPushed(), os.Stdout)
relCmd.Cmd.SetArgs([]string{"--include", "^feat"})

err := relCmd.Cmd.Execute()
require.NoError(t, err)

assert.True(t, changelogExists(t))

cl := readChangelog(t)
assert.Contains(t, cl, "feat: a new feat")
assert.NotContains(t, cl, "fix: a new fix")
assert.NotContains(t, cl, "ci: a ci task")
assert.NotContains(t, cl, "docs: some new docs")
}
54 changes: 38 additions & 16 deletions cmd/uplift/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,45 @@ import (
)

const (
tagDesc = `Tags a git repository with the next semantic version. The tag
is based on the conventional commit message from the last commit.`
tagLongDesc = `Generates a new git tag by scanning the git log of a repository for any
conventional commits since the last release (or identifiable tag). When
examining the git log, Uplift will always calculate the next semantic version
based on the most significant detected increment. Uplift automatically handles
the creation and pushing of a new git tag to the remote, but this behavior can
be disabled, to manage this action manually.

examples = ` # Tag the repository with the next calculated semantic version
uplift tag
Conventional Commits is a set of rules for creating an explicit commit history,
which makes building automation tools like Uplift much easier. Uplift adheres to
v1.0.0 of the specification:

# Identify the next semantic version and write to stdout.
# Repository is not tagged
uplift tag --next --silent
https://www.conventionalcommits.org/en/v1.0.0`

# Identify the current semantic version and write to stdout.
# Repository is not tagged
uplift tag --current
tagExamples = `
# Tag the repository with the next calculated semantic version
uplift tag

# Identify the next and current semantic versions and write to stdout.
# Repository is not tagged
uplift tag --current --next --silent`
# Identify the next semantic version and write to stdout. Repository is
# not tagged
uplift tag --next --silent

# Identify the current semantic version and write to stdout. Repository
# is not tagged
uplift tag --current

# Identify the current and next semantic versions and write both to stdout.
# Repository is not tagged
uplift tag --current --next --silent

# Ensure the calculated version explicitly aheres to the SemVer specification
# by stripping the "v" prefix from the generated tag
uplift tag --no-prefix

# Append a prerelease suffix to the next calculated semantic version
uplift tag --prerelease beta.1

# Tag the repository with the next calculated semantic version, but do not
# push the tag to the remote
uplift tag --no-push`
)

var (
Expand Down Expand Up @@ -112,9 +134,9 @@ func newTagCmd(gopts *globalOptions, out io.Writer) *tagCommand {

cmd := &cobra.Command{
Use: "tag",
Short: "Tag a git repository with the next semantic version",
Long: tagDesc,
Example: examples,
Short: "Tag a git repository with the next calculated semantic version",
Long: tagLongDesc,
Example: tagExamples,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
// If only the current tag is to be printed, skip running a pipeline
Expand Down