Skip to content

Commit c828166

Browse files
authored
Merge pull request #4 from yuque/chore/release-engineering
chore: add tag-driven release workflow and community health files
2 parents 2c5ba31 + 6040f4b commit c828166

8 files changed

Lines changed: 300 additions & 1 deletion

File tree

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Bug report
2+
description: Something in the CLI behaves incorrectly
3+
labels: [bug]
4+
body:
5+
- type: input
6+
id: version
7+
attributes:
8+
label: CLI version
9+
description: Output of `yuque --version`
10+
placeholder: 1.1.0
11+
validations:
12+
required: true
13+
- type: input
14+
id: environment
15+
attributes:
16+
label: Environment
17+
description: OS and Node.js version (`node --version`)
18+
placeholder: macOS 15 / Node 22.11.0
19+
validations:
20+
required: true
21+
- type: textarea
22+
id: command
23+
attributes:
24+
label: Command and behavior
25+
description: >-
26+
The exact command you ran (redact tokens and private doc slugs), what
27+
happened, and what you expected. Include the exit code (`echo $?`)
28+
and output — `--json` output is especially helpful.
29+
placeholder: |
30+
$ yuque doc get team/handbook onboarding
31+
exit code: 4
32+
...
33+
validations:
34+
required: true
35+
- type: textarea
36+
id: context
37+
attributes:
38+
label: Additional context
39+
description: >-
40+
Anything else relevant — custom `--host` / space host, whether a team
41+
token or personal token is used, proxy setup, etc.
42+
validations:
43+
required: false

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
blank_issues_enabled: true
2+
contact_links:
3+
- name: Security vulnerability
4+
url: https://github.com/yuque/yuque-open-cli/security/advisories/new
5+
about: Please report security issues privately via a security advisory, not a public issue.
6+
- name: Yuque OpenAPI documentation
7+
url: https://www.yuque.com/yuque/developer/api
8+
about: Questions about the Yuque API itself (rather than this CLI) are answered here.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Feature request
2+
description: Propose a new command, flag, or behavior
3+
labels: [enhancement]
4+
body:
5+
- type: textarea
6+
id: problem
7+
attributes:
8+
label: Problem
9+
description: What are you trying to do that the CLI currently makes hard?
10+
validations:
11+
required: true
12+
- type: textarea
13+
id: proposal
14+
attributes:
15+
label: Proposed command surface
16+
description: >-
17+
Sketch the command(s) as you would type them. If this maps to a Yuque
18+
OpenAPI endpoint, link it — the CLI surface is spec-driven.
19+
placeholder: |
20+
yuque note list --all --json
21+
validations:
22+
required: true
23+
- type: textarea
24+
id: alternatives
25+
attributes:
26+
label: Alternatives considered
27+
description: Workarounds you use today (scripts, other tools, raw curl).
28+
validations:
29+
required: false

.github/pull_request_template.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<!-- Describe what changes and why. Link the issue if there is one. -->
2+
3+
## Checklist
4+
5+
- [ ] `npm run check` passes locally (the exact gate CI runs)
6+
- [ ] User-visible changes are reflected in **both** `README.md` and `README.zh-CN.md`, and in `CHANGELOG.md`
7+
- [ ] API-surface changes follow the spec-driven flow: `spec/yuque-openapi.yaml` edited, `npm run gen:types` run, command surface extended (see [CONTRIBUTING.md](https://github.com/yuque/yuque-open-cli/blob/main/CONTRIBUTING.md))
8+
- [ ] Structural changes are reflected in `AGENTS.md`

.github/workflows/release.yml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: Release
2+
3+
# Tag-driven release: push a `vX.Y.Z` tag and this workflow runs the full
4+
# check gate, publishes to npm with provenance, and creates the GitHub
5+
# Release from the matching CHANGELOG.md section.
6+
#
7+
# One-time setup: add an npm automation token as the NPM_TOKEN repo secret
8+
# (Settings → Secrets and variables → Actions). Publishing fails fast with a
9+
# clear error if the secret is missing.
10+
#
11+
# Release steps (also documented in CONTRIBUTING.md):
12+
# 1. Bump `version` in package.json and add the `## X.Y.Z` CHANGELOG entry.
13+
# 2. Land that on main, then: git tag vX.Y.Z && git push origin vX.Y.Z
14+
15+
on:
16+
push:
17+
tags: ['v*.*.*']
18+
19+
permissions:
20+
contents: write # create the GitHub Release
21+
id-token: write # npm provenance attestation
22+
23+
jobs:
24+
release:
25+
runs-on: ubuntu-latest
26+
steps:
27+
- uses: actions/checkout@v4
28+
- uses: actions/setup-node@v4
29+
with:
30+
node-version: 22
31+
cache: npm
32+
registry-url: https://registry.npmjs.org
33+
# npm install, not npm ci — see ci.yml for the lockfile rationale.
34+
- run: npm install --no-audit --no-fund
35+
- name: Verify tag matches package.json version
36+
run: |
37+
pkg_version="$(node -p "require('./package.json').version")"
38+
tag_version="${GITHUB_REF_NAME#v}"
39+
if [ "$pkg_version" != "$tag_version" ]; then
40+
echo "Tag $GITHUB_REF_NAME does not match package.json version $pkg_version" >&2
41+
exit 1
42+
fi
43+
- name: Full check gate
44+
run: npm run check
45+
- name: Publish to npm (with provenance)
46+
run: |
47+
if [ -z "$NODE_AUTH_TOKEN" ]; then
48+
echo "NPM_TOKEN secret is not configured (Settings → Secrets and variables → Actions)" >&2
49+
exit 1
50+
fi
51+
npm publish --provenance --access public
52+
env:
53+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
54+
- name: Create GitHub Release from CHANGELOG
55+
run: |
56+
version="${GITHUB_REF_NAME#v}"
57+
awk -v ver="$version" '
58+
$0 ~ "^## "ver"$" { found=1; next }
59+
found && /^## / { exit }
60+
found { print }
61+
' CHANGELOG.md > /tmp/release-notes.md
62+
if ! [ -s /tmp/release-notes.md ]; then
63+
echo "No CHANGELOG.md section found for $version" >&2
64+
exit 1
65+
fi
66+
gh release create "$GITHUB_REF_NAME" \
67+
--title "$GITHUB_REF_NAME" \
68+
--notes-file /tmp/release-notes.md
69+
env:
70+
GH_TOKEN: ${{ github.token }}

CONTRIBUTING.md

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Contributing to yuque-open-cli
2+
3+
Thanks for your interest in improving the Yuque CLI! This document covers the
4+
development workflow, the conventions the codebase enforces, and how releases
5+
are cut.
6+
7+
> Working with an AI agent (or as one)? [AGENTS.md](./AGENTS.md) is the
8+
> authoritative architecture map and convention guide — it is kept in lockstep
9+
> with the code by tests.
10+
11+
## Development setup
12+
13+
Requirements: Node.js ≥ 20.
14+
15+
```bash
16+
git clone https://github.com/yuque/yuque-open-cli.git
17+
cd yuque-open-cli
18+
npm install
19+
npm run dev -- --help # run the CLI from source (tsx)
20+
```
21+
22+
To exercise commands against the real API you need a token from
23+
[Yuque Developer Settings](https://www.yuque.com/settings/tokens):
24+
25+
```bash
26+
YUQUE_TOKEN=... npm run dev -- auth status
27+
```
28+
29+
## The check gate
30+
31+
Every change must pass the single unified gate — the same command CI runs:
32+
33+
```bash
34+
npm run check
35+
```
36+
37+
That is: ESLint, Prettier check, generated-types drift check, `tsc`, unit
38+
tests with coverage, build, packaged-CLI smoke test, and the mock-server e2e
39+
suite. If `npm run check` is green locally, CI will be green.
40+
41+
Useful narrower loops while iterating:
42+
43+
```bash
44+
npm test # unit tests once
45+
npm run test:watch # unit tests in watch mode
46+
npm run test:e2e # build + e2e against the bundled mock server
47+
```
48+
49+
## Spec-driven workflow
50+
51+
The OpenAPI spec is the source of truth for the API surface:
52+
53+
1. Edit `spec/yuque-openapi.yaml` — never edit `src/client/types.gen.ts` by
54+
hand.
55+
2. Run `npm run gen:types` to regenerate the types.
56+
3. Adapt the thin compatibility layer in `src/client/types.ts` if public type
57+
names changed.
58+
59+
`npm run gen:types:check` (part of the check gate) fails if the generated
60+
file drifts from the spec. `tests/spec-coverage.test.ts` fails if a spec
61+
operation has no corresponding CLI command, so extending the spec means
62+
extending the command surface in the same change.
63+
64+
## Code layout and conventions
65+
66+
```
67+
bin.ts → cli.ts (commander program, error → exit code)
68+
└── commands/<domain>.ts (flags, confirmation, rendering)
69+
└── client/api/<domain>.ts (typed calls, envelope unwrap)
70+
└── client/http.ts (auth header, retry/backoff, YuqueError)
71+
```
72+
73+
- One domain = one `src/commands/<domain>.ts` exporting a single
74+
`register<Domain>Commands` function, plus one thin `src/client/api/<domain>.ts`.
75+
- `src/client/http.ts` is the only HTTP exit; `src/errors.ts` is the only
76+
place exit codes are defined.
77+
- Destructive commands must go through `confirmDestructive` (`--yes` to skip).
78+
- Every command supports `--json`; human-readable output goes through the
79+
helpers in `src/output.ts`.
80+
- The full `--help` surface is pinned by a golden file — when you add or
81+
change flags, regenerate it as instructed by the failing test and review
82+
the diff.
83+
84+
## Pull requests
85+
86+
- Branch from `main`; keep PRs focused on one concern.
87+
- Update docs in the same PR: both `README.md` and `README.zh-CN.md` for any
88+
user-visible change, `AGENTS.md` for structural changes, and `CHANGELOG.md`
89+
under the upcoming version heading.
90+
- `npm run check` must pass.
91+
92+
## Releasing (maintainers)
93+
94+
Releases are tag-driven via `.github/workflows/release.yml`:
95+
96+
1. Bump `version` in `package.json` and add the matching `## X.Y.Z` section
97+
at the top of `CHANGELOG.md`; land that on `main`.
98+
2. Tag and push:
99+
100+
```bash
101+
git tag vX.Y.Z && git push origin vX.Y.Z
102+
```
103+
104+
The workflow re-runs the full check gate, publishes to npm with provenance,
105+
and creates the GitHub Release from the CHANGELOG section. It requires the
106+
`NPM_TOKEN` repository secret (an npm automation token with publish rights on
107+
`yuque-open-cli`).
108+
109+
## Reporting security issues
110+
111+
Please do not open public issues for vulnerabilities — see
112+
[SECURITY.md](./SECURITY.md).

SECURITY.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Security Policy
2+
3+
## Supported versions
4+
5+
Only the latest release published on npm receives security fixes.
6+
7+
## Reporting a vulnerability
8+
9+
Please report vulnerabilities privately via
10+
[GitHub Security Advisories](https://github.com/yuque/yuque-open-cli/security/advisories/new)
11+
— do not open a public issue.
12+
13+
Include what you can: affected version, reproduction steps, and impact. You
14+
can expect an acknowledgement within a few business days.
15+
16+
## Scope notes for this CLI
17+
18+
- The CLI authenticates with a Yuque API token supplied via `--token`,
19+
`YUQUE_TOKEN`, or `YUQUE_PERSONAL_TOKEN`. Tokens are only ever sent to the
20+
configured Yuque host (`https://www.yuque.com` by default, or the host you
21+
set via `--host` / `YUQUE_HOST`) as the `X-Auth-Token` header.
22+
- The CLI never writes your token to disk. Prefer the environment variable
23+
over `--token` in shared environments — command-line flags can be visible
24+
to other processes and shell history.
25+
- Anything that would trick the CLI into sending the token to a non-Yuque
26+
host, leaking it into output/logs, or executing content returned by the
27+
API is in scope and we want to hear about it.

src/cli.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ const { version: VERSION } = require('../package.json') as { version: string };
1616
export function buildProgram(): Command {
1717
const program = new Command('yuque');
1818
program
19-
.description('Scriptable toolkit for the Yuque (语雀) Open API — search, read, write, and manage docs')
19+
.description(
20+
'Scriptable toolkit for the Yuque (语雀) Open API — search, read, write, and manage docs'
21+
)
2022
.version(VERSION, '-v, --version', 'print the CLI version')
2123
.option('--token <token>', 'Yuque API token (overrides YUQUE_TOKEN / YUQUE_PERSONAL_TOKEN)')
2224
.option('--host <host>', 'Yuque host, e.g. https://your-space.yuque.com (overrides YUQUE_HOST)')

0 commit comments

Comments
 (0)