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

Add command to prepare GBM release #158

Merged
merged 35 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c7e7dd4
Add base gbm prepare command
derekblank Oct 11, 2023
db9339b
Add CloneGBM function to git pkg
derekblank Oct 11, 2023
f3bbb6f
Add git submodule utility functions
derekblank Oct 11, 2023
606055c
Update gbm.go
derekblank Oct 11, 2023
0973f88
Merge trunk
derekblank Oct 11, 2023
485270c
Add Submodule to git client
derekblank Oct 12, 2023
d64997c
Update gbm.go steps
derekblank Oct 12, 2023
e00416d
Add UpdateReleaseNotes util
derekblank Oct 12, 2023
3e4d3cc
Add Bundle exec command
derekblank Oct 12, 2023
33ef3ca
Add GBM PR body template
derekblank Oct 12, 2023
368b70c
Add steps to preview and create Gutenberg Mobile PR
derekblank Oct 12, 2023
f90bd9c
Add code comments to gbm prepare command
derekblank Oct 12, 2023
03fa629
Merge remote-tracking branch 'origin' into cli/gbm-prepare
derekblank Oct 13, 2023
e9ee191
Merge remote-tracking branch 'origin' into cli/gbm-prepare
derekblank Oct 13, 2023
ba0a457
Call CreateGbmPR from gbm release subcommand
derekblank Oct 13, 2023
c7318b0
Add shell package for shell based commands
jhnstn Oct 13, 2023
4f4fc6b
Update gb.go to use the new shell commands
jhnstn Oct 13, 2023
0a74d43
Update gbm release package
jhnstn Oct 13, 2023
c5961fa
Add SetUpstreamTo and AddRemote git interfaces
derekblank Oct 17, 2023
9c0a1a1
Add remote and set upstream to GBM prepare command
derekblank Oct 17, 2023
f5fa9f6
Place the success message after verifying the PR was created
jhnstn Oct 17, 2023
32d354d
Add prepare cmd utils
jhnstn Oct 17, 2023
41a304e
Update SetUpstreamTo signature
jhnstn Oct 17, 2023
0afefb1
Reorder some events and clean up logging messages
jhnstn Oct 17, 2023
8710371
Add a cmd utils package
jhnstn Oct 16, 2023
254ae11
Move temp directory helpers to the cmd utils
jhnstn Oct 16, 2023
8b705b5
Deprecate the console error functions
jhnstn Oct 16, 2023
53b59f2
Use the cmd utils to exit on error
jhnstn Oct 16, 2023
7da8dbb
Fix how the deferred function is handling cleanup
jhnstn Oct 16, 2023
73c3499
Add git submodule utility functions
derekblank Oct 11, 2023
8a6485f
Add Submodule to git client
derekblank Oct 12, 2023
b449907
Call CreateGbmPR from gbm release subcommand
derekblank Oct 13, 2023
a9c1530
Update gb.go to use the new shell commands
jhnstn Oct 13, 2023
3764813
Update exit on prepare gbm command
jhnstn Oct 17, 2023
ac2d874
Merge branch 'trunk' into cli/gbm-prepare
jhnstn Oct 17, 2023
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
133 changes: 133 additions & 0 deletions cli/pkg/gbm/gbm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package gbm

import (
"fmt"
"os"
"path/filepath"

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

func PrepareBranch(dir string, pr *gh.PullRequest, gbPr *gh.PullRequest, verbose bool) (gh.Repo, error) {

gbmDir := filepath.Join(dir, "gutenberg-mobile")
npm := execNpm(gbmDir, verbose)

version := pr.ReleaseVersion
var (
gbmr *g.Repository
err error
)
// If we already have a copy of GBM, initialize the repo
// Otherwise clone at pr.Base
if _, ok := os.Stat(gbmDir); ok != nil {
os.MkdirAll(gbmDir, os.ModePerm)
console.Info("Cloning Gutenberg Mobile")
gbmr, err = git.CloneGBM(dir, *pr, verbose)
if err != nil {
return nil, err
}
} else {
console.Info("Initializing Gutenberg Mobile Repo at %s", gbmDir)
gbmr, err = git.Open(gbmDir)
if err != nil {
return nil, fmt.Errorf("issue opening gutenberg-mobile (err %s)", err)
}
}

if err := git.Switch(gbmDir, "gutenberg-mobile", pr.Head.Ref, verbose); err != nil {
return nil, err
}
// Set up GB
if err := setupGb(gbmDir, gbmr, gbPr, verbose); err != nil {
return nil, err
}

console.Info("Set up Node")
if err := exec.SetupNode(gbmDir, verbose); err != nil {
return nil, fmt.Errorf("failed to update node (err %s)", err)
}

console.Info("Installing npm packages")
if err := npm("ci"); err != nil {
return nil, fmt.Errorf("failed to update node packages (err %s)", err)
}

console.Info("Update XCFramework builders project Podfile.lock")
xcfDir := filepath.Join(gbmDir, "ios-xcframework")
if err := exec.BundleInstall(xcfDir, verbose); err != nil {
return nil, err
}
if err := exec.PodInstall(xcfDir, verbose); err != nil {
return nil, err
}

if err := git.CommitAll(gbmr, "Release script: Sync XCFramework `Podfile.lock`"); err != nil {
return nil, err
}

// If there is a version we should update the package json
if version != "" {

console.Info("Updating the version")
if err := npm("--no-git-tag-version", "version", version); err != nil {
return nil, err
}

if err := git.CommitAll(gbmr, "Update Version", "package.json", "package-lock.json"); err != nil {
return nil, err
}

} else {
// Otherwise just update the bundle
if err := npm("run", "bundle"); err != nil {
return nil, err
}
}

console.Info("Updating the bundle")
if err := git.CommitAll(gbmr, "Release script: Update bundle for "+version); err != nil {
return nil, err
}

return gbmr, nil
}

func setupGb(gbmDir string, gbmr gh.Repo, gbPr *gh.PullRequest, verbose bool) error {
console.Info("Checking Gutenberg")

gb, err := git.GetSubmodule(gbmr, "gutenberg")
jhnstn marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return err
}
if curr, err := git.IsSubmoduleCurrent(gb, gbPr.Head.Sha); err != nil {
jhnstn marked this conversation as resolved.
Show resolved Hide resolved
return fmt.Errorf("issue checking the submodule (err %s)", err)
} else if !curr {
if err := git.Switch(filepath.Join(gbmDir, "gutenberg"), "gutenberg", gbPr.Head.Ref, verbose); err != nil {
return fmt.Errorf("unable to switch to %s (err %s)", gbPr.Head.Ref, err)
}
}

console.Info("Updating Gutenberg")
if clean, _ := git.IsPorcelain(gbmr); !clean {
if err = git.CommitSubmodule(gbmDir, "Release script: Updating gutenberg ref", "gutenberg", verbose); err != nil {
return fmt.Errorf("failed to update gutenberg: %s", err)
}
}

return nil
}

func CreatePr(gbmr *g.Repository, pr *gh.PullRequest, verbose bool) error {
// TODO: make sure we are not on trunk before pushing
console.Info("Pushing the branch")
if err := git.Push(gbmr, verbose); err != nil {
return err
}

console.Info("Creating the PR")
return gh.CreatePr("gutenberg-mobile", pr)
}
81 changes: 81 additions & 0 deletions cli/pkg/git/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"

"github.com/wordpress-mobile/gbm-cli/pkg/exec"
"github.com/wordpress-mobile/gbm-cli/pkg/gh"
"github.com/wordpress-mobile/gbm-cli/pkg/repo"
)

func Clone(repo, dir string, shallow bool) error {
Expand All @@ -14,6 +16,30 @@ func Clone(repo, dir string, shallow bool) error {
return cmd("clone", repo)
}

func CloneGBM(dir string, pr gh.PullRequest, verbose bool) (*g.Repository, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about putting something this GBM specific in the git package. Feels like it belongs in gbm/gbm.go

Not a blocker but something to consider as a refactor.

git := exec.ExecGit(dir, verbose)
jhnstn marked this conversation as resolved.
Show resolved Hide resolved

org, _ := repo.GetOrg("gutenberg-mobile")
url := fmt.Sprintf("[email protected]:%s/%s.git", org, "gutenberg-mobile")

cmd := []string{"clone", "--recurse-submodules", "--depth", "1"}

fmt.Println("Checking remote branch...")
// check to see if the remote branch exists
if err := git("ls-remote", "--exit-code", "--heads", url, pr.Head.Ref); err != nil {
jhnstn marked this conversation as resolved.
Show resolved Hide resolved
cmd = append(cmd, url)
} else {
cmd = append(cmd, "--branch", pr.Head.Ref, url)
}

if err := git(cmd...); err != nil {
return nil, fmt.Errorf("unable to clone gutenberg mobile %s", err)
}
// return Open(filepath.Join(dir, "gutenberg-mobile"))

return false, nil
}

func Switch(dir, branch string, create bool) error {
cmd := exec.ExecGit(dir, true)
if create {
Expand All @@ -29,3 +55,58 @@ func CommitAll(dir, format string, args ...interface{}) error {
func Push(dir, branch string) error {
return exec.ExecGit(dir, true)("push", "origin", branch)
}

func GetSubmodule(r gh.Repo, path string) (*g.Submodule, error) {
w, err := r.Worktree()
if err != nil {
return nil, err
}

return w.Submodule(path)
}

func CommitSubmodule(dir, message, submodule string, verbose bool) error {
git := exec.ExecGit(dir, verbose)

if err := git("add", submodule); err != nil {
return fmt.Errorf("unable to add submodule %s in %s :%s", submodule, dir, err)
}

if err := git("commit", "-m", message); err != nil {
return fmt.Errorf("unable to commit submodule update %s : %s", submodule, err)
}
return nil
}

func IsSubmoduleCurrent(s gh.Submodule, expectedHash string) (bool, error) {
// Check if the submodule is porcelain
jhnstn marked this conversation as resolved.
Show resolved Hide resolved
sr, err := s.Repository()
if clean, err := IsPorcelain(sr); err != nil {
return false, err
} else if !clean {
return false, &NotPorcelainError{fmt.Errorf("submodule %s is not clean", s.Config().Name)}
}

if err != nil {
return false, err
}
stat, err := s.Status()
if err != nil {
return false, err
}
eh := plumbing.NewHash(expectedHash)

return stat.Current == eh, nil
}

func IsPorcelain(r gh.Repo) (bool, error) {
w, err := r.Worktree()
if err != nil {
return false, err
}
status, err := w.Status()
if err != nil {
return false, err
}
return status.IsClean(), nil
}
Loading