Files
ToolBox/.gitea/workflows/ci.yml
T
renjue 0044cd6e32
CI / docker (push) Failing after 1m55s
初始化 ToolBox 开发者工具箱。
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-25 10:32:25 +08:00

264 lines
9.9 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ToolBoxVue 前端 CIGitea Actions
#
# 单 jobnpm test + Docker 多架构构建/推送
# 约定:Dockerfile 在仓库根目录
#
# 前置:act_runnerubuntu-latest + docker.sock)、Secret REGISTRY_TOKEN
# VariablesREGISTRY、IMAGE_NAME、DOCKER_IMAGE_PREFIX、RUN_NPM_TEST 等
name: CI
on:
push:
branches: [main, master]
tags: ['v*']
pull_request:
workflow_dispatch:
env:
REGISTRY: ${{ vars.REGISTRY }}
GITEA_ROOT_URL: ${{ vars.GITEA_ROOT_URL }}
IMAGE_NAME: ${{ vars.IMAGE_NAME }}
DOCKERFILE: ${{ vars.DOCKERFILE }}
DOCKER_PLATFORMS: ${{ vars.DOCKER_PLATFORMS }}
RUN_NPM_TEST: ${{ vars.RUN_NPM_TEST }}
DOCKER_IMAGE_PREFIX: ${{ vars.DOCKER_IMAGE_PREFIX }}
jobs:
docker:
runs-on: ubuntu-latest
container:
image: catthehacker/ubuntu:act-22.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Docker
run: |
set -eux
if ! command -v docker >/dev/null 2>&1; then
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y docker.io
fi
if [ ! -S /var/run/docker.sock ]; then
echo "ERROR: /var/run/docker.sock 未挂载到 job 容器。" >&2
echo "请在 act_runner config.yaml 中配置:" >&2
echo " container.options: -v /var/run/docker.sock:/var/run/docker.sock" >&2
echo " container.valid_volumes: [/var/run/docker.sock]" >&2
exit 1
fi
docker info
- name: Run npm tests
if: vars.RUN_NPM_TEST != 'false'
shell: bash
run: |
set -euo pipefail
NODE_VERSION=20.20.2
ARCH=$(uname -m | sed 's/x86_64/x64/; s/aarch64/arm64/')
TAR="node-v${NODE_VERSION}-linux-${ARCH}.tar.gz"
if ! command -v node >/dev/null 2>&1 || ! node -v | grep -qE "v20\."; then
downloaded=0
for url in \
"https://npmmirror.com/mirrors/node/v${NODE_VERSION}/${TAR}" \
"https://mirrors.aliyun.com/nodejs-release/v${NODE_VERSION}/${TAR}" \
"https://nodejs.org/dist/v${NODE_VERSION}/${TAR}"; do
echo "trying ${url}"
if curl -fsSL --connect-timeout 20 --retry 3 --retry-delay 5 --max-time 600 \
"$url" -o /tmp/node.tar.gz; then
downloaded=1
break
fi
done
[ "$downloaded" -eq 1 ] || { echo "failed to download Node ${NODE_VERSION}" >&2; exit 1; }
rm -rf /usr/local/node
mkdir -p /usr/local/node
tar -xzf /tmp/node.tar.gz -C /usr/local/node --strip-components=1
export PATH="/usr/local/node/bin:${PATH}"
fi
node -v
npm -v
# act-runner 工作区 volume 可能残留旧 lockfile,强制与当前 commit 一致
git checkout HEAD -- package-lock.json package.json .npmrc
echo "commit: $(git rev-parse --short HEAD)"
echo "lockfile sample:"
grep -m3 '"resolved"' package-lock.json || true
if grep -qE 'artifactory|xiaohongshu' package-lock.json; then
echo "ERROR: package-lock.json 仍含内网源,请检查 checkout" >&2
exit 1
fi
# 清除 runner 注入的内网 npm 配置,使用独立缓存目录
unset NPM_CONFIG_REGISTRY NPM_REGISTRY npm_config_registry NODE_AUTH_TOKEN 2>/dev/null || true
export CI=true
export NPM_CONFIG_USERCONFIG=/tmp/toolbox-npmrc
export NPM_CONFIG_GLOBALCONFIG=/tmp/toolbox-npmrc-global
export npm_config_cache=/tmp/toolbox-npm-cache
export npm_config_progress=true
export npm_config_loglevel=info
export npm_config_registry=https://registry.npmmirror.com
export npm_config_esbuild_binary_host_mirror=https://npmmirror.com/mirrors/esbuild
printf '%s\n' 'registry=https://registry.npmmirror.com' > /tmp/toolbox-npmrc-global
printf '%s\n' \
'registry=https://registry.npmmirror.com' \
'esbuild_binary_host_mirror=https://npmmirror.com/mirrors/esbuild' \
'always-auth=false' \
> /tmp/toolbox-npmrc
rm -rf node_modules /tmp/toolbox-npm-cache
mkdir -p /tmp/toolbox-npm-cache
npm cache clean --force
echo "npm registry: $(npm config get registry)"
echo "=== npm ci ==="
npm ci --userconfig=/tmp/toolbox-npmrc --registry=https://registry.npmmirror.com
echo "=== npm test ==="
npm run test:run -- --pool=forks --maxWorkers=2 --reporter=verbose
- name: Resolve registry
id: reg
if: gitea.event_name == 'push'
shell: bash
env:
GITEA_SERVER_URL: ${{ gitea.server_url }}
run: |
set -euo pipefail
url_to_host() {
echo "$1" | sed -e 's|^https://||' -e 's|^http://||' -e 's|/.*||'
}
is_internal_host() {
local host="${1%%:*}"
case "$host" in
localhost|127.*|10.*|192.168.*) return 0 ;;
172.*)
local second
second=$(echo "$host" | cut -d. -f2)
[ "$second" -ge 16 ] && [ "$second" -le 31 ]
return
;;
*) return 1 ;;
esac
}
registry="${REGISTRY:-}"
if [ -z "$registry" ] && [ -n "${GITEA_ROOT_URL:-}" ]; then
registry=$(url_to_host "${GITEA_ROOT_URL}")
fi
if [ -z "$registry" ]; then
registry=$(url_to_host "${GITEA_SERVER_URL}")
fi
if is_internal_host "$registry"; then
echo "ERROR: Registry 主机 '${registry}' 是内网地址。" >&2
echo "请设置 Variable REGISTRY=公网 Gitea 域名(如 git.example.com)。" >&2
exit 1
fi
echo "registry host: ${registry}"
auth_header=""
if auth_header=$(curl -fsS -D - "https://${registry}/v2/" -o /dev/null 2>&1 | grep -i '^www-authenticate:'); then
if echo "$auth_header" | grep -qiE '127\.0\.0\.1|172\.(1[6-9]|2[0-9]|3[01])\.|localhost|:13827'; then
echo "ERROR: Registry token realm 指向内网地址:${auth_header}" >&2
exit 1
fi
fi
echo "host=${registry}" >> "${GITHUB_OUTPUT}"
- name: Log in to Container Registry
if: gitea.event_name == 'push'
shell: bash
run: |
set -euo pipefail
echo "${{ secrets.REGISTRY_TOKEN }}" | \
docker login "${{ steps.reg.outputs.host }}" -u "${{ gitea.actor }}" --password-stdin
- name: Build image
shell: bash
env:
GITEA_SHA: ${{ gitea.sha }}
GITEA_REF: ${{ gitea.ref }}
GITEA_REPOSITORY: ${{ gitea.repository }}
GITEA_REPOSITORY_OWNER: ${{ gitea.repository_owner }}
GITEA_EVENT_NAME: ${{ gitea.event_name }}
REGISTRY_HOST: ${{ steps.reg.outputs.host }}
run: |
set -euo pipefail
dockerfile="${DOCKERFILE:-Dockerfile}"
if [ "${DOCKER_IMAGE_PREFIX:-}" = "hub" ] || [ "${DOCKER_IMAGE_PREFIX:-}" = "docker.io" ]; then
image_prefix=""
elif [ -z "${DOCKER_IMAGE_PREFIX:-}" ] || [ "${DOCKER_IMAGE_PREFIX}" = "1panel" ]; then
image_prefix="docker.1panel.live/library/"
elif [ "${DOCKER_IMAGE_PREFIX}" = "daocloud" ]; then
image_prefix="docker.m.daocloud.io/library/"
else
image_prefix="${DOCKER_IMAGE_PREFIX}"
[[ "${image_prefix}" == */ ]] || image_prefix="${image_prefix}/"
fi
echo "using IMAGE_PREFIX=${image_prefix:-<docker.io>}"
build_args=(--build-arg "IMAGE_PREFIX=${image_prefix}")
builder_id="gitea-buildx-${GITEA_REPOSITORY//\//-}"
if [ "${GITEA_EVENT_NAME}" = "push" ]; then
install_binfmt() {
for img in \
"docker.1panel.live/tonistiigi/binfmt:latest" \
"docker.m.daocloud.io/tonistiigi/binfmt:latest" \
"tonistiigi/binfmt:latest"; do
echo "trying binfmt image: ${img}"
if docker run --privileged --rm "${img}" --install all; then
return 0
fi
done
return 1
}
install_binfmt || true
registry="${REGISTRY_HOST}"
image_name="${IMAGE_NAME:-$(echo "${GITEA_REPOSITORY##*/}" | tr '[:upper:]' '[:lower:]')}"
platforms="${DOCKER_PLATFORMS:-linux/amd64,linux/arm64}"
image="${registry}/${GITEA_REPOSITORY_OWNER}/${image_name}"
tags="${image}:sha-${GITEA_SHA:0:7}"
case "${GITEA_REF}" in
refs/heads/main|refs/heads/master)
tags="${tags},${image}:latest"
;;
refs/tags/v*)
tags="${tags},${image}:${GITEA_REF#refs/tags/}"
;;
esac
docker buildx create --name "${builder_id}" --use 2>/dev/null || docker buildx use "${builder_id}"
docker buildx inspect --bootstrap
tag_args=()
IFS=',' read -r -a tag_list <<< "$tags"
for t in "${tag_list[@]}"; do
tag_args+=(-t "$t")
done
docker buildx build \
--platform "${platforms}" \
-f "${dockerfile}" \
"${build_args[@]}" \
"${tag_args[@]}" \
--push \
.
else
# PR:仅单架构构建验证 Dockerfile,不推送
docker buildx create --name "${builder_id}" --use 2>/dev/null || docker buildx use "${builder_id}"
docker buildx inspect --bootstrap
docker buildx build \
--platform linux/amd64 \
-f "${dockerfile}" \
"${build_args[@]}" \
--load \
.
fi