Skip to content

Commit d7b78b3

Browse files
authored
Merge pull request #20 from manicminer/feature/trim-github-branches
Optionally trim branches on GitHub that are not present in GitLab
2 parents d2bc64b + ac73492 commit d7b78b3

File tree

5 files changed

+81
-2
lines changed

5 files changed

+81
-2
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ Written in Go, this is a cross-platform CLI utility that accepts the following r
6161
report on primitives to be migrated instead of beginning migration
6262
-skip-invalid-merge-requests
6363
when true, will log and skip invalid merge requests instead of raising an error
64+
-trim-branches-on-github
65+
when true, will delete any branches on GitHub that are no longer present in GitLab
6466
-version
6567
output version information
6668
```

cache.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import (
88
)
99

1010
const (
11-
githubPullRequestCacheType uint8 = iota
11+
githubBranchesCacheType uint8 = iota
12+
githubPullRequestCacheType
1213
githubSearchResultsCacheType
1314
githubUserCacheType
1415
gitlabUserCacheType
@@ -21,6 +22,7 @@ type objectCache struct {
2122

2223
func newObjectCache() *objectCache {
2324
store := make(map[uint8]map[string]any)
25+
store[githubBranchesCacheType] = make(map[string]any)
2426
store[githubPullRequestCacheType] = make(map[string]any)
2527
store[githubSearchResultsCacheType] = make(map[string]any)
2628
store[githubUserCacheType] = make(map[string]any)
@@ -32,6 +34,21 @@ func newObjectCache() *objectCache {
3234
}
3335
}
3436

37+
func (c objectCache) getGithubBranches(query string) []*github.Branch {
38+
c.mutex.RLock()
39+
defer c.mutex.RUnlock()
40+
if v, ok := c.store[githubBranchesCacheType][query]; ok {
41+
return v.([]*github.Branch)
42+
}
43+
return nil
44+
}
45+
46+
func (c objectCache) setGithubBranches(query string, result []*github.Branch) {
47+
c.mutex.Lock()
48+
defer c.mutex.Unlock()
49+
c.store[githubBranchesCacheType][query] = result
50+
}
51+
3552
func (c objectCache) getGithubPullRequest(query string) *github.PullRequest {
3653
c.mutex.RLock()
3754
defer c.mutex.RUnlock()

helper.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,28 @@ import (
1414
"github.com/xanzy/go-gitlab"
1515
)
1616

17+
func getGithubBranches(ctx context.Context, owner, repo string) ([]*github.Branch, error) {
18+
var err error
19+
cacheToken := fmt.Sprintf("%s/%s", owner, repo)
20+
result := cache.getGithubBranches(cacheToken)
21+
if result == nil {
22+
logger.Debug("listing branches")
23+
result, _, err = gh.Repositories.ListBranches(ctx, owner, repo, nil)
24+
if err != nil {
25+
return nil, fmt.Errorf("listing branches: %v", err)
26+
}
27+
28+
if result == nil {
29+
return nil, fmt.Errorf("nil result was returned when listing branches for repo: %s/%s", owner, repo)
30+
}
31+
32+
logger.Trace("caching GitHub branches", "repo", fmt.Sprintf("%s/%s", owner, repo))
33+
cache.setGithubBranches(cacheToken, result)
34+
}
35+
36+
return result, nil
37+
}
38+
1739
func getGithubPullRequest(ctx context.Context, org, repo string, prNumber int) (*github.PullRequest, error) {
1840
var err error
1941
cacheToken := fmt.Sprintf("%s/%s/%d", org, repo, prNumber)

main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const (
3030
)
3131

3232
var loop, report bool
33-
var deleteExistingRepos, enablePullRequests, renameMasterToMain, skipInvalidMergeRequests bool
33+
var deleteExistingRepos, enablePullRequests, renameMasterToMain, skipInvalidMergeRequests, trimGithubBranches bool
3434
var githubDomain, githubRepo, githubToken, githubUser, gitlabDomain, gitlabProject, gitlabToken, projectsCsvPath, renameTrunkBranch string
3535
var mergeRequestsAge int
3636

@@ -98,6 +98,7 @@ func main() {
9898
flag.BoolVar(&enablePullRequests, "migrate-pull-requests", false, "whether pull requests should be migrated")
9999
flag.BoolVar(&renameMasterToMain, "rename-master-to-main", false, "rename master branch to main and update pull requests (incompatible with -rename-trunk-branch)")
100100
flag.BoolVar(&skipInvalidMergeRequests, "skip-invalid-merge-requests", false, "when true, will log and skip invalid merge requests instead of raising an error")
101+
flag.BoolVar(&trimGithubBranches, "trim-branches-on-github", false, "when true, will delete any branches on GitHub that are no longer present in GitLab")
101102
flag.BoolVar(&showVersion, "version", false, "output version information")
102103

103104
flag.StringVar(&githubDomain, "github-domain", defaultGithubDomain, "specifies the GitHub domain to use")

project.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,10 @@ func (p *project) migrate(ctx context.Context) error {
185185
return fmt.Errorf("retrieving branches: %v", err)
186186
}
187187

188+
gitlabBranches := make([]string, 0)
188189
refSpecs := make([]config.RefSpec, 0)
189190
if err = branches.ForEach(func(ref *plumbing.Reference) error {
191+
gitlabBranches = append(gitlabBranches, ref.Name().Short())
190192
refSpecs = append(refSpecs, config.RefSpec(fmt.Sprintf("%[1]s:%[1]s", ref.Name())))
191193
return nil
192194
}); err != nil {
@@ -207,6 +209,41 @@ func (p *project) migrate(ctx context.Context) error {
207209
}
208210
}
209211

212+
if trimGithubBranches {
213+
logger.Debug("determining old branches to trim on GitHub repository", "name", p.gitlabPath[1], "group", p.gitlabPath[0], "url", githubUrl)
214+
refSpecsToDelete := make([]config.RefSpec, 0)
215+
githubBranches, err := getGithubBranches(ctx, p.githubPath[0], p.githubPath[1])
216+
if err != nil {
217+
return fmt.Errorf("listing branches from GitHub: %v", err)
218+
}
219+
for _, githubBranch := range githubBranches {
220+
found := false
221+
for _, gitlabBranch := range gitlabBranches {
222+
if githubBranch.Name != nil && *githubBranch.Name == gitlabBranch {
223+
found = true
224+
break
225+
}
226+
}
227+
if !found {
228+
refSpecsToDelete = append(refSpecsToDelete, config.RefSpec(fmt.Sprintf(":refs/heads/%s", *githubBranch.Name)))
229+
}
230+
}
231+
232+
logger.Debug("trimming old branches on GitHub repository", "name", p.gitlabPath[1], "group", p.gitlabPath[0], "url", githubUrl, "count", len(refSpecs))
233+
if err = p.repo.PushContext(ctx, &git.PushOptions{
234+
RemoteName: "github",
235+
Force: true,
236+
RefSpecs: refSpecsToDelete,
237+
//Prune: true, // causes error, attempts to delete main branch
238+
}); err != nil {
239+
if errors.Is(err, git.NoErrAlreadyUpToDate) {
240+
logger.Debug("repository already up-to-date on GitHub", "name", p.gitlabPath[1], "group", p.gitlabPath[0], "url", githubUrl)
241+
} else {
242+
return fmt.Errorf("pushing to github repo: %v", err)
243+
}
244+
}
245+
}
246+
210247
logger.Debug("force-pushing tags to GitHub repository", "name", p.gitlabPath[1], "group", p.gitlabPath[0], "url", githubUrl)
211248
if err = p.repo.PushContext(ctx, &git.PushOptions{
212249
RemoteName: "github",

0 commit comments

Comments
 (0)