Skip to content

Commit c76c3b6

Browse files
committed
feature: 自定义标签
1 parent c338ff5 commit c76c3b6

File tree

8 files changed

+259
-905
lines changed

8 files changed

+259
-905
lines changed

.github/ISSUE_TEMPLATE/hub-mirror.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ labels: ["hub-mirror"]
77

88
{
99
"hub-mirror": [
10-
"格式:你需要转换的镜像$自定义镜像名",
11-
"实例1:ghcr.io/jenkins-x/jx-boot:3.10.3",
12-
"实例2:ghcr.io/jenkins-x/jx-boot:3.10.3$jx-boot",
10+
"格式:你需要转换的镜像$自定义镜像名:自定义标签名",
11+
"$自定义镜像名:自定义标签名 是可选的",
12+
"示例1:registry.k8s.io/kube-apiserver:v1.27.4",
13+
"示例2:registry.k8s.io/kube-apiserver:v1.27.4$my-kube-apiserver",
14+
"示例3:registry.k8s.io/kube-apiserver:v1.27.4$my-kube-apiserver:mytag",
1315
"要求:hub-mirror 标签是必选的,标题随意,每次最多支持转换 11 个镜像",
14-
"建议:修改这个 json",
15-
"......"
16+
"建议:按照这个 json 格式修改",
17+
"请确保 json 格式是正确的,比如这里最后一个是没有逗号的"
1618
]
1719
}

.github/workflows/hub-mirror.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ name: hub-mirror
44
# 当新建或者修改 issues 时,触发当前 workflow
55
on:
66
issues:
7-
types: [opened, edited]
7+
types: [ opened, edited ]
88

99
# 需要执行的任务列表
1010
jobs:
@@ -23,7 +23,7 @@ jobs:
2323
- name: Setup go
2424
uses: actions/setup-go@v2
2525
with:
26-
go-version: 1.17
26+
go-version: 1.20
2727
# 3. 运行 go 代码
2828
- name: Run code
2929
run: go run main.go --username=${{ secrets.DOCKER_USERNAME }} --password=${{ secrets.DOCKER_TOKEN }} --repository=${{ secrets.DOCKER_REPOSITORY }} --content='${{ github.event.issue.body }}' --maxContent=11 --outputPath=output.sh

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2022 寻寻觅觅的Gopher
3+
Copyright (c) 2022 togettoyou
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

go.mod

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
module github.com/togettoyou/hub-mirror
22

3-
go 1.17
3+
go 1.20
44

55
require (
66
github.com/docker/docker v20.10.12+incompatible
77
github.com/spf13/pflag v1.0.5
8+
github.com/stretchr/testify v1.7.0
89
)
910

1011
require (
11-
github.com/Microsoft/go-winio v0.4.17 // indirect
12-
github.com/containerd/containerd v1.5.9 // indirect
13-
github.com/docker/distribution v2.7.1+incompatible // indirect
12+
github.com/Microsoft/go-winio v0.5.2 // indirect
13+
github.com/containerd/containerd v1.5.17 // indirect
14+
github.com/davecgh/go-spew v1.1.1 // indirect
15+
github.com/docker/distribution v2.8.2+incompatible // indirect
1416
github.com/docker/go-connections v0.4.0 // indirect
1517
github.com/docker/go-units v0.4.0 // indirect
1618
github.com/gogo/protobuf v1.3.2 // indirect
@@ -21,12 +23,14 @@ require (
2123
github.com/opencontainers/go-digest v1.0.0 // indirect
2224
github.com/opencontainers/image-spec v1.0.2 // indirect
2325
github.com/pkg/errors v0.9.1 // indirect
26+
github.com/pmezard/go-difflib v1.0.0 // indirect
2427
github.com/sirupsen/logrus v1.8.1 // indirect
25-
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect
26-
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect
28+
golang.org/x/net v0.0.0-20210610124326-52da8fb2a613 // indirect
29+
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
2730
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
2831
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect
2932
google.golang.org/grpc v1.43.0 // indirect
3033
google.golang.org/protobuf v1.27.1 // indirect
34+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
3135
gotest.tools/v3 v3.1.0 // indirect
3236
)

go.sum

Lines changed: 12 additions & 791 deletions
Large diffs are not rendered by default.

main.go

Lines changed: 35 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,23 @@ package main
22

33
import (
44
"context"
5-
"encoding/base64"
65
"encoding/json"
76
"fmt"
8-
"io"
97
"os"
10-
"strings"
118
"sync"
129
"text/template"
1310

14-
"github.com/docker/docker/api/types"
15-
"github.com/docker/docker/client"
1611
"github.com/spf13/pflag"
12+
"github.com/togettoyou/hub-mirror/pkg"
1713
)
1814

1915
var (
2016
content = pflag.StringP("content", "", "", "原始镜像,格式为:{ \"hub-mirror\": [] }")
21-
maxContent = pflag.IntP("maxContent", "", 10, "原始镜像个数限制")
22-
username = pflag.StringP("username", "", "", "docker hub 用户名")
23-
password = pflag.StringP("password", "", "", "docker hub 密码")
17+
maxContent = pflag.IntP("maxContent", "", 11, "原始镜像个数限制")
18+
repository = pflag.StringP("repository", "", "", "推送仓库地址,为空默认为 hub.docker.com")
19+
username = pflag.StringP("username", "", "", "仓库用户名")
20+
password = pflag.StringP("password", "", "", "仓库密码")
2421
outputPath = pflag.StringP("outputPath", "", "output.sh", "结果输出路径")
25-
repository = pflag.StringP("repository", "", "", "仓库地址,如果为空,默认推到dockerHub")
2622
)
2723

2824
func main() {
@@ -36,123 +32,61 @@ func main() {
3632
if err != nil {
3733
panic(err)
3834
}
35+
3936
if len(hubMirrors.Content) > *maxContent {
40-
panic("content is too long.")
37+
panic("提交的原始镜像个数超出了最大限制")
4138
}
39+
4240
fmt.Printf("%+v\n", hubMirrors)
4341

44-
fmt.Println("连接 Docker")
45-
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
42+
fmt.Println("初始化 Docker 客户端")
43+
cli, err := pkg.NewCli(context.Background(), *repository, *username, *password)
4644
if err != nil {
4745
panic(err)
4846
}
4947

50-
fmt.Println("验证 Docker 用户名密码")
51-
if *username == "" || *password == "" {
52-
panic("username or password cannot be empty.")
53-
}
54-
authConfig := types.AuthConfig{
55-
Username: *username,
56-
Password: *password,
57-
ServerAddress: *repository,
58-
}
59-
encodedJSON, err := json.Marshal(authConfig)
60-
if err != nil {
61-
panic(err)
62-
}
63-
authStr := base64.URLEncoding.EncodeToString(encodedJSON)
64-
_, err = cli.RegistryLogin(context.Background(), authConfig)
65-
if err != nil {
66-
panic(err)
67-
}
68-
69-
fmt.Println("开始转换镜像")
70-
output := make([]struct {
71-
Source string
72-
Target string
73-
Repository string
74-
}, 0)
75-
48+
outputs := make([]*pkg.Output, 0)
49+
mu := sync.Mutex{}
7650
wg := sync.WaitGroup{}
7751

7852
for _, source := range hubMirrors.Content {
53+
source := source
54+
7955
if source == "" {
8056
continue
8157
}
82-
83-
target := source
84-
// 查看是否配置自定义镜像名,如果配置的话使用自定义镜像名
85-
if strings.Contains(source, "$") {
86-
str1 := strings.Split(source, "$")
87-
repository := strings.Split(str1[0], ":")
88-
target = str1[1] + ":" + repository[len(repository)-1]
89-
source = str1[0]
90-
}
91-
92-
// 如果为空,默认推送到 DockerHub 用户名 下
93-
// 如果指定了值,则推动到指定的仓库下,用户名不一定与repository后缀相同
94-
if *repository == "" {
95-
target = *username + "/" + strings.ReplaceAll(target, "/", ".")
96-
} else {
97-
target = *repository + "/" + strings.ReplaceAll(target, "/", ".")
98-
}
99-
58+
fmt.Println("开始转换镜像", source)
10059
wg.Add(1)
101-
go func(source, target, repository string) {
60+
go func() {
10261
defer wg.Done()
10362

104-
fmt.Println("开始转换", source, "=>", target)
105-
ctx := context.Background()
106-
107-
// 拉取镜像
108-
pullOut, err := cli.ImagePull(ctx, source, types.ImagePullOptions{})
63+
output, err := cli.PullTagPushImage(context.Background(), source)
10964
if err != nil {
110-
panic(err)
65+
return
11166
}
112-
defer pullOut.Close()
113-
io.Copy(os.Stdout, pullOut)
11467

115-
// 重新标签
116-
err = cli.ImageTag(ctx, source, target)
117-
if err != nil {
118-
panic(err)
119-
}
120-
121-
// 上传镜像
122-
pushOut, err := cli.ImagePush(ctx, target, types.ImagePushOptions{
123-
RegistryAuth: authStr,
124-
})
125-
if err != nil {
126-
panic(err)
127-
}
128-
defer pushOut.Close()
129-
io.Copy(os.Stdout, pushOut)
130-
131-
output = append(output, struct {
132-
Source string
133-
Target string
134-
Repository string
135-
}{Source: source, Target: target, Repository: repository})
136-
fmt.Println("转换成功", source, "=>", target)
137-
}(source, target, *repository)
68+
mu.Lock()
69+
defer mu.Unlock()
70+
outputs = append(outputs, output)
71+
}()
13872
}
13973

14074
wg.Wait()
14175

142-
if len(output) == 0 {
143-
panic("output is empty.")
76+
if len(outputs) == 0 {
77+
panic("没有转换成功的镜像")
14478
}
14579

14680
tmpl, err := template.New("pull_images").Parse(`{{- range . -}}
14781
148-
{{if .Repository}}
149-
# if your repository is private,please login...
150-
# docker login {{ .Repository }} --username={your username}
151-
{{end}}
152-
docker pull {{ .Target }}
153-
docker tag {{ .Target }} {{ .Source }}
154-
155-
{{ end -}}`)
82+
{{if .Repository}}
83+
# if your repository is private,please login...
84+
# docker login {{ .Repository }} --username={your username}
85+
{{end}}
86+
docker pull {{ .Target }}
87+
docker tag {{ .Target }} {{ .Source }}
88+
89+
{{ end -}}`)
15690
if err != nil {
15791
panic(err)
15892
}
@@ -161,9 +95,10 @@ docker tag {{ .Target }} {{ .Source }}
16195
panic(err)
16296
}
16397
defer outputFile.Close()
164-
err = tmpl.Execute(outputFile, output)
98+
99+
err = tmpl.Execute(outputFile, outputs)
165100
if err != nil {
166101
panic(err)
167102
}
168-
fmt.Println(output)
103+
fmt.Println(outputs)
169104
}

0 commit comments

Comments
 (0)