Skip to content

feat(providers): add CNB (cnb.cool) git provider#208

Open
Eyre921 wants to merge 1 commit into
Tencent:mainfrom
Eyre921:feat/cnb-provider
Open

feat(providers): add CNB (cnb.cool) git provider#208
Eyre921 wants to merge 1 commit into
Tencent:mainfrom
Eyre921:feat/cnb-provider

Conversation

@Eyre921

@Eyre921 Eyre921 commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a third GitProviderCNB (cnb.cool) — alongside github and tgit, using the exact "thin class over a platform CLI" shape the TGit provider established. CNB's official CLI (@cnbcool/cnb-cli) already exposes everything the GitProvider interface needs, so this is mostly mechanical mirroring of the existing pattern.

A question for maintainers, up front: a provider is a permanent maintenance surface (every future interface change now lands in three providers). I'm opening this as a complete, live-tested implementation so the accept/decline decision is concrete rather than hypothetical — but if you'd rather not carry a CNB provider, feel free to close and I'll keep it in my fork. CNB is a Tencent-adjacent platform, so it may or may not be in scope for you.

Type of Change

  • New feature (non-breaking change that adds functionality)

How each interface method maps to the CNB CLI

GitProvider CNB CLI
authenticate / isAuthenticated cnb login (OAuth2 device flow) + cnb status
cloneRepo git clone with token, or cnb git-credential helper
createPullRequest cnb pulls post-pull
createRepo cnb repositories create-repo
username cnb users get-user-info (or CNB_USERNAME)

Auth mirrors the GitHub provider's dual path: interactive cnb login on a dev machine, or a CNB_TOKEN env var for headless/CI use (no login step) — the same idea as GITHUB_TOKEN.

Wiring: registry.ts maps cnb.cool / cnb.woa.com hosts to the provider and registers it in the factory. No behavior changes for existing providers.

Test Plan

  • npx tsc --noEmit, npm run build
  • npx vitest run — 142 files, 1751 tests; 6 new in cnb-provider.test.ts (host detection, factory, repo-input parsing incl. nested group paths)
  • Live end-to-end against real cnb.cool (token in env), driving the wrapper functions: createRepo → cloneRepo → push main + feature → createPullRequest → delete-repo cleanup. The PR URL came back https://cnb.cool/<owner>/<repo>/-/pulls/1.

Two bugs the live run surfaced (and this PR fixes) — build alone didn't catch them:

  • cnbWhoami() returned the CNB_USERNAME credential placeholder ("cnb") instead of the real account; now parses username: from the API first.
  • the CLI prints YAML, not JSON, so username / PR-URL parsing is regex-based rather than JSON.parse.

Notes for Reviewers

  • The live E2E is intentionally not committed as a CI test: it needs a CNB_TOKEN secret and creates/deletes a real repo. Only the pure unit tests run in CI. Happy to add a gated e2e test (behind CNB_TOKEN, self-cleaning) if you want one in the suite.
  • No new runtime dependency — the provider shells out to the cnb CLI, exactly as tgit shells out to gf. ensureInstalled() installs it via npm i -g @cnbcool/cnb-cli when missing.
  • getDefaultProvider() is untouched: CNB is only selected by explicit cnb.cool host, never as a fallback.

Adds a third GitProvider alongside github and tgit, following the same
"thin class over a platform CLI" shape as the TGit provider. CNB's official CLI
(`@cnbcool/cnb-cli`) exposes everything the GitProvider interface needs:

- `cnb login` (OAuth2 device flow) + `cnb status`  → authenticate / isAuthenticated
- git clone with token / `cnb git-credential`       → cloneRepo
- `cnb pulls post-pull`                             → createPullRequest
- `cnb repositories create-repo`                    → createRepo
- `cnb users get-user-info`                         → username

Auth mirrors the GitHub provider's dual path: interactive `cnb login`, or a
`CNB_TOKEN` env var for headless/CI use — the same pattern as GITHUB_TOKEN.

registry.ts maps `cnb.cool` / `cnb.woa.com` to this provider and registers it.

Three robustness issues surfaced by live testing against real cnb.cool and fixed
here (none were caught by a build-only check):
- cnbWhoami() returned the CNB_USERNAME credential placeholder ("cnb") instead
  of the real account; now parses the API's `username:` first.
- the CLI prints YAML, not JSON, so username / PR-URL parsing is regex-based.
- the CLI exits 0 even on a 4xx API response, so a non-zero exit code is not
  enough to detect failure; `assertCnbApiOk()` now also checks the printed
  `status:` and throws on >= 400 (with the API's errmsg).

Test Plan:
- npx tsc --noEmit ; npm run build
- npx vitest run — 142 files, 1754 tests; 9 new in cnb-provider.test.ts (host
  detection, factory, repo-input parsing incl. nested groups, assertCnbApiOk).
- Opt-in live smoke in src/__tests__/e2e/cnb-provider-live.test.ts (skipped
  without CNB_TOKEN): asserts isAuthenticated() + a real account username.
  Read-only by design — some CNB namespaces block Open-API resource deletion, so
  a create/delete test would orphan repos.
- The full mutating flow (createRepo → cloneRepo → push → createPullRequest) was
  verified manually against real cnb.cool; PR URL came back
  https://cnb.cool/<owner>/<repo>/-/pulls/1.

Claude-Session: https://claude.ai/code/session_01GEV81Xj6mhPzSPsyBrDPSd
@Eyre921
Eyre921 force-pushed the feat/cnb-provider branch from d65f445 to 1273c83 Compare July 18, 2026 10:47
@jeff-r2026

Copy link
Copy Markdown
Collaborator

Thanks for the thorough implementation and the live-tested E2E — the spawnSync-with-args design, the assertCnbApiOk guard for the "CLI exits 0 but API returned 4xx" case, and the cnbWhoami API-first parsing are all solid.

One blocker before this can merge, per our docs-sync convention (see CLAUDE.md): adding a user-selectable provider is an observable behavior change, so the docs need to be updated in the same PR. Right now the PR touches no documentation. Please update:

  • docs/providers.md — add a cnb row to the platform table (host cnb.cool / cnb.woa.com, auth via cnb login or CNB_TOKEN), and add the detection rules (https://cnb.cool/o/r → cnb, git@cnb.cool:o/r.git → cnb).
  • docs/usage-guide.md — the provider: field in the teamai.yaml section currently only documents github/tgit; please mention cnb as a valid value.
  • Keep the bilingual pair in sync: mirror the same changes into docs/usage-guide.zh-CN.md (and any zh-CN counterpart of providers.md if one exists).

While updating the guide, please also call out the current capability gap: fetchMergeRequest and listOrgRepos are not implemented for CNB, so a CNB repo can be cloned / created / opened-as-PR but can't yet drive teamai ci extract-mr or org-repo listing. Documenting this avoids users assuming CNB is at full parity with tgit.

The accept/decline call on carrying a third provider is for the maintainers, but getting the docs in now makes it a complete, mergeable PR either way. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants