Skip to content

Commit 7b3248c

Browse files
feat: 支持 prefix 和 name 两种命名模式
- 添加 nameMode 字段(prefix/name),控制是否添加时间戳 - 添加时间戳生成和名称清理工具函数 - prefix 模式:自动添加时间戳,清理时需使用输出文件 - name 模式:使用固定名称,可直接使用配置文件清理 - 创建 examples 目录存放示例配置文件 - 更新文档说明使用方式
1 parent 0a745a4 commit 7b3248c

File tree

6 files changed

+231
-3
lines changed

6 files changed

+231
-3
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,8 @@ my-users.yaml
3838
dev-users.yaml
3939
ci-users.yaml
4040
test-users.yaml
41+
user.yaml
42+
43+
# Output files
44+
output.yaml
45+
*.output.yaml

README.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,47 @@ export GITLAB_TOKEN=your-personal-access-token
6767
--host https://your-gitlab.com \
6868
--token your-token \
6969
-f config.yaml
70+
71+
# ⚠️ 注意:prefix 模式下的清理
72+
# 如果使用 nameMode: prefix(添加时间戳),清理时需要使用创建时输出的文件
73+
# 因为实际的用户名、组名、项目名都带有时间戳
74+
75+
# 1. 创建时保存输出文件
76+
./bin/gitlab-cli user create \
77+
-f config.yaml \
78+
-o output.yaml
79+
80+
# 2. 清理时使用输出文件
81+
./bin/gitlab-cli user cleanup \
82+
-f output.yaml
7083
```
7184

7285
## 📖 配置文件示例
7386

87+
### 命名模式说明
88+
89+
配置文件支持两种命名模式:
90+
91+
**1. prefix 模式(默认)**
92+
- 自动在 username、email、group path、project path 后添加时间戳
93+
- 示例:`tektoncd``tektoncd-20251030150000`
94+
- 适用场景:测试环境、需要创建多个相似资源
95+
- ⚠️ 清理时必须使用创建时输出的文件
96+
97+
**2. name 模式**
98+
- 不添加时间戳,直接使用配置文件中的名称
99+
- 示例:`test-user-001``test-user-001`(不变)
100+
- 适用场景:生产环境、固定名称的资源
101+
- 可直接使用配置文件清理
102+
74103
### 基本配置
75104

76105
```yaml
77106
# test-users.yaml
78107
users:
79-
- username: tektoncd
108+
# 使用 prefix 模式(默认)
109+
- nameMode: prefix # 可选,默认为 prefix
110+
username: tektoncd
80111
81112
name: tektoncd-test
82113
password: "MyStr0ng!Pass2024"

examples/template-example.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# GitLab CLI 输出模板示例
2+
# 支持 Go template 语法,可以访问 OutputConfig 结构中的所有数据
3+
# 数据结构: .Endpoint (完整 URL), .Scheme (http/https), .Host (主机名) 是 GitLab 服务器配置
4+
# 数据结构: .Users[0] 包含 Username, Email, Name, UserID, Token, Groups
5+
6+
{{- range .Users }}
7+
# ========================================
8+
# 用户: {{ .Username }}
9+
# ========================================
10+
11+
toolchains:
12+
gitlab:
13+
# endpoint is the full endpoint of the server
14+
endpoint: {{ $.Endpoint }}
15+
host: {{ $.Host }}
16+
# scheme, http or https
17+
scheme: {{ $.Scheme }}
18+
# username, the user name of the login account
19+
username: {{ .Username }}
20+
# email
21+
email: {{ .Email }}
22+
{{- if .Token }}
23+
# Personal Access Token
24+
token:
25+
value: {{ .Token.Value }}
26+
scope: {{ range $i, $s := .Token.Scope }}{{ if $i }}, {{ end }}{{ $s }}{{ end }}
27+
expires_at: {{ .Token.ExpiresAt }}
28+
{{- end }}
29+
{{- if .Groups }}
30+
# Groups and Projects
31+
TestGroups:
32+
default: {{ .Username }}
33+
{{- range .Groups }}
34+
- name: {{ .Name }}
35+
path: {{ .Path }}
36+
group_id: {{ .GroupID }}
37+
visibility: {{ .Visibility }}
38+
{{- if .Projects }}
39+
projects:
40+
{{- range .Projects }}
41+
- name: {{ .Name }}
42+
{{- end }}
43+
{{- end }}
44+
{{- end }}
45+
{{- end }}
46+
{{- end }}

examples/user.yaml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
users:
2+
# 示例 1: prefix 模式(添加时间戳)- 默认模式
3+
# ⚠️ 注意:prefix 模式下,清理时需要使用创建时输出的文件
4+
# 使用方法:
5+
# 1. 创建:./bin/gitlab-cli user create -f user.yaml -o output.yaml
6+
# 2. 清理:./bin/gitlab-cli user cleanup -f output.yaml
7+
- nameMode: prefix # 可选,默认为 prefix
8+
username: tektoncd
9+
10+
name: tektoncd-test
11+
password: "MyStr0ng!Pass2024"
12+
# Personal Access Token 配置(可选)
13+
token:
14+
scope:
15+
- api
16+
- read_user
17+
- read_repository
18+
- write_repository
19+
- read_api
20+
- create_runner
21+
# expires_at: 2026-01-01 # 可选,不指定则默认为第2天
22+
23+
# 组和项目配置
24+
groups:
25+
- name: backend-group
26+
path: backend-group
27+
visibility: private
28+
projects:
29+
- name: demo
30+
path: demo
31+
description: demo project
32+
visibility: private
33+
34+
# 示例 2: name 模式(不添加时间戳)
35+
# 使用方法:
36+
# 1. 创建:./bin/gitlab-cli user create -f user.yaml
37+
# 2. 清理:./bin/gitlab-cli user cleanup -f user.yaml # 可直接使用同一配置文件
38+
# - nameMode: name
39+
# username: test-user-001
40+
41+
# name: Test User 001
42+
# password: "MyStr0ng!Pass2024"
43+
# groups:
44+
# - name: test-group
45+
# path: test-group
46+
# visibility: private
47+
# projects:
48+
# - name: test-project
49+
# path: test-project
50+
# description: Test project
51+
# visibility: private

internal/utils/utils.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,101 @@
11
package utils
22

3+
import (
4+
"fmt"
5+
"regexp"
6+
"strings"
7+
"time"
8+
)
9+
310
// GetVisibility 获取可见性设置,默认为 private
411
func GetVisibility(v string) string {
512
if v == "" {
613
return "private"
714
}
815
return v
916
}
17+
18+
// GenerateTimestampSuffix 生成时间戳后缀(格式:20060102150405)
19+
func GenerateTimestampSuffix() string {
20+
return time.Now().Format("20060102150405")
21+
}
22+
23+
// GenerateUsernameWithTimestamp 基于前缀生成符合 GitLab 要求的 username
24+
// 格式:prefix-timestamp
25+
func GenerateUsernameWithTimestamp(prefix string) string {
26+
timestamp := GenerateTimestampSuffix()
27+
username := fmt.Sprintf("%s-%s", prefix, timestamp)
28+
// 确保符合 GitLab username 规则:只能包含字母、数字、下划线、点号、破折号
29+
username = sanitizeUsername(username)
30+
// 限制长度为 255
31+
if len(username) > 255 {
32+
username = username[:255]
33+
}
34+
return username
35+
}
36+
37+
// GenerateEmailWithTimestamp 基于前缀生成唯一的 email
38+
// 格式:prefix-timestamp@domain
39+
func GenerateEmailWithTimestamp(emailPrefix string) string {
40+
// 解析邮箱前缀和域名
41+
parts := strings.Split(emailPrefix, "@")
42+
if len(parts) != 2 {
43+
// 如果不是有效的邮箱格式,使用默认域名
44+
return fmt.Sprintf("%s-%[email protected]", emailPrefix, GenerateTimestampSuffix())
45+
}
46+
47+
localPart := parts[0]
48+
domain := parts[1]
49+
timestamp := GenerateTimestampSuffix()
50+
51+
return fmt.Sprintf("%s-%s@%s", localPart, timestamp, domain)
52+
}
53+
54+
// GenerateGroupPathWithTimestamp 基于前缀生成符合 GitLab 要求的 group path
55+
// 格式:prefix-timestamp
56+
func GenerateGroupPathWithTimestamp(prefix string) string {
57+
timestamp := GenerateTimestampSuffix()
58+
path := fmt.Sprintf("%s-%s", prefix, timestamp)
59+
// 确保符合 GitLab group path 规则:只能包含小写字母、数字、下划线、破折号
60+
path = sanitizeGroupPath(path)
61+
// 限制长度为 255
62+
if len(path) > 255 {
63+
path = path[:255]
64+
}
65+
return path
66+
}
67+
68+
// GenerateProjectPathWithTimestamp 基于前缀生成符合 GitLab 要求的 project path
69+
// 格式:prefix-timestamp(项目 path 规则与组 path 相同)
70+
func GenerateProjectPathWithTimestamp(prefix string) string {
71+
return GenerateGroupPathWithTimestamp(prefix)
72+
}
73+
74+
// sanitizeUsername 清理 username,确保符合 GitLab 规则
75+
// 允许:字母、数字、下划线、点号、破折号
76+
func sanitizeUsername(username string) string {
77+
// 移除不允许的字符
78+
reg := regexp.MustCompile(`[^a-zA-Z0-9_.-]`)
79+
username = reg.ReplaceAllString(username, "")
80+
81+
// 确保不以破折号或点号开头/结尾
82+
username = strings.Trim(username, "-.")
83+
84+
return username
85+
}
86+
87+
// sanitizeGroupPath 清理 group path,确保符合 GitLab 规则
88+
// 允许:小写字母、数字、下划线、破折号
89+
func sanitizeGroupPath(path string) string {
90+
// 转换为小写
91+
path = strings.ToLower(path)
92+
93+
// 移除不允许的字符
94+
reg := regexp.MustCompile(`[^a-z0-9_-]`)
95+
path = reg.ReplaceAllString(path, "")
96+
97+
// 确保不以破折号开头/结尾
98+
path = strings.Trim(path, "-")
99+
100+
return path
101+
}

pkg/types/types.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ type UserConfig struct {
77

88
// UserSpec 用户规格定义
99
type UserSpec struct {
10+
NameMode string `yaml:"nameMode,omitempty"` // 命名模式: "prefix" (添加时间戳) 或 "name" (不添加时间戳),默认为 "prefix"
1011
Username string `yaml:"username"`
1112
Email string `yaml:"email"`
1213
Name string `yaml:"name"`
1314
Password string `yaml:"password"`
14-
Token *TokenSpec `yaml:"token"` // Personal Access Token 配置
15-
Groups []GroupSpec `yaml:"groups"` // 支持多个组
15+
Token *TokenSpec `yaml:"token"` // Personal Access Token 配置
16+
Groups []GroupSpec `yaml:"groups"` // 支持多个组
1617
}
1718

1819
// TokenSpec Personal Access Token 规格定义
@@ -23,6 +24,7 @@ type TokenSpec struct {
2324

2425
// GroupSpec 组规格定义
2526
type GroupSpec struct {
27+
NameMode string `yaml:"nameMode,omitempty"` // 命名模式: "prefix" (添加时间戳) 或 "name" (不添加时间戳),继承 UserSpec.NameMode
2628
Name string `yaml:"name"`
2729
Path string `yaml:"path"`
2830
Visibility string `yaml:"visibility"`
@@ -31,6 +33,7 @@ type GroupSpec struct {
3133

3234
// ProjectSpec 项目规格定义
3335
type ProjectSpec struct {
36+
NameMode string `yaml:"nameMode,omitempty"` // 命名模式: "prefix" (添加时间戳) 或 "name" (不添加时间戳),继承 GroupSpec.NameMode
3437
Name string `yaml:"name"`
3538
Path string `yaml:"path"`
3639
Description string `yaml:"description"`

0 commit comments

Comments
 (0)