Skip to content

Commit 02e0f51

Browse files
authored
feat: support new options Merge pull request #1 from BoxBoxJason/dev
feat: support new options
2 parents 02af09c + 2c2cdd8 commit 02e0f51

File tree

7 files changed

+171
-76
lines changed

7 files changed

+171
-76
lines changed

.github/workflows/go.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: lint-test
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
pull_request:
7+
8+
permissions:
9+
contents: read
10+
11+
jobs:
12+
golangci-lint:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
- uses: actions/setup-go@v5
17+
with:
18+
go-version: stable
19+
- run: go mod tidy
20+
- name: golangci-lint
21+
uses: golangci/golangci-lint-action@v7
22+
with:
23+
version: v2.0
24+
continue-on-error: true
25+
26+
27+
gosec:
28+
runs-on: ubuntu-latest
29+
env:
30+
GO111MODULE: on
31+
steps:
32+
- uses: actions/checkout@v4
33+
- uses: actions/setup-go@v5
34+
with:
35+
go-version: '1.23.7'
36+
- run: go mod tidy
37+
- name: Run Gosec Security Scanner
38+
uses: securego/gosec@master
39+
with:
40+
args: ./...
41+
continue-on-error: true
42+
43+
44+
gotestsum:
45+
runs-on: ubuntu-latest
46+
steps:
47+
- uses: actions/checkout@v4
48+
- uses: actions/setup-go@v5
49+
with:
50+
go-version: '1.23.7'
51+
- run: go mod tidy
52+
- name: go-test
53+
run: |
54+
go test -v ./...

mirroring/get.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,12 @@ func (g *GitlabInstance) fetchProjects(projectFilters *map[string]bool, groupFil
6767
}
6868

6969
// Add the project to the mirror mapping
70-
mirrorMapping.AddProject(project.PathWithNamespace, &utils.ProjectMirroringOptions{
71-
CI_CD_Catalog: groupCreationOptions.CI_CD_Catalog,
72-
Issues: groupCreationOptions.Issues,
73-
DestinationPath: filepath.Join(groupCreationOptions.DestinationPath, relativePath),
70+
mirrorMapping.AddProject(project.PathWithNamespace, &utils.MirroringOptions{
71+
DestinationPath: filepath.Join(groupCreationOptions.DestinationPath, relativePath),
72+
CI_CD_Catalog: groupCreationOptions.CI_CD_Catalog,
73+
Issues: groupCreationOptions.Issues,
74+
MirrorTriggerBuilds: groupCreationOptions.MirrorTriggerBuilds,
75+
Visibility: groupCreationOptions.Visibility,
7476
})
7577
}
7678
break
@@ -143,10 +145,12 @@ func (g *GitlabInstance) fetchGroups(groupFilters *map[string]bool, mirrorMappin
143145
}
144146

145147
// Add the group to the mirror mapping
146-
mirrorMapping.AddGroup(group.FullPath, &utils.GroupMirroringOptions{
147-
CI_CD_Catalog: groupCreationOptions.CI_CD_Catalog,
148-
Issues: groupCreationOptions.Issues,
149-
DestinationPath: filepath.Join(groupCreationOptions.DestinationPath, relativePath),
148+
mirrorMapping.AddGroup(group.FullPath, &utils.MirroringOptions{
149+
DestinationPath: filepath.Join(groupCreationOptions.DestinationPath, relativePath),
150+
CI_CD_Catalog: groupCreationOptions.CI_CD_Catalog,
151+
Issues: groupCreationOptions.Issues,
152+
MirrorTriggerBuilds: groupCreationOptions.MirrorTriggerBuilds,
153+
Visibility: groupCreationOptions.Visibility,
150154
})
151155
}
152156
break

mirroring/main_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ func TestProcessFilters(t *testing.T) {
1919
{
2020
name: "EmptyMirrorMapping",
2121
mirrorMapping: &utils.MirrorMapping{
22-
Projects: make(map[string]*utils.ProjectMirroringOptions),
23-
Groups: make(map[string]*utils.GroupMirroringOptions),
22+
Projects: make(map[string]*utils.MirroringOptions),
23+
Groups: make(map[string]*utils.MirroringOptions),
2424
},
2525
expectedSourceProjectFilters: map[string]bool{},
2626
expectedSourceGroupFilters: map[string]bool{},
@@ -30,14 +30,14 @@ func TestProcessFilters(t *testing.T) {
3030
{
3131
name: "SingleProjectAndGroup",
3232
mirrorMapping: &utils.MirrorMapping{
33-
Projects: map[string]*utils.ProjectMirroringOptions{
33+
Projects: map[string]*utils.MirroringOptions{
3434
"sourceProject": {
3535
DestinationPath: "destinationGroupPath/destinationProjectPath",
3636
CI_CD_Catalog: true,
3737
Issues: true,
3838
},
3939
},
40-
Groups: map[string]*utils.GroupMirroringOptions{
40+
Groups: map[string]*utils.MirroringOptions{
4141
"sourceGroup": {
4242
DestinationPath: "destinationGroupPath",
4343
CI_CD_Catalog: true,
@@ -61,7 +61,7 @@ func TestProcessFilters(t *testing.T) {
6161
{
6262
name: "MultipleProjectsAndGroups",
6363
mirrorMapping: &utils.MirrorMapping{
64-
Projects: map[string]*utils.ProjectMirroringOptions{
64+
Projects: map[string]*utils.MirroringOptions{
6565
"sourceProject1": {
6666
DestinationPath: "destinationGroupPath1/destinationProjectPath1",
6767
CI_CD_Catalog: true,
@@ -73,7 +73,7 @@ func TestProcessFilters(t *testing.T) {
7373
Issues: false,
7474
},
7575
},
76-
Groups: map[string]*utils.GroupMirroringOptions{
76+
Groups: map[string]*utils.MirroringOptions{
7777
"sourceGroup1": {
7878
DestinationPath: "destinationGroupPath3",
7979
CI_CD_Catalog: true,

mirroring/post.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,15 +143,16 @@ func createProjects(sourceGitlab *GitlabInstance, destinationGitlab *GitlabInsta
143143
return utils.MergeErrors(errorChan, 2)
144144
}
145145

146-
func (g *GitlabInstance) createProjectFromSource(sourceProject *gitlab.Project, copyOptions *utils.ProjectMirroringOptions) (*gitlab.Project, error) {
146+
func (g *GitlabInstance) createProjectFromSource(sourceProject *gitlab.Project, copyOptions *utils.MirroringOptions) (*gitlab.Project, error) {
147147
projectCreationArgs := &gitlab.CreateProjectOptions{
148148
Name: &sourceProject.Name,
149149
Path: &sourceProject.Path,
150150
DefaultBranch: &sourceProject.DefaultBranch,
151151
Description: &sourceProject.Description,
152-
MirrorTriggerBuilds: gitlab.Ptr(true),
152+
MirrorTriggerBuilds: gitlab.Ptr(copyOptions.MirrorTriggerBuilds),
153153
Mirror: gitlab.Ptr(true),
154154
Topics: &sourceProject.Topics,
155+
Visibility: gitlab.Ptr(gitlab.VisibilityValue(copyOptions.Visibility)),
155156
}
156157

157158
utils.LogVerbosef("Retrieving project namespace ID for %s", copyOptions.DestinationPath)
@@ -173,7 +174,7 @@ func (g *GitlabInstance) createProjectFromSource(sourceProject *gitlab.Project,
173174
return destinationProject, nil
174175
}
175176

176-
func (g *GitlabInstance) createGroupFromSource(sourceGroup *gitlab.Group, copyOptions *utils.GroupMirroringOptions) (*gitlab.Group, error) {
177+
func (g *GitlabInstance) createGroupFromSource(sourceGroup *gitlab.Group, copyOptions *utils.MirroringOptions) (*gitlab.Group, error) {
177178
groupCreationArgs := &gitlab.CreateGroupOptions{
178179
Name: &sourceGroup.Name,
179180
Path: &sourceGroup.Path,

mirroring/put.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func (g *GitlabInstance) copyGroupAvatar(destinationGitlabInstance *GitlabInstan
6969
return nil
7070
}
7171

72-
func (g *GitlabInstance) updateProjectFromSource(sourceGitlab *GitlabInstance, sourceProject *gitlab.Project, destinationProject *gitlab.Project, copyOptions *utils.ProjectMirroringOptions) error {
72+
func (g *GitlabInstance) updateProjectFromSource(sourceGitlab *GitlabInstance, sourceProject *gitlab.Project, destinationProject *gitlab.Project, copyOptions *utils.MirroringOptions) error {
7373
wg := sync.WaitGroup{}
7474
maxErrors := 2
7575
if copyOptions.CI_CD_Catalog {

utils/types.go

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313
"os"
1414
"strings"
1515
"sync"
16+
17+
gitlab "gitlab.com/gitlab-org/api/client-go"
1618
)
1719

1820
// ParserArgs defines the command line arguments
@@ -42,21 +44,12 @@ type ParserArgs struct {
4244
// - destination_url: the URL of the destination GitLab instance
4345
// - ci_cd_catalog: whether to add the project to the CI/CD catalog
4446
// - issues: whether to mirror the issues
45-
type ProjectMirroringOptions struct {
46-
DestinationPath string `json:"destination_path"`
47-
CI_CD_Catalog bool `json:"ci_cd_catalog"`
48-
Issues bool `json:"issues"`
49-
}
50-
51-
// GroupMirrorOptions defines how the group should be mirrored
52-
// to the destination GitLab instance
53-
// - destination_url: the URL of the destination GitLab instance
54-
// - ci_cd_catalog: whether to add the group to the CI/CD catalog
55-
// - issues: whether to mirror the issues
56-
type GroupMirroringOptions struct {
57-
DestinationPath string `json:"destination_path"`
58-
CI_CD_Catalog bool `json:"ci_cd_catalog"`
59-
Issues bool `json:"issues"`
47+
type MirroringOptions struct {
48+
DestinationPath string `json:"destination_path"`
49+
CI_CD_Catalog bool `json:"ci_cd_catalog"`
50+
Issues bool `json:"issues"`
51+
MirrorTriggerBuilds bool `json:"mirror_trigger_builds"`
52+
Visibility string `json:"visibility"`
6053
}
6154

6255
// MirrorMapping defines the mapping of projects and groups
@@ -65,19 +58,19 @@ type GroupMirroringOptions struct {
6558
// - projects: a map of project names to their mirroring options
6659
// - groups: a map of group names to their mirroring options
6760
type MirrorMapping struct {
68-
Projects map[string]*ProjectMirroringOptions `json:"projects"`
69-
Groups map[string]*GroupMirroringOptions `json:"groups"`
61+
Projects map[string]*MirroringOptions `json:"projects"`
62+
Groups map[string]*MirroringOptions `json:"groups"`
7063
muProjects sync.Mutex
7164
muGroups sync.Mutex
7265
}
7366

74-
func (m *MirrorMapping) AddProject(project string, options *ProjectMirroringOptions) {
67+
func (m *MirrorMapping) AddProject(project string, options *MirroringOptions) {
7568
m.muProjects.Lock()
7669
defer m.muProjects.Unlock()
7770
m.Projects[project] = options
7871
}
7972

80-
func (m *MirrorMapping) AddGroup(group string, options *GroupMirroringOptions) {
73+
func (m *MirrorMapping) AddGroup(group string, options *MirroringOptions) {
8174
m.muGroups.Lock()
8275
defer m.muGroups.Unlock()
8376
m.Groups[group] = options
@@ -88,8 +81,8 @@ func (m *MirrorMapping) AddGroup(group string, options *GroupMirroringOptions) {
8881
// It returns the mapping and an error if any
8982
func OpenMirrorMapping(path string) (*MirrorMapping, error) {
9083
mapping := &MirrorMapping{
91-
Projects: make(map[string]*ProjectMirroringOptions),
92-
Groups: make(map[string]*GroupMirroringOptions),
84+
Projects: make(map[string]*MirroringOptions),
85+
Groups: make(map[string]*MirroringOptions),
9386
}
9487

9588
// Read the file
@@ -115,7 +108,7 @@ func OpenMirrorMapping(path string) (*MirrorMapping, error) {
115108
}
116109

117110
func (m *MirrorMapping) check() error {
118-
errChan := make(chan error, 3*(len(m.Projects)+len(m.Groups)+1))
111+
errChan := make(chan error, 4*(len(m.Projects)+len(m.Groups))+1)
119112
// Check if the mapping is valid
120113
if len(m.Projects) == 0 && len(m.Groups) == 0 {
121114
errChan <- errors.New("no projects or groups defined in the mapping")
@@ -134,6 +127,11 @@ func (m *MirrorMapping) check() error {
134127
} else if strings.Count(options.DestinationPath, "/") < 1 {
135128
errChan <- fmt.Errorf("invalid project destination path (must be in a namespace): %s", options.DestinationPath)
136129
}
130+
visibilityString := strings.TrimSpace(string(options.Visibility))
131+
if visibilityString != "" && !checkVisibility(visibilityString) {
132+
errChan <- fmt.Errorf("invalid project visibility: %s", string(options.Visibility))
133+
options.Visibility = string(gitlab.PublicVisibility)
134+
}
137135
}
138136

139137
// Check if the groups are valid
@@ -147,11 +145,31 @@ func (m *MirrorMapping) check() error {
147145
if strings.HasPrefix(options.DestinationPath, "/") || strings.HasSuffix(options.DestinationPath, "/") {
148146
errChan <- fmt.Errorf("invalid destination path (must not start or end with /): %s", options.DestinationPath)
149147
}
148+
visibilityString := strings.TrimSpace(string(options.Visibility))
149+
if visibilityString != "" && !checkVisibility(visibilityString) {
150+
errChan <- fmt.Errorf("invalid group visibility: %s", string(options.Visibility))
151+
options.Visibility = string(gitlab.PublicVisibility)
152+
}
150153
}
151154
close(errChan)
152155
return MergeErrors(errChan, 2)
153156
}
154157

158+
func checkVisibility(visibility string) bool {
159+
var valid bool
160+
switch visibility {
161+
case string(gitlab.PublicVisibility):
162+
valid = true
163+
case string(gitlab.InternalVisibility):
164+
valid = true
165+
case string(gitlab.PrivateVisibility):
166+
valid = true
167+
default:
168+
valid = false
169+
}
170+
return valid
171+
}
172+
155173
// GraphQLClient is a client for sending GraphQL requests to GitLab
156174
type GraphQLClient struct {
157175
token string

0 commit comments

Comments
 (0)