# 通用 Go + Vue 项目 CI(Gitea Actions) # # 复制整个 .gitea/ 到任意仓库即可使用,约定: # - 仓库根目录有 go.mod、Dockerfile # - 前端(可选)默认在 web/,含 package.json # # 前置条件: # 1. 在线 act_runner(runs-on: ubuntu-latest,见 act-runner/README.md) # 2. 仓库 Secret:REGISTRY_TOKEN(PAT,write:package 权限) # # 可选:仓库 Settings → Actions → Variables 覆盖下方空默认值 # REGISTRY、IMAGE_NAME、DOCKERFILE、DOCKER_PLATFORMS、WEB_DIR、GO_TEST_SCOPE、GOPROXY、GOSUMDB name: CI on: push: branches: [main, master] tags: ['v*'] pull_request: env: REGISTRY: ${{ vars.REGISTRY }} IMAGE_NAME: ${{ vars.IMAGE_NAME }} DOCKERFILE: ${{ vars.DOCKERFILE }} DOCKER_PLATFORMS: ${{ vars.DOCKER_PLATFORMS }} WEB_DIR: ${{ vars.WEB_DIR }} GO_TEST_SCOPE: ${{ vars.GO_TEST_SCOPE }} DOCKER_IMAGE_PREFIX: ${{ vars.DOCKER_IMAGE_PREFIX }} GOPROXY: ${{ vars.GOPROXY }} GOSUMDB: ${{ vars.GOSUMDB }} jobs: test: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Go shell: bash env: GITEA_SERVER_URL: ${{ gitea.server_url }} run: | set -euo pipefail export GOPROXY="${GOPROXY:-https://goproxy.cn,direct}" export GOSUMDB="${GOSUMDB:-sum.golang.google.cn}" GO_VERSION=$(grep '^go ' go.mod | awk '{print $2}') ARCH=$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/') TAR="go${GO_VERSION}.linux-${ARCH}.tar.gz" if command -v go >/dev/null 2>&1 && go version | grep -q "go${GO_VERSION} "; then go version else downloaded=0 for url in \ "https://mirrors.aliyun.com/golang/${TAR}" \ "https://golang.google.cn/dl/${TAR}" \ "https://go.dev/dl/${TAR}"; do echo "trying ${url}" if curl -fsSL --connect-timeout 20 --retry 3 --retry-delay 5 --max-time 600 \ "$url" -o /tmp/go.tgz; then downloaded=1 break fi done if [ "$downloaded" -ne 1 ]; then echo "failed to download Go ${GO_VERSION}" >&2 exit 1 fi rm -rf /usr/local/go tar -C /usr/local -xzf /tmp/go.tgz fi echo "/usr/local/go/bin" >> "$GITHUB_PATH" /usr/local/go/bin/go version - name: Run Go tests shell: bash run: | set -euo pipefail export GOPROXY="${GOPROXY:-https://goproxy.cn,direct}" export GOSUMDB="${GOSUMDB:-sum.golang.google.cn}" scope="${GO_TEST_SCOPE:-./...}" go test "${scope}" - name: Build web (optional) shell: bash run: | set -euo pipefail web_dir="${WEB_DIR:-web}" if [ ! -f "${web_dir}/package.json" ]; then echo "skip: ${web_dir}/package.json not found" exit 0 fi if ! command -v npm >/dev/null 2>&1; then echo "skip: npm not in PATH (frontend will be built in Docker stage)" exit 0 fi cd "${web_dir}" if [ -f package-lock.json ]; then npm ci else npm install fi npm run build docker: runs-on: ubuntu-latest container: image: catthehacker/ubuntu:act-22.04 needs: test if: gitea.event_name == 'push' 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: Log in to Container Registry shell: bash env: GITEA_SERVER_URL: ${{ gitea.server_url }} run: | set -euo pipefail registry="${REGISTRY:-}" if [ -z "$registry" ]; then registry=$(echo "${GITEA_SERVER_URL}" | sed -e 's|^https://||' -e 's|^http://||' -e 's|/.*||') fi echo "${{ secrets.REGISTRY_TOKEN }}" | \ docker login "${registry}" -u "${{ gitea.actor }}" --password-stdin - name: Build and push shell: bash env: GITEA_SHA: ${{ gitea.sha }} GITEA_REF: ${{ gitea.ref }} GITEA_REPOSITORY: ${{ gitea.repository }} GITEA_REPOSITORY_OWNER: ${{ gitea.repository_owner }} GITEA_SERVER_URL: ${{ gitea.server_url }} run: | set -euo pipefail registry="${REGISTRY:-}" if [ -z "$registry" ]; then registry=$(echo "${GITEA_SERVER_URL}" | sed -e 's|^https://||' -e 's|^http://||' -e 's|/.*||') fi image_name="${IMAGE_NAME:-}" if [ -z "$image_name" ]; then image_name=$(echo "${GITEA_REPOSITORY##*/}" | tr '[:upper:]' '[:lower:]') fi dockerfile="${DOCKERFILE:-Dockerfile}" 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 builder_id="gitea-buildx-${GITEA_REPOSITORY//\//-}" docker run --privileged --rm tonistiigi/binfmt --install all 2>/dev/null || true 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 build_args=() if [ -n "${DOCKER_IMAGE_PREFIX:-}" ]; then build_args+=(--build-arg "IMAGE_PREFIX=${DOCKER_IMAGE_PREFIX}") fi docker buildx build \ --platform "${platforms}" \ -f "${dockerfile}" \ "${build_args[@]}" \ "${tag_args[@]}" \ --push \ .