Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .claude/skills/new-cli-command/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
name: new-cli-command
description: Use when adding a new command or a new product command group to greennode-cli ("add a command", "tạo CLI cho <product>", "implement grn <product>", "new subcommand"). Guides scaffolding and the command implementation flow.
---

# Adding to greennode-cli

`grn` is a single Go binary; each product is a self-registering command group under
`go/cmd/<product>/`. Read the root `CLAUDE.md` (repo conventions) and the target
product's `go/cmd/<product>/CLAUDE.md` (API quirks) first.

## New product CLI → scaffold

```bash
./scripts/new-product <product> # lowercase, valid Go package name (e.g. vdb)
```

Generates the package (parent command, example command, helpers, starter test,
product CLAUDE.md), docs, self-registration in `go/cmd/register.go`, and CODEOWNERS
lines. Then: add `<product>_endpoint` to `internal/config` REGIONS, replace the
`list-examples` starter, and fill in the product CLAUDE.md.

## New command in an existing product (TDD)

1. Add `go/cmd/<product>/<verb>_<noun>.go`; register it in the product's parent
`init()`.
2. Follow the conventions (the `go/cmd/conventions_test.go` test enforces them):
- Name is `verb-noun` (canonical verbs: list/get/create/update/delete/configure/
upgrade/generate/validate/wait). vServer uses `noun verb` nesting — match the
product's existing style.
- `validator.ValidateID(id, "flag")` before interpolating an ID into a URL.
- Struct-valued flags via `cli.ParseStructFlag` / `ParseStructFlagTyped`
(shorthand `k=v,k2=v2` or JSON).
- Destructive commands (`delete`, `stop`, `reboot`): add `--dry-run` and
`--force`; use `cli.DryRunNotice` / `cli.Confirm`.
- Output via `cli.Output` (product helper `outputResult`).
3. Write table-driven tests (use `httptest`); build/test with the macOS linker
workaround: `CGO_ENABLED=1 go test -ldflags='-linkmode=external' ./...`.
4. Add an AWS-CLI-style doc page under `docs/commands/<product>/` (type, Required,
Default, Possible values, Constraints; Members + Shorthand/JSON for struct flags)
and link it in that product's `index.md`.

## PR

Open a PR with a **Conventional Commit** title (`feat(...)`, `fix(...)`) — it becomes
the squash-merge commit release-please reads. Do not edit the version or CHANGELOG.
37 changes: 37 additions & 0 deletions .claude/skills/release-cli/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
name: release-cli
description: Use when releasing greennode-cli, cutting a version, tagging, or publishing binaries ("release the CLI", "cut a release", "bump version", "publish grn"). Everything is release-please driven — never bump versions or tag by hand.
---

# Releasing greennode-cli

Versioning and `CHANGELOG.md` are automated by **release-please**. **Never** edit
the version (`go/cmd/root.go` `cliVersion`), edit `CHANGELOG.md`, or create tags by
hand — release-please derives all of it from commit messages.

## How a release happens

1. `feat:` / `fix:` PRs merge to `main` (squash-merged; the PR title is the commit
message, enforced by the `Conventional Commits title` check).
- `fix:` → patch, `feat:` → minor, `feat!:` / `BREAKING CHANGE:` → major.
2. release-please opens/refreshes a **`chore: release main`** PR that bumps
`go/cmd/root.go` and updates `CHANGELOG.md`.
3. **Squash-merge that release PR** to publish: it tags `vX.Y.Z`, creates the GitHub
Release, and `release.yml` builds + attaches the multi-platform binaries.

## Verify

```bash
gh pr list # find the "chore: release main" PR
gh run list --workflow=release-please.yml # after merge: release + build
gh release view vX.Y.Z # binaries attached
```

## Troubleshooting

- **Release PR checks don't start** → default `GITHUB_TOKEN` limitation; close &
reopen the PR once, or set a `RELEASE_PLEASE_TOKEN` PAT (contents + pull-requests
write) so checks auto-run.
- **Wrong version bump** → fix the offending PR title; never edit the version file.
- **Emergency/manual**: `release.yml` still accepts a tag push (`git tag vX.Y.Z &&
git push --tags`) or `workflow_dispatch`. Prefer release-please for normal releases.
41 changes: 41 additions & 0 deletions go/cmd/vks/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# VKS CLI — product notes

Tier-2 notes for the `grn vks` command group. The root `CLAUDE.md` has the
repo-wide conventions; this file records what is specific to VKS.

## Client & endpoint

- `createClient(cmd)` → `cli.NewClient(cmd, "vks")`. The endpoint is resolved from
`internal/config` REGIONS key `vks_endpoint`
(`https://vks.api.vngcloud.vn` HCM-3, `https://vks-han-1.api.vngcloud.vn` HAN).
- Auth: shared GreenNode IAM bearer token (see `internal/auth`).

## API quirks

- **Pagination is 0-based**: params `page` (from 0) + `pageSize`. The `list-*`
commands default `--page -1`, a sentinel meaning "auto-paginate all pages".
- Paths are under `/v1/clusters/...`.
- Cluster/node-group **status** values: `CREATING`, `ACTIVE`, `ERROR` (waiters key
on these; see `wait.go`).
- **Kubeconfig is asynchronous**: `generate-kubeconfig` (POST) requests generation,
then `update-kubeconfig` (GET) fetches + merges once status is `ACTIVE`
(`NONE`/`CREATING`/`ERROR` are the other states).

## Command specifics

- `create-cluster` creates the **control plane only**. The API's `nodeGroups` array
is deprecated — do not send it; add workers with `create-nodegroup`.
- `update-nodegroup`: all body fields optional. Labels/tags/taints are **deprecated**
on this endpoint — use `update-nodegroup-metadata`.
- `config-auto-upgrade` (the former `set-auto-upgrade-config` is a deprecated alias).
- `--k8s-version` values come from `list-cluster-versions`.
- Network types: `TIGERA`, `CILIUM_OVERLAY`, `CILIUM_NATIVE_ROUTING`; `--cidr` is
required for `TIGERA`/`CILIUM_OVERLAY`. OS images: `ubuntu`, `linux`, `rocky`.

## Struct-valued flags (shorthand `k=v,k2=v2` or JSON)

- `--auto-scale` → `autoScaleConfig` (int: `minSize`, `maxSize`)
- `--upgrade-config` → `upgradeConfig` (int: `maxSurge`, `maxUnavailable`; string `strategy`)
- `--placement-group` → `placementGroupConfigDto` (strings)
- `--auto-upgrade-config` → `autoUpgradeConfig` (`weekdays` — use JSON for multiple days; `time`)
- `--auto-healing-config` → `autoHealingConfig` (bool `enableAutoHealing`, int `timeoutUnhealthy`)
38 changes: 38 additions & 0 deletions go/cmd/vserver/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# vServer CLI — product notes

Tier-2 notes for the `grn vserver` command group. The root `CLAUDE.md` has the
repo-wide conventions; this file records what is specific to vServer.

## Client & endpoint (differs from vks)

- Build the client with **`vserverclient.BuildClient(cmd)`**, which returns
`(client, cfg, error)` — NOT `cli.NewClient`. Most helpers wrap it (see
`helpers.go` in each subpackage).
- Endpoint: `internal/config` REGIONS key `vserver_endpoint`
(`https://hcm-3.api.vngcloud.vn/vserver/vserver-gateway`).
- **`project_id` is required** and goes in the URL path. Get it via
`vserverclient.ProjectID(cfg)` (from `grn configure` or `GRN_DEFAULT_PROJECT_ID`);
it errors clearly if unset.

## API quirks (differ from vks — do not copy vks assumptions)

- **Pagination is 1-based**: params `page` (from **1**) + **`size`** (note: `size`,
not `pageSize`).
- Paths are under **`/v2/{projectID}/...`** (servers, volumes, networks, secgroups),
except **images** which are under `/v1/{projectID}/images/...`.
- Subnets carry both `uuid` and `id`; list/complete code prefers `uuid`, falling
back to `id`.

## Command style (differs from vks)

- vServer uses **noun-group + verb**: `grn vserver server create`, `volume delete`,
`secgroup rule create` — versus vks's flat `create-nodegroup`. Both satisfy the
conventions test (the leaf verb is canonical). Keep new vServer commands in this
nested style for consistency within the product.
- Destructive commands (`delete`, `server stop`/`reboot`) carry `--dry-run` +
`--force` (see the conventions test).

## Output

- List/detail commands render selected columns via `vserverclient.OutputWithColumns`
(see the per-subpackage `helpers.go` column definitions).
Loading