Skip to content

Commit

Permalink
CLI: Refactor the temp directories in the commands (#180)
Browse files Browse the repository at this point in the history
* Add yaml processor

* Fix mod files

* Pass pr by value to preview function

* Add new subcommand for target repos

* Add a cmd utils package

* Move temp directory helpers to the cmd utils

* Deprecate the console error functions

* Use the cmd utils to exit on error

* Fix how the deferred function is handling cleanup

* Add command to prepare GBM release (#158)

* Add base gbm prepare command

* Add CloneGBM function to git pkg

* Add git submodule utility functions

* Update gbm.go

* Add Submodule to git client

* Update gbm.go steps

* Add UpdateReleaseNotes util

* Add Bundle exec command

* Add GBM PR body template

* Add steps to preview and create Gutenberg Mobile PR

* Add code comments to gbm prepare command

* Call CreateGbmPR from gbm release subcommand

* Add shell package for shell based commands

inludes git, npm, and bundler

* Update gb.go to use the new shell commands

* Update gbm release package

* Add SetUpstreamTo and AddRemote git interfaces

* Add remote and set upstream to GBM prepare command

* Place the success message after verifying the PR was created

* Add prepare cmd utils

* Update SetUpstreamTo signature

* Reorder some events and clean up logging messages

* Add a cmd utils package

* Move temp directory helpers to the cmd utils

* Deprecate the console error functions

* Use the cmd utils to exit on error

* Fix how the deferred function is handling cleanup

* Add git submodule utility functions

* Add Submodule to git client

* Call CreateGbmPR from gbm release subcommand

* Update gb.go to use the new shell commands

* Update exit on prepare gbm command

---------

Co-authored-by: jhnstn <[email protected]>
Co-authored-by: Jason Johnston <[email protected]>

* Make shell command interfaces public

Also rename factory functions to add clarity

* Work in progress

* add dir to the try exec command

* Update yq test to handle dots in values

* Update integration package to return the pr

* Fill in the create pr flows to the integrate cmd

* Update integrate to use the new exit flow

* Get Android PR working

* Add keep flag to keep the temp directory around after the command

* Add cleaner factory function

* Add rake to the shell package

* get integrate working for ios

* Add workspace package for managing the temp directories

* update commands to use the new workspace package

* Refactor workspace into an interface

---------

Co-authored-by: Derek Blank <[email protected]>
  • Loading branch information
jhnstn and derekblank authored Oct 23, 2023
1 parent a3e5efd commit c7d178f
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 83 deletions.
11 changes: 0 additions & 11 deletions cli/cmd/release/integrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,6 @@ var IntegrateCmd = &cobra.Command{
version, err := utils.GetVersionArg(args)
exitIfError(err, 1)

tempDir, err := utils.SetTempDir()
exitIfError(err, 1)

cleanup := tempDirCleaner(tempDir)
defer cleanup()

// reassign exitIfError to handle the cleanup
exitIfError = utils.ExitIfErrorHandler(cleanup)

console.Info("Created temporary directory %s", tempDir)

androidRi := release.ReleaseIntegration{
Android: true,
Version: version,
Expand Down
14 changes: 1 addition & 13 deletions cli/cmd/release/prepare/gb.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var gbCmd = &cobra.Command{
Short: "Prepare Gutenberg for a mobile release",
Long: `Use this command to prepare a Gutenberg release PR`,
Run: func(cc *cobra.Command, args []string) {

tempDir := workspace.Dir()
version, err := utils.GetVersionArg(args)
exitIfError(err, 1)

Expand All @@ -26,18 +26,6 @@ var gbCmd = &cobra.Command{

console.Info("Preparing Gutenberg for release %s", version)

tempDir, err := utils.SetTempDir()
exitIfError(err, 1)
cleanup := func() {
utils.CleanupTempDir(tempDir)
}
defer cleanup()

// Reset the exitIfError to handle the cleanup
exitIfError = utils.ExitIfErrorHandler(cleanup)

console.Info("Created temporary directory %s", tempDir)

pr, err := release.CreateGbPR(version, tempDir)
exitIfError(err, 1)

Expand Down
16 changes: 2 additions & 14 deletions cli/cmd/release/prepare/gbm.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var gbmCmd = &cobra.Command{
Short: "Prepare Gutenberg Mobile release",
Long: `Use this command to prepare a Gutenberg Mobile release PR`,
Run: func(cmd *cobra.Command, args []string) {
tempDir := workspace.Dir()
version, err := utils.GetVersionArg(args)
exitIfError(err, 1)

Expand All @@ -25,22 +26,9 @@ var gbmCmd = &cobra.Command{

console.Info("Preparing Gutenberg Mobile for release %s", version)

tempDir, err := utils.SetTempDir()
exitIfError(err, 1)

cleanup := func() {
utils.CleanupTempDir(tempDir)
}

// Reset the exitIfError to handle the cleanup
exitIfError = utils.ExitIfErrorHandler(cleanup)
defer cleanup()

console.Info("Created temporary directory %s", tempDir)

pr, err := release.CreateGbmPR(version, tempDir)
exitIfError(err, 1)

console.Info("Created PR %s", pr.Url)
},
}
}
18 changes: 17 additions & 1 deletion cli/cmd/release/prepare/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ package prepare
import (
"github.com/spf13/cobra"
"github.com/wordpress-mobile/gbm-cli/cmd/utils"
wp "github.com/wordpress-mobile/gbm-cli/cmd/workspace"
)

var exitIfError func(error, int)
var keepTempDir bool
var workspace wp.Workspace

var PrepareCmd = &cobra.Command{
Use: "prepare",
Expand All @@ -15,11 +18,24 @@ var PrepareCmd = &cobra.Command{
func Execute() {
err := PrepareCmd.Execute()
exitIfError(err, 1)
if keepTempDir {
workspace.Keep()
}
defer workspace.Cleanup()
}

func init() {
exitIfError = utils.ExitIfErrorHandler(func() {})
var err error
workspace, err = wp.NewWorkspace()
utils.ExitIfError(err, 1)

exitIfError = func(err error, code int) {
if err != nil {
utils.Exit(code, workspace.Cleanup)
}
}

PrepareCmd.AddCommand(gbmCmd)
PrepareCmd.AddCommand(gbCmd)
PrepareCmd.PersistentFlags().BoolVar(&keepTempDir, "k", false, "Keep temporary directory after running command")
}
34 changes: 18 additions & 16 deletions cli/cmd/release/root.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
package release

import (
"os"

"github.com/spf13/cobra"
"github.com/wordpress-mobile/gbm-cli/cmd/release/prepare"
"github.com/wordpress-mobile/gbm-cli/cmd/utils"
"github.com/wordpress-mobile/gbm-cli/pkg/console"
wp "github.com/wordpress-mobile/gbm-cli/cmd/workspace"
)

var exitIfError func(error, int)
var tempDirCleaner func(string) func()
var keepTempDir bool
var tempDir string
var workspace wp.Workspace

var ReleaseCmd = &cobra.Command{
Use: "release",
Expand All @@ -20,24 +19,27 @@ var ReleaseCmd = &cobra.Command{

func Execute() {
err := ReleaseCmd.Execute()
if err != nil {
console.Error(err)
os.Exit(1)
exitIfError(err, 1)

if keepTempDir {
workspace.Keep()
}

defer workspace.Cleanup()
}

func init() {
exitIfError = utils.ExitIfErrorHandler(func() {})
tempDirCleaner = func(tempDir string) func() {
return func() {
if keepTempDir {
console.Info("Keeping temporary directory %s", tempDir)
return
}
utils.CleanupTempDir(tempDir)
var err error
workspace, err = wp.NewWorkspace()
utils.ExitIfError(err, 1)

exitIfError = func(err error, code int) {
if err != nil {
utils.Exit(code, workspace.Cleanup)
}
}
tempDir = workspace.Dir()
ReleaseCmd.AddCommand(prepare.PrepareCmd)
ReleaseCmd.AddCommand(IntegrateCmd)
ReleaseCmd.PersistentFlags().BoolVar(&keepTempDir, "k", false, "Keep temporary directory after running command")
}
}
2 changes: 1 addition & 1 deletion cli/cmd/render/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ var RenderCmd = &cobra.Command{
}

func init() {
exitIfError = utils.ExitIfErrorHandler(func() {})
exitIfError = utils.ExitIfError
RenderCmd.AddCommand(ChecklistCmd)
RenderCmd.AddCommand(AztecCmd)
RenderCmd.PersistentFlags().BoolVar(&writeToClipboard, "c", false, "Send output to clipboard")
Expand Down
35 changes: 10 additions & 25 deletions cli/cmd/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,39 +12,24 @@ func GetVersionArg(args []string) (string, error) {
if len(args) == 0 {
return "", fmt.Errorf("missing version")
}
return utils.NormalizeVersion(args[0])
}

func SetTempDir() (string, error) {
tempDir, err := os.MkdirTemp("", "gbm-")
if err != nil {
return "", err
if !utils.ValidateVersion(args[0]) {
return "", fmt.Errorf("invalid version %s. Versions must have a `Major.Minor.Patch` form", args[0])
}
return tempDir, nil
return utils.NormalizeVersion(args[0])
}

func CleanupTempDir(tempDir string) error {
console.Info("Cleaning up temporary directory %s", tempDir)
err := os.RemoveAll(tempDir)
func ExitIfError(err error, code int) {
if err != nil {
return err
console.Error(err)
Exit(code)
}
return nil
}

func ExitIfErrorHandler(deferred func()) func(error, int) {
return func(err error, code int) {
if err != nil {
console.Error(err)

Exit(deferred, code)
}
}
}

func Exit(deferred func(), code int) {
func Exit(code int, deferred ...func()) {
os.Exit(func() int {
defer deferred()
for _, d := range deferred {
d()
}
return code
}())
}
92 changes: 92 additions & 0 deletions cli/cmd/workspace/workspace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package workspace

import (
"os"
"os/signal"
"path"

"github.com/wordpress-mobile/gbm-cli/pkg/console"
)

type Workspace interface {
Cleanup()
Dir() string
Keep()
create() error
setCleaner()
}

type workspace struct {
dir string
keep bool
prefix string
cleaner func()
disabled bool
}

func NewWorkspace() (Workspace, error) {
w := &workspace{prefix: "gbm-"}
if _, noWorkspace := os.LookupEnv("GBM_NO_WORKSPACE"); noWorkspace {
console.Info("GBM_NO_WORKSPACE is set, not creating a workspace directory")
w.disabled = true
}
if err := w.create(); err != nil {
return nil, err
}
w.setCleaner()
return w, nil
}

func (w *workspace) create() error {
// if we're disabled, don't create a temp directory
if w.disabled {
return nil
}
tempDir, err := os.MkdirTemp("", w.prefix)
if err != nil {
return err
}
w.dir = tempDir
return nil
}

func (w *workspace) setCleaner() {
w.cleaner = func() {
if w.disabled || w.dir == "" {
return
}

if w.keep {
console.Info("Keeping temporary directory %s", w.dir)
return
}

if err := os.RemoveAll(w.dir); err != nil {
console.Error(err)
}
}
// register a listener for ^C, call the cleanup function
go func() {
sigchan := make(chan os.Signal, 1)
signal.Notify(sigchan, os.Interrupt)
<-sigchan // wait for ^C
w.cleaner()
os.Exit(1)
}()
}

func (w *workspace) Dir() string {
// if the workspace is disabled, return the current directory
if w.disabled {
return path.Base(".")
}
return w.dir
}

func (w *workspace) Keep() {
w.keep = true
}

func (w *workspace) Cleanup() {
w.cleaner()
}
15 changes: 15 additions & 0 deletions cli/pkg/exec/exec.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package exec

import (
"errors"
"os"
"os/exec"
"time"
)

// Deprecated: Use shell package instead
Expand Down Expand Up @@ -53,6 +55,19 @@ func BundleInstall(dir string, verbose bool, args ...string) error {
return Bundle(dir, true, append([]string{"install"}, args...)...)
}

func Try(times int, cmd string, dir string, args ...string) error {

for times > 0 {
err := exc(true, "", cmd, args...)
if err == nil {
return nil
}
times--
time.Sleep(time.Second)
}
return errors.New("failed to execute command")
}

func exc(verbose bool, dir, cmd string, args ...string) error {
exc := exec.Command(cmd, args...)

Expand Down
3 changes: 1 addition & 2 deletions cli/pkg/release/gb.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func CreateGbPR(version, dir string) (gh.PullRequest, error) {

org, err := repo.GetOrg("gutenberg")
if err != nil {
return pr, fmt.Errorf("error getting the org: %v", err)
return pr, err
}
branch := "rnmobile/release_" + version

Expand All @@ -44,7 +44,6 @@ func CreateGbPR(version, dir string) (gh.PullRequest, error) {
// Let's clone into the current directory so that the git client can find the .git directory
err := git.Clone(repo.GetRepoPath("gutenberg"), "--depth=1", ".")


if err != nil {
return pr, fmt.Errorf("error cloning the Gutenberg repository: %v", err)
}
Expand Down

0 comments on commit c7d178f

Please sign in to comment.