From 972b67b9d732d88b6a864827304ebf62a1842780 Mon Sep 17 00:00:00 2001 From: krong Date: Sun, 30 Jun 2024 23:33:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0shell=E8=84=9A=E6=9C=AC?= =?UTF-8?q?=E8=A7=A6=E5=8F=91action=20workflow=20(#5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + README.md | 70 +++++++++++ exec.sh | 339 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 410 insertions(+) create mode 100755 exec.sh diff --git a/.gitignore b/.gitignore index e43b0f9..594bea6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .DS_Store +*.log \ No newline at end of file diff --git a/README.md b/README.md index 57b54fb..795e7e6 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ Docker 的一些服务所在域名被封杀,无法直接访问和拉取镜像 阿里云容器镜像仓库地址: [https://cr.console.aliyun.com/](https://cr.console.aliyun.com/) +支持用命令行触发workflow运行,[点此查看方法](#使用命令行直接同步镜像) + ## Copy.yml 运行介绍 这个工具主要是将 DockerHub 上某个仓库下的某个标签同步到阿里云容器镜像仓库。 @@ -64,6 +66,74 @@ Docker 的一些服务所在域名被封杀,无法直接访问和拉取镜像 > ``` > 只需要填写需要同步的仓库和目标仓库所在的scope + +## 使用命令行直接同步镜像 + +现在提供脚本 ```exec.sh``` 可以在linux或者macos上运行,下面介绍运行方法: + +1. 命令行上基于 [github-cli](https://github.com/cli/cli) 实现的,所以需要先安装 github-cli 工具 + +```shell +# 快速安装方法 +curl -sS https://webi.sh/gh | sh +# 或者可以查看 github-cli 文档自己下载安装 +# https://github.com/cli/cli?#installation +``` + +2. 安装 github-cli 后需要登陆 + +```shell +# 登陆命令 +gh auth login +``` + +3. fork本仓库,并且按照 [上面copy.yml中密码相关配置](#copyyml-运行介绍) 进行配置 + +4. 使用git clone你fork后的仓库,然后开始执行根目录下的 exec.sh 文件,注意文件的执行权限 + +5. 命令行运行 copy.yml workflow + +以将 nginx:1.13 复制到 registry.cn-beijing.aliyuncs.com/ikrong/nginx:1.13 仓库为例 + +```shell +# 命令行如下: +./exec.sh trigger -w copy.yml destination=registry.cn-beijing.aliyuncs.com source_repo=nginx:1.13 destination_repo=ikrong/nginx:1.13 +# 可以省略等号前面的,但是顺序不能变 +./exec.sh trigger -w copy.yml registry.cn-beijing.aliyuncs.com nginx:1.13 ikrong/nginx:1.13 +# 由于脚本默认 registry.cn-beijing.aliyuncs.com ,所以这个也可以省略 +./exec.sh trigger -w copy.yml nginx:1.13 ikrong/nginx:1.13 +# 另外 trigger -w copy.yml 可以简写为 copy,所以命令可以改为 +./exec.sh copy nginx:1.13 ikrong/nginx:1.13 + +# 查看运行状态,不过上面的 trigger 命令执行时会自动输出 status,下面的命令一般不需要执行 +./exec.sh status -w copy.yml +``` + +6. 命令行运行 sync.yml workflow + +以将 nginx 同步到 registry.cn-beijing.aliyuncs.com/ikrong/nginx 仓库为例 + +```shell +# 命令行如下 +./exec.sh trigger -w sync.yml destination=registry.cn-beijing.aliyuncs.com source_repo=nginx destination_scope=ikrong +# 仍然可以省略等号前面的 +./exec.sh trigger -w sync.yml nginx ikrong +# 另外 trigger -w sync.yml 可以简写为 sync,所以命令可以改为 +./exec.sh sync nginx ikrong +``` + +7. 推荐使用命令 + +```shell +# 如果想要复制1个标签,如 nginx:1.13 到 registry.cn-beijing.aliyuncs.com/ikrong/nginx:1.13 +# 则可以使用命令 +./exec.sh copy nginx:1.13 ikrong/nginx:1.13 + +# 如果想要同步某个仓库,如 nginx 到 registry.cn-beijing.aliyuncs.com/ikrong/nginx 仓库 +# 则可以使用命令 +./exec.sh sync nginx ikrong +``` + ## 镜像同步之后如何使用 当使用上面办法将镜像同步到阿里云容器镜像仓库后,就可以直接使用阿里云容器镜像仓库的镜像了。 diff --git a/exec.sh b/exec.sh new file mode 100755 index 0000000..c140e86 --- /dev/null +++ b/exec.sh @@ -0,0 +1,339 @@ +#!/bin/bash +CMD= +REPO= +WORKFLOW= +BRANCH="main" +INPUTS= + +# 你可以在这里修改执行的默认值,请保证顺序一致 +INPUT_CONFIGS=(docker.io registry.cn-beijing.aliyuncs.com) + +INPUT_SHORT=() + +RUN_ID= + +function usage() { + echo + echo "Usage: $0 [options]" + echo + echo "COMMAND:" + echo + echo " trigger -repo,-r -branch,-b -workflow,-w [input]=[value]" + echo + echo " copy shortcut for 'trigger -w copy.yml'" + echo " copy -repo,-r -branch,-b [input]=[value]" + echo + echo " sync shortcut for 'trigger -w sync.yml'" + echo " sync -repo,-r -branch,-b [input]=[value]" + echo + echo " status -repo,-r -workflow,-w " + echo +} + +function r() { + echo -e "\033[31m$1\033[0m" +} + +function g() { + echo -e "\033[32m$1\033[0m" +} + +function b() { + echo -e "\033[34m$1\033[0m" +} + +function getRepo() { + if [ -z "$REPO" ]; then + REPO=$(git remote get-url origin | awk -F ':' '{print $2}') + REPO=${REPO%.git} + REPO=${REPO/https:\/\//} + fi +} + +function read_copy_config() { + case $1 in + source) + INPUT_CONFIGS[0]=$2 + ;; + destination) + INPUT_CONFIGS[1]=$2 + ;; + source_repo) + INPUT_CONFIGS[2]=$2 + ;; + destination_repo) + INPUT_CONFIGS[3]=$2 + ;; + esac +} + +function read_sync_config() { + case $1 in + source) + INPUT_CONFIGS[0]=$2 + ;; + destination) + INPUT_CONFIGS[1]=$2 + ;; + source_repo) + INPUT_CONFIGS[2]=$2 + ;; + destination_scope) + INPUT_CONFIGS[3]=$2 + ;; + esac +} + +function format_config() { + timestamp=$(date "+%Y-%m-%d %H:%M:%S") + case $WORKFLOW in + copy.yml) + echo "[$timestamp] COPY ${INPUT_CONFIGS[0]}/${INPUT_CONFIGS[2]} ${INPUT_CONFIGS[1]}/${INPUT_CONFIGS[3]} <$1>" + ;; + sync.yml) + echo "[$timestamp] SYNC ${INPUT_CONFIGS[0]}/${INPUT_CONFIGS[2]} ${INPUT_CONFIGS[1]}/${INPUT_CONFIGS[3]} <$1>" + ;; + esac +} + +function copy() { + WORKFLOW="copy.yml" + trigger +} + +function sync() { + WORKFLOW="sync.yml" + trigger +} + +function trigger() { + if [ "$INPUTS" = "" ]; then + if [ ${#INPUT_SHORT[@]} = 2 ]; then + if [ "$WORKFLOW" = "copy.yml" ]; then + INPUTS="source_repo=${INPUT_SHORT[0]} destination_repo=${INPUT_SHORT[1]}" + else + INPUTS="source_repo=${INPUT_SHORT[0]} destination_scope=${INPUT_SHORT[1]}" + fi + fi + if [ ${#INPUT_SHORT[@]} = 3 ]; then + if [ "$WORKFLOW" = "copy.yml" ]; then + INPUTS="destination=${INPUT_SHORT[0]} source_repo=${INPUT_SHORT[1]} destination_repo=${INPUT_SHORT[2]}" + else + INPUTS="destination=${INPUT_SHORT[0]} source_repo=${INPUT_SHORT[1]} destination_scope=${INPUT_SHORT[2]}" + fi + fi + if [ ${#INPUT_SHORT[@]} = 4 ]; then + if [ "$WORKFLOW" = "copy.yml" ]; then + INPUTS="source=${INPUT_SHORT[0]} destination=${INPUT_SHORT[1]} source_repo=${INPUT_SHORT[2]} destination_repo=${INPUT_SHORT[3]}" + else + INPUTS="source=${INPUT_SHORT[0]} destination=${INPUT_SHORT[1]} source_repo=${INPUT_SHORT[2]} destination_scope=${INPUT_SHORT[3]}" + fi + fi + fi + + params= + inputs=($INPUTS) + for INPUT in "${inputs[@]}"; do + KEY=$(echo $INPUT | cut -d '=' -f 1) + VALUE=$(echo $INPUT | cut -d '=' -f 2) + case $WORKFLOW in + sync.yml) + read_sync_config $KEY $VALUE + ;; + copy.yml) + read_copy_config $KEY $VALUE + ;; + esac + done + + if [ "$INPUTS" != "" ]; then + case $WORKFLOW in + sync.yml) + params="-f 'inputs[source]=${INPUT_CONFIGS[0]}' \ + -f 'inputs[destination]=${INPUT_CONFIGS[1]}' \ + -f 'inputs[source_repo]=${INPUT_CONFIGS[2]}' \ + -f 'inputs[destination_scope]=${INPUT_CONFIGS[3]}'" + ;; + copy.yml) + params="-f 'inputs[source]=${INPUT_CONFIGS[0]}' \ + -f 'inputs[destination]=${INPUT_CONFIGS[1]}' \ + -f 'inputs[source_repo]=${INPUT_CONFIGS[2]}' \ + -f 'inputs[destination_repo]=${INPUT_CONFIGS[3]}'" + ;; + esac + fi + + if [ "$REPO" == "" ]; then + echo "$(r "No repository specified, use -repo or -r")" + exit 1 + fi + + if [ "$WORKFLOW" == "" ]; then + echo "$(r "No workflow specified, use -workflow or -w")" + exit 1 + fi + + echo + if [ "$INPUTS" != "" ]; then + echo "Triggering workflow $(r $WORKFLOW) on repository $(r $REPO) with branch $(r $BRANCH) and providing the following inputs:" + echo + echo "$(g $(echo "${inputs[@]}" | tr ' ' ', '))" + else + echo "$(r 'Inputs not specified')" + usage + exit 1 + fi + echo + read -p "Confirm? [Y/n] " + echo + if [[ $REPLY =~ ^[Yy]$ ]] || [ -z $REPLY ]; then + echo "gh api \ + --method POST \ + -H \"Accept: application/vnd.github.v3+json\" \ + -H \"X-GitHub-Api-Version: 2022-11-28\" \ + /repos/$REPO/actions/workflows/$WORKFLOW/dispatches \ + -f \"ref=$BRANCH\" \ + $params + " | sh + + if [ $? -ne 0 ]; then + echo $(r "Failed to trigger workflow") + exit 1 + else + echo $(g "Workflow Triggered") + echo + echo $(b "Wait to check workflow running status...") + sleep 15 + status + fi + fi +} + +function get_workflow_runid() { + get_run_id_try=0 + get_run_id_cmd="gh api \ + --method GET \ + -H 'Accept: application/vnd.github+json' \ + -H 'X-GitHub-Api-Version: 2022-11-28' \ + /repos/$REPO/actions/workflows/$WORKFLOW/runs \ + -f 'per_page=1' -f 'status=in_progress' \ + --jq '.workflow_runs.[0].id' + " + RUN_ID=$(echo "$get_run_id_cmd" | sh) + while [ "$RUN_ID" == "" ] && [ $get_run_id_try -lt 6 ]; do + clear + echo "Get running id, retring $get_run_id_try/5 times..." + get_run_id_try=$((get_run_id_try+1)) + sleep 10 + RUN_ID=$(echo "$get_run_id_cmd" | sh) + done +} + +function status() { + get_workflow_runid + if [ "$RUN_ID" != "" ]; then + status_cmd="gh api \ + --method GET \ + -H 'Accept: application/vnd.github+json' \ + -H 'X-GitHub-Api-Version: 2022-11-28' \ + /repos/$REPO/actions/runs/$RUN_ID \ + --template '{{.status}} {{.run_started_at}}' + " + result=($(echo $status_cmd | sh)) + status=${result[0]} + time=${result[1]} + while [ "$status" == "in_progress" ] || [ "$status" == "" ]; do + clear + duration=$(( $(date "+%s") - $(date -u -jf "%Y-%m-%dT%H:%M:%SZ" "$time" "+%s") )) + if [ $duration -ge 3600 ]; then + duration="$((duration/60))min" + else + duration="${duration}s" + fi + echo "Workflow $(g $WORKFLOW) RunID: $(b $RUN_ID) $(g $status) $duration" + echo "Open https://github.com/$REPO/actions/runs/$RUN_ID to see log" + sleep 20 + result=($(echo $status_cmd | sh)) + echo ${result[0]} + status=${result[0]} + done + clear + echo "Workflow $(g $WORKFLOW) has finished with status: $(g $status)" + if [ "$CMD" = "trigger" ]; then + format_config $status >> run.log + fi + echo "Open https://github.com/$REPO/actions/runs/$RUN_ID to see log" + else + echo "No running workflow" + fi +} + +function main() { + gh auth status -h github.com >> /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo + echo $(r "Need login first, you can run with following command:") + echo + echo $(b "gh auth login") + echo + exit 1 + fi + getRepo + $CMD +} + +command -v gh > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo + echo $(r "You need to install github cli tool.") + echo $(r "Run with following command to install: ") + echo + echo $(g "curl -sS https://webi.sh/gh | sh") + echo + echo $(g "Visit https://github.com/cli/cli?#installation for more install instructions.") + echo + exit 1 +fi + +while [ $# -gt 0 ]; do + case $1 in + -repo | -r) + shift + REPO=$1 + ;; + -branch | -b) + shift + BRANCH=$1 + ;; + -workflow | -w) + shift + WORKFLOW=$1 + ;; + trigger) + CMD="trigger" + ;; + status) + CMD="status" + ;; + copy) + CMD="copy" + ;; + sync) + CMD="sync" + ;; + *=*) + INPUTS="$INPUTS $1 " + ;; + *) + INPUT_SHORT+=($1) + ;; + esac + shift +done + +if [ "$CMD" = "" ] || [[ "$CMD" != "trigger" && "$CMD" != "status" && "$CMD" != "copy" && "$CMD" != "sync" ]]; then + usage + exit 1 +fi + +main \ No newline at end of file