From af8cd1f67a7b1d52d7b4b5ac88595795e747708a Mon Sep 17 00:00:00 2001 From: p4u1 Date: Tue, 12 Dec 2023 14:46:20 +0000 Subject: [PATCH] feat: abra release now asks for a release note (!393) This implements https://git.coopcloud.tech/coop-cloud/organising/issues/540 by checking if a`release/next` file exists and if so moves it to `release/`. When no release notes exists it prompts for them. Reviewed-on: https://git.coopcloud.tech/coop-cloud/abra/pulls/393 Reviewed-by: moritz Co-authored-by: p4u1 Co-committed-by: p4u1 --- cli/recipe/release.go | 88 ++++++++++++++++++++++++++- pkg/git/add.go | 27 ++++++++ tests/integration/app_cp.bats | 25 -------- tests/integration/helpers/common.bash | 1 + tests/integration/helpers/file.bash | 24 ++++++++ tests/integration/helpers/git.bash | 7 +++ tests/integration/recipe_release.bats | 28 +++++++-- 7 files changed, 168 insertions(+), 32 deletions(-) create mode 100644 pkg/git/add.go create mode 100644 tests/integration/helpers/file.bash diff --git a/cli/recipe/release.go b/cli/recipe/release.go index 74cc83bd..d2da8230 100644 --- a/cli/recipe/release.go +++ b/cli/recipe/release.go @@ -1,7 +1,9 @@ package recipe import ( + "errors" "fmt" + "os" "path" "strconv" "strings" @@ -140,7 +142,7 @@ your SSH keys configured on your account. // getImageVersions retrieves image versions for a recipe func getImageVersions(recipe recipe.Recipe) (map[string]string, error) { - var services = make(map[string]string) + services := make(map[string]string) missingTag := false for _, service := range recipe.Config.Services { @@ -207,6 +209,10 @@ func createReleaseFromTag(recipe recipe.Recipe, tagString, mainAppVersion string tagString = fmt.Sprintf("%s+%s", tag.String(), mainAppVersion) } + if err := addReleaseNotes(recipe, tagString); err != nil { + logrus.Fatal(err) + } + if err := commitRelease(recipe, tagString); err != nil { logrus.Fatal(err) } @@ -237,6 +243,82 @@ func getTagCreateOptions(tag string) (git.CreateTagOptions, error) { return git.CreateTagOptions{Message: msg}, nil } +// addReleaseNotes checks if the release/next release note exists and moves the +// file to release/. +func addReleaseNotes(recipe recipe.Recipe, tag string) error { + repoPath := path.Join(config.RECIPES_DIR, recipe.Name) + tagReleaseNotePath := path.Join(repoPath, "release", tag) + if _, err := os.Stat(tagReleaseNotePath); err == nil { + // Release note for current tag already exist exists. + return nil + } else if !errors.Is(err, os.ErrNotExist) { + return err + } + + nextReleaseNotePath := path.Join(repoPath, "release", "next") + if _, err := os.Stat(nextReleaseNotePath); err == nil { + // release/next note exists. Move it to release/ + if internal.Dry { + logrus.Debugf("dry run: move release note from 'next' to %s", tag) + return nil + } + if !internal.NoInput { + prompt := &survey.Input{ + Message: "Use release note in release/next?", + } + var addReleaseNote bool + if err := survey.AskOne(prompt, &addReleaseNote); err != nil { + return err + } + if !addReleaseNote { + return nil + } + } + err := os.Rename(nextReleaseNotePath, tagReleaseNotePath) + if err != nil { + return err + } + err = gitPkg.Add(repoPath, path.Join("release", "next"), internal.Dry) + if err != nil { + return err + } + err = gitPkg.Add(repoPath, path.Join("release", tag), internal.Dry) + if err != nil { + return err + } + } else if !errors.Is(err, os.ErrNotExist) { + return err + } + + // No release note exists for the current release. + if internal.NoInput { + return nil + } + + prompt := &survey.Input{ + Message: "Release Note (leave empty for no release note)", + } + var releaseNote string + if err := survey.AskOne(prompt, &releaseNote); err != nil { + return err + } + + if releaseNote == "" { + return nil + } + + err := os.WriteFile(tagReleaseNotePath, []byte(releaseNote), 0o644) + if err != nil { + return err + } + err = gitPkg.Add(repoPath, path.Join("release", tag), internal.Dry) + if err != nil { + return err + } + + return nil +} + func commitRelease(recipe recipe.Recipe, tag string) error { if internal.Dry { logrus.Debugf("dry run: no changes committed") @@ -404,6 +486,10 @@ func createReleaseFromPreviousTag(tagString, mainAppVersion string, recipe recip } } + if err := addReleaseNotes(recipe, tagString); err != nil { + logrus.Fatal(err) + } + if err := commitRelease(recipe, tagString); err != nil { logrus.Fatalf("failed to commit changes: %s", err.Error()) } diff --git a/pkg/git/add.go b/pkg/git/add.go new file mode 100644 index 00000000..36668568 --- /dev/null +++ b/pkg/git/add.go @@ -0,0 +1,27 @@ +package git + +import ( + "github.com/go-git/go-git/v5" + "github.com/sirupsen/logrus" +) + +// Add adds a file to the git index. +func Add(repoPath, path string, dryRun bool) error { + repo, err := git.PlainOpen(repoPath) + if err != nil { + return err + } + + worktree, err := repo.Worktree() + if err != nil { + return err + } + + if dryRun { + logrus.Debugf("dry run: adding %s", path) + } else { + worktree.Add(path) + } + + return nil +} diff --git a/tests/integration/app_cp.bats b/tests/integration/app_cp.bats index 4c1f52a0..524ff866 100644 --- a/tests/integration/app_cp.bats +++ b/tests/integration/app_cp.bats @@ -19,31 +19,6 @@ setup(){ _common_setup } -_mkfile() { - run bash -c "echo $2 > $1" - assert_success -} - -_mkfile_remote() { - run $ABRA app run "$TEST_APP_DOMAIN" app "bash -c \"echo $2 > $1\"" - assert_success -} - -_mkdir() { - run bash -c "mkdir -p $1" - assert_success -} - -_rm() { - run rm -rf "$1" - assert_success -} - -_rm_remote() { - run "$ABRA" app run "$TEST_APP_DOMAIN" app rm -rf "$1" - assert_success -} - @test "validate app argument" { run $ABRA app cp assert_failure diff --git a/tests/integration/helpers/common.bash b/tests/integration/helpers/common.bash index a97d3e94..9f434436 100644 --- a/tests/integration/helpers/common.bash +++ b/tests/integration/helpers/common.bash @@ -5,6 +5,7 @@ _common_setup() { bats_load_library bats-assert bats_load_library bats-file + load "$PWD/tests/integration/helpers/file" load "$PWD/tests/integration/helpers/app" load "$PWD/tests/integration/helpers/git" load "$PWD/tests/integration/helpers/recipe" diff --git a/tests/integration/helpers/file.bash b/tests/integration/helpers/file.bash new file mode 100644 index 00000000..5cb91869 --- /dev/null +++ b/tests/integration/helpers/file.bash @@ -0,0 +1,24 @@ +_mkfile() { + run bash -c "echo $2 > $1" + assert_success +} + +_mkfile_remote() { + run $ABRA app run "$TEST_APP_DOMAIN" app "bash -c \"echo $2 > $1\"" + assert_success +} + +_mkdir() { + run bash -c "mkdir -p $1" + assert_success +} + +_rm() { + run rm -rf "$1" + assert_success +} + +_rm_remote() { + run "$ABRA" app run "$TEST_APP_DOMAIN" app rm -rf "$1" + assert_success +} diff --git a/tests/integration/helpers/git.bash b/tests/integration/helpers/git.bash index f2654944..e11b76de 100644 --- a/tests/integration/helpers/git.bash +++ b/tests/integration/helpers/git.bash @@ -28,3 +28,10 @@ _reset_tags() { assert_success refute_output '0' } + +_set_git_author() { + run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" config --local user.email test@example.com + assert_success + run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" config --local user.name test + assert_success +} diff --git a/tests/integration/recipe_release.bats b/tests/integration/recipe_release.bats index 2ebe226c..4c10f691 100644 --- a/tests/integration/recipe_release.bats +++ b/tests/integration/recipe_release.bats @@ -15,6 +15,11 @@ teardown_file(){ setup(){ load "$PWD/tests/integration/helpers/common" _common_setup + _set_git_author +} + +teardown() { + _reset_recipe } @test "validate recipe argument" { @@ -51,8 +56,6 @@ setup(){ run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" tag --list assert_success assert_output --partial '0.2.1+1.21.6' - - _reset_recipe } # NOTE(d1): this test can't assert hardcoded versions since we upgrade a minor @@ -81,8 +84,6 @@ setup(){ run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" tag --list assert_success assert_output --regexp '0\.3\.0\+1\.2.*' - - _reset_recipe "$TEST_RECIPE" } @test "unknown files not committed" { @@ -100,6 +101,21 @@ setup(){ run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" rm foo assert_failure assert_output --partial "fatal: pathspec 'foo' did not match any files" - - _reset_recipe +} + +# NOTE: relies on 0.2.x being the last minor version +@test "release with next release note" { + _mkfile "$ABRA_DIR/recipes/$TEST_RECIPE/release/next" "those are some release notes for the next release" + run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" add release/next + assert_success + run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" commit -m "added some release notes" + assert_success + + run $ABRA recipe release "$TEST_RECIPE" --no-input --minor + assert_success + assert_output --partial 'no -p/--publish passed, not publishing' + + assert_not_exists "$ABRA_DIR/recipes/$TEST_RECIPE/release/next" + assert_exists "$ABRA_DIR/recipes/$TEST_RECIPE/release/0.3.0+1.21.0" + assert_file_contains "$ABRA_DIR/recipes/$TEST_RECIPE/release/0.3.0+1.21.0" "those are some release notes for the next release" }