/** * @file OpenAPI fragment for the git bar's Branches panel (server/lib/git-refs.js): * the `GET /api/lanes/{id}/git/refs` read, plus `extend()`, which adds the * branch & tag writes to the existing `POST /api/lanes/{id}/git/{action}` * entry in place (its enum and description) rather than replacing that entry. * @author Nguyễn Ngọc Trí Vĩ */ const { REF_ACTIONS } = require("../lib/git-refs"); const REF_ACTIONS_DOC = " Branch & tag tools (server/lib/git-refs.js; every ref named in the body is LOOKED UP in refs/heads, refs/remotes or refs/tags — or a hex sha verified as a commit — and git gets the full refname, never the request's text; every write here except branch-create runs only from a repo-root lane (400 ESUBDIR) and never while a merge, cherry-pick, revert or rebase is open (409 EMERGING)): branch-create also takes {from} (a local/remote branch, a tag, or a commit sha; 400 EBADREF, 400 EAMBIGUOUS when a branch and a tag share the name — spell out refs/tags/x) and {switch:true} (clean tree only, 400 EDIRTY); branch-rename {branch, name} (`git branch -m`; refuses main/master/development/develop 400 EPROTECTED, an existing name 400 EBRANCHEXISTS, a name `check-ref-format --branch` rejects 400 EBADBRANCH); branch-upstream {branch, upstream} sets it to a fetched remote branch (`origin/x`, 400 ENOBRANCH otherwise) and {branch} with no upstream unsets it (400 ENOUPSTREAM when none); tag-create {tag, message?, from?} (annotated when a message is given; on HEAD or a looked-up start point; 400 EBADTAG / ETAGEXISTS / ENOCOMMITS); tag-delete {tag, confirm:true} (irreversible: 400 ECONFIRM without it, 400 ENOTAG); tag-push {tag, credentials?} pushes ONE tag `refs/tags/:refs/tags/` to origin (else the only remote, 400 ENOREMOTE) — no --tags, no force, so a remote tag at another commit is a 409 in git's words."; const paths = { "/api/lanes/{id}/git/refs": { get: { tags: ["Lanes"], summary: "Every branch and tag of the lane's repo, for the Branches panel", description: "`local`: each local branch with its upstream, ahead/behind against it (null without one, `gone` when the upstream ref is gone), last commit subject and date, `merged` (into HEAD — what `branch -d` checks), `worktree` (another worktree holding it), `protected` and `current`. `remotes`: the fetched remote-tracking branches grouped by remote (symbolic HEADs left out). `tags`: name, target commit `sha`, and for an annotated tag its `message`, `tagger` and `date`. At most 1000 of each kind (`truncated`). The repo comes from the lane row (or `?session` / `?source` / `?repo`), never a path from the query; a folder that is not a repo answers available:false with HTTP 200. Read-only, no same-origin guard.", operationId: "listLaneGitRefs", parameters: [ { name: "id", in: "path", required: true, schema: { type: "integer" } }, { name: "session", in: "query", required: false, schema: { type: "string" } }, { name: "source", in: "query", required: false, schema: { type: "integer" } }, { name: "repo", in: "query", required: false, schema: { type: "string" } }, ], responses: { 200: { description: "{available, current, head, local[], remotes[{remote, branches[]}], tags[], truncated}.", }, 404: { description: "Lane not found, ENOSOURCE, ENOREPO or ENOWORKTREE." }, }, }, }, }; /** Add the branch & tag writes to the combined spec's git action entry. */ function extend(out) { const post = out.paths["/api/lanes/{id}/git/{action}"]?.post; if (!post) return out; const action = (post.parameters || []).find((p) => p.name === "action"); const list = action?.schema?.enum; if (Array.isArray(list)) for (const a of REF_ACTIONS) if (!list.includes(a)) list.push(a); if (!post.description.includes("git-refs.js")) post.description += REF_ACTIONS_DOC; return out; } module.exports = { tags: [], schemas: {}, paths, extend };