Skip to content

Commit c5b10e3

Browse files
authored
Merge pull request #14 from rm3l/force-sync
2 parents fbd4b7b + 87fbe40 commit c5b10e3

File tree

3 files changed

+31
-9
lines changed

3 files changed

+31
-9
lines changed

Diff for: README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
## Installation
1212

1313
- Install the `gh` CLI. See [https://github.com/cli/cli#installation](https://github.com/cli/cli#installation) for further details.
14-
- If not done already, also install [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) of course.
14+
- If not done already, also install [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git).
1515
- To be able to clone private repos you have access to inside the Organization, authenticate with your GitHub account by running `gh auth login`. Alternatively, the CLI will respect the `GITHUB_TOKEN` [environment variable](https://cli.github.com/manual/gh_help_environment).
1616
- Install the extension:
1717

@@ -31,6 +31,9 @@ Options:
3131
-dry-run
3232
dry run mode. to display the repositories that will get cloned or updated,
3333
without actually performing those actions
34+
-force
35+
whether to force sync repositories.
36+
Caution: this will hard-reset the branch of the destination repository to match the source repository.
3437
-output string
3538
the output path (default ".")
3639
-protocol string

Diff for: internal/reposync/repo_handler.go

+19-5
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,15 @@ const (
3333
// HandleRepository determines whether a directory with the repository name does exist.
3434
// If it does, it checks out its default branch and updates it locally.
3535
// Otherwise, it clones it.
36-
func HandleRepository(_ context.Context, dryRun bool, output, organization string, repositoryInfo github.RepositoryInfo, protocol CloneProtocol) error {
36+
func HandleRepository(
37+
_ context.Context,
38+
dryRun bool,
39+
output,
40+
organization string,
41+
repositoryInfo github.RepositoryInfo,
42+
protocol CloneProtocol,
43+
force bool,
44+
) error {
3745
repository := repositoryInfo.Name
3846
repoPath, err := safeAbsPath(fmt.Sprintf("%s/%s", output, repository))
3947
if err != nil {
@@ -62,7 +70,7 @@ func HandleRepository(_ context.Context, dryRun bool, output, organization strin
6270
return nil
6371
}
6472
log.Println("[debug] updating local clone for repo:", repoPath)
65-
return updateLocalClone(repoPath, organization, repositoryInfo)
73+
return updateLocalClone(repoPath, organization, repositoryInfo, force)
6674
}
6775

6876
func clone(output, organization string, repository string, protocol CloneProtocol) error {
@@ -88,13 +96,13 @@ func clone(output, organization string, repository string, protocol CloneProtoco
8896
return err
8997
}
9098

91-
func updateLocalClone(outputPath, organization string, repositoryInfo github.RepositoryInfo) error {
99+
func updateLocalClone(outputPath, organization string, repositoryInfo github.RepositoryInfo, force bool) error {
92100
repository := repositoryInfo.Name
93101
repoPath, err := safeAbsPath(outputPath)
94102
if err != nil {
95103
return err
96104
}
97-
err = fetchAllRemotes(repoPath)
105+
err = fetchAllRemotes(repoPath, force)
98106
if err != nil {
99107
return err
100108
}
@@ -103,16 +111,22 @@ func updateLocalClone(outputPath, organization string, repositoryInfo github.Rep
103111
return nil
104112
}
105113
args := []string{"repo", "sync", "--source", fmt.Sprintf("%s/%s", organization, repository)}
114+
if force {
115+
args = append(args, "--force")
116+
}
106117
_, _, err = github.RunGhCliInDir(repoPath, nil, args...)
107118
return err
108119
}
109120

110-
func fetchAllRemotes(outputPath string) error {
121+
func fetchAllRemotes(outputPath string, force bool) error {
111122
repoPath, err := safeAbsPath(outputPath)
112123
if err != nil {
113124
return err
114125
}
115126
args := []string{"fetch", "--all", "--prune", "--tags", "--recurse-submodules"}
127+
if force {
128+
args = append(args, "--force")
129+
}
116130
_, _, err = cli.RunCommandInDir("git", repoPath, nil, args...)
117131
return err
118132
}

Diff for: main.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ func main() {
2828
var batchSize int
2929
var output string
3030
var protocol string
31+
var force bool
3132
flag.BoolVar(&dryRun, "dry-run", false,
3233
`dry run mode. to display the repos that will get cloned or updated,
3334
without actually performing those actions`)
@@ -41,6 +42,10 @@ See https://bit.ly/3HurHe3 for more details on the search syntax`)
4142
fmt.Sprintf("the protocol to use for cloning. Possible values: %s, %s, %s.", reposync.SystemProtocol,
4243
reposync.SSHProtocol, reposync.HTTPSProtocol))
4344
flag.StringVar(&output, "output", ".", "the output path")
45+
flag.BoolVar(&force, "force", false,
46+
`whether to force sync repositories.
47+
Caution: this will hard-reset the branch of the destination repository to match the source repository.`)
48+
4449
flag.Usage = func() {
4550
//goland:noinspection GoUnhandledErrorResult
4651
fmt.Fprintln(os.Stderr, "Usage: gh org-repo-sync <organization> [options]")
@@ -87,11 +92,11 @@ See https://bit.ly/3HurHe3 for more details on the search syntax`)
8792
for _, repository := range repositories {
8893
g.Go(func(repo github.RepositoryInfo) func() error {
8994
return func() error {
90-
err := reposync.HandleRepository(ctx, dryRun, output, organization, repo, cloneProtocol)
95+
err := reposync.HandleRepository(ctx, dryRun, output, organization, repo, cloneProtocol, force)
9196
if err != nil {
92-
log.Println(fmt.Sprintf("[warn] an error occurred while handling repo %q:", repo.Name), err)
97+
return fmt.Errorf("error while handling repo %q: %w", repo.Name, err)
9398
}
94-
return err
99+
return nil
95100
}
96101
}(repository))
97102
}

0 commit comments

Comments
 (0)