Files
teamai-cli/.coding-ci.yaml
T
Saul Moro f7da1bb8b6 ci(lint): add oxlint and fail CI on any warning (#828) (#839)
* fix(tags,roles): honor --dry-run in tags subscribe, tags unsubscribe and roles set (#836)

The three commands saved the local config and reset lastPullRev even
under the global --dry-run, which is documented as "Preview mode, no
changes made". Their siblings (tags add/remove, roles init/add/remove/
update) already return early with a [dry-run] message.

The roles set preview names the additional roles it would save,
including none, because a real run replaces the existing list.

oxlint reported the unused options parameter in tagsSubscribe and
tagsUnsubscribe; rolesSet has the same bug but reads options.add.

* chore(lint): add oxlint with its default rules

Pinned to an exact version so a new default rule arrives in its own PR,
not as a CI failure on an unrelated one. The no-unused-vars options
keep oxlint's _ ignore patterns and add ignoreRestSiblings, which the
rest-omit in dashboard.ts relies on to keep config and roots out of
/api/workspaces.

* style(lint): apply oxlint safe fixes

Drop redundant escapes in regex character classes and template literals,
empty-object fallbacks in object spreads (spreading undefined adds
nothing), and anchored regexes that are plain startsWith/endsWith
checks. No behavior change.

* refactor(lint): remove unused imports and an unused catch binding

Applied with oxlint --fix-suggestions and reviewed by hand. Every
removed whole import is a library module with no import-time side
effects.

* refactor(lint): remove dead code reported by no-unused-vars

Each hit was checked against its callers and git history; none is
missing wiring (the two that were, tags subscribe/unsubscribe, are fixed
in the preceding commit). Removed: unused locals and functions, the
options parameter of tagsList, rolesList and generateDigest (read-only
commands), the never-read interactive option of importFromRepo, the
empty test/e2e.mjs left over from the E2E migration, and a try/catch
that only rethrew. new Array(n) becomes Array.from. No behavior change.

* test(lint): fix lint hits in tests

- contribute dry-run test asserted nothing; it now checks that the run
  leaves the repo/HOME tree unchanged (verified to fail when the dry-run
  early return is removed).
- Drop a no-op expect(result).not.toThrow on a string.
- Keep undefined in two optional-chain casts so a regression fails the
  assertion instead of throwing a TypeError.
- Remove unused locals, helpers and imports; new Array(n) becomes
  Array.from.

* refactor(lint): write control-character classes as \p{Cc}

no-control-regex flags literal control ranges. \p{Cc} names the same
set (C0, DEL, C1) and reads as what it means. Checked against the old
classes on every code point from U+0000 to U+10FFFF: manifest-schema and
agent-format match exactly, and contribute-check's normalization
pipeline produces the same output. The test assertion is now stricter
and checks every control character the sanitizer removes.

* refactor(lint): remove disable directives for rules that are not enabled

Four eslint-disable comments named rules this repo never ran
(no-await-in-loop, @typescript-eslint/no-explicit-any), so they
suppressed nothing.

* ci(lint): fail CI on any oxlint warning (#828)

npm run lint runs oxlint --deny-warnings and runs before the type check
in both GitHub Actions and Coding CI. The repo is at zero warnings, so
new code must stay clean. --report-unused-disable-directives also fails
on a disable comment that suppresses nothing, so a suppression cannot
outlive the code it was written for. CLAUDE.md, AGENTS.md,
CONTRIBUTING.md and the PR template list the command so contributors
and agents run it before opening a PR.

Closes #828

* chore(lint): pin oxlint 1.16.0, the newest release that accepts Node 20.0

oxlint 1.17.0 and later declare engines.node ^20.19.0 || >=22.12.0,
while the repo supports Node >=20. 1.16.0 declares >=8, supports
--deny-warnings and --report-unused-disable-directives, and reports 0
warnings on this branch.

* Revert "fix(tags,roles): honor --dry-run in tags subscribe, tags unsubscribe and roles set (#836)"

This reverts commit 224d459c99.

* refactor(lint): mark the unused options parameter of tags subscribe and unsubscribe

With the #837 dry-run fix reverted out of this PR, both functions no
longer read options. The underscore prefix keeps the signature and call
sites unchanged, so #837 can rebase onto it by renaming the parameter
back.

* chore(lint): restore oxlint 1.85.0

This reverts commit e2347efa. oxlint is a devDependency, so its Node
requirement (^20.19.0 || >=22.12.0) never reaches users installing
teamai-cli, and CI's node-version 20 resolves to the latest 20.x.
Staying on 1.85.0 keeps the #836 warning counts and the planned
type-aware follow-up on the same version.

* docs(contributing): note the Node version npm run lint needs

* docs(agents): note the Node version npm run lint needs
2026-09-26 19:56:03 +08:00

149 lines
5.2 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.
version: 2
env:
TEAMAI_TEST_TOKEN:
secret: ${TEAMAI_TEST_TOKEN_SECRET}
TEAMAI_TEST_REPO_URL:
secret: ${TEAMAI_TEST_REPO_URL_SECRET}
NPM_USERNAME: ${NPM_USERNAME}
NPM_TOKEN:
secret: ${NPM_TOKEN_SECRET}
stages:
- stage: validate
tasks:
- task: lint-and-test
artifacts:
- coverage/cobertura-coverage.xml
cmds:
- plugin: cmds
params:
cmds:
- node --version && npm --version
- npm ci --ignore-scripts
- echo "=== Lint ==="
- npm run lint
- echo "=== Typecheck ==="
- npx tsc --noEmit
- echo "=== Unit Tests + Coverage ==="
- npx vitest run --coverage
- stage: build
tasks:
- task: build
artifacts:
- dist/
cmds:
- plugin: cmds
params:
cmds:
- echo "=== Build ==="
- npm ci --ignore-scripts
- npm run build
- stage: e2e
tasks:
- task: e2e
cmds:
- plugin: cmds
params:
cmds:
- echo "=== E2E Tests ==="
- npm ci --ignore-scripts
- npm run build
- |
# CI commits (tags add/remove, env add/remove, source roundtrip 等
# 测试会改写 fixture 仓工作树) 需要 git identity,否则 git 会拒绝。
git config --global user.email "ci@teamai.test"
git config --global user.name "TeamAI CI"
- |
# 准备 teamai 远程 e2e 测试 fixture(user-scope ~/.teamai)。
# 没配 secrets 时(如 fork 仓的 PR)跳过,e2e.test.ts 里 skipIf
# 会把 remote 用例自动跳过。
if [ -n "$TEAMAI_TEST_TOKEN" ] && [ -n "$TEAMAI_TEST_REPO_URL" ]; then
echo "Setting up teamai for remote E2E tests..."
mkdir -p ~/.teamai
REPO_LOCAL=~/.teamai/team-repo
if [ ! -d "$REPO_LOCAL" ]; then
case "$TEAMAI_TEST_REPO_URL" in
http://*|https://*) CLONE_URL="$TEAMAI_TEST_REPO_URL";;
*) CLONE_URL="https://git.woa.com/${TEAMAI_TEST_REPO_URL}.git";;
esac
git clone -c "http.extraHeader=PRIVATE-TOKEN: $TEAMAI_TEST_TOKEN" \
"$CLONE_URL" "$REPO_LOCAL" || { echo "Clone failed"; exit 1; }
fi
cat > ~/.teamai/config.yaml <<EOFCFG
repo:
localPath: "$REPO_LOCAL"
remote: "$TEAMAI_TEST_REPO_URL"
username: ci
updatePolicy: auto
EOFCFG
echo "teamai config ready"
fi
- npx vitest run --config vitest.e2e.config.ts --reporter=verbose
- stage: publish
tasks:
- task: publish
cmds:
- plugin: cmds
params:
cmds:
- echo "=== Publish to tnpm (internal mirror) ==="
- "if [ \"$QCI_TRIGGER_TYPE\" != \"TRIGGER_TAG\" ]; then\n echo \"⏭ Not a\
\ tag build (trigger=$QCI_TRIGGER_TYPE), skipping publish\"\n exit 0\n\
fi\n"
# The public package name is `teamai-cli` on npmjs.org.
# For the internal tnpm mirror we publish under the scoped name `@tencent/teamai-cli`.
- "npm pkg set name=@tencent/teamai-cli"
- "PKG_VERSION=$(node -p \"require('./package.json').version\")\nif npm view\
\ \"@tencent/teamai-cli@${PKG_VERSION}\" version --registry http://r.tnpm.oa.com\
\ 2>/dev/null; then\n echo \"ERROR: @tencent/teamai-cli@${PKG_VERSION}\
\ is already published.\"\n exit 1\nfi\n"
- "echo \"//r.tnpm.oa.com/:_auth=$(echo -n \"${NPM_USERNAME}:${NPM_TOKEN}\" | base64)\" > .npmrc"
- npm ci --ignore-scripts
- npm run build
# Resolve the dist-tag from the version: a prerelease (e.g. 0.21.0-beta.0)
# publishes to its own channel (beta/rc/...), never to `latest` — the tag
# the CLI's auto-update check reads for @tencent/teamai-cli (src/update.ts).
- "PKG_VERSION=$(node -p \"require('./package.json').version\")\ncase \"$PKG_VERSION\" in\n *-*)\n PRE=\"${PKG_VERSION#*-}\"\n DIST_TAG=\"${PRE%%.*}\"\n case \"$DIST_TAG\" in\n ''|*[!a-zA-Z]*) DIST_TAG=\"beta\" ;;\n esac\n ;;\n *)\n DIST_TAG=\"latest\"\n ;;\nesac\necho \"Publishing $PKG_VERSION with dist-tag: $DIST_TAG\"\nnpm publish --registry http://r.tnpm.oa.com --tag \"$DIST_TAG\"\n"
- rm -f .npmrc
trigger:
branches:
include:
- main
tags:
include:
- /^v\d+\.\d+\.\d+/
mr:
branches:
include:
- main
is_block_mr: 0
finally:
failure:
cmds:
- plugin: cmds
params:
cmds:
- echo "CI pipeline 失败!"
- |
# e2e fixture 仓清理:失败可能在 fixture 仓工作树留下 dirty state,
# 下次跑会卡住。守卫 [ -d ... ] 兜底其他 stage 失败时仓库不存在的情况。
REPO_LOCAL=~/.teamai/team-repo
if [ -d "$REPO_LOCAL/.git" ]; then
echo "Cleaning up e2e fixture repo state..."
cd "$REPO_LOCAL"
git reset --hard HEAD || true
git clean -fdx || true
fi
notifications:
- name: TeamAI CLI CI 通知
channel: ENWECHAT
group: QCI_JOB_ADMIN
on_success: change
on_failure: always
maximum_builds: 1
is_no_revert: 0
is_auto_cancel: 1
worker:
label: JOB_MATRIX_DEVCLOUD
tools: []
language: node_js-22.19.0