Repository navigation
feat(codeup): add a Codeup (codeup.aliyun.com) git provider - #1857
killingwolf wants to merge 6 commits into
Conversation
Adds a provider for Aliyun Yunxiao (云效) Codeup so `teamai push` opens merge requests automatically instead of falling back to the generic git transport, which only pushes the branch. - src/providers/codeup/: REST client for the Yunxiao OpenAPI (openapi-rdc.aliyuncs.com, x-yunxiao-token PAT auth). MRs are created as changeRequests with sourceBranch/targetBranch/sourceProjectId/ targetProjectId; the numeric repo id is resolved from the full org/group/repo path, the organizationId from CODEUP_ORG_ID or the user's lastOrganization. whoami is /oapi/v1/platform/user. - Token resolution: CODEUP_TOKEN > YUNXIAO_TOKEN > ~/.netrc, with an interactive paste-on-first-init flow that persists to ~/.netrc (0600). - Git transport stays SSH (git@codeup.aliyun.com:...), like the generic provider; HTTPS Basic is used when a netrc username+token pair exists. - Multi-level repo paths (org/group/repo) are kept whole; browser web-route suffixes (/changeRequest/list, /tree/main, ...) are stripped. - findOpen/history lookup for workflow delivery, Region-edition support via CODEUP_API_BASE_URL / YUNXIAO_EDITION, doctor check, and docs. - Request/response shapes verified against the official alibabacloud-devops-mcp-server implementation. Reviewers from teamai.yaml are not assigned: the OpenAPI wants numeric reviewerUserIds, which teamai does not resolve. Co-Authored-By: Claude Code <noreply@anthropic.com>
authenticate() depended on GET /oapi/v1/platform/user returning a username, but a PAT created with only codeup scope gets 403 there (verified live) — every `teamai init` with such a token exited at the auth gate. Now the token is validated with a codeup-scoped probe (the org repository list) and the username comes from CODEUP_USERNAME or ~/.teamai/codeup.json; interactive init asks for the missing organizationId and username, validates both, and persists them. cloneUrl() also stopped switching to HTTPS Basic (PAT as the git password — an unverified path) as soon as a netrc username+token pair existed: SSH stays the default, and CODEUP_TRANSPORT=https opts in explicitly. Verified end-to-end against a live codeup-scope-only PAT: init auth, clone, pull, and all three error paths (missing token, rejected token, missing org id) answer with actionable guidance. Co-Authored-By: Claude Code <noreply@anthropic.com>
Reviewed only the specified diff; nothing from the PR was run, built, or installed. |
I ran the built CLI in verify worlds at 2a9a8c3 against a local stub of the Yunxiao OpenAPI. Live Codeup wasn't available. [P1 blocking]
[P2 non-blocking]
[P3 nit]
CI review. We agree with seven of its eight findings. Its "short inputs" path case didn't reproduce, because of the Merge risk. High until the SSH clone is fixed: it breaks @jeff-r2026 your call on this one. It's a new provider, with its own API key storage and a change to how codeup URLs are cloned. |
…, netrc and MR lookups Co-Authored-By: Claude Code <noreply@anthropic.com>
… the generated reference Co-Authored-By: Claude Code <noreply@anthropic.com>
|
Findings
Resolved Earlier Findings Reviewed only the specified diff; nothing from the PR was run, built, or installed. |
|
Pushed f693074 (upstream/main merged in, no force-push) addressing the triage review: P1 blocking
P2 non-blocking
P3 nit
CI on the previous head failed on the oxlint type-aware errors in the new files and on |
…auth username from ~/.netrc too Co-Authored-By: Claude Code <noreply@anthropic.com>
|
f3180b3 addresses the second review pass:
codeup suite is at 50 cases; typecheck, |
|
Findings
Resolved Earlier Findings Testing Reviewed only the specified diff; nothing from the PR was run, built, or installed. |
Re-checked at f693074, then at f3180b3. Fixed since our last comment
Three things are still worth fixing or settling before merge. [P2 non-blocking]
[P3 nit]
CI review. Its P1, the missing real-CLI record, read the body from before your edit 20 seconds later. The record is there now. Two of its P2s are fixed at f3180b3; the third is the browser URL above. The other CI workflows are waiting for approval to run on this fork. Merge risk. Medium, mainly because of the API key in @jeff-r2026 your call on this one. |
What
Adds a Codeup (Aliyun Yunxiao code management, codeup.aliyun.com) git provider so
teamai pushopens merge requests automatically instead of falling back to the generic git transport, which only pushes the branch.Why
Codeup is a mainstream Aliyun code hosting platform. With the generic
gitprovider, a contributor'steamai/push/*branch lands on the host, but the merge request has to be opened by hand on the web. This provider closes that gap the same way the GitLab and GitCode providers do for their hosts.How
https://openapi-rdc.aliyuncs.com,x-yunxiao-tokenPAT auth). Codeup calls merge requests changeRequests: created withPOST …/repositories/{id}/changeRequestsandsourceBranch/targetBranch/sourceProjectId/targetProjectId; the numeric repository id is resolved from the fullorg/group/repopath, the organizationId fromCODEUP_ORG_IDor the authenticated user'slastOrganization. Request/response shapes follow the official alibabacloud-devops-mcp-server reference implementation.CODEUP_TOKEN>YUNXIAO_TOKEN>~/.netrc, with an interactive paste-on-first-init flow that persists to~/.netrc(0600) plus~/.teamai/codeup.json(organizationId / username). The netrc read/write handles one-line and multiline machine entries.authenticate()handles a PAT with only codeup scope: the platform user endpoint answers 403 for such tokens (verified live), so the token is validated with an org-scoped repository-list probe and the username comes fromCODEUP_USERNAME/ the config file. A missing organizationId is asked and persisted interactively; a Region-edition deployment needs none, and an unreachable API is reported as unreachable rather than as a rejected token.https://URL clones over HTTPS — with the PAT as the Basic password when its username is known too (CODEUP_USERNAME/~/.teamai/codeup.json/~/.netrc), otherwise through the member's own git credential setup; an SSH URL or the bareorg/group/repoform clones over SSH.CODEUP_TRANSPORT=https|sshoverrides.org/group/repo) are kept whole —ownerholds the first path segment andrepothe rest, so${owner}/${repo}reproduces the full path. Web-route suffixes (/change/1,/tree/main, …) are stripped only in browser URLs and only when a sub-path follows the route segment, so a nested group named like a route (org/team/files/repo) survives. A URL on an explicit foreign host is rejected.CODEUP_API_BASE_URL/YUNXIAO_EDITION, a doctor check, docs, and 48 unit tests.Verification
src/__tests__/codeup-provider.test.ts), plus an opt-in live e2e test (src/__tests__/e2e/codeup-provider-live.test.ts, gated onCODEUP_TOKEN+CODEUP_ORG_ID).state(notstatus),createdAt/updatedAt, and the MR web path/change/<id>.20261114T021949-bbcce4—Build f693074f7f73+dirty, teamai 0.22.0, sha256 df4d06266f99(the+dirtyis the untrackednode_modulessymlink of the build worktree, not a source change) — against a local stub of the Yunxiao OpenAPI answering the exact shapes above (codeup-scope-only PAT:/oapi/v1/platform/user→ 403), with the world's gitconfig rewritinghttps://codeup.aliyun.com/team/repo.gitto a seeded bare repo and a trap rewritinggit@codeup.aliyun.com:to a nonexistent path so any SSH attempt fails loudly:teamai init https://codeup.aliyun.com/team/repo.git --agent claude→ exit 0:Authenticated as zhangsan(403 whoami → org repo-list probe 200 →CODEUP_USERNAME),Team repo clonedover HTTPS — the SSH trap never fired (the same input clonedgit@codeup.aliyun.com …at 2a9a8c3, the P1 regression; fixed),teamai.yamlwritten withprovider: codeup, member registered, claude hooks installed.teamai doctor→ exit 0, all checks pass, including the new✔ Codeup token is configured.teamai push --skill .claude/skills/verify-skill --shared --all→ exit 0: pushed branchteamai/push/zhangsan/20261114-103208(over the same HTTPS URL), resolved the numeric repo id (GET …/repositories/team%2Frepo→2813489),POST …/repositories/2813489/changeRequests→✔ Pull Request created: https://codeup.aliyun.com/team/repo/change/1.Ledger: 1 LEAK— the emptyproject/.claude/skillsdirectory afterteamai uninstall; generic init creates it for every provider (this provider installs no directory or hook of its own) and it is the same family as the known leftover issue teamai uninstall leaves files and directories that init and pull created #1808 listed next to it. No codeup-specific residue:~/.netrcuntouched (token came via env) and~/.teamai/codeup.jsonabsent (the headless path persists nothing).🤖 Generated with Claude Code