diff --git a/README.md b/README.md index 0c59c99..682d6f7 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Go Version](https://img.shields.io/badge/Go-1.26%2B-blue.svg)](https://golang.org) [![npm version](https://img.shields.io/npm/v/@gitlink-ai/cli.svg)](https://www.npmjs.com/package/@gitlink-ai/cli) -The official [GitLink](https://www.gitlink.org.cn) CLI tool — built for humans and AI Agents. Supports **macOS, Linux, and Windows**. Covers repository management, issue tracking, pull requests, webhooks, member collaboration, CI/CD, and AI-powered workflows, with 40+ commands and AI Agent [Skills](./skills/). +The official [GitLink](https://www.gitlink.org.cn) CLI tool — built for humans and AI Agents. Supports **macOS, Linux, and Windows**. Covers repository management, issue tracking, pull requests, webhooks, member collaboration, CI/CD, and AI-powered workflows, with 40+ commands and AI Agent [Skills](./skills/README.md). **[中文文档](./README.zh-CN.md)** @@ -78,11 +78,19 @@ The official [GitLink](https://www.gitlink.org.cn) CLI tool — built for humans jiangtx
jiangtx +
+ luwanzhou +
luwanzhou +
+
+ whale_hihihi +
whale_hihihi +
## Why gitlink-cli? -- **Agent-Native Design** — Structured [Skills](./skills/) out of the box, compatible with Claude Code, OpenClaw, and other AI platforms — Agents can operate GitLink with zero extra setup +- **Agent-Native Design** — Structured [Skills](./skills/README.md) out of the box, compatible with Claude Code, OpenClaw, and other AI platforms — Agents can operate GitLink with zero extra setup - **Wide Coverage** — Repository, Issue, PR, Webhook, Member, Branch, Release, CI, Pipeline, Org, Search, and User workflows are covered by high-level commands - **AI-Friendly & Optimized** — Every command is tested with real Agents, featuring concise parameters, smart defaults, and structured output - **Cross-Platform** — Runs on macOS, Linux, and Windows (x64/arm64), install via `npm install -g @gitlink-ai/cli` in one command, binary auto-downloaded @@ -96,7 +104,7 @@ The official [GitLink](https://www.gitlink.org.cn) CLI tool — built for humans | Category | Capabilities | |----------|-------------| | 📦 Repo | List, create, fork, delete repositories, view repo info, insights, and interactions | -| 🐛 Issue | Create, update, close, batch close, comment on issues | +| 🐛 Issue | Create, update, close, batch close/update/delete, comment on issues | | 🔖 Label | Create, list, update, delete issue labels | | 🔀 PR | Create, merge, review pull requests, view changed files | | 👥 Member | List, add, remove repository members, change roles, create and accept invite links | @@ -106,8 +114,11 @@ The official [GitLink](https://www.gitlink.org.cn) CLI tool — built for humans | 🔧 CI | View builds, logs, CI/CD operations | | ⚙️ Pipeline | Run, inspect, enable, disable, delete pipeline workflows and logs | | 🔔 Webhook | Manage repo webhooks and test deliveries | +| 📖 Wiki | List, view, create, update, and delete wiki pages | | 🔍 Search | Search repositories, users | +| 📊 Dataset | Query research datasets by project | | 👤 User | View user profiles and info | +| 📊 Profile | User ability, role, major, activity, and contribution statistics | | 📋 PM | Sprint management, kanban boards, weekly reports | | 🤖 Workflow | AI-powered issue triage, PR review, release notes | @@ -216,11 +227,6 @@ gitlink-cli repo +readme --owner Gitlink --repo forgeplus --ref master gitlink-cli repo +tree --owner Gitlink --repo forgeplus --ref master gitlink-cli repo +tree --owner Gitlink --repo forgeplus --path src --ref main -# Read raw files and common dependency manifests -gitlink-cli repo +raw --owner Gitlink --repo forgeplus --path LICENSE --ref master -gitlink-cli repo +file-exists --owner Gitlink --repo forgeplus --path package.json --ref master -gitlink-cli repo +manifest --owner Gitlink --repo forgeplus --kind go --ref master - # Show language breakdown gitlink-cli repo +languages --owner Gitlink --repo forgeplus @@ -268,6 +274,28 @@ gitlink-cli webhook +test --owner Gitlink --repo forgeplus --id 68 gitlink-cli webhook +tasks --owner Gitlink --repo forgeplus --id 68 ``` +### Wiki Management + +```bash +# List wiki pages (table of contents) +gitlink-cli wiki +list --owner Gitlink --repo forgeplus --project-id 12345 + +# View a wiki page by page name +gitlink-cli wiki +view --owner Gitlink --repo forgeplus --project-id 12345 -n home + +# Create a wiki page +gitlink-cli wiki +create --owner Gitlink --repo forgeplus --project-id 12345 \ + -n getting-started -t "Getting Started" -c "# Getting Started Guide" + +# Update a wiki page title and/or content +gitlink-cli wiki +update --owner Gitlink --repo forgeplus --project-id 12345 -n home -t "New Title" +gitlink-cli wiki +update --owner Gitlink --repo forgeplus --project-id 12345 -n home -c "# Updated content" +gitlink-cli wiki +update --owner Gitlink --repo forgeplus --project-id 12345 -n home -t "New Title" -c "New content" + +# Delete a wiki page +gitlink-cli wiki +delete --owner Gitlink --repo forgeplus --project-id 12345 -n old-page +``` + ### Member Management ```bash @@ -290,31 +318,6 @@ gitlink-cli member +role --owner Gitlink --repo forgeplus --user-id 101 --role D gitlink-cli member +invite-link --owner Gitlink --repo forgeplus --role developer --apply true ``` -### Organization Operations - -```bash -# List organizations -gitlink-cli org +list --page 1 --limit 20 - -# Show organization details -gitlink-cli org +info --id Gitlink - -# List organization members with team or keyword filters -gitlink-cli org +members --id Gitlink --team Platform --format json -gitlink-cli org +members --id Gitlink --keyword alice --limit 50 --format json - -# List organization teams with normalized user details -gitlink-cli org +teams --id Gitlink --authorize write --include-users --format json - -# Preview and create an organization team -gitlink-cli org +team-create --id Gitlink --name platform --nickname "Platform Team" --dry-run -gitlink-cli org +team-create --id Gitlink --name platform --nickname "Platform Team" - -# Preview and remove an organization member -gitlink-cli org +member-remove --id Gitlink --login alice --dry-run -gitlink-cli org +member-remove --id Gitlink --user-id 101 -``` - ### Issue Management ```bash @@ -324,59 +327,34 @@ gitlink-cli issue +list --owner Gitlink --repo forgeplus # Create an issue gitlink-cli issue +create --owner Gitlink --repo forgeplus -t "Bug: Login failed" -b "Steps to reproduce..." -# Create an issue from a Markdown file -gitlink-cli issue +create --owner Gitlink --repo forgeplus -t "Bug: Login failed" --body-file issue.md - # Create an issue with metadata gitlink-cli issue +create --owner Gitlink --repo forgeplus -t "Bug: Login failed" --priority-id 3 --tag-ids 4,5 --assigner-ids 7 # View an issue -gitlink-cli issue +view --owner Gitlink --repo forgeplus --number 123 +gitlink-cli issue +view --owner Gitlink --repo forgeplus -i 123 # Update issue metadata gitlink-cli issue +update --owner Gitlink --repo forgeplus --number 123 --priority-id 4 --branch bugfix/login --due-date 2026-06-15 -# Update issue description from a file -gitlink-cli issue +update --owner Gitlink --repo forgeplus --number 123 --body-file update.md - # Close an issue -gitlink-cli issue +close --owner Gitlink --repo forgeplus --number 123 +gitlink-cli issue +close --owner Gitlink --repo forgeplus -i 123 # Preview batch close without changing data gitlink-cli issue +batch-close --owner Gitlink --repo forgeplus --numbers 123,124 --dry-run -# Preview a shared batch update -gitlink-cli issue +batch-update --owner Gitlink --repo forgeplus --numbers 123,124 --state closed --priority-id 4 --dry-run - -# Batch update issues from a CSV file -gitlink-cli issue +batch-update --owner Gitlink --repo forgeplus --from issues.csv --assigner-ids 7 --due-date 2026-06-15 - # Batch close issues from a CSV file gitlink-cli issue +batch-close --owner Gitlink --repo forgeplus --from issues.csv +# Preview batch metadata update by API issue IDs +# Note: --ids uses API issue IDs, not web URL issue numbers. +gitlink-cli issue +batch-update --owner Gitlink --repo forgeplus --ids 101,102 --status-id 3 --priority-id 2 --dry-run + +# Destructive batch delete requires both dry-run first and --yes for real execution +gitlink-cli issue +batch-delete --owner Gitlink --repo forgeplus --ids 101,102 --dry-run +gitlink-cli issue +batch-delete --owner Gitlink --repo forgeplus --ids 101,102 --yes + # Add a comment -gitlink-cli issue +comment --owner Gitlink --repo forgeplus --number 123 -b "Fixed" - -# List, update, delete, and inspect issue comments/journals -gitlink-cli issue +comments --owner Gitlink --repo forgeplus --number 123 --category comment -gitlink-cli issue +comment-update --owner Gitlink --repo forgeplus --number 123 --comment-id 58 -b "Updated comment" --dry-run -gitlink-cli issue +comment-delete --owner Gitlink --repo forgeplus --number 123 --comment-id 58 --dry-run -gitlink-cli issue +comment-children --owner Gitlink --repo forgeplus --number 123 --comment-id 58 - -# Add a comment from a file -gitlink-cli issue +comment --owner Gitlink --repo forgeplus -i 123 --body-file comment.md - -# Batch comment on issues -gitlink-cli issue +batch-comment --owner Gitlink --repo forgeplus --numbers 123,124 --body-file comment.md --dry-run - -# Reply to a comment and list a comment's replies -gitlink-cli issue +comment --owner Gitlink --repo forgeplus -i 123 -b "Agreed" --reply-to 456 -gitlink-cli issue +comment-replies --owner Gitlink --repo forgeplus -n 123 -c 456 - -# List, edit, and delete issue comments -gitlink-cli issue +comments --owner Gitlink --repo forgeplus -n 123 --category comment -gitlink-cli issue +comment-edit --owner Gitlink --repo forgeplus -n 123 -c 456 -b "Updated" -gitlink-cli issue +comment-delete --owner Gitlink --repo forgeplus -n 123 -c 456 +gitlink-cli issue +comment --owner Gitlink --repo forgeplus -i 123 -b "Fixed" # List issue assigners gitlink-cli issue +assigners --owner Gitlink --repo forgeplus @@ -454,12 +432,6 @@ gitlink-cli pr +reviews --owner Gitlink --repo forgeplus -i 42 # Create a PR review (with dry-run preview) gitlink-cli pr +review --owner Gitlink --repo forgeplus -i 42 --status approved -c "LGTM" --dry-run gitlink-cli pr +review --owner Gitlink --repo forgeplus -i 42 --status approved -c "LGTM" - -# List and manage PR review comments -gitlink-cli pr +review-comments --owner Gitlink --repo forgeplus -i 42 --state opened -gitlink-cli pr +review-comment --owner Gitlink --repo forgeplus -i 42 --review-id 10 --commit abc123 --line-code abc123_0_10 --path README.md --note "Please fix" --dry-run -gitlink-cli pr +review-comment-update --owner Gitlink --repo forgeplus -i 42 --comment-id 200 --state resolved --dry-run -gitlink-cli pr +review-comment-delete --owner Gitlink --repo forgeplus -i 42 --comment-id 200 --dry-run ``` ### Branch Management @@ -536,6 +508,36 @@ gitlink-cli pipeline +disable --owner Gitlink --repo forgeplus --id 7 --workflow gitlink-cli pipeline +delete --owner Gitlink --repo forgeplus --id 7 --dry-run ``` +### Project Management + +`pm` surfaces GitLink project-management data for dashboards, sprints, weekly +issues, labels, pipelines, and action runs. PM commands require the numeric +GitLink project ID. + +```bash +# Query PM dashboards and sprint issues +gitlink-cli pm +dashboards --project-id 123 --limit 20 +gitlink-cli pm +sprint-issues --project-id 123 --page 1 --limit 20 + +# Query weekly issues and PM issue tags +gitlink-cli pm +weekly-issues --project-id 123 +gitlink-cli pm +issue-tags --project-id 123 + +# Query PM pipelines and action runs +gitlink-cli pm +pipelines --project-id 123 +gitlink-cli pm +action-runs --project-id 123 +``` + +### Ignore File Templates + +```bash +# List all available .gitignore templates +gitlink-cli ignore +list + +# Filter templates by name +gitlink-cli ignore +list --name Go +``` + ### Search ```bash @@ -546,6 +548,29 @@ gitlink-cli search +repos -k "machine learning" gitlink-cli search +users -k "zhangsan" ``` +### User Profile + +`profile` surfaces GitLink's native user statistics (ability, role, major, activity, +contribution). When `--user` is omitted it defaults to the authenticated user. + +```bash +# Development ability scores + language breakdown +gitlink-cli profile +ability --user zhangsan + +# Role positioning / major (discipline) categories +gitlink-cli profile +role --user zhangsan +gitlink-cli profile +major --user zhangsan + +# Ability within a time window (Unix timestamps) +gitlink-cli profile +ability --user zhangsan --start-time 1704067200 --end-time 1735689600 + +# Recent activity (issues / PRs / commits per day) for the current user +gitlink-cli profile +activity + +# Contribution heatmap for a given year +gitlink-cli profile +contribution --user zhangsan --year 2025 +``` + ### Workflow Agent Commands `workflow` provides rule-based repository analysis for maintainers and AI Agents. It currently supports: @@ -645,6 +670,32 @@ Safety: - `workflow +pr-summary` does not comment, approve, reject, or merge pull requests. - `workflow +repo-report` aggregates health, issue triage, and PR review summary signals without remote writes. +### Dataset + +`dataset` manages and queries GitLink research datasets (title, description, +paper content, license, owning project). + +```bash +# List datasets for one or more projects (by numeric project ID) +gitlink-cli dataset +list --ids 5988 + +# View a repository's dataset and attachments +gitlink-cli dataset +view --owner Gitlink --repo forgeplus + +# Create / update a repository's dataset (preview first with --dry-run) +gitlink-cli dataset +create --owner me --repo proj -t "My dataset" -d "..." --license-id 359 --dry-run +gitlink-cli dataset +update --owner me --repo proj -t "My dataset" -d "updated" + +# Delete a dataset attachment (destructive: preview, then confirm with --yes) +gitlink-cli dataset +delete-attachment --owner me --repo proj --uuid --dry-run +gitlink-cli dataset +delete-attachment --owner me --repo proj --uuid --yes +``` + +> Note: `dataset +list` (platform dataset query) is verified on production +> gitlink.org.cn. The per-repo `+view`/`+create`/`+update` routes follow the +> published OpenAPI contract but are not yet deployed on production (they return +> 404 there); they will work once the platform enables them. + ### Raw API For endpoints not covered by shortcuts, use the Raw API directly: @@ -701,13 +752,13 @@ git push gitlink The `skills/` directory contains Agent Skill files for AI-automated GitLink operations. -See [skills/README.md](skills/README.md) for details. +See [skills/README.md](./skills/README.md) for details. | Skill | Description | |-------|-------------| | `gitlink-shared` | Authentication, global parameters, safety rules, API notes | | `gitlink-repo` | Repository operations (create, view, delete, fork, insights, etc.) | -| `gitlink-issue` | Issue operations (create, update, close, comment, etc.) | +| `gitlink-issue` | Issue operations (create, update, close, batch update/delete, comment, etc.) | | `gitlink-pr` | Pull request operations (create, merge, review, etc.) | | `gitlink-member` | Repository member and invite link management | | `gitlink-branch` | Branch management (create, delete, list, protect, unprotect) | @@ -748,6 +799,7 @@ gitlink-cli/ │ ├── org/ # Organization shortcuts │ ├── ci/ # CI shortcuts │ ├── pipeline/ # Pipeline shortcuts +│ ├── pm/ # Project management shortcuts │ ├── search/ # Search shortcuts │ ├── user/ # User shortcuts │ └── register.go # Registration entry point @@ -771,7 +823,7 @@ gitlink-cli/ ## Documentation -- [Skills Guide](skills/README.md) — AI Agent Skills detailed documentation +- [Skills Guide](./skills/README.md) — AI Agent Skills detailed documentation - [Design Document](doc/design.md) — Architecture design and development plan ## FAQ @@ -836,7 +888,7 @@ gitlink-cli uses Windows Credential Manager for secure token storage. If Credent ### Q: Where can I find the full API reference? -See [skills/gitlink-shared/REFERENCE.md](skills/gitlink-shared/REFERENCE.md). +See [skills/gitlink-shared/references/api-reference.md](./skills/gitlink-shared/references/api-reference.md). ## License diff --git a/README.zh-CN.md b/README.zh-CN.md index 84368c9..a1fc10a 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -553,6 +553,25 @@ gitlink-cli pipeline +disable --owner Gitlink --repo forgeplus --id 7 --workflow gitlink-cli pipeline +delete --owner Gitlink --repo forgeplus --id 7 --dry-run ``` +### 项目管理 + +`pm` 暴露 GitLink 项目管理数据,覆盖看板、Sprint、周报、标签、流水线和 Action 运行记录。 +PM 命令需要传入数字项目 ID。 + +```bash +# 查询 PM 看板和 Sprint Issue +gitlink-cli pm +dashboards --project-id 123 --limit 20 +gitlink-cli pm +sprint-issues --project-id 123 --page 1 --limit 20 + +# 查询周报 Issue 和 PM Issue 标签 +gitlink-cli pm +weekly-issues --project-id 123 +gitlink-cli pm +issue-tags --project-id 123 + +# 查询 PM 流水线和 Action 运行记录 +gitlink-cli pm +pipelines --project-id 123 +gitlink-cli pm +action-runs --project-id 123 +``` + ### 忽略文件模板 ```bash @@ -718,6 +737,7 @@ gitlink-cli/ │ ├── org/ # 组织 shortcuts │ ├── ci/ # CI shortcuts │ ├── pipeline/ # Pipeline shortcuts +│ ├── pm/ # 项目管理 shortcuts │ ├── search/ # 搜索 shortcuts │ ├── user/ # 用户 shortcuts │ └── register.go # 注册入口 diff --git a/doc/changes/pm-shortcuts.md b/doc/changes/pm-shortcuts.md new file mode 100644 index 0000000..aa05e5b --- /dev/null +++ b/doc/changes/pm-shortcuts.md @@ -0,0 +1,60 @@ +# PM shortcuts + +## Background + +The `gitlink-pm` Skill documented GitLink project-management workflows but had +to call Raw API paths under `/pm/...` directly. That made Sprint reports, weekly +issue summaries, board inspection, and PM pipeline checks less discoverable for +users and agents. + +This change adds a first-class `pm` shortcut group for read-only PM data. + +## New shortcuts + +- `pm +dashboards` lists PM dashboards for a project. +- `pm +sprint-issues` lists Sprint issues. +- `pm +weekly-issues` lists weekly issues. +- `pm +issue-tags` lists PM issue tags. +- `pm +pipelines` lists PM pipelines. +- `pm +action-runs` lists PM action run records. + +All commands require `--project-id` and accept `--page`/`--limit`. + +## Examples + +```bash +gitlink-cli pm +dashboards --project-id 123 --limit 20 +gitlink-cli pm +sprint-issues --project-id 123 --page 1 --limit 20 +gitlink-cli pm +weekly-issues --project-id 123 +gitlink-cli pm +issue-tags --project-id 123 +gitlink-cli pm +pipelines --project-id 123 +gitlink-cli pm +action-runs --project-id 123 +``` + +## Documentation updates + +- README and README.zh-CN include PM usage examples. +- `skills/gitlink-pm` now prefers `pm +...` shortcuts instead of Raw API calls. +- The Skills overview lists the new PM commands. + +## Tests + +Unit tests cover: + +- all PM shortcut endpoint mappings; +- `project_id`, `page`, and `limit` query construction; +- default pagination; +- required `--project-id` validation; +- HTTP error propagation. + +Suggested verification: + +```bash +go test ./shortcuts/pm ./shortcuts +``` + +Full project verification: + +```bash +go test ./... +``` diff --git a/internal/i18n/locales/en-US.json b/internal/i18n/locales/en-US.json index d5af1ca..f86243e 100644 --- a/internal/i18n/locales/en-US.json +++ b/internal/i18n/locales/en-US.json @@ -56,6 +56,13 @@ "cmd.org.list.short": "List organizations", "cmd.org.members.short": "List organization members", "cmd.org.short": "Organization operations", + "cmd.pm.action_runs.short": "List PM action run records", + "cmd.pm.dashboards.short": "List PM dashboards", + "cmd.pm.issue_tags.short": "List PM issue tags", + "cmd.pm.pipelines.short": "List PM pipelines", + "cmd.pm.short": "Project management operations", + "cmd.pm.sprint_issues.short": "List PM sprint issues", + "cmd.pm.weekly_issues.short": "List PM weekly issues", "cmd.pr.close.short": "Close a pull request", "cmd.pr.comment.short": "Add a comment to a pull request", "cmd.pr.create.short": "Create a pull request", @@ -189,6 +196,7 @@ "flag.org.name": "Organization name", "flag.owner": "Repository owner (auto-detected from git remote)", "flag.page": "Page number", + "flag.pm.project_id": "GitLink project ID", "flag.pr.assignee_id": "Assignee user ID", "flag.pr.base": "Target branch", "flag.pr.body": "PR description", diff --git a/internal/i18n/locales/zh-CN.json b/internal/i18n/locales/zh-CN.json index 4c5d175..cc8b61b 100644 --- a/internal/i18n/locales/zh-CN.json +++ b/internal/i18n/locales/zh-CN.json @@ -56,6 +56,13 @@ "cmd.org.list.short": "列出组织", "cmd.org.members.short": "列出组织成员", "cmd.org.short": "组织操作", + "cmd.pm.action_runs.short": "列出 PM Action 运行记录", + "cmd.pm.dashboards.short": "列出 PM 看板", + "cmd.pm.issue_tags.short": "列出 PM Issue 标签", + "cmd.pm.pipelines.short": "列出 PM 流水线", + "cmd.pm.short": "项目管理操作", + "cmd.pm.sprint_issues.short": "列出 PM Sprint Issue", + "cmd.pm.weekly_issues.short": "列出 PM 周报 Issue", "cmd.pr.close.short": "关闭拉取请求", "cmd.pr.comment.short": "给拉取请求添加评论", "cmd.pr.create.short": "创建拉取请求", @@ -189,6 +196,7 @@ "flag.org.name": "组织名称", "flag.owner": "仓库所有者(自动从 git remote 检测)", "flag.page": "页码", + "flag.pm.project_id": "GitLink 项目 ID", "flag.pr.assignee_id": "指派人用户 ID", "flag.pr.base": "目标分支", "flag.pr.body": "PR 描述", diff --git a/shortcuts/pm/pm.go b/shortcuts/pm/pm.go index 991a4e4..4ecbdb1 100644 --- a/shortcuts/pm/pm.go +++ b/shortcuts/pm/pm.go @@ -1,137 +1,71 @@ +// Package pm implements GitLink project management shortcuts. package pm import ( "net/url" + "strings" + "github.com/gitlink-org/gitlink-cli/internal/i18n" "github.com/gitlink-org/gitlink-cli/shortcuts/common" ) -// Shortcuts returns project management shortcuts for GitLink. -// -// The pm domain provides commands for viewing dashboards, sprints, -// weekly issues, tags, pipelines, and action runs associated with -// a project. -func Shortcuts() []*common.Shortcut { +// Shortcuts returns project management read shortcuts. +func Shortcuts(translators ...*i18n.Translator) []*common.Shortcut { + tr := shortcutTranslator(translators...) return []*common.Shortcut{ - { - Name: "dashboards", - Description: "查看项目仪表盘数据", - Flags: []common.Flag{ - {Name: "project", Usage: "项目 ID", Required: true}, - }, - Run: func(ctx *common.RuntimeContext) error { - project, err := ctx.RequireArg("project") - if err != nil { - return err - } - q := url.Values{} - q.Set("project_id", project) - env, err := ctx.CallAPIWithQuery("GET", "/pm/dashboards", q) - if err != nil { - return err - } - return ctx.Output(env) - }, + pmListShortcut(tr, "dashboards", tr.T("cmd.pm.dashboards.short"), "/pm/dashboards"), + pmListShortcut(tr, "sprint-issues", tr.T("cmd.pm.sprint_issues.short"), "/pm/sprint_issues"), + pmListShortcut(tr, "weekly-issues", tr.T("cmd.pm.weekly_issues.short"), "/pm/weekly_issues"), + pmListShortcut(tr, "issue-tags", tr.T("cmd.pm.issue_tags.short"), "/pm/issue_tags"), + pmListShortcut(tr, "pipelines", tr.T("cmd.pm.pipelines.short"), "/pm/pipelines"), + pmListShortcut(tr, "action-runs", tr.T("cmd.pm.action_runs.short"), "/pm/action_runs"), + } +} + +func pmListShortcut(tr *i18n.Translator, name, description, path string) *common.Shortcut { + return &common.Shortcut{ + Name: name, + Description: description, + Flags: []common.Flag{ + {Name: "project-id", Short: "P", Usage: tr.T("flag.pm.project_id"), Required: true}, + {Name: "page", Short: "p", Usage: tr.T("flag.page"), Default: "1"}, + {Name: "limit", Short: "l", Usage: tr.T("flag.limit"), Default: "20"}, }, - { - Name: "sprints", - Description: "查看 Sprint 任务列表", - Flags: []common.Flag{ - {Name: "project", Usage: "项目 ID", Required: true}, - }, - Run: func(ctx *common.RuntimeContext) error { - project, err := ctx.RequireArg("project") - if err != nil { - return err - } - q := url.Values{} - q.Set("project_id", project) - env, err := ctx.CallAPIWithQuery("GET", "/pm/sprint_issues", q) - if err != nil { - return err - } - return ctx.Output(env) - }, - }, - { - Name: "weekly", - Description: "查看周报任务", - Flags: []common.Flag{ - {Name: "project", Usage: "项目 ID", Required: true}, - }, - Run: func(ctx *common.RuntimeContext) error { - project, err := ctx.RequireArg("project") - if err != nil { - return err - } - q := url.Values{} - q.Set("project_id", project) - env, err := ctx.CallAPIWithQuery("GET", "/pm/weekly_issues", q) - if err != nil { - return err - } - return ctx.Output(env) - }, - }, - { - Name: "tags", - Description: "查看项目 Issue 标签", - Flags: []common.Flag{ - {Name: "project", Usage: "项目 ID", Required: true}, - }, - Run: func(ctx *common.RuntimeContext) error { - project, err := ctx.RequireArg("project") - if err != nil { - return err - } - q := url.Values{} - q.Set("project_id", project) - env, err := ctx.CallAPIWithQuery("GET", "/pm/issue_tags", q) - if err != nil { - return err - } - return ctx.Output(env) - }, - }, - { - Name: "pipelines", - Description: "查看项目 CI/CD 流水线列表", - Flags: []common.Flag{ - {Name: "project", Usage: "项目 ID", Required: true}, - }, - Run: func(ctx *common.RuntimeContext) error { - project, err := ctx.RequireArg("project") - if err != nil { - return err - } - q := url.Values{} - q.Set("project_id", project) - env, err := ctx.CallAPIWithQuery("GET", "/pm/pipelines", q) - if err != nil { - return err - } - return ctx.Output(env) - }, - }, - { - Name: "runs", - Description: "查看项目 Action 运行记录", - Flags: []common.Flag{ - {Name: "project", Usage: "项目 ID", Required: true}, - }, - Run: func(ctx *common.RuntimeContext) error { - project, err := ctx.RequireArg("project") - if err != nil { - return err - } - q := url.Values{} - q.Set("project_id", project) - env, err := ctx.CallAPIWithQuery("GET", "/pm/action_runs", q) - if err != nil { - return err - } - return ctx.Output(env) - }, + Run: func(ctx *common.RuntimeContext) error { + projectID, err := ctx.RequireArg("project-id") + if err != nil { + return err + } + q := pmQuery(ctx, projectID) + env, err := ctx.CallAPIWithQuery("GET", path, q) + if err != nil { + return err + } + return ctx.Output(env) }, } } + +func pmQuery(ctx *common.RuntimeContext, projectID string) url.Values { + q := url.Values{} + q.Set("project_id", strings.TrimSpace(projectID)) + q.Set("page", firstNonEmpty(ctx.Arg("page"), "1")) + q.Set("limit", firstNonEmpty(ctx.Arg("limit"), "20")) + return q +} + +func firstNonEmpty(values ...string) string { + for _, value := range values { + if strings.TrimSpace(value) != "" { + return strings.TrimSpace(value) + } + } + return "" +} + +func shortcutTranslator(translators ...*i18n.Translator) *i18n.Translator { + if len(translators) > 0 && translators[0] != nil { + return translators[0] + } + return i18n.Default() +} diff --git a/shortcuts/pm/pm_test.go b/shortcuts/pm/pm_test.go index 781d09f..dc3fd1d 100644 --- a/shortcuts/pm/pm_test.go +++ b/shortcuts/pm/pm_test.go @@ -4,192 +4,26 @@ import ( "encoding/json" "net/http" "net/http/httptest" - "strings" "testing" "github.com/gitlink-org/gitlink-cli/internal/client" + "github.com/gitlink-org/gitlink-cli/internal/i18n" "github.com/gitlink-org/gitlink-cli/shortcuts/common" ) -func TestPmDashboards(t *testing.T) { - tests := []struct { - name string - mockStatus int - mockBody string - wantErr bool - errContains string - }{ - {"正常返回", 200, `{"dashboards": []}`, false, ""}, - {"API 404", 404, `{"error": "not found"}`, true, "404"}, - {"返回 HTML", 200, `Login`, true, "HTML"}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.Method != "GET" { - t.Errorf("expected GET, got %s", r.Method) - } - if !strings.Contains(r.URL.Path, "/pm/dashboards") { - t.Errorf("expected path containing /pm/dashboards, got %s", r.URL.Path) - } - if got := r.URL.Query().Get("project_id"); got != "123" { - t.Errorf("expected project_id=123, got %s", got) - } - w.WriteHeader(tt.mockStatus) - w.Write([]byte(tt.mockBody)) - })) - defer server.Close() - - shortcut := findPmShortcut(t, "dashboards") - ctx := &common.RuntimeContext{ - Client: &client.Client{HTTP: server.Client(), BaseURL: server.URL}, - Owner: "test", Repo: "test", Format: "json", - Args: map[string]string{"project": "123"}, - } - err := shortcut.Run(ctx) - - if tt.wantErr && err == nil { - t.Fatal("期望错误但为 nil") - } - if !tt.wantErr && err != nil { - t.Fatalf("不期望错误: %v", err) - } - if tt.wantErr && tt.errContains != "" && err != nil { - if !strings.Contains(err.Error(), tt.errContains) { - t.Errorf("错误应包含 %q: %s", tt.errContains, err.Error()) - } - } - }) - } -} - -func TestPmSprints(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.Method != "GET" { - t.Errorf("expected GET, got %s", r.Method) - } - if !strings.Contains(r.URL.Path, "/pm/sprint_issues") { - t.Errorf("expected path containing /pm/sprint_issues, got %s", r.URL.Path) - } - w.WriteHeader(200) - w.Write([]byte(`{"sprint_issues": []}`)) - })) - defer server.Close() - - shortcut := findPmShortcut(t, "sprints") +func runShortcut(t *testing.T, server *httptest.Server, name string, args map[string]string) error { + t.Helper() + shortcut := findShortcut(t, name) ctx := &common.RuntimeContext{ Client: &client.Client{HTTP: server.Client(), BaseURL: server.URL}, - Owner: "test", Repo: "test", Format: "json", - Args: map[string]string{"project": "456"}, - } - if err := shortcut.Run(ctx); err != nil { - t.Fatalf("sprints shortcut failed: %v", err) + Format: "json", + Args: args, + Tr: i18n.Default(), } + return shortcut.Run(ctx) } -func TestPmWeekly(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if !strings.Contains(r.URL.Path, "/pm/weekly_issues") { - t.Errorf("expected path containing /pm/weekly_issues, got %s", r.URL.Path) - } - w.WriteHeader(200) - w.Write([]byte(`{"weekly_issues": []}`)) - })) - defer server.Close() - - shortcut := findPmShortcut(t, "weekly") - ctx := &common.RuntimeContext{ - Client: &client.Client{HTTP: server.Client(), BaseURL: server.URL}, - Owner: "test", Repo: "test", Format: "json", - Args: map[string]string{"project": "789"}, - } - if err := shortcut.Run(ctx); err != nil { - t.Fatalf("weekly shortcut failed: %v", err) - } -} - -func TestPmTags(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if !strings.Contains(r.URL.Path, "/pm/issue_tags") { - t.Errorf("expected path containing /pm/issue_tags, got %s", r.URL.Path) - } - w.WriteHeader(200) - w.Write([]byte(`{"issue_tags": []}`)) - })) - defer server.Close() - - shortcut := findPmShortcut(t, "tags") - ctx := &common.RuntimeContext{ - Client: &client.Client{HTTP: server.Client(), BaseURL: server.URL}, - Owner: "test", Repo: "test", Format: "json", - Args: map[string]string{"project": "100"}, - } - if err := shortcut.Run(ctx); err != nil { - t.Fatalf("tags shortcut failed: %v", err) - } -} - -func TestPmPipelines(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if !strings.Contains(r.URL.Path, "/pm/pipelines") { - t.Errorf("expected path containing /pm/pipelines, got %s", r.URL.Path) - } - w.WriteHeader(200) - w.Write([]byte(`{"pipelines": []}`)) - })) - defer server.Close() - - shortcut := findPmShortcut(t, "pipelines") - ctx := &common.RuntimeContext{ - Client: &client.Client{HTTP: server.Client(), BaseURL: server.URL}, - Owner: "test", Repo: "test", Format: "json", - Args: map[string]string{"project": "200"}, - } - if err := shortcut.Run(ctx); err != nil { - t.Fatalf("pipelines shortcut failed: %v", err) - } -} - -func TestPmRuns(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if !strings.Contains(r.URL.Path, "/pm/action_runs") { - t.Errorf("expected path containing /pm/action_runs, got %s", r.URL.Path) - } - w.WriteHeader(200) - w.Write([]byte(`{"action_runs": []}`)) - })) - defer server.Close() - - shortcut := findPmShortcut(t, "runs") - ctx := &common.RuntimeContext{ - Client: &client.Client{HTTP: server.Client(), BaseURL: server.URL}, - Owner: "test", Repo: "test", Format: "json", - Args: map[string]string{"project": "300"}, - } - if err := shortcut.Run(ctx); err != nil { - t.Fatalf("runs shortcut failed: %v", err) - } -} - -func TestPmMissingProject(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - t.Fatal("should not call API when --project is missing") - })) - defer server.Close() - - shortcut := findPmShortcut(t, "dashboards") - ctx := &common.RuntimeContext{ - Client: &client.Client{HTTP: server.Client(), BaseURL: server.URL}, - Owner: "test", Repo: "test", Format: "json", - Args: map[string]string{}, - } - err := shortcut.Run(ctx) - if err == nil { - t.Fatal("expected error when --project is missing") - } -} - -func findPmShortcut(t *testing.T, name string) *common.Shortcut { +func findShortcut(t *testing.T, name string) *common.Shortcut { t.Helper() for _, shortcut := range Shortcuts() { if shortcut.Name == name { @@ -200,21 +34,100 @@ func findPmShortcut(t *testing.T, name string) *common.Shortcut { return nil } -func assertPmRequest(t *testing.T, r *http.Request, method, pathPrefix string) { +func writeJSON(t *testing.T, w http.ResponseWriter, v interface{}) { t.Helper() - if r.Method != method { - t.Fatalf("got method %s, want %s", r.Method, method) - } - if !strings.HasPrefix(r.URL.Path, pathPrefix) { - t.Fatalf("got path %s, want prefix %s", r.URL.Path, pathPrefix) + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(v); err != nil { + t.Fatalf("write JSON: %v", err) } } -func decodePmJSON(t *testing.T, r *http.Request) map[string]interface{} { - t.Helper() - var payload map[string]interface{} - if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { - t.Fatalf("failed to decode request body: %v", err) +func TestPMReadShortcuts(t *testing.T) { + tests := []struct { + name string + path string + }{ + {name: "dashboards", path: "/pm/dashboards.json"}, + {name: "sprint-issues", path: "/pm/sprint_issues.json"}, + {name: "weekly-issues", path: "/pm/weekly_issues.json"}, + {name: "issue-tags", path: "/pm/issue_tags.json"}, + {name: "pipelines", path: "/pm/pipelines.json"}, + {name: "action-runs", path: "/pm/action_runs.json"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + t.Fatalf("method = %s, want GET", r.Method) + } + if r.URL.Path != tt.path { + t.Fatalf("path = %s, want %s", r.URL.Path, tt.path) + } + if got := r.URL.Query().Get("project_id"); got != "123" { + t.Fatalf("project_id = %q, want 123", got) + } + if got := r.URL.Query().Get("page"); got != "2" { + t.Fatalf("page = %q, want 2", got) + } + if got := r.URL.Query().Get("limit"); got != "50" { + t.Fatalf("limit = %q, want 50", got) + } + writeJSON(t, w, map[string]interface{}{"status": 0, "message": "success"}) + })) + defer server.Close() + + err := runShortcut(t, server, tt.name, map[string]string{ + "project-id": "123", + "page": "2", + "limit": "50", + }) + if err != nil { + t.Fatalf("%s failed: %v", tt.name, err) + } + }) + } +} + +func TestPMReadShortcutsDefaultPagination(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/pm/dashboards.json" { + t.Fatalf("path = %s, want /pm/dashboards.json", r.URL.Path) + } + if got := r.URL.Query().Get("page"); got != "1" { + t.Fatalf("page = %q, want 1", got) + } + if got := r.URL.Query().Get("limit"); got != "20" { + t.Fatalf("limit = %q, want 20", got) + } + writeJSON(t, w, map[string]interface{}{"status": 0}) + })) + defer server.Close() + + if err := runShortcut(t, server, "dashboards", map[string]string{"project-id": "123"}); err != nil { + t.Fatalf("dashboards failed: %v", err) + } +} + +func TestPMReadShortcutRequiresProjectID(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + t.Fatalf("missing project-id should fail before remote API: %s %s", r.Method, r.URL.Path) + })) + defer server.Close() + + if err := runShortcut(t, server, "dashboards", nil); err == nil { + t.Fatal("expected missing project-id error") + } +} + +func TestPMReadShortcutHTTPError(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte("server error")) + })) + defer server.Close() + + if err := runShortcut(t, server, "dashboards", map[string]string{"project-id": "123"}); err == nil { + t.Fatal("expected error for HTTP 500") } - return payload } diff --git a/shortcuts/register.go b/shortcuts/register.go index ea27013..33e3360 100644 --- a/shortcuts/register.go +++ b/shortcuts/register.go @@ -18,6 +18,7 @@ import ( "github.com/gitlink-org/gitlink-cli/shortcuts/milestone" "github.com/gitlink-org/gitlink-cli/shortcuts/org" "github.com/gitlink-org/gitlink-cli/shortcuts/pipeline" + "github.com/gitlink-org/gitlink-cli/shortcuts/pm" "github.com/gitlink-org/gitlink-cli/shortcuts/pr" "github.com/gitlink-org/gitlink-cli/shortcuts/profile" "github.com/gitlink-org/gitlink-cli/shortcuts/release" @@ -43,6 +44,7 @@ func RegisterAll(root *cobra.Command, translators ...*i18n.Translator) { "member": member.Shortcuts(), "milestone": milestone.Shortcuts(), "pipeline": pipeline.Shortcuts(), + "pm": pm.Shortcuts(tr), "pr": pr.Shortcuts(tr), "profile": profile.Shortcuts(tr), "release": release.Shortcuts(tr), @@ -68,6 +70,7 @@ func RegisterAll(root *cobra.Command, translators ...*i18n.Translator) { "member": "Repository member operations", "milestone": "Milestone operations", "pipeline": "Pipeline operations", + "pm": tr.T("cmd.pm.short"), "pr": tr.T("cmd.pr.short"), "profile": tr.T("cmd.profile.short"), "release": tr.T("cmd.release.short"), diff --git a/shortcuts/register_test.go b/shortcuts/register_test.go index c4bc025..4c14316 100644 --- a/shortcuts/register_test.go +++ b/shortcuts/register_test.go @@ -13,8 +13,8 @@ func TestRegisterAll(t *testing.T) { expectedGroups := []string{ "repo", "issue", "label", "license", "pr", "profile", "release", "branch", "org", "user", "search", "ci", "workflow", - "compare", "member", "milestone", "pipeline", "webhook", - "dataset", "health", "ignore", "template", + "compare", "member", "milestone", "pipeline", "pm", "webhook", + "dataset", "health", "ignore", "wiki", } groupSet := map[string]bool{} diff --git a/skills/README.md b/skills/README.md index e022aa0..9be10f1 100644 --- a/skills/README.md +++ b/skills/README.md @@ -32,7 +32,7 @@ gitlink-cli auth status gitlink-cli user +me ``` -详见: [gitlink-shared/examples/auth-workflow.md](gitlink-shared/examples/auth-workflow.md) +详见: [gitlink-shared/SKILL.md](gitlink-shared/SKILL.md) ### 2. 查看可用命令 @@ -64,25 +64,19 @@ skills/ ├── README.md # 本文件 ├── gitlink-shared/ # 共享基础规则 │ ├── SKILL.md # 认证、全局参数、安全规则、分支约定 -│ ├── REFERENCE.md # API 详细参考、错误处理 -│ ├── TROUBLESHOOTING.md # 常见问题排查 -│ └── examples/ -│ └── auth-workflow.md # 认证工作流示例 +│ └── references/ +│ ├── api-reference.md # API 详细参考、错误处理 +│ ├── raw-api-batch.md # 批量 Raw API 调用参考 +│ └── troubleshooting.md # 常见问题排查 ├── gitlink-repo/ # 仓库管理 │ ├── SKILL.md # 仓库操作指南 -│ ├── REFERENCE.md # 仓库 API 参考 -│ └── examples/ -│ └── repo-workflow.md # 仓库管理工作流 +│ └── references/ # 仓库命令参考文档 ├── gitlink-issue/ # Issue 管理 │ ├── SKILL.md # Issue 操作指南 -│ ├── REFERENCE.md # Issue API 参考 -│ └── examples/ -│ └── issue-workflow.md # Issue 全流程工作流 +│ └── references/ # Issue 命令参考文档 ├── gitlink-pr/ # Pull Request │ ├── SKILL.md # PR 操作指南 -│ ├── REFERENCE.md # PR API 参考 -│ └── examples/ -│ └── pr-workflow.md # PR 工作流 +│ └── references/ # PR 命令参考文档 ├── gitlink-member/ # 仓库成员管理 │ └── SKILL.md # 成员与邀请链接操作指南 ├── gitlink-branch/ # 分支管理 @@ -91,25 +85,24 @@ skills/ │ └── branch-workflow.md # 分支工作流 ├── gitlink-release/ # 版本发布 │ ├── SKILL.md # Release 操作指南 -│ ├── REFERENCE.md # Release API 参考 -│ └── examples/ -│ └── release-workflow.md # Release 工作流 +│ └── references/ # Release 命令参考文档 +├── gitlink-release-auto/ # 自动化 Release 管理 +│ └── SKILL.md # 自动发版、版本号推荐、Release Notes 生成 ├── gitlink-search/ # 搜索功能 │ ├── SKILL.md # 搜索操作指南 -│ └── examples/ -│ └── search-workflow.md # 搜索工作流 +│ └── references/ # 搜索命令参考文档 ├── gitlink-user/ # 用户管理 -│ └── SKILL.md # 用户操作指南 +│ ├── SKILL.md # 用户操作指南 +│ └── references/ # 用户命令参考文档 ├── gitlink-org/ # 组织管理 │ ├── SKILL.md # 组织操作指南 -│ └── examples/ -│ └── org-workflow.md # 组织工作流 +│ └── references/ # 组织命令参考文档 ├── gitlink-ci/ # CI/CD -│ ├── SKILL.md # CI 操作指南 -│ └── examples/ -│ └── ci-workflow.md # CI 工作流 +│ └── SKILL.md # CI 操作指南 ├── gitlink-pipeline/ # 流水线工作流 │ └── SKILL.md # Pipeline 操作指南 +├── gitlink-wiki/ # Wiki 页面管理 +│ └── SKILL.md # Wiki 操作指南 ├── gitlink-pm/ # 项目管理 │ └── SKILL.md # PM 操作指南 ├── gitlink-health/ # 项目健康度分析 @@ -135,8 +128,8 @@ skills/ |-------|------|----------| | **gitlink-shared** | 认证、全局参数、API 参考、安全规则、分支约定 | `auth login`, `auth status` | | **gitlink-repo** | 仓库管理与洞察 | `repo +list`, `repo +info`, `repo +languages`, `repo +contributors`, `repo +code-stats`, `repo +follow`, `repo +like` | -| **gitlink-issue** | Issue 管理 | `issue +create`, `issue +list`, `issue +view`, `issue +close`, `issue +batch-close`, `issue +comments` | -| **gitlink-pr** | Pull Request | `pr +list`, `pr +create`, `pr +view`, `pr +merge`, `pr +versions`, `pr +version-diff`, `pr +reviews`, `pr +review`, `pr +review-comments` | +| **gitlink-issue** | Issue 管理 | `issue +create`, `issue +list`, `issue +view`, `issue +close`, `issue +batch-close`, `issue +batch-update`, `issue +batch-delete` | +| **gitlink-pr** | Pull Request | `pr +list`, `pr +create`, `pr +view`, `pr +merge`, `pr +versions`, `pr +version-diff`, `pr +reviews`, `pr +review` | | **gitlink-member** | 仓库成员管理 | `member +list`, `member +add`, `member +batch-add`, `member +role`, `member +invite-link` | | **gitlink-branch** | 分支管理 | `branch +list`, `branch +create`, `branch +delete`, `branch +protect` | | **gitlink-release** | 版本发布 | `release +list`, `release +create`, `release +edit`, `release +update`, `release +view` | @@ -150,7 +143,8 @@ skills/ | **gitlink-org** | 组织管理 | `org +list`, `org +info`, `org +members` | | **gitlink-ci** | CI/CD | `ci +builds`, `ci +logs` | | **gitlink-pipeline** | 流水线工作流 | `pipeline +runs`, `pipeline +run`, `pipeline +logs` | -| **gitlink-pm** | 项目管理 | 通过 Raw API 访问 | +| **gitlink-wiki** | Wiki 页面管理 | `wiki +list`, `wiki +view`, `wiki +create`, `wiki +update`, `wiki +delete` | +| **gitlink-pm** | 项目管理 | `pm +dashboards`, `pm +sprint-issues`, `pm +weekly-issues`, `pm +action-runs` | | **gitlink-workflow** | AI 工作流 | Issue 分类、PR Review、Release Notes | | **gitlink-health** | 开源项目健康度 | 详情见SKILL.md | @@ -169,7 +163,7 @@ gitlink-cli repo +info gitlink-cli repo +info --owner wbtiger --repo gitlink-cli ``` -详见: [gitlink-repo/examples/repo-workflow.md](gitlink-repo/examples/repo-workflow.md) +详见: [gitlink-repo/SKILL.md](gitlink-repo/SKILL.md) ### 场景 2:创建和管理 Issue @@ -190,7 +184,7 @@ gitlink-cli issue +close -i 123 gitlink-cli issue +batch-close --numbers 123,124 --dry-run ``` -详见: [gitlink-issue/examples/issue-workflow.md](gitlink-issue/examples/issue-workflow.md) +详见: [gitlink-issue/SKILL.md](gitlink-issue/SKILL.md) ### 场景 3:管理分支和发布 @@ -208,7 +202,7 @@ gitlink-cli release +create -t v1.0.0 -n "v1.0.0 正式版" -b "更新内容..." gitlink-cli release +view -i ``` -详见: [gitlink-release/examples/release-workflow.md](gitlink-release/examples/release-workflow.md) +详见: [gitlink-release/SKILL.md](gitlink-release/SKILL.md) ### 场景 4:搜索和发现 @@ -224,7 +218,7 @@ gitlink-cli org +list gitlink-cli org +info -i Gitlink ``` -详见: [gitlink-search/examples/search-workflow.md](gitlink-search/examples/search-workflow.md) +详见: [gitlink-search/SKILL.md](gitlink-search/SKILL.md) --- @@ -233,8 +227,8 @@ gitlink-cli org +info -i Gitlink ### 快速查找 - **我想了解认证**: [gitlink-shared/SKILL.md](gitlink-shared/SKILL.md) -- **我想查看 API 细节**: [gitlink-shared/REFERENCE.md](gitlink-shared/REFERENCE.md) -- **我遇到了错误**: [gitlink-shared/TROUBLESHOOTING.md](gitlink-shared/TROUBLESHOOTING.md) +- **我想查看 API 细节**: [gitlink-shared/references/api-reference.md](gitlink-shared/references/api-reference.md) +- **我遇到了错误**: [gitlink-shared/references/troubleshooting.md](gitlink-shared/references/troubleshooting.md) - **我想看工作流示例**: 查看各 Skill 下的 `examples/` 目录 ### 按功能分类 @@ -242,12 +236,12 @@ gitlink-cli org +info -i Gitlink **仓库操作**: - [gitlink-repo/SKILL.md](gitlink-repo/SKILL.md) - 仓库命令 - [gitlink-branch/SKILL.md](gitlink-branch/SKILL.md) - 分支命令 -- [gitlink-repo/examples/repo-workflow.md](gitlink-repo/examples/repo-workflow.md) - 完整工作流 +- [gitlink-repo/SKILL.md](gitlink-repo/SKILL.md) - 完整工作流 **Issue 和 PR**: - [gitlink-issue/SKILL.md](gitlink-issue/SKILL.md) - Issue 命令 - [gitlink-pr/SKILL.md](gitlink-pr/SKILL.md) - PR 命令 -- [gitlink-issue/examples/issue-workflow.md](gitlink-issue/examples/issue-workflow.md) - Issue 工作流 +- [gitlink-issue/SKILL.md](gitlink-issue/SKILL.md) - Issue 工作流 **发布和搜索**: - [gitlink-release/SKILL.md](gitlink-release/SKILL.md) - Release 命令 @@ -289,11 +283,11 @@ gitlink-cli auth login ### Q: 如何查看完整的 API 参考? -A: 查看 [gitlink-shared/REFERENCE.md](gitlink-shared/REFERENCE.md) +A: 查看 [gitlink-shared/references/api-reference.md](gitlink-shared/references/api-reference.md) ### Q: 遇到错误怎么办? -A: 查看 [gitlink-shared/TROUBLESHOOTING.md](gitlink-shared/TROUBLESHOOTING.md) +A: 查看 [gitlink-shared/references/troubleshooting.md](gitlink-shared/references/troubleshooting.md) --- @@ -329,7 +323,7 @@ AI 代理可以: - 所有边界情况处理正确 - 完整的文档和示例 -详见: [../doc/SKILLS_TEST_REPORT_2026-04-02.md](../doc/SKILLS_TEST_REPORT_2026-04-02.md) +详见: [../doc/design.md](../doc/design.md) --- @@ -337,8 +331,7 @@ AI 代理可以: - [主项目 README](../README.md) - gitlink-cli 项目说明 - [设计文档](../doc/design.md) - 架构设计和开发计划 -- [测试报告](../doc/SKILLS_TEST_REPORT_2026-04-02.md) - 功能测试报告 -- [代码同步方案](../doc/CODE_SYNC_STRATEGY_FINAL.md) - GitHub ↔ GitLink 同步设计 +- [API 参考文档](../doc/gitlink_api_reference.md) - GitLink API 参考文档 - [gitlink-bisync](https://www.gitlink.org.cn/wbtiger/gitlink-bisync) - 代码双向同步系统 --- @@ -346,8 +339,8 @@ AI 代理可以: ## 📞 获取帮助 - **命令帮助**: `gitlink-cli --help` -- **故障排查**: [gitlink-shared/TROUBLESHOOTING.md](gitlink-shared/TROUBLESHOOTING.md) -- **API 参考**: [gitlink-shared/REFERENCE.md](gitlink-shared/REFERENCE.md) +- **故障排查**: [gitlink-shared/references/troubleshooting.md](gitlink-shared/references/troubleshooting.md) +- **API 参考**: [gitlink-shared/references/api-reference.md](gitlink-shared/references/api-reference.md) - **工作流示例**: 查看各 Skill 下的 `examples/` 目录 --- @@ -355,7 +348,7 @@ AI 代理可以: ## 🎓 下一步 1. 阅读 [gitlink-shared/SKILL.md](gitlink-shared/SKILL.md) 了解基础 -2. 查看 [gitlink-shared/examples/auth-workflow.md](gitlink-shared/examples/auth-workflow.md) 完成认证 +2. 查看 [gitlink-shared/SKILL.md](gitlink-shared/SKILL.md) 完成认证 3. 根据需求选择相应的 Skill 文档 4. 参考 `examples/` 目录中的工作流示例 5. 使用 AI 代理自动化你的工作流 diff --git a/skills/gitlink-pm/SKILL.md b/skills/gitlink-pm/SKILL.md index f5333ed..d8707bc 100644 --- a/skills/gitlink-pm/SKILL.md +++ b/skills/gitlink-pm/SKILL.md @@ -1,6 +1,6 @@ --- name: gitlink-pm -version: 1.0.0 +version: 2.0.0 description: "项目管理(PM):Sprint、看板、周报等项目管理功能。当用户需要使用 GitLink PM 功能时触发。" metadata: requires: @@ -10,37 +10,56 @@ metadata: # gitlink-pm(项目管理) -> **前置条件:** 先阅读 [`../gitlink-shared/SKILL.md`](../gitlink-shared/SKILL.md) +> **前置条件:** 先阅读 [`../gitlink-shared/SKILL.md`](../gitlink-shared/SKILL.md)。 -**CRITICAL — GitLink 操作只能用 `gitlink-cli`。禁止用 `gh`(GitHub CLI)操作 GitLink 资源。`gh` 仅适用于 GitHub 平台。** +**CRITICAL — GitLink 操作只能用 `gitlink-cli`。禁止用 `gh`(GitHub CLI)操作 GitLink 资源。** -GitLink PM 模块提供敏捷项目管理能力,目前通过 Raw API 访问。 +GitLink PM 模块提供敏捷项目管理能力。优先使用 `pm` shortcut,不再直接拼接 `/pm/...` Raw API。 -## API 端点 - -> 前缀:`/api/pm` +## 命令 ```bash # 看板 -gitlink-cli api GET /pm/dashboards --query 'project_id=123' +gitlink-cli pm +dashboards --project-id 123 --format json # Sprint Issue 列表 -gitlink-cli api GET /pm/sprint_issues --query 'project_id=123' +gitlink-cli pm +sprint-issues --project-id 123 --page 1 --limit 20 --format json -# 周报 -gitlink-cli api GET /pm/weekly_issues --query 'project_id=123' +# 周报 Issue +gitlink-cli pm +weekly-issues --project-id 123 --format json -# Issue 标签 -gitlink-cli api GET /pm/issue_tags --query 'project_id=123' +# PM Issue 标签 +gitlink-cli pm +issue-tags --project-id 123 --format json -# 流水线 -gitlink-cli api GET /pm/pipelines --query 'project_id=123' +# PM 流水线 +gitlink-cli pm +pipelines --project-id 123 --format json # Action 运行记录 -gitlink-cli api GET /pm/action_runs --query 'project_id=123' +gitlink-cli pm +action-runs --project-id 123 --format json ``` +## 参数 + +| 参数 | 必填 | 说明 | +|------|------|------| +| `--project-id, -P` | 是 | GitLink 数字项目 ID | +| `--page, -p` | 否 | 页码,默认 `1` | +| `--limit, -l` | 否 | 每页数量,默认 `20` | + +## API 映射 + +| Shortcut | API | +|----------|-----| +| `pm +dashboards` | `GET /pm/dashboards` | +| `pm +sprint-issues` | `GET /pm/sprint_issues` | +| `pm +weekly-issues` | `GET /pm/weekly_issues` | +| `pm +issue-tags` | `GET /pm/issue_tags` | +| `pm +pipelines` | `GET /pm/pipelines` | +| `pm +action-runs` | `GET /pm/action_runs` | + ## 注意事项 -- PM 接口需要项目 ID(`project_id`),可通过 `repo +info` 获取 -- PM 功能需要项目开启 PM 模块 +- PM 接口需要项目 ID(`project_id`),可通过 `repo +info` 获取。 +- PM 功能需要项目开启 PM 模块。 +- 这些命令均为只读查询,适合 Agent 生成 Sprint 报告、看板摘要和项目管理周报。 +- 建议在 Agent 场景始终使用 `--format json`。