From e80083f02bf0a579e0a1d9f0c5636f2621cc5c65 Mon Sep 17 00:00:00 2001 From: ypjama <3822534+ypjama@users.noreply.github.com> Date: Sun, 6 Oct 2024 09:49:46 +0300 Subject: [PATCH 01/11] Simplify readme usage section --- README.md | 51 --------------------------------------------------- 1 file changed, 51 deletions(-) diff --git a/README.md b/README.md index 4484ec0..0fcd045 100644 --- a/README.md +++ b/README.md @@ -63,57 +63,6 @@ The commands are: Use "conflictless help " for more information about that topic. ``` -`conflictless help check` - -``` txt -Usage: conflictless check [flags] - -The flags are: - - -d, --dir - Directory where to look for change-files (default: changes) -``` - -`conflictless help create` - -```txt -Usage: conflictless create [flags] - -The flags are: - - -d, --dir - Directory where the change-file should be created (default: changes) - -f, --format - File format and extension yml/yaml/json for the change-file (default: yml) - -t, --types - Types of changes you want for the change-file (default: changed) - - Multiple values can be given by separating values with commas. - Example: '--format added,changed,deprecated,removed,fixed,security'. - -n, --name - Name for the change-file without file extension - - If this flag is not given the name will be derived from the name of the - current git branch you're on. -``` - -`conflictless help generate` - -``` txt -Usage: conflictless generate [flags] - -The flags are: - - -b, --bump - Bump version patch/minor/major (default: minor) - -c, --changelog - Changelog file (default: CHANGELOG.md) - -d, --dir - Directory where to look for change-files (default: changes) - -s, --skip-version-links - Skip version links in changelog file (default: false) -``` - ## Suggested workflow Each project should have a directory for storing unreleased changes, e.g. a directory named `changes`. In this directory developers can create _YAML_ or _JSON_ files for each merge/pull request. The filename can be freely chosen and can be derived from the branch name, e.g. `fix-broken-dependency.yml`. This way each merge/pull request would have its own `changes` file and there would not be any merge conflicts regarding the changelog. From fd17d445f16386a02ca70cbb0d92e74988f58d9d Mon Sep 17 00:00:00 2001 From: ypjama <3822534+ypjama@users.noreply.github.com> Date: Sun, 6 Oct 2024 09:52:24 +0300 Subject: [PATCH 02/11] Update help message --- README.md | 1 + internal/pkg/conflictless/usage.go | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index 0fcd045..2521201 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ The commands are: create Creates a new change-file generate Generates a version entry to changelog file help Prints this help message + preview Prints a preview of unreleased changes Use "conflictless help " for more information about that topic. ``` diff --git a/internal/pkg/conflictless/usage.go b/internal/pkg/conflictless/usage.go index 619b284..dc2b35e 100644 --- a/internal/pkg/conflictless/usage.go +++ b/internal/pkg/conflictless/usage.go @@ -60,6 +60,7 @@ The commands are: create Creates a new change-file generate Generates a version entry to changelog file help Prints this help message + preview Prints a preview of unreleased changes Use "conflictless help " for more information about that topic. ` From 91d739c8b4fb035f3289b4062f1d8c34d9dd21cd Mon Sep 17 00:00:00 2001 From: ypjama <3822534+ypjama@users.noreply.github.com> Date: Sun, 6 Oct 2024 10:27:06 +0300 Subject: [PATCH 03/11] Update usage message for preview --- README.md | 2 +- internal/pkg/conflictless/usage.go | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2521201..e7b51f5 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ The commands are: create Creates a new change-file generate Generates a version entry to changelog file help Prints this help message - preview Prints a preview of unreleased changes + preview Prints a preview of the next changelog entry Use "conflictless help " for more information about that topic. ``` diff --git a/internal/pkg/conflictless/usage.go b/internal/pkg/conflictless/usage.go index dc2b35e..67786ba 100644 --- a/internal/pkg/conflictless/usage.go +++ b/internal/pkg/conflictless/usage.go @@ -60,7 +60,7 @@ The commands are: create Creates a new change-file generate Generates a version entry to changelog file help Prints this help message - preview Prints a preview of unreleased changes + preview Prints a preview of the next changelog entry Use "conflictless help " for more information about that topic. ` @@ -111,6 +111,21 @@ The flags are: ) } +func usageTextForPreview() string { + return fmt.Sprintf(`Usage: conflictless preview [flags] + +The flags are: + +%s +%s +%s +`, + flagDescriptionBump, + flagDescriptionDir, + flagDescriptionSkipVersionLinks, + ) +} + func usage() { fmt.Fprint(os.Stdout, usageText()) } @@ -142,3 +157,11 @@ func usageGenerate() { func usageGenerateOnError() { fmt.Fprint(os.Stderr, usageTextForGenerate()) } + +func usagePreview() { + fmt.Fprint(os.Stdout, usageTextForPreview()) +} + +func usagePreviewOnError() { + fmt.Fprint(os.Stderr, usageTextForPreview()) +} From 0bf2fb6036dd9eda3b713d4abbd379c50f377d00 Mon Sep 17 00:00:00 2001 From: ypjama <3822534+ypjama@users.noreply.github.com> Date: Sun, 6 Oct 2024 10:27:23 +0300 Subject: [PATCH 04/11] Add a change-file --- changes/add-preview-command.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changes/add-preview-command.json diff --git a/changes/add-preview-command.json b/changes/add-preview-command.json new file mode 100644 index 0000000..698b586 --- /dev/null +++ b/changes/add-preview-command.json @@ -0,0 +1,5 @@ +{ + "added": [ + "New command 'preview' which prints a preview of the next changelog entry." + ] +} \ No newline at end of file From 11fb6bc90138170188ba485c3a143c59a7a6ba51 Mon Sep 17 00:00:00 2001 From: ypjama <3822534+ypjama@users.noreply.github.com> Date: Sun, 6 Oct 2024 10:29:03 +0300 Subject: [PATCH 05/11] Add new command 'preview' --- internal/pkg/conflictless/cli.go | 10 +++++++++ internal/pkg/conflictless/config.go | 31 +++++++++++++++++++++++++++ internal/pkg/conflictless/generate.go | 19 +--------------- internal/pkg/conflictless/help.go | 2 ++ internal/pkg/conflictless/preview.go | 11 ++++++++++ internal/pkg/conflictless/print.go | 5 +++++ 6 files changed, 60 insertions(+), 18 deletions(-) create mode 100644 internal/pkg/conflictless/preview.go diff --git a/internal/pkg/conflictless/cli.go b/internal/pkg/conflictless/cli.go index b556eb6..a81364a 100644 --- a/internal/pkg/conflictless/cli.go +++ b/internal/pkg/conflictless/cli.go @@ -14,6 +14,7 @@ const ( commandCreate = "create" commandGen = "generate" commandHelp = "help" + commandPreview = "preview" defaultBump = BumpMinor defaultChangeFileFormat = "yml" defaultChangeTypesCSV = "changed" @@ -59,6 +60,8 @@ func CLI() { Create(&cfg) case commandGen: Generate(&cfg) + case commandPreview: + Preview(&cfg) case commandHelp: Help() default: @@ -116,6 +119,13 @@ func parseCLIFlags(cfg *Config) { defineCreateTypeFlags(cfg, cmd) defineDirFlags(cfg, cmd) defineChangeFileNameFlags(cfg, cmd) + case commandPreview: + cmd = flag.NewFlagSet(commandPreview, flag.ExitOnError) + cmd.Usage = usagePreviewOnError + + defineBumpFlags(cfg, cmd) + defineDirFlags(cfg, cmd) + defineSkipFlags(cfg, cmd) } if cmd != nil { diff --git a/internal/pkg/conflictless/config.go b/internal/pkg/conflictless/config.go index c3f5209..55df47d 100644 --- a/internal/pkg/conflictless/config.go +++ b/internal/pkg/conflictless/config.go @@ -50,6 +50,12 @@ func (cfg *Config) SetCheckConfigsFromFlags() { cfg.SetDirectoryFromFlags() } +func (cfg *Config) SetPreviewConfigsFromFlags() error { + cfg.SetDirectoryFromFlags() + + return cfg.SetBumpFromFlags() +} + func (cfg *Config) SetDirectoryFromFlags() { if cfg.Flags.Directory != nil { cfg.Directory = *cfg.Flags.Directory @@ -117,3 +123,28 @@ func (cfg *Config) SetChangeFileFormatFromFlags() error { return nil } + +func (cfg *Config) GenerateNewSection() string { + var err error + + cfg.Changelog, err = ReadChangelog(cfg) + if err != nil { + PrintErrorAndExit(err.Error(), func() {}) + } + + combined, err := scanDir(cfg.Directory) + if err != nil { + PrintErrorAndExit(err.Error(), func() {}) + } + + if combined.IsEmpty() { + PrintErrorAndExit("no changelog entries found", func() {}) + } + + newSection := DataToMarkdown(cfg, combined) + if newSection == "" { + PrintErrorAndExit("failed to generate a new version section", func() {}) + } + + return newSection +} diff --git a/internal/pkg/conflictless/generate.go b/internal/pkg/conflictless/generate.go index e6dda7b..8f6ec68 100644 --- a/internal/pkg/conflictless/generate.go +++ b/internal/pkg/conflictless/generate.go @@ -15,24 +15,7 @@ func Generate(cfg *Config) { PrintErrorAndExit(err.Error(), usageGenerateOnError) } - cfg.Changelog, err = ReadChangelog(cfg) - if err != nil { - PrintErrorAndExit(err.Error(), func() {}) - } - - combined, err := scanDir(cfg.Directory) - if err != nil { - PrintErrorAndExit(err.Error(), func() {}) - } - - if combined.IsEmpty() { - PrintErrorAndExit("no changelog entries found", func() {}) - } - - newSection := DataToMarkdown(cfg, combined) - if newSection == "" { - PrintErrorAndExit("failed to generate a new version section", func() {}) - } + newSection := cfg.GenerateNewSection() err = cfg.Changelog.WriteSection(newSection) if err != nil { diff --git a/internal/pkg/conflictless/help.go b/internal/pkg/conflictless/help.go index c7fbac5..950234a 100644 --- a/internal/pkg/conflictless/help.go +++ b/internal/pkg/conflictless/help.go @@ -22,6 +22,8 @@ func Help() { usageCreate() case commandGen: usageGenerate() + case commandPreview: + usagePreview() case "": usage() default: diff --git a/internal/pkg/conflictless/preview.go b/internal/pkg/conflictless/preview.go new file mode 100644 index 0000000..be04b75 --- /dev/null +++ b/internal/pkg/conflictless/preview.go @@ -0,0 +1,11 @@ +package conflictless + +// Preview prints a preview of unreleased changes. +func Preview(cfg *Config) { + err := cfg.SetPreviewConfigsFromFlags() + if err != nil { + PrintErrorAndExit(err.Error(), usagePreviewOnError) + } + + PrintPreviewSuccess(cfg.GenerateNewSection()) +} diff --git a/internal/pkg/conflictless/print.go b/internal/pkg/conflictless/print.go index dd0ceb0..ed0f965 100644 --- a/internal/pkg/conflictless/print.go +++ b/internal/pkg/conflictless/print.go @@ -60,3 +60,8 @@ func PrintCreateSuccess(cfg *Config) { //nolint:forbidigo fmt.Printf("Created new change-file '%s' successfully!\n", filepath.Join(cfg.Directory, cfg.ChangeFile)) } + +func PrintPreviewSuccess(section string) { + //nolint:forbidigo + fmt.Printf("```md\n%s```\n", section) +} From dad9d14e4f3bcfdbe94f4725fe4ab2233537f307 Mon Sep 17 00:00:00 2001 From: ypjama <3822534+ypjama@users.noreply.github.com> Date: Sun, 6 Oct 2024 11:04:10 +0300 Subject: [PATCH 06/11] Add tests --- internal/pkg/conflictless/cli_test.go | 1 + .../pkg/conflictless/conflictless_test.go | 55 +++++++++++++++++++ internal/pkg/conflictless/generate_test.go | 3 +- internal/pkg/conflictless/preview_test.go | 50 +++++++++++++++++ 4 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 internal/pkg/conflictless/preview_test.go diff --git a/internal/pkg/conflictless/cli_test.go b/internal/pkg/conflictless/cli_test.go index 6898a09..6e31408 100644 --- a/internal/pkg/conflictless/cli_test.go +++ b/internal/pkg/conflictless/cli_test.go @@ -113,6 +113,7 @@ func TestCLIHelp(t *testing.T) { {"help check", []string{"help", "check"}, false}, {"help create", []string{"help", "create"}, false}, {"help generate", []string{"help", "generate"}, false}, + {"help preview", []string{"help", "preview"}, false}, {"help unknown", []string{"help", "unknown"}, true}, } { t.Run(testCase.description, func(t *testing.T) { diff --git a/internal/pkg/conflictless/conflictless_test.go b/internal/pkg/conflictless/conflictless_test.go index 61ba63c..d751764 100644 --- a/internal/pkg/conflictless/conflictless_test.go +++ b/internal/pkg/conflictless/conflictless_test.go @@ -1,15 +1,27 @@ package conflictless_test import ( + "bytes" + "io" "os" "testing" ) +type readWriteCapture struct { + original *os.File + read *os.File + write *os.File + outChannel chan string +} + const ( mkdirFileMode = 0o755 writeFileMode = 0o644 ) +//nolint:gochecknoglobals +var stdoutCapture *readWriteCapture + func writeDataToFile(t *testing.T, data []byte, file *os.File) { t.Helper() @@ -40,3 +52,46 @@ func createTempFile(t *testing.T, dir, pattern string) *os.File { return file } + +func startStdoutCapture(t *testing.T) { + t.Helper() + + stdoutCapture = new(readWriteCapture) + stdoutCapture.original = os.Stdout + + read, write, _ := os.Pipe() + stdoutCapture.read = read + stdoutCapture.write = write + + os.Stdout = stdoutCapture.write + + stdoutCapture.outChannel = make(chan string) + + go func() { + var buf bytes.Buffer + + _, err := io.Copy(&buf, read) + if err != nil { + t.Error(err.Error()) + } + + stdoutCapture.outChannel <- buf.String() + }() +} + +func stopStdoutCapture(t *testing.T) string { + t.Helper() + + if stdoutCapture == nil { + t.Errorf("could not stop stdout capture because stdout capture wasn't initialized") + } + + stdoutCapture.write.Close() + os.Stdout = stdoutCapture.original + + output := <-stdoutCapture.outChannel + + stdoutCapture = nil + + return output +} diff --git a/internal/pkg/conflictless/generate_test.go b/internal/pkg/conflictless/generate_test.go index c6b6b41..37803d8 100644 --- a/internal/pkg/conflictless/generate_test.go +++ b/internal/pkg/conflictless/generate_test.go @@ -16,8 +16,6 @@ func TestGenerate(t *testing.T) { defer os.RemoveAll(changesDir) - os.TempDir() - changesFile := createFile(t, changesDir, "test-generate.json") defer os.Remove(changesFile.Name()) @@ -36,6 +34,7 @@ func TestGenerate(t *testing.T) { cfg := new(conflictless.Config) cfg.Flags.Directory = &changesDir cfg.Flags.Bump = &flagValueBumpPatch + cfg.Flags.SkipVersionLinks = true cfg.ChangelogFile = changelogFile.Name() cfg.RepositoryConfigFile = gitConfigFile.Name() diff --git a/internal/pkg/conflictless/preview_test.go b/internal/pkg/conflictless/preview_test.go new file mode 100644 index 0000000..749982f --- /dev/null +++ b/internal/pkg/conflictless/preview_test.go @@ -0,0 +1,50 @@ +package conflictless_test + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/ypjama/conflictless-keepachangelog/internal/pkg/conflictless" +) + +func TestPreview(t *testing.T) { + t.Parallel() + + changesDir, err := os.MkdirTemp(os.TempDir(), "changes") + assert.NoError(t, err) + + defer os.RemoveAll(changesDir) + + changesFile := createFile(t, changesDir, "test-preview.json") + defer os.Remove(changesFile.Name()) + + changelogFile := createTempFile(t, os.TempDir(), "test-preview-CHANGELOG.md") + defer os.Remove(changelogFile.Name()) + + gitConfigFile := createTempFile(t, os.TempDir(), "test-preview.gitconfig") + defer os.Remove(gitConfigFile.Name()) + + writeDataToFile(t, []byte(`{"added":["New major feature"]}`), changesFile) + writeDataToFile(t, []byte(changelogContent), changelogFile) + writeDataToFile(t, []byte(gitConfig), gitConfigFile) + + flagValueBumpPatch := "major" + + cfg := new(conflictless.Config) + cfg.Flags.Directory = &changesDir + cfg.Flags.Bump = &flagValueBumpPatch + cfg.Flags.SkipVersionLinks = true + cfg.ChangelogFile = changelogFile.Name() + cfg.RepositoryConfigFile = gitConfigFile.Name() + + startStdoutCapture(t) + + conflictless.Preview(cfg) + + output := stopStdoutCapture(t) + + assert.Contains(t, output, "```md\n") + assert.Contains(t, output, "## [2.0.0]") + assert.Contains(t, output, "### Added\n\n- New major feature\n") +} From 19a31f3d19b67ea40d028698aab0a5efcf78f896 Mon Sep 17 00:00:00 2001 From: ypjama <3822534+ypjama@users.noreply.github.com> Date: Sun, 6 Oct 2024 11:52:31 +0300 Subject: [PATCH 07/11] Add --dir flag to preview --- internal/pkg/conflictless/cli.go | 1 + internal/pkg/conflictless/cli_test.go | 62 +++++++++++++++++++ internal/pkg/conflictless/config.go | 1 + .../pkg/conflictless/conflictless_test.go | 2 +- internal/pkg/conflictless/usage.go | 2 + 5 files changed, 67 insertions(+), 1 deletion(-) diff --git a/internal/pkg/conflictless/cli.go b/internal/pkg/conflictless/cli.go index a81364a..7a2f5a8 100644 --- a/internal/pkg/conflictless/cli.go +++ b/internal/pkg/conflictless/cli.go @@ -124,6 +124,7 @@ func parseCLIFlags(cfg *Config) { cmd.Usage = usagePreviewOnError defineBumpFlags(cfg, cmd) + defineChangeLogFlags(cfg, cmd) defineDirFlags(cfg, cmd) defineSkipFlags(cfg, cmd) } diff --git a/internal/pkg/conflictless/cli_test.go b/internal/pkg/conflictless/cli_test.go index 6e31408..e61e788 100644 --- a/internal/pkg/conflictless/cli_test.go +++ b/internal/pkg/conflictless/cli_test.go @@ -5,6 +5,7 @@ import ( "net/url" "os" "os/exec" + "path/filepath" "testing" "github.com/stretchr/testify/assert" @@ -269,3 +270,64 @@ func TestCLICreateWithInvalidFlags(t *testing.T) { assert.Empty(t, string(stdoutData)) assert.NotEmpty(t, string(stderrData)) } + +func TestCliPreview(t *testing.T) { + t.Parallel() + + if os.Getenv("TEST_CLI_PREVIEW") != "" { + conflictless.CLI() + + return + } + + tmpDir := filepath.Join(os.TempDir(), "conflictless-cli-preview-test") + changesDir := filepath.Join(tmpDir, "changes-test") + + err := os.MkdirAll(changesDir, mkdirFileMode) + assert.NoError(t, err) + changelogFile := createFile(t, tmpDir, "test-cli-preview-CHANGELOG.md") + changesFile := createFile(t, changesDir, "thing-removed.json") + + defer os.RemoveAll(tmpDir) + writeDataToFile(t, []byte(`{"removed":["that thing"]}`), changesFile) + writeDataToFile(t, []byte(changelogContent), changelogFile) + + stdoutFile := createTempFile(t, os.TempDir(), "test-cli-preview-stdout") + defer os.Remove(stdoutFile.Name()) + + stderrFile := createTempFile(t, os.TempDir(), "test-cli-preview-stderr") + defer os.Remove(stderrFile.Name()) + + //nolint:gosec // this is a test package so G204 doesn't really matter here. + cmd := exec.Command( + os.Args[0], + "-test.run=^TestCliPreview$", + "preview", + "--skip-version-links", + "--dir", + changesDir, + "--changelog", + changelogFile.Name(), + "--bump", + "minor", + ) + + cmd.Stdout = stdoutFile + cmd.Stderr = stderrFile + + cmd.Env = append(os.Environ(), "TEST_CLI_PREVIEW=1") + err = cmd.Run() + + assert.NoError(t, err) + + stdoutData, err := os.ReadFile(stdoutFile.Name()) + assert.NoError(t, err) + + stderrData, err := os.ReadFile(stderrFile.Name()) + assert.NoError(t, err) + + assert.NotEmpty(t, string(stdoutData)) + assert.Empty(t, string(stderrData)) + + assert.Contains(t, string(stdoutData), "### Removed\n\n- that thing\n") +} diff --git a/internal/pkg/conflictless/config.go b/internal/pkg/conflictless/config.go index 55df47d..5a2d853 100644 --- a/internal/pkg/conflictless/config.go +++ b/internal/pkg/conflictless/config.go @@ -51,6 +51,7 @@ func (cfg *Config) SetCheckConfigsFromFlags() { } func (cfg *Config) SetPreviewConfigsFromFlags() error { + cfg.SetChangelogFileFromFlags() cfg.SetDirectoryFromFlags() return cfg.SetBumpFromFlags() diff --git a/internal/pkg/conflictless/conflictless_test.go b/internal/pkg/conflictless/conflictless_test.go index d751764..439bd0f 100644 --- a/internal/pkg/conflictless/conflictless_test.go +++ b/internal/pkg/conflictless/conflictless_test.go @@ -83,7 +83,7 @@ func stopStdoutCapture(t *testing.T) string { t.Helper() if stdoutCapture == nil { - t.Errorf("could not stop stdout capture because stdout capture wasn't initialized") + t.Fatal("could not stop stdout capture because stdout capture wasn't initialized") } stdoutCapture.write.Close() diff --git a/internal/pkg/conflictless/usage.go b/internal/pkg/conflictless/usage.go index 67786ba..99a0206 100644 --- a/internal/pkg/conflictless/usage.go +++ b/internal/pkg/conflictless/usage.go @@ -119,8 +119,10 @@ The flags are: %s %s %s +%s `, flagDescriptionBump, + flagDescriptionChangelog, flagDescriptionDir, flagDescriptionSkipVersionLinks, ) From 4af0e48a8db2b2e87463bf04f13aef34a1d46037 Mon Sep 17 00:00:00 2001 From: ypjama <3822534+ypjama@users.noreply.github.com> Date: Sun, 6 Oct 2024 13:04:10 +0300 Subject: [PATCH 08/11] Add tests --- internal/pkg/conflictless/cli.go | 66 +++++++++----- internal/pkg/conflictless/cli_test.go | 108 +++++++++++++++++++++++ internal/pkg/conflictless/export_test.go | 6 ++ 3 files changed, 159 insertions(+), 21 deletions(-) create mode 100644 internal/pkg/conflictless/export_test.go diff --git a/internal/pkg/conflictless/cli.go b/internal/pkg/conflictless/cli.go index 7a2f5a8..d873d32 100644 --- a/internal/pkg/conflictless/cli.go +++ b/internal/pkg/conflictless/cli.go @@ -137,43 +137,67 @@ func parseCLIFlags(cfg *Config) { } } -func defineChangeLogFlags(cfg *Config, fs *flag.FlagSet) { +func defineChangeLogFlags(cfg *Config, flagset *flag.FlagSet) { defaultChangelogFile := "CHANGELOG.md" - fs.StringVar(cfg.Flags.ChangelogFile, "changelog", defaultChangelogFile, "") - fs.StringVar(cfg.Flags.ChangelogFile, "c", defaultChangelogFile, "") + if cfg.Flags.ChangelogFile == nil { + cfg.Flags.ChangelogFile = new(string) + } + + flagset.StringVar(cfg.Flags.ChangelogFile, "changelog", defaultChangelogFile, "") + flagset.StringVar(cfg.Flags.ChangelogFile, "c", defaultChangelogFile, "") } -func defineBumpFlags(cfg *Config, fs *flag.FlagSet) { +func defineBumpFlags(cfg *Config, flagset *flag.FlagSet) { defaultBumpStr := "minor" - fs.StringVar(cfg.Flags.Bump, "bump", defaultBumpStr, "") - fs.StringVar(cfg.Flags.Bump, "b", defaultBumpStr, "") + if cfg.Flags.Bump == nil { + cfg.Flags.Bump = new(string) + } + + flagset.StringVar(cfg.Flags.Bump, "bump", defaultBumpStr, "") + flagset.StringVar(cfg.Flags.Bump, "b", defaultBumpStr, "") } -func defineDirFlags(cfg *Config, fs *flag.FlagSet) { +func defineDirFlags(cfg *Config, flagset *flag.FlagSet) { defaultDir := "changes" - fs.StringVar(cfg.Flags.Directory, "dir", defaultDir, "") - fs.StringVar(cfg.Flags.Directory, "d", defaultDir, "") + if cfg.Flags.Directory == nil { + cfg.Flags.Directory = new(string) + } + + flagset.StringVar(cfg.Flags.Directory, "dir", defaultDir, "") + flagset.StringVar(cfg.Flags.Directory, "d", defaultDir, "") } -func defineFormatFlags(cfg *Config, fs *flag.FlagSet) { - fs.StringVar(cfg.Flags.ChangeFileFormat, "format", defaultChangeFileFormat, "") - fs.StringVar(cfg.Flags.ChangeFileFormat, "f", defaultChangeFileFormat, "") +func defineFormatFlags(cfg *Config, flagset *flag.FlagSet) { + if cfg.Flags.ChangeFileFormat == nil { + cfg.Flags.ChangeFileFormat = new(string) + } + + flagset.StringVar(cfg.Flags.ChangeFileFormat, "format", defaultChangeFileFormat, "") + flagset.StringVar(cfg.Flags.ChangeFileFormat, "f", defaultChangeFileFormat, "") } -func defineCreateTypeFlags(cfg *Config, fs *flag.FlagSet) { - fs.StringVar(cfg.Flags.ChangeTypesCsv, "types", defaultChangeTypesCSV, "") - fs.StringVar(cfg.Flags.ChangeTypesCsv, "t", defaultChangeTypesCSV, "") +func defineCreateTypeFlags(cfg *Config, flagset *flag.FlagSet) { + if cfg.Flags.ChangeTypesCsv == nil { + cfg.Flags.ChangeTypesCsv = new(string) + } + + flagset.StringVar(cfg.Flags.ChangeTypesCsv, "types", defaultChangeTypesCSV, "") + flagset.StringVar(cfg.Flags.ChangeTypesCsv, "t", defaultChangeTypesCSV, "") } -func defineChangeFileNameFlags(cfg *Config, fs *flag.FlagSet) { - fs.StringVar(cfg.Flags.ChangeFileName, "name", "", "") - fs.StringVar(cfg.Flags.ChangeFileName, "n", "", "") +func defineChangeFileNameFlags(cfg *Config, flagset *flag.FlagSet) { + if cfg.Flags.ChangeFileName == nil { + cfg.Flags.ChangeFileName = new(string) + } + + flagset.StringVar(cfg.Flags.ChangeFileName, "name", "", "") + flagset.StringVar(cfg.Flags.ChangeFileName, "n", "", "") } -func defineSkipFlags(cfg *Config, fs *flag.FlagSet) { - fs.BoolVar(&cfg.Flags.SkipVersionLinks, "skip-version-links", false, "") - fs.BoolVar(&cfg.Flags.SkipVersionLinks, "s", false, "") +func defineSkipFlags(cfg *Config, flagset *flag.FlagSet) { + flagset.BoolVar(&cfg.Flags.SkipVersionLinks, "skip-version-links", false, "") + flagset.BoolVar(&cfg.Flags.SkipVersionLinks, "s", false, "") } diff --git a/internal/pkg/conflictless/cli_test.go b/internal/pkg/conflictless/cli_test.go index e61e788..4512a72 100644 --- a/internal/pkg/conflictless/cli_test.go +++ b/internal/pkg/conflictless/cli_test.go @@ -12,6 +12,114 @@ import ( "github.com/ypjama/conflictless-keepachangelog/internal/pkg/conflictless" ) +type parseCliFlagsTestCase struct { + description string + argsAfterMain []string + expectedFlags conflictless.FlagCollection +} + +//nolint:funlen +func TestParseCLIFlags(t *testing.T) { + t.Parallel() + + originalArgs := os.Args + + dir := "directory-for-cli-parse-test" + bump := "major" + changelog := "changelog-for-cli-parse-test.md" + format := "json" + types := "added,changed,removed" + name := "foo-bar-baz" + + for _, testCase := range []parseCliFlagsTestCase{ + { + "check", + []string{"check", "--dir", dir}, + conflictless.FlagCollection{ + Bump: nil, + ChangeFileFormat: nil, + ChangeFileName: nil, + ChangelogFile: nil, + ChangeTypesCsv: nil, + Command: "check", + Directory: &dir, + SkipVersionLinks: false, + }, + }, + { + "create", + []string{"create", "-d", dir, "-f", format, "-t", types, "-n", name}, + conflictless.FlagCollection{ + Bump: nil, + ChangeFileFormat: &format, + ChangeFileName: &name, + ChangelogFile: nil, + ChangeTypesCsv: &types, + Command: "create", + Directory: &dir, + SkipVersionLinks: false, + }, + }, + { + "generate", + []string{"generate", "-c", changelog, "-s", "-d", dir, "-b", bump}, + conflictless.FlagCollection{ + Bump: &bump, + ChangeFileFormat: nil, + ChangeFileName: nil, + ChangelogFile: &changelog, + ChangeTypesCsv: nil, + Command: "generate", + Directory: &dir, + SkipVersionLinks: true, + }, + }, + { + "help", + []string{"help"}, + conflictless.FlagCollection{ + Bump: nil, + ChangeFileFormat: nil, + ChangeFileName: nil, + ChangelogFile: nil, + ChangeTypesCsv: nil, + Command: "help", + Directory: nil, + SkipVersionLinks: false, + }, + }, + { + "preview", + []string{"preview", "--changelog", changelog, "--skip-version-links", "--dir", dir, "--bump", bump}, + conflictless.FlagCollection{ + Bump: &bump, + ChangeFileFormat: nil, + ChangeFileName: nil, + ChangelogFile: &changelog, + ChangeTypesCsv: nil, + Command: "preview", + Directory: &dir, + SkipVersionLinks: true, + }, + }, + } { + t.Run(testCase.description, func(t *testing.T) { + t.Parallel() + + args := []string{"conflictless"} + args = append(args, testCase.argsAfterMain...) + os.Args = args + + cfg := new(conflictless.Config) + conflictless.ParseCLIFlags(cfg) + + os.Args = originalArgs + + assert.EqualValues(t, testCase.expectedFlags, cfg.Flags) + }) + } +} + func TestCLIWithoutArguments(t *testing.T) { t.Parallel() diff --git a/internal/pkg/conflictless/export_test.go b/internal/pkg/conflictless/export_test.go new file mode 100644 index 0000000..c1cc051 --- /dev/null +++ b/internal/pkg/conflictless/export_test.go @@ -0,0 +1,6 @@ +package conflictless + +// Export functions for tests + +//nolint:gochecknoglobals +var ParseCLIFlags = parseCLIFlags From 8552300ebffe8cd3bb68fa2e42a024c287f1675e Mon Sep 17 00:00:00 2001 From: ypjama <3822534+ypjama@users.noreply.github.com> Date: Sun, 6 Oct 2024 13:14:06 +0300 Subject: [PATCH 09/11] Add tests --- internal/pkg/conflictless/cli_test.go | 77 ++++++++++++++------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/internal/pkg/conflictless/cli_test.go b/internal/pkg/conflictless/cli_test.go index 4512a72..da5d732 100644 --- a/internal/pkg/conflictless/cli_test.go +++ b/internal/pkg/conflictless/cli_test.go @@ -266,60 +266,61 @@ func TestCLIHelp(t *testing.T) { } } -func TestCLIGenerateWithInvalidFlags(t *testing.T) { +func TestCLIWithInvalidDirFlag(t *testing.T) { t.Parallel() - if os.Getenv("TEST_CLI_GENERATE_INVALID_FLAGS") != "" { + if os.Getenv("TEST_CLI_INVALID_DIR_FLAG") != "" { conflictless.CLI() return } - stdoutFile := createTempFile(t, os.TempDir(), "test-cli-generate-with-invalid-flags-stdout") - defer os.Remove(stdoutFile.Name()) - - stderrFile := createTempFile(t, os.TempDir(), "test-cli-generate-with-invalid-flags-stderr") - defer os.Remove(stderrFile.Name()) - - //nolint:gosec // this is a test package so G204 doesn't really matter here. - cmd := exec.Command( - os.Args[0], - "-test.run=^TestCLIGenerateWithInvalidFlags$", + for _, command := range []string{ + "check", "generate", - "--dir", - "rhymenocerous", - "--changelog", - "HIPPOPOTAMUS.md", - "--bump", - "steve", - ) - - cmd.Stdout = stdoutFile - cmd.Stderr = stderrFile - - cmd.Env = append(os.Environ(), "TEST_CLI_GENERATE_INVALID_FLAGS=1") - err := cmd.Run() + "preview", + } { + t.Run("invalid_dir_flag_with_command_"+command, func(t *testing.T) { + t.Parallel() - assert.Error(t, err) + stdoutFile := createTempFile(t, os.TempDir(), "test-cli-generate-with-invalid-flags-stdout") + defer os.Remove(stdoutFile.Name()) - assert.IsType(t, new(exec.ExitError), err) + stderrFile := createTempFile(t, os.TempDir(), "test-cli-generate-with-invalid-flags-stderr") + defer os.Remove(stderrFile.Name()) - exitErr := new(*exec.ExitError) - errors.As(err, exitErr) + //nolint:gosec // this is a test package so G204 doesn't really matter here. + cmd := exec.Command( + os.Args[0], + "-test.run=^TestCLIWithInvalidDirFlag$", + command, + "--dir", + "rhymenocerous", + ) - expectedCode := 2 - exitCode := (*exitErr).ExitCode() + cmd.Stdout = stdoutFile + cmd.Stderr = stderrFile - assert.Equal(t, expectedCode, exitCode, "process exited with %d, want exit status %d", expectedCode, exitCode) + cmd.Env = append(os.Environ(), "TEST_CLI_INVALID_DIR_FLAG=1") + err := cmd.Run() - stdoutData, err := os.ReadFile(stdoutFile.Name()) - assert.NoError(t, err) + assert.Error(t, err) + assert.IsType(t, new(exec.ExitError), err) - stderrData, err := os.ReadFile(stderrFile.Name()) - assert.NoError(t, err) + exitErr := new(*exec.ExitError) + errors.As(err, exitErr) + exitCode := (*exitErr).ExitCode() + expectedCode := 2 + assert.Equal(t, expectedCode, exitCode, "process exited with %d, want exit status %d", expectedCode, exitCode) - assert.Empty(t, string(stdoutData)) - assert.NotEmpty(t, string(stderrData)) + stdoutData, err := os.ReadFile(stdoutFile.Name()) + assert.NoError(t, err) + stderrData, err := os.ReadFile(stderrFile.Name()) + assert.NoError(t, err) + assert.Empty(t, string(stdoutData)) + assert.NotEmpty(t, string(stderrData)) + }) + } } func TestCLICreateWithInvalidFlags(t *testing.T) { From bd45709d8ae877502512f2a7148a979a57cd8ac3 Mon Sep 17 00:00:00 2001 From: ypjama <3822534+ypjama@users.noreply.github.com> Date: Sun, 6 Oct 2024 13:15:37 +0300 Subject: [PATCH 10/11] Sort variables alphabetically --- internal/pkg/conflictless/cli_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/pkg/conflictless/cli_test.go b/internal/pkg/conflictless/cli_test.go index da5d732..ecee737 100644 --- a/internal/pkg/conflictless/cli_test.go +++ b/internal/pkg/conflictless/cli_test.go @@ -24,12 +24,12 @@ func TestParseCLIFlags(t *testing.T) { originalArgs := os.Args - dir := "directory-for-cli-parse-test" bump := "major" changelog := "changelog-for-cli-parse-test.md" + dir := "directory-for-cli-parse-test" format := "json" - types := "added,changed,removed" name := "foo-bar-baz" + types := "added,changed,removed" for _, testCase := range []parseCliFlagsTestCase{ { From d3cb418d54d4f159566856b0a4fe0651237c37e9 Mon Sep 17 00:00:00 2001 From: ypjama <3822534+ypjama@users.noreply.github.com> Date: Sun, 6 Oct 2024 13:20:10 +0300 Subject: [PATCH 11/11] Generate changelog entry for v0.3.0 --- CHANGELOG.md | 8 ++++++++ changes/add-preview-command.json | 5 ----- 2 files changed, 8 insertions(+), 5 deletions(-) delete mode 100644 changes/add-preview-command.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 9328f95..e3bef6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.3.0] - 2024-10-06 + +[0.3.0]: https://github.com/ypjama/conflictless-keepachangelog/releases/tag/v0.3.0 + +### Added + +- New command 'preview' which prints a preview of the next changelog entry. + ## [0.2.0] - 2024-10-05 [0.2.0]: https://github.com/ypjama/conflictless-keepachangelog/releases/tag/v0.2.0 diff --git a/changes/add-preview-command.json b/changes/add-preview-command.json deleted file mode 100644 index 698b586..0000000 --- a/changes/add-preview-command.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "added": [ - "New command 'preview' which prints a preview of the next changelog entry." - ] -} \ No newline at end of file