Skip to content
3 changes: 1 addition & 2 deletions gomonorepo/cmd/gomonorepo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main

import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
Expand Down Expand Up @@ -50,6 +49,6 @@ func main() {
if fErr, ok := err.(*flags.Error); ok && fErr.Type == flags.ErrHelp {
parser.WriteHelp(os.Stdout)
} else if err != nil {
fmt.Fprint(os.Stderr, err.Error())
opts.Errorf("Fatal: %s", err.Error())
}
}
86 changes: 80 additions & 6 deletions gomonorepo/git_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func getIgnoredDirectories(
cmd.Stderr = stderr
err := cmd.Run()
if err != nil {
return nil, fmt.Errorf("failed to run git diff: %w\n%s", err, stderr.String())
return nil, fmt.Errorf("failed to get ignored files: %w\n%s", err, stderr.String())
}

result := make([]string, 0, 8)
Expand All @@ -41,7 +41,7 @@ func getIgnoredDirectories(
return result, nil
}

func listChangedFiles(ctx context.Context, parent string) ([]string, error) {
func listChangedFiles(ctx context.Context, opts *AppOptions, parent string, patched bool) ([]string, error) {
stdout, done := GetBuffer()
defer done(stdout)
stderr, done := GetBuffer()
Expand All @@ -51,6 +51,14 @@ func listChangedFiles(ctx context.Context, parent string) ([]string, error) {
cmd.Stderr = stderr
err := cmd.Run()
if err != nil {
if !patched && strings.HasPrefix(stderr.String(), "fatal: ambiguous argument '"+parent+"'") {
opts.Infof("Parent %q not found locally, attempting to fetch it from remote.\n", parent)
err = tryFetchParentRevision(ctx, parent)
if err != nil {
return nil, err
}
return listChangedFiles(ctx, opts, parent, true)
}
return nil, fmt.Errorf("failed to run git diff: %w\n%s", err, stderr.String())
}

Expand All @@ -66,18 +74,84 @@ func listChangedFiles(ctx context.Context, parent string) ([]string, error) {
return result, nil
}

func tryFetchParentRevision(ctx context.Context, parent string) error {
remote, err := getConfiguredRemoteName(ctx)
if err != nil {
return err
}
branch := parent
if strings.HasPrefix(parent, remote) {
branch = strings.TrimPrefix(parent, remote+"/")
}

stdout, done := GetBuffer()
defer done(stdout)
stderr, done := GetBuffer()
defer done(stderr)

cmd := exec.CommandContext(ctx, "git", "fetch", remote, branch)
cmd.Stdout = stdout
cmd.Stderr = stderr
err = cmd.Run()
if err != nil {
return fmt.Errorf("failed to fetch parent revision: %w\n%s", err, stderr.String())
}
return nil
}

// getConfiguredRemoteName returns the first remote name configured in the git repository.
func getConfiguredRemoteName(ctx context.Context) (string, error) {
stdout, done := GetBuffer()
defer done(stdout)
stderr, done := GetBuffer()
defer done(stderr)

cmd := exec.CommandContext(ctx, "git", "remote")
cmd.Stdout = stdout
cmd.Stderr = stderr
err := cmd.Run()
if err != nil {
return "", fmt.Errorf("failed to get remote name: %w\n%s", err, stderr.String())
}

// Get the first remote name
remotes := strings.Split(stdout.String(), "\n")
if len(remotes) == 0 {
return "", fmt.Errorf("no remotes found")
}

return remotes[0], nil
}

// getCurrentBranch returns the current branch name.
func getCurrentBranch(ctx context.Context) (string, error) {
func getCurrentBranch(ctx context.Context) (remote string, branch string, err error) {
stdout, done := GetBuffer()
defer done(stdout)
stderr, done := GetBuffer()
defer done(stderr)

// Get the current branch / revision name excluding the remote:
cmd := exec.CommandContext(ctx, "git", "rev-parse", "--abbrev-ref", "HEAD")
cmd.Stdout = stdout
cmd.Stderr = stderr
err := cmd.Run()
err = cmd.Run()
if err != nil {
return "", "", fmt.Errorf("failed to get branch name: %w\n%s", err, stderr.String())
}
branch = strings.TrimSpace(stdout.String())

stdout.Reset()
stderr.Reset()

// Get the branch name AND its upstream remote (e.g. origin/main):
cmd = exec.CommandContext(ctx, "git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{upstream}")
cmd.Stdout = stdout
cmd.Stderr = stderr
err = cmd.Run()
if err != nil {
return "", fmt.Errorf("failed to run git diff: %w\n%s", err, stderr.String())
// noop. there is no remote.
return "", branch, nil
}
return strings.TrimSpace(stdout.String()), nil
remote = strings.TrimSuffix(strings.TrimSpace(stdout.String()), "/"+branch)
return remote, branch, nil
}
6 changes: 3 additions & 3 deletions gomonorepo/module_changes.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@ func listAllChangedModulesWithTree(
return set.Make(tree.AllModules...), nil
}

changedFiles, err := listChangedFiles(ctx, parentCommit)
changedFiles, err := listChangedFiles(ctx, opts, parentCommit, false)
if err != nil {
return nil, err
}
if len(changedFiles) == 0 {
current, err := getCurrentBranch(ctx)
remote, current, err := getCurrentBranch(ctx)
if err != nil {
return nil, err
}
if current == parentCommit {
if current == parentCommit || remote+"/"+current == parentCommit {
opts.Infof("Currently on %q with no changes; will run command on all %d moduels.\n",
current,
len(tree.AllModules))
Expand Down
Loading