提交 d0ceddc9 authored 作者: likai's avatar likai

chore: 初始化 bingo gitlab ci builder skill

上级
# Bingo GitLab CI 构建器
这是一个面向 Codex / 智能代理的 GitLab CI 技能仓库,用于为前端项目或多模块项目生成、修复、重构一套保守、可审查、兼容旧版 GitLab 的流水线配置。
它特别适合以下场景:
- 需要生成或修复 `.gitlab-ci.yml`
- 需要严格区分 `build_x``release_x`
- 项目依赖 `ci/*.sh` 脚本执行构建与发布
- 需要按环境、模块或 tag 前缀精确触发流水线
- 需要兼容 GitLab 11.x 等较老版本,避免 `extends``needs``rules` 等新语法
- 发布阶段需要走 OSS 上传,而不是仅保留 GitLab artifacts
## 核心能力
- 根据真实仓库结构识别单模块、多模块、按环境发布等 CI 模式
- 生成成对的 `build_x + release_x` Job,避免只构建不发布
- 优先复用仓库现有 shell 脚本、包管理器和构建命令
- 为旧版 GitLab 输出更保守的 YAML 语法,优先使用 `stages``only`、YAML anchors
- 支持按 tag 前缀路由不同环境或模块,例如 `web-*``admin-*``demo-default-*`
- 支持生成 `ci/build-dist.sh``ci/release-dist.sh``CI_USAGE.md`
- 强调与已有发布约定兼容,例如固定镜像、固定脚本签名、固定上传变量名等
## 仓库结构
```text
.
├── SKILL.md
├── agents/
│ └── openai.yaml
├── assets/
│ ├── gitlab-tag-release-template/
│ │ ├── CI_USAGE.md
│ │ └── ci/
│ │ ├── build-dist.sh
│ │ └── release-dist.sh
│ └── gitlab-multi-frontend-template/
│ ├── CI_USAGE.md
│ └── ci/
│ ├── build-dist.sh
│ └── release-dist.sh
└── references/
└── legacy-gitlab-patterns.md
```
各目录职责如下:
- `SKILL.md`:技能主说明,定义适用场景、工作流、输出模式、兼容约束与校验要求
- `agents/openai.yaml`:代理侧展示信息与默认提示词
- `assets/`:可复用模板资产
- `references/legacy-gitlab-patterns.md`:旧版 GitLab 兼容规则、常见故障与反模式清单
## 模板说明
### 1. `gitlab-tag-release-template`
适用于单模块或单环境前端项目,典型特点:
- 基于 tag 触发
- `build``release` 分离
- 使用 `ci/build-dist.sh``ci/release-dist.sh`
- 阶段之间通过共享传输目录交接产物
- 需要兼容较老版本 GitLab
模板内常见占位符包括:
- `__PACKAGE_DIR__`
- `__RUNNER_TAG__`
- `__BUILD_IMAGE__`
- `__RELEASE_IMAGE__`
- `__BUILD_TARGET__`
- `__INSTALL_COMMAND__`
- `__BUILD_COMMAND__`
- `__MODULE_NAME__`
- `__JOB_SUFFIX__`
- `__TAG_PREFIX__`
### 2. `gitlab-multi-frontend-template`
适用于包含多个前端模块的仓库,例如 `web``admin`,典型特点:
- 每个模块拥有独立的 `build_x + release_x`
- 每个模块有独立的构建命令、产物目录与 OSS 发布名
- 可按模块 tag 前缀分别触发,例如 `web-*``admin-*`
## 技能工作流
该技能默认遵循以下流程:
1. 先分析仓库,而不是直接写 CI
2. 读取已有 `.gitlab-ci.yml``package.json`、shell 脚本和项目级 `AGENTS.md`
3. 确认是单模块还是多模块,是否存在固定发布约定
4. 识别真实的 Node 版本、包管理器与构建入口
5. 选择合适模板或按约束手工生成 CI
6. 补齐需要的 `ci/*.sh` 脚本和说明文档
7. 校验 YAML、shell 语法以及 job 配对关系
## 设计原则
- 以“保守兼容、便于审查、易于维护”为优先目标
- 不盲目套用示例注释或“项目级说明”,必须以真实仓库内容为准
- 不默认引入 GitLab 新特性,尤其在 11.x 场景下
- 不把发布逻辑弱化成仅 artifacts 输出
- 不随意改写用户已经确定的发布契约、镜像、变量名或脚本参数顺序
- npm 项目默认使用 `npm install`,而不是 `npm ci`
## 推荐使用方式
如果你是在 Codex 技能体系中使用本仓库,建议通过技能名触发,例如:
```text
使用 $bingo-gitlab-ci-builder 为当前项目生成或修复一套 GitLab CI
```
更具体的请求也适合,例如:
```text
请基于当前仓库生成兼容 GitLab 11.1.4 的 .gitlab-ci.yml,
要求保留 build_demo + release_demo 成对结构,
发布走 OSS,tag 前缀使用 demo-default-*。
```
## 输出结果通常包含
- `.gitlab-ci.yml`
- `ci/build-dist.sh`
- `ci/release-dist.sh`
- `CI_USAGE.md`
具体文件是否生成,取决于目标仓库是否真的需要这些内容。
## 参考资料
- [SKILL.md](./SKILL.md)
- [legacy-gitlab-patterns.md](./references/legacy-gitlab-patterns.md)
- [gitlab-tag-release-template/CI_USAGE.md](./assets/gitlab-tag-release-template/CI_USAGE.md)
- [gitlab-multi-frontend-template/CI_USAGE.md](./assets/gitlab-multi-frontend-template/CI_USAGE.md)
## 适用价值总结
如果你希望代理在处理 GitLab CI 时更加稳妥,而不是一上来就输出一份现代但不兼容旧环境的配置,这个仓库就是为这种需求准备的。它的重点不是“最炫的新语法”,而是“能落地、能维护、能适配旧项目”的 CI 生成能力。
---
name: bingo-gitlab-ci-builder
description: 为前端项目或多模块项目生成、修复、重构 GitLab CI 流水线。适用于用户提到 `.gitlab-ci.yml`、构建发布分离、基于 `.sh` 的编译脚本、OSS 发布、按环境或模块隔离产物、以及旧版 GitLab 兼容性时,尤其是 GitLab 11.x 这类需要避免 `extends`、`needs`、`rules` 等较新语法的场景。
---
# Bingo GitLab CI 构建器
Use this skill to create or repair GitLab CI for projects that need conservative, reviewable pipelines.
## Workflow
1. Inspect the repository before writing CI.
Read the existing `.gitlab-ci.yml` if present.
Search for build entrypoints such as `package.json`, `pnpm` scripts, root `.sh` files, Docker-based build scripts, OSS upload helpers, and any project `AGENTS.md` rules.
Treat project-level comment blocks and copied examples as hints until they are confirmed by the repository or by the user. Do not copy a sample “第二部分:项目级说明” into the final CI as if it were automatically true for the current project.
2. Identify the deployment model.
Determine whether the project builds one module or multiple modules.
Determine whether the project expects `build_x + release_x` pairs.
Determine whether artifacts are passed through a shared transfer directory instead of GitLab artifacts.
Determine whether build output directories must be isolated by module or environment.
Determine whether the user wants tag-prefix routing so only one environment or module job set runs for a given tag.
Determine whether the repository or the user has already established a release contract, such as a fixed `.release_template`, a required release image like `springjk/ci-helper:latest`, a required script signature like `sh ci/release-dist.sh "$BUILD_TARGET" "$OSS_DEPLOY_NAME"`, or a required uploader like `oss-deploy`.
Unless the user explicitly asks to collapse stages, preserve strict `build_x + release_x` pairing and keep release focused on zip packaging plus OSS upload.
If an existing repository or user-provided snippet establishes the release contract, treat that contract as mandatory and preserve it unless the user explicitly asks to replace it.
3. Confirm the GitLab compatibility target.
If the user mentions an old GitLab version such as 11.x, assume conservative compatibility.
For GitLab 11.1.4 or similarly old versions, avoid `extends`, `needs`, `rules`, and other newer pipeline features unless verified locally or explicitly provided by the user.
Prefer `stages`, `variables`, `only`, explicit `tags`, and YAML anchors.
Detect the project Node major version from primary sources such as `package.json` `engines`, `package.json` `volta`, `.nvmrc`, `.node-version`, existing official `node:X` images in CI, or the project’s documented runtime. Prefer official images like `node:16-alpine` or `node:24-alpine`. Do not introduce repository-specific custom build images unless the repository already depends on them or the user explicitly requires them.
4. Generate outputs as code, not just advice.
Create or update `.gitlab-ci.yml`.
Create helper shell scripts when the build or release logic is repeated.
Create or update a usage document when the pipeline is non-trivial.
Preserve mandatory comment blocks exactly when the user says they must not change.
If the request matches the default legacy pattern, start from the bundled asset template instead of rewriting the whole skeleton from scratch.
## Output Pattern
Default to this structure unless the repo clearly needs something else:
- `build_*` jobs only compile and copy dist to a shared transfer directory.
- `release_*` jobs only package and publish from the transfer directory.
- Dist paths are isolated by module or environment, for example `/cache/transfer/${CI_PIPELINE_ID}/demo/dist`.
- Helper scripts live under `ci/` when they are reused by multiple jobs.
- Usage documentation lives in `CI_USAGE.md` when the pipeline has multiple environments or non-obvious constraints.
- If the user wants selective execution, add explicit tag-prefix conditions per job pair so one tag only triggers the intended `build_x + release_x`.
- Prefer OSS-oriented release behavior by default: generate `dist-x-<date>.zip` and `dist-x-latest.zip`, stage them into upload directories when needed, and upload from release jobs. Do not silently replace this with “copy to server directory + switch current symlink” unless the repository already uses that deployment model and the user wants to preserve it.
- If the repository or the user already defines a concrete OSS release skeleton, preserve the release image, script entry, argument order, uploader contract, and variable names unless the user explicitly requests a migration. Do not downgrade that release stage to GitLab artifacts-only output, ad hoc server-directory copying, or a different uploader contract.
## Legacy GitLab Rules
When targeting old GitLab versions:
- Use explicit `tags:` on every concrete job.
- Use `only: [tags]` when the project wants tag-only pipelines.
- Use `only: refs + variables` when the project wants tag-prefix routing.
- Use stage ordering instead of `needs`.
- Use YAML anchors instead of `extends`.
- Do not introduce `rules`, `workflow`, `parallel:matrix`, child pipelines, or other modern features unless verified.
- Avoid advanced regex such as negative lookahead on GitLab 11.1.4. Prefer disjoint prefixes like `demo-default-*` and `demo-bingo-*` instead of overlapping patterns that require complex expressions.
- Keep syntax flat and predictable.
## Recommended Prefix Naming
When the project uses tag-prefix routing, prefer readable and mutually exclusive prefixes.
- For a default environment plus a variant, use `demo-default-*` and `demo-bingo-*` instead of `demo-*` and `demo-bingo-*`.
- For multiple independent environments, use full environment names such as `dev-bingo-*`, `qsh-bingo-*`, and `demo-bingo-*`.
- For multiple frontend modules, use module names such as `web-*` and `admin-*`.
- If the user wants one tag to trigger all pairs, introduce a dedicated shared prefix such as `all-*` and add it explicitly to each intended job pair.
Prefer explicitness over brevity. On older GitLab versions, a slightly longer but non-overlapping prefix is safer than a short prefix that requires complex regex to disambiguate.
## Build and Release Rules
Keep build and release separated unless the user explicitly asks to combine them.
For each environment or module X:
- Add `build_x` and `release_x` together.
- Put build output in `$TRANSFER_BASE_DIR/x/dist`.
- Package release output as `dist-x-<date>.zip` and `dist-x-latest.zip` when the project wants versioned zips.
- If the uploader only accepts directories, stage zip files inside dedicated upload directories before calling the uploader.
- If the project already uses a release template such as `image: springjk/ci-helper:latest` plus `sh ci/release-dist.sh "$BUILD_TARGET" "$OSS_DEPLOY_NAME"`, keep that structure and wire every `release_x` job through `OSS_DEPLOY_NAME`. Do not rename the variable or replace the image unless the user explicitly approves the change.
- If using tag-prefix routing, give each pair a unique non-overlapping prefix and apply the same prefix condition to both `build_x` and `release_x`.
- Do not keep only `build_x` when the skill is supposed to follow the default OSS release pattern; if a release job is intentionally omitted, document why and confirm that this is a user choice rather than an accidental drift from the standard pattern.
## Shell Script Rules
When the repository already uses `.sh` build scripts:
- Prefer calling repository shell scripts or their equivalent logic from CI.
- If several jobs share the same sequence, factor it into `ci/build-dist.sh` and `ci/release-dist.sh`.
- Make scripts POSIX `sh` unless the repository clearly needs `bash`.
- Validate shell syntax after editing.
- Match the install command to the actual repository package manager. Do not force `pnpm` only because a copied comment block says so if the repository actually uses `npm` or `yarn`.
- For npm-based repositories in this skill, use `npm install`. Do not use `npm ci`.
## Validation
After edits, validate at least these points:
- YAML parses successfully.
- Unsupported keys for the target GitLab version are absent.
- Every active `build_*` job has a matching `release_*` job.
- Every concrete job has `tags: ["web"]` if the project requires that runner tag.
- Tag-prefix expressions do not overlap unless the user explicitly wants multiple pairs to run.
- Shell scripts pass `sh -n`.
- Documentation matches the actual active jobs.
- The selected Node image is an official `node:X-alpine` image whose version matches the project evidence.
- Project-level notes copied into comments have been verified against real build scripts before being treated as facts.
- If the repository or user provided a release snippet, the final `.release_template` still uses the required release image, script command, argument order, and uploader variable names.
- The release path still stages zip files into directories before calling the uploader when that uploader contract requires directories.
## References
Read [`references/legacy-gitlab-patterns.md`](references/legacy-gitlab-patterns.md) when you need the detailed checklist, compatibility notes, or reusable output skeleton.
## Assets
When the project fits the common pattern of tag-triggered frontend publishing with shell-based build helpers, reuse the bundled template at [`assets/gitlab-tag-release-template`](assets/gitlab-tag-release-template).
Copy only the files that fit the target repository, then replace placeholders such as `__MODULE_NAME__`, `__BUILD_TARGET__`, `__PNPM_BUILD_SCRIPT__`, `__RUNNER_TAG__`, `__PACKAGE_DIR__`, and `__TAG_PREFIX__`.
When the project has multiple frontend modules such as `web` and `admin`, prefer [`assets/gitlab-multi-frontend-template`](assets/gitlab-multi-frontend-template).
Use it when each module needs its own isolated build output directory, its own `build_x + release_x` pair, and optionally its own tag prefix such as `web-*` or `admin-*`.
interface:
display_name: "Bingo GitLab CI 构建器"
short_description: "生成保守兼容的成对式 GitLab CI OSS 发布脚本"
default_prompt: "使用 $bingo-gitlab-ci-builder 为当前项目生成或修复一套 build_x + release_x 成对、按真实仓库脚本和 Node 版本适配的 GitLab CI。"
variables:
PNPM_HOME: "/pnpm-store"
TRANSFER_BASE_DIR: "/cache/transfer/${CI_PIPELINE_ID}"
stages:
- build
- release
.build_template: &build_template
stage: build
image: node:24-alpine
tags:
- __RUNNER_TAG__
before_script:
- corepack enable
- corepack prepare pnpm@10.28.2 --activate
- pnpm config set registry https://registry.npmmirror.com
- pnpm config set store-dir "$PNPM_HOME"
script:
- sh ci/build-dist.sh "$MODULE_NAME" "$PACKAGE_DIR" "$PNPM_BUILD_SCRIPT" "$DIST_SUBDIR"
only:
- tags
.release_template: &release_template
stage: release
image: __RELEASE_IMAGE__
tags:
- __RUNNER_TAG__
script:
- sh ci/release-dist.sh "$MODULE_NAME" "$OSS_DEPLOY_NAME"
only:
- tags
build_web:
<<: *build_template
tags:
- __RUNNER_TAG__
only:
refs:
- tags
variables:
- $CI_COMMIT_TAG =~ /^__WEB_TAG_PREFIX__.*$/
variables:
MODULE_NAME: "web"
PACKAGE_DIR: "__WEB_PACKAGE_DIR__"
PNPM_BUILD_SCRIPT: "__WEB_BUILD_SCRIPT__"
DIST_SUBDIR: "__WEB_DIST_SUBDIR__"
release_web:
<<: *release_template
tags:
- __RUNNER_TAG__
only:
refs:
- tags
variables:
- $CI_COMMIT_TAG =~ /^__WEB_TAG_PREFIX__.*$/
variables:
MODULE_NAME: "web"
OSS_DEPLOY_NAME: "__WEB_OSS_NAME__"
build_admin:
<<: *build_template
tags:
- __RUNNER_TAG__
only:
refs:
- tags
variables:
- $CI_COMMIT_TAG =~ /^__ADMIN_TAG_PREFIX__.*$/
variables:
MODULE_NAME: "admin"
PACKAGE_DIR: "__ADMIN_PACKAGE_DIR__"
PNPM_BUILD_SCRIPT: "__ADMIN_BUILD_SCRIPT__"
DIST_SUBDIR: "__ADMIN_DIST_SUBDIR__"
release_admin:
<<: *release_template
tags:
- __RUNNER_TAG__
only:
refs:
- tags
variables:
- $CI_COMMIT_TAG =~ /^__ADMIN_TAG_PREFIX__.*$/
variables:
MODULE_NAME: "admin"
OSS_DEPLOY_NAME: "__ADMIN_OSS_NAME__"
# Multi-frontend CI Usage
Use this template when the repository has multiple frontend modules such as `web` and `admin`.
## Replace these placeholders
- `__RUNNER_TAG__`
- `__BUILD_IMAGE__`
- `__RELEASE_IMAGE__`
- `__WEB_PACKAGE_DIR__`
- `__WEB_INSTALL_COMMAND__`
- `__WEB_BUILD_COMMAND__`
- `__WEB_DIST_SUBDIR__`
- `__WEB_OSS_NAME__`
- `__WEB_TAG_PREFIX__`
- `__ADMIN_PACKAGE_DIR__`
- `__ADMIN_INSTALL_COMMAND__`
- `__ADMIN_BUILD_COMMAND__`
- `__ADMIN_DIST_SUBDIR__`
- `__ADMIN_OSS_NAME__`
- `__ADMIN_TAG_PREFIX__`
## Default behavior
1. `build_web` and `build_admin` compile independently.
2. Each module writes its output to its own transfer directory.
3. `release_web` and `release_admin` package and upload independently.
4. Dist directories are normalized to `/cache/transfer/${CI_PIPELINE_ID}/web/dist` and `/cache/transfer/${CI_PIPELINE_ID}/admin/dist`.
5. Only tags matching the configured module prefix trigger that module pair.
6. Prefer an official Node image such as `node:16-alpine` or `node:24-alpine`, selected from project evidence.
## Package manager rule
Choose each module's install and build commands from the checked-in repository:
- npm module: `__WEB_INSTALL_COMMAND__` could be `npm install`, `__WEB_BUILD_COMMAND__` could be `npm run build`
- pnpm module: `__ADMIN_INSTALL_COMMAND__` could be `pnpm install --frozen-lockfile`, `__ADMIN_BUILD_COMMAND__` could be `pnpm run build --filter=@vben/web-antdv-next`
- yarn module: use `yarn install --frozen-lockfile` plus the module's real build command
Do not assume all modules use `pnpm` just because one copied project note mentions it.
Do not use `npm ci` as the default npm install command in this template.
## Prefix design rule
On older GitLab versions, use simple non-overlapping prefixes.
- Good: `web-` and `admin-`
- Good: `demo-default-` and `demo-bingo-`
- Bad: `demo-` and `demo-bingo-`
#!/bin/sh
set -eu
MODULE_NAME="${1:?missing module name}"
PACKAGE_DIR="${2:?missing package dir}"
DIST_SUBDIR="${3:-dist}"
TRANSFER_BASE_DIR="${TRANSFER_BASE_DIR:?missing TRANSFER_BASE_DIR}"
INSTALL_COMMAND="${INSTALL_COMMAND:?missing install command}"
BUILD_COMMAND="${BUILD_COMMAND:?missing build command}"
TARGET_DIR="${TRANSFER_BASE_DIR}/${MODULE_NAME}"
cd "${PACKAGE_DIR}"
sh -lc "${INSTALL_COMMAND}"
sh -lc "${BUILD_COMMAND}"
if [ ! -d "${DIST_SUBDIR}" ]; then
echo "未找到构建产物目录: ${PACKAGE_DIR}/${DIST_SUBDIR}" >&2
exit 1
fi
mkdir -p "${TARGET_DIR}"
rm -rf "${TARGET_DIR}/dist"
cp -R "${DIST_SUBDIR}" "${TARGET_DIR}/dist"
#!/bin/sh
set -eu
MODULE_NAME="${1:?missing module name}"
OSS_DEPLOY_NAME="${2:-${MODULE_NAME}}"
TRANSFER_BASE_DIR="${TRANSFER_BASE_DIR:?missing TRANSFER_BASE_DIR}"
SOURCE_DIR="${TRANSFER_BASE_DIR}/${MODULE_NAME}/dist"
RELEASE_DIR="${TRANSFER_BASE_DIR}/${MODULE_NAME}/release"
DATE_TAG="$(date '+%Y-%m-%d-%H-%M-%S')"
DATED_ZIP="${RELEASE_DIR}/dist-${MODULE_NAME}-${DATE_TAG}.zip"
LATEST_ZIP="${RELEASE_DIR}/dist-${MODULE_NAME}-latest.zip"
DATED_UPLOAD_DIR="${RELEASE_DIR}/upload-${MODULE_NAME}-${DATE_TAG}"
LATEST_UPLOAD_DIR="${RELEASE_DIR}/upload-${MODULE_NAME}-latest"
if [ ! -d "${SOURCE_DIR}" ]; then
echo "未找到待发布目录: ${SOURCE_DIR}" >&2
exit 1
fi
if ! command -v zip >/dev/null 2>&1; then
echo "缺少 zip 命令,请在 Runner 镜像或执行环境中安装 zip" >&2
exit 1
fi
if ! command -v oss-deploy >/dev/null 2>&1; then
echo "缺少 oss-deploy 命令,请在 Runner 镜像或执行环境中提供 oss-deploy" >&2
exit 1
fi
mkdir -p "${RELEASE_DIR}"
rm -rf "${DATED_ZIP}" "${LATEST_ZIP}" "${DATED_UPLOAD_DIR}" "${LATEST_UPLOAD_DIR}"
(
cd "${SOURCE_DIR}"
zip -qr "${DATED_ZIP}" .
)
cp "${DATED_ZIP}" "${LATEST_ZIP}"
mkdir -p "${DATED_UPLOAD_DIR}" "${LATEST_UPLOAD_DIR}"
cp "${DATED_ZIP}" "${DATED_UPLOAD_DIR}/"
cp "${LATEST_ZIP}" "${LATEST_UPLOAD_DIR}/"
oss-deploy "${OSS_DEPLOY_NAME}" "${DATED_UPLOAD_DIR}"
oss-deploy "${OSS_DEPLOY_NAME}-latest" "${LATEST_UPLOAD_DIR}"
variables:
PNPM_HOME: "/pnpm-store"
TRANSFER_BASE_DIR: "/cache/transfer/${CI_PIPELINE_ID}"
PACKAGE_DIR: "__PACKAGE_DIR__"
stages:
- build
- release
.build_template: &build_template
stage: build
image: node:24-alpine
tags:
- __RUNNER_TAG__
before_script:
- corepack enable
- corepack prepare pnpm@10.28.2 --activate
- pnpm config set registry https://registry.npmmirror.com
- pnpm config set store-dir "$PNPM_HOME"
script:
- sh ci/build-dist.sh "$BUILD_TARGET" "$PNPM_BUILD_SCRIPT"
only:
- tags
.release_template: &release_template
stage: release
image: __RELEASE_IMAGE__
tags:
- __RUNNER_TAG__
script:
- sh ci/release-dist.sh "$BUILD_TARGET" "$OSS_DEPLOY_NAME"
only:
- tags
build___JOB_SUFFIX__:
<<: *build_template
tags:
- __RUNNER_TAG__
only:
refs:
- tags
variables:
- $CI_COMMIT_TAG =~ /^__TAG_PREFIX__.*$/
variables:
BUILD_TARGET: "__BUILD_TARGET__"
PNPM_BUILD_SCRIPT: "__PNPM_BUILD_SCRIPT__"
release___JOB_SUFFIX__:
<<: *release_template
tags:
- __RUNNER_TAG__
only:
refs:
- tags
variables:
- $CI_COMMIT_TAG =~ /^__TAG_PREFIX__.*$/
variables:
BUILD_TARGET: "__BUILD_TARGET__"
OSS_DEPLOY_NAME: "__MODULE_NAME__"
# CI Usage
Use this template when the project needs:
- tag-triggered GitLab CI
- build and release separation
- shell-based helper scripts under `ci/`
- a shared transfer directory between stages
- conservative syntax for older GitLab versions
## Replace these placeholders
- `__PACKAGE_DIR__`
- `__RUNNER_TAG__`
- `__BUILD_IMAGE__`
- `__RELEASE_IMAGE__`
- `__BUILD_TARGET__`
- `__INSTALL_COMMAND__`
- `__BUILD_COMMAND__`
- `__MODULE_NAME__`
- `__JOB_SUFFIX__`
- `__TAG_PREFIX__`
## Required files
- `.gitlab-ci.yml`
- `ci/build-dist.sh`
- `ci/release-dist.sh`
## Default behavior
1. Build job installs dependencies and runs one target build command.
2. Dist is copied to `$TRANSFER_BASE_DIR/<target>/dist`.
3. Release job creates dated and latest zip files.
4. Each zip is staged inside an upload directory before calling `oss-deploy`.
5. Only tags matching `__TAG_PREFIX__*` trigger this job pair.
6. Prefer an official Node image such as `node:16-alpine` or `node:24-alpine`, selected from project evidence.
## Package manager rule
Choose install and build commands from the checked-in repository, not from copied comments:
- npm repo: `__INSTALL_COMMAND__` might be `npm install`, `__BUILD_COMMAND__` might be `npm run build:demo`
- pnpm repo: `__INSTALL_COMMAND__` might be `pnpm install --frozen-lockfile`, `__BUILD_COMMAND__` might be `pnpm run build:demo`
- yarn repo: `__INSTALL_COMMAND__` might be `yarn install --frozen-lockfile`, `__BUILD_COMMAND__` might be `yarn build:demo`
Do not hardcode `pnpm` in the template output unless the repository actually uses `pnpm`.
Do not use `npm ci` as the default npm install command in this template.
## Prefix design rule
On older GitLab versions, use simple non-overlapping prefixes.
- Good: `demo-default-` and `demo-bingo-`
- Bad: `demo-` and `demo-bingo-`
#!/bin/sh
set -eu
BUILD_TARGET="${1:?missing build target}"
PACKAGE_DIR="${PACKAGE_DIR:-__PACKAGE_DIR__}"
TRANSFER_BASE_DIR="${TRANSFER_BASE_DIR:?missing TRANSFER_BASE_DIR}"
INSTALL_COMMAND="${INSTALL_COMMAND:-__INSTALL_COMMAND__}"
BUILD_COMMAND="${BUILD_COMMAND:-__BUILD_COMMAND__}"
TARGET_DIR="${TRANSFER_BASE_DIR}/${BUILD_TARGET}"
cd "${PACKAGE_DIR}"
sh -lc "${INSTALL_COMMAND}"
sh -lc "${BUILD_COMMAND}"
if [ ! -d "dist" ]; then
echo "未找到构建产物目录: ${PACKAGE_DIR}/dist" >&2
exit 1
fi
mkdir -p "${TARGET_DIR}"
rm -rf "${TARGET_DIR}/dist"
cp -R dist "${TARGET_DIR}/dist"
#!/bin/sh
set -eu
BUILD_TARGET="${1:?missing build target}"
OSS_DEPLOY_NAME="${2:-${BUILD_TARGET}}"
TRANSFER_BASE_DIR="${TRANSFER_BASE_DIR:?missing TRANSFER_BASE_DIR}"
SOURCE_DIR="${TRANSFER_BASE_DIR}/${BUILD_TARGET}/dist"
RELEASE_DIR="${TRANSFER_BASE_DIR}/${BUILD_TARGET}/release"
DATE_TAG="$(date '+%Y-%m-%d-%H-%M-%S')"
DATED_ZIP="${RELEASE_DIR}/dist-${BUILD_TARGET}-${DATE_TAG}.zip"
LATEST_ZIP="${RELEASE_DIR}/dist-${BUILD_TARGET}-latest.zip"
DATED_UPLOAD_DIR="${RELEASE_DIR}/upload-${BUILD_TARGET}-${DATE_TAG}"
LATEST_UPLOAD_DIR="${RELEASE_DIR}/upload-${BUILD_TARGET}-latest"
if [ ! -d "${SOURCE_DIR}" ]; then
echo "未找到待发布目录: ${SOURCE_DIR}" >&2
exit 1
fi
if ! command -v zip >/dev/null 2>&1; then
echo "缺少 zip 命令,请在 Runner 镜像或执行环境中安装 zip" >&2
exit 1
fi
if ! command -v oss-deploy >/dev/null 2>&1; then
echo "缺少 oss-deploy 命令,请在 Runner 镜像或执行环境中提供 oss-deploy" >&2
exit 1
fi
mkdir -p "${RELEASE_DIR}"
rm -rf "${DATED_ZIP}" "${LATEST_ZIP}" "${DATED_UPLOAD_DIR}" "${LATEST_UPLOAD_DIR}"
(
cd "${SOURCE_DIR}"
zip -qr "${DATED_ZIP}" .
)
cp "${DATED_ZIP}" "${LATEST_ZIP}"
mkdir -p "${DATED_UPLOAD_DIR}" "${LATEST_UPLOAD_DIR}"
cp "${DATED_ZIP}" "${DATED_UPLOAD_DIR}/"
cp "${LATEST_ZIP}" "${LATEST_UPLOAD_DIR}/"
oss-deploy "${OSS_DEPLOY_NAME}" "${DATED_UPLOAD_DIR}"
oss-deploy "${OSS_DEPLOY_NAME}-latest" "${LATEST_UPLOAD_DIR}"
# Legacy GitLab CI patterns
## Checklist
1. Read project `AGENTS.md` and preserve any mandatory comment blocks.
2. Inspect `.gitlab-ci.yml`, root shell scripts, package manager files, and module layout.
3. Verify whether any copied “项目级说明” block is factual for this repo or only a reusable example; do not assume it is true without checking.
4. Map each environment to a concrete build command.
5. Detect the Node major version from primary evidence and prefer an official `node:X-alpine` image with the matching major version.
6. Decide whether helper scripts under `ci/` reduce repetition.
7. Generate `build_x + release_x` pairs only for active environments.
8. If the user wants one tag to run only one pair, assign unique tag prefixes per pair.
9. Remove paused environments completely, including matching release jobs and documentation references.
10. If the repository or user provides a release snippet, preserve its release image, script signature, uploader contract, and variable names unless explicitly asked to migrate.
11. Validate YAML and shell syntax.
12. Update usage docs if you changed active jobs, file names, or release behavior.
## Conservative syntax for GitLab 11.x
Prefer:
```yaml
stages:
- build
- release
.build_template: &build_template
stage: build
image: node:24-alpine
tags:
- web
script:
- sh ci/build-dist.sh "$BUILD_TARGET" "$PNPM_BUILD_SCRIPT"
only:
- tags
```
Concrete jobs should merge the anchor:
```yaml
build_demo:
<<: *build_template
tags:
- web
only:
refs:
- tags
variables:
- $CI_COMMIT_TAG =~ /^demo-default-.*$/
variables:
BUILD_TARGET: "demo"
PNPM_BUILD_SCRIPT: "build:demo"
```
If you need per-environment selective triggering on GitLab 11.x, prefer `only: refs + variables` with disjoint prefixes.
Good: `demo-default-*` and `demo-bingo-*`
Bad: `demo-*` and `demo-bingo-*` together, because the first pattern also matches the second.
## Recommended prefix conventions
Use prefixes that are:
1. Human-readable
2. Mutually exclusive
3. Stable across time
Recommended patterns:
- Single environment only: keep one explicit prefix such as `release-*`
- Default plus variant: `demo-default-*`, `demo-bingo-*`
- Many environments: `dev-bingo-*`, `qsh-bingo-*`, `demo-bingo-*`
- Many modules: `web-*`, `admin-*`
- Run all pairs intentionally: `all-*`
Avoid designing prefixes that need complex regex subtraction to distinguish them.
Avoid these on old GitLab unless verified:
- `extends`
- `needs`
- `rules`
- `workflow`
- `parallel:matrix`
- child pipeline syntax
- negative lookahead or other advanced regex features that older GitLab variable expressions may reject
## Default file set
When the request is to build a reusable CI setup, create these files when useful:
- `.gitlab-ci.yml`
- `ci/build-dist.sh`
- `ci/release-dist.sh`
- `CI_USAGE.md`
If the repository follows the common frontend release pattern, start from the bundled asset template in `assets/gitlab-tag-release-template/` and then trim or expand jobs to match only the active environments.
If the repository has two or more frontend modules, start from `assets/gitlab-multi-frontend-template/` and replace the module-specific placeholders before adding or removing pairs.
## Default build script behavior
`ci/build-dist.sh` usually should:
1. Read build target and build command name from arguments.
2. Install dependencies with the repository package manager.
3. Enter the module directory.
4. Run the specific build command.
5. Copy `dist` to `$TRANSFER_BASE_DIR/<target>/dist`.
Pick the install command from real repository evidence:
- `pnpm install --frozen-lockfile` when the repo actually uses `pnpm`
- `npm install` when the repo actually uses `npm`
- `yarn install --frozen-lockfile` when the repo actually uses `yarn`
Do not force `pnpm` because a copied comment block says so if the checked-in repository does not support it.
Do not use `npm ci` in this skill. For npm-based repositories, use `npm install`.
## Default release script behavior
`ci/release-dist.sh` usually should:
1. Read build target and publish name from arguments.
2. Load dist from `$TRANSFER_BASE_DIR/<target>/dist`.
3. Generate dated and latest zip files.
4. If uploader only accepts directories, copy each zip into a dedicated upload directory.
5. Call the uploader for the dated package and latest package.
Default to OSS-oriented release logic. Only switch to server-directory deployment when the repository already uses that model and the user wants to preserve it.
If the repository or the user already established a release contract such as `springjk/ci-helper:latest` and `OSS_DEPLOY_NAME`, preserve that contract exactly unless the user explicitly requests a migration.
## Common failure patterns
### `unknown keys: extends`
The GitLab instance is too old for the chosen syntax.
Replace `extends` with YAML anchors and merge keys.
### `unknown keys: needs`
Use stage ordering only.
Do not add `needs` on GitLab 11.1.4.
### `only 变量 invalid expression syntax`
The GitLab instance may reject advanced regex syntax.
Replace complex expressions with simple prefix matches and redesign prefixes so they do not overlap.
Example: replace `demo-*` plus `demo-bingo-*` with `demo-default-*` plus `demo-bingo-*`.
### Tag can’t trigger any job
The configured prefixes may not match the tag the user is actually creating, or the CI may have been rewritten from selective routing to all-tags or vice versa without confirming intent.
Re-check the real build-script-to-prefix mapping and ensure the selected tag format matches one concrete `build_x + release_x` pair.
### Skill copied a sample project section as if it were real
The “第二部分:项目级说明” may be a reusable example rather than a description of the current repository.
Treat it as a hint, then confirm against `package.json`, root scripts, and existing CI before applying it.
### Custom repository image drift
Using a project-specific custom image can hide the actual Node version decision and make CI less portable.
Prefer official images such as `node:16-alpine` or `node:24-alpine`, selected from project evidence.
### `npm ci` breaks the build setup
Some repositories or runner environments fail on `npm ci` even though `npm install` works normally.
For npm-based repositories in this skill, always use `npm install`.
### Uploader says source path not found
The uploader may expect a directory instead of a file.
Stage the zip file inside an upload directory, then pass the directory path to the uploader.
### Release template lost the required OSS contract
The skill may have simplified release into `artifacts`, a generic Alpine image, or a different script signature and accidentally removed the real uploader flow.
Re-check whether the repository or the user already specified a release image, `oss-deploy`, `OSS_DEPLOY_NAME`, or a fixed `ci/release-dist.sh` call shape.
When those exist, they are not optional hints. Restore them and align every `release_x` job to the same contract.
### UI shows jobs the user no longer wants
Remove the matching `build_x` and `release_x` jobs together.
Also remove outdated references in usage docs and sample paths.
## Anti-patterns
Do not do these unless the user explicitly wants them:
- Do not replace the standard `build_x + release_x` OSS flow with server-directory deployment.
- Do not replace an existing or user-specified OSS release template such as `springjk/ci-helper:latest` plus `sh ci/release-dist.sh "$BUILD_TARGET" "$OSS_DEPLOY_NAME"` with a generic image, `artifacts`, or another release contract.
- Do not use custom repository-specific Node images when an official `node:X-alpine` image can be selected from project evidence.
- Do not treat copied “项目级说明” sections as proven facts without checking the repository.
- Do not use `npm ci` as the default npm install command.
- Do not leave only `build_x` without `release_x` when the default OSS release pattern is expected.
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论