Skip to content

Commit ab9534b

Browse files
authored
Merge pull request #18 from manicminer/feature/skip-merge-requests-with-no-branch
Skip merge requests with no head/source branch
2 parents 6836202 + 867082e commit ab9534b

File tree

4 files changed

+71
-46
lines changed

4 files changed

+71
-46
lines changed

README.md

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,21 @@ Written in Go, this is a cross-platform CLI utility that accepts the following r
5757
-rename-trunk-branch string
5858
specifies the new trunk branch name (incompatible with -rename-master-to-main)
5959
-report
60-
report on primitives to be migrated instead of beginning migration```
60+
report on primitives to be migrated instead of beginning migration
61+
-skip-invalid-merge-requests
62+
when true, will log and skip invalid merge requests instead of raising an error
63+
```
64+
65+
## Authentication
66+
67+
For authentication, the `GITLAB_TOKEN` and `GITHUB_TOKEN` environment variables must be populated. You cannot specify tokens as command-line arguments.
6168

6269
Use the `-github-user` argument to specify the GitHub username for whom the authentication token was issued (mandatory). You can also specify this with the `GITHUB_USER` environment variable.
6370

71+
Specify the location of a self-hosted instance of GitLab with the `-gitlab-domain` argument, or a GitHub Enterprise instance with the `-github-domain` argument.
72+
73+
## Specify repositories
74+
6475
You can specify an individual GitLab project with the `-gitlab-project` argument, along with the target GitHub repository with the `-github-repo` argument.
6576

6677
Alternatively, you can supply the path to a CSV file with the `-projects-csv` argument, which should contain two columns:
@@ -69,18 +80,39 @@ Alternatively, you can supply the path to a CSV file with the `-projects-csv` ar
6980
gitlab-group/gitlab-project-name,github-org-or-user/github-repo-name
7081
```
7182

72-
For authentication, the `GITLAB_TOKEN` and `GITHUB_TOKEN` environment variables must be populated. You cannot specify tokens as command-line arguments.
83+
If the destination repository does not exist, this tool will attempt to create a private repository. If the destination repo already exists, it will be used unless you specify `-delete-existing-repos`
84+
85+
> [!WARNING]
86+
> To delete existing GitHub repos prior to migrating, pass the `-delete-existing-repos` argument. _This is potentially dangerous, you won't be asked for confirmation!_
87+
88+
## Pull requests
7389

7490
To enable migration of GitLab merge requests to GitHub pull requests (including closed/merged ones!), specify `-migrate-pull-requests`.
7591

76-
To delete existing GitHub repos prior to migrating, pass the `-delete-existing-repos` argument. _This is potentially dangerous, you won't be asked for confirmation._
92+
Whilst the git repository itself will be migrated verbatim, the pull requests are managed using the GitHub API and typically will be authored by the person supplying the authentication token.
7793

78-
Note: If the destination repository does not exist, this tool will attempt to create a private repository. If the destination repo already exists, it will be used unless you specify `-delete-existing-repos`
94+
Each pull request, along with every comment, will be prepended with a Markdown table showing the original author and some other metadata that is useful to know. This is also used to map pull requests and their comments to their counterparts in GitLab and enables the tool to be idempotent.
7995

80-
Specify the location of a self-hosted instance of GitLab with the `-gitlab-domain` argument, or a GitHub Enterprise instance with the `-github-domain` argument.
96+
As a bonus, if your GitLab users add the URL to their GitHub profile in the `Website` field of their GitLab profile, this tool will add a link to their GitHub profile in the markdown header of any PR or comment they originally authored.
97+
98+
This tool also migrates merged/closed merge requests from your GitLab projects. It does this by reconstructing temporary branches in each repo, pushing them to GitHub, creating then closing the pull request, and lastly deleting the temporary branches. Once the tool has completed, you should not have any of these temporary branches in your repo - although GitHub will not garbage collect them immediately such that you can click the `Restore branch` button in any of these PRs.
99+
100+
If you have a large number of merge requests, or projects with a long history spanning many GitLab upgrades, you may wish to specify the `-skip-invalid-merge-requests` argument. This will cause the tool to emit INFO messages for merge requests that it considers invalid, such as those that are still marked as Open but have no source/head branch, or where there is no diff for a closed merge request. Without this option, an error will be logged instead.
101+
102+
_Example migrated pull request (open)_
103+
104+
![example migrated open pull request](pr-example-open.jpeg)
105+
106+
_Example migrated pull request (closed)_
107+
108+
![example migrated closed pull request](pr-example-closed.jpeg)
109+
110+
## Renaming the default/trunk branch
81111

82112
As a bonus, this tool can transparently rename the trunk branch on your GitHub repository - enable with the `-rename-trunk-branch` argument. This will also work for any open merge requests as they are translated to pull requests.
83113

114+
## Concurrency
115+
84116
By default, 4 workers will be spawned to migrate up to 4 projects in parallel. You can increase or decrease this with the `-max-concurrency` argument. Note that due to GitHub API rate-limiting, you may not experience any significant speed-up. See [GitHub API docs](https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api) for details.
85117

86118
Specify `-loop` to continue migrating projects until canceled. This is useful for daemonizing the migration tool, or automatically restarting when migrating a large number of projects (or a small number of very large projects).
@@ -106,24 +138,6 @@ _Note that this tool performs a forced mirror push, so it's not recommended to r
106138

107139
For pull requests and their comments, the corresponding IDs from GitLab are added to the Markdown header, this is parsed to enable idempotence (see next section).
108140

109-
## Pull Requests
110-
111-
Whilst the git repository will be migrated verbatim, the pull requests are managed using the GitHub API and typically will be authored by the person supplying the authentication token.
112-
113-
Each pull request, along with every comment, will be prepended with a Markdown table showing the original author and some other metadata that is useful to know. This is also used to map pull requests and their comments to their counterparts in GitLab and enables the tool to be idempotent.
114-
115-
As a bonus, if your GitLab users add the URL to their GitHub profile in the `Website` field of their GitLab profile, this tool will add a link to their GitHub profile in the markdown header of any PR or comment they originally authored.
116-
117-
This tool also migrates merged/closed merge requests from your GitLab projects. It does this by reconstructing temporary branches in each repo, pushing them to GitHub, creating then closing the pull request, and lastly deleting the temporary branches. Once the tool has completed, you should not have any of these temporary branches in your repo - although GitHub will not garbage collect them immediately such that you can click the `Restore branch` button in any of these PRs.
118-
119-
_Example migrated pull request (open)_
120-
121-
![example migrated open pull request](pr-example-open.jpeg)
122-
123-
_Example migrated pull request (closed)_
124-
125-
![example migrated closed pull request](pr-example-closed.jpeg)
126-
127141
## Contributing, reporting bugs etc...
128142

129143
Please use GitHub issues & pull requests. This project is licensed under the MIT license.

helper.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"io"
99
"net/http"
10+
"strings"
1011
"time"
1112

1213
"github.com/google/go-github/v74/github"
@@ -108,6 +109,28 @@ func pointer[T any](v T) *T {
108109
return &v
109110
}
110111

112+
func parseProjectSlugs(slugs []string) ([]string, []string, error) {
113+
if len(slugs) != 2 {
114+
return nil, nil, fmt.Errorf("too many fields")
115+
}
116+
117+
delimPosition := strings.LastIndex(slugs[0], "/")
118+
gitlabPath := []string{
119+
slugs[0][:delimPosition],
120+
slugs[0][delimPosition+1:],
121+
}
122+
githubPath := strings.Split(slugs[1], "/")
123+
124+
if len(gitlabPath) != 2 {
125+
return nil, nil, fmt.Errorf("invalid GitLab project: %s", slugs[0])
126+
}
127+
if len(githubPath) != 2 {
128+
return nil, nil, fmt.Errorf("invalid GitHub project: %s", slugs[1])
129+
}
130+
131+
return gitlabPath, githubPath, nil
132+
}
133+
111134
func roundDuration(d, r time.Duration) time.Duration {
112135
if r <= 0 {
113136
return d

main.go

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"os/signal"
1313
"regexp"
1414
"strconv"
15-
"strings"
1615
"sync"
1716
"time"
1817

@@ -326,28 +325,6 @@ func main() {
326325
}
327326
}
328327

329-
func parseProjectSlugs(slugs []string) ([]string, []string, error) {
330-
if len(slugs) != 2 {
331-
return nil, nil, fmt.Errorf("too many fields")
332-
}
333-
334-
delimPosition := strings.LastIndex(slugs[0], "/")
335-
gitlabPath := []string{
336-
slugs[0][:delimPosition],
337-
slugs[0][delimPosition+1:],
338-
}
339-
githubPath := strings.Split(slugs[1], "/")
340-
341-
if len(gitlabPath) != 2 {
342-
return nil, nil, fmt.Errorf("invalid GitLab project: %s", slugs[0])
343-
}
344-
if len(githubPath) != 2 {
345-
return nil, nil, fmt.Errorf("invalid GitHub project: %s", slugs[1])
346-
}
347-
348-
return gitlabPath, githubPath, nil
349-
}
350-
351328
func printReport(ctx context.Context, projects []Project) {
352329
logger.Debug("building report")
353330

project.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,17 @@ func (p *project) migrateMergeRequest(ctx context.Context, mergeRequest *gitlab.
335335
}
336336
}
337337

338+
if strings.EqualFold(mergeRequest.State, "opened") {
339+
if _, err = p.repo.Branch(mergeRequest.SourceBranch); err != nil {
340+
if errors.Is(err, git.ErrBranchNotFound) && skipInvalidMergeRequests {
341+
logger.Info("skipping invalid merge request as source branch does not exist", "name", p.gitlabPath[1], "group", p.gitlabPath[0], "project_id", p.project.ID, "merge_request_id", mergeRequest.IID, "source_branch", mergeRequest.SourceBranch)
342+
return false, nil
343+
} else {
344+
return false, fmt.Errorf("checking source branch for merge request: %v", err)
345+
}
346+
}
347+
}
348+
338349
// Proceed to create temporary branches when migrating a merged/closed merge request that doesn't yet have a counterpart PR in GitHub (can't create one without a branch)
339350
if pullRequest == nil && !strings.EqualFold(mergeRequest.State, "opened") {
340351
logger.Trace("searching for existing branch for closed/merged merge request", "name", p.gitlabPath[1], "group", p.gitlabPath[0], "project_id", p.project.ID, "merge_request_id", mergeRequest.IID, "source_branch", mergeRequest.SourceBranch)

0 commit comments

Comments
 (0)