diff --git a/.claude/rules/git-rules.md b/.claude/rules/git-rules.md index 02384fa5c2..27e083fbf0 100644 --- a/.claude/rules/git-rules.md +++ b/.claude/rules/git-rules.md @@ -4,10 +4,15 @@ | Type | Format | Example | |---------|-------------------------------------|-------------------------------------| -| Feature | `feature/AND-xxx_short_description` | `feature/AND-13391_balance_fetcher` | -| Bugfix | `bugfix/AND-xxx_short_description` | `bugfix/AND-14000_fix_crash` | -| Release | `releases/x.xx` | `releases/5.36` | -| Hotfix | `releases/x.xx.x` | `releases/5.36.1` | +| Feature | `feature/AND-xxx_short_description` | `feature/AND-13391_balance_fetcher` | +| Bugfix | `bugfix/AND-xxx_short_description` | `bugfix/AND-14000_fix_crash` | +| Technical | `tech/short_description` | `tech/update_ci_scripts` | +| Release | `releases/x.xx` | `releases/5.36` | +| Hotfix | `releases/x.xx.x` | `releases/5.36.1` | + +**Technical (`tech/`) branches** are for chore / tooling work with **no Jira task** — CI, scripts, +build/config, docs, repo tooling. They carry **no `AND-xxx`** in the branch name, commit subject, or +PR title. **Key branches:** @@ -21,4 +26,6 @@ Format: `AND-xxx Description` - Start with the Jira task number (AND-xxx) - Followed by a space and a short description in English -- Example: `[REDACTED_TASK_KEY] Finalize CryptoCurrencyBalanceFetcher refactoring` \ No newline at end of file +- Example: `[REDACTED_TASK_KEY] Finalize CryptoCurrencyBalanceFetcher refactoring` +- **Technical (`tech/`) branches** have no Jira task, so their commit subject (and PR title) is just + the English description, with **no `AND-xxx` prefix** — e.g. `Update CI scripts`. \ No newline at end of file diff --git a/.claude/skills/create-pr/SKILL.md b/.claude/skills/create-pr/SKILL.md new file mode 100644 index 0000000000..7bd8630f2d --- /dev/null +++ b/.claude/skills/create-pr/SKILL.md @@ -0,0 +1,297 @@ +--- +name: create-pr +description: Open a GitHub pull request for the current work via the GitHub CLI (gh), following Tangem repo conventions — branch naming (feature/bugfix/AND-xxx), commit format (AND-xxx Description), base develop, required trailers. Picks which changes to include, creates a feature branch off a protected branch, commits, and — only after explicit confirmation — pushes and opens the PR. Use when the user asks to "open/create a PR", "создай ПР / пул-реквест", "open a pull request", "залей в PR". +allowed-tools: Read, Bash, AskUserQuestion, Monitor, TaskStop +argument-hint: [AND-xxxxx] [title...] [--base develop] [--dry-run] +--- + +Open a GitHub pull request for the current changes via `gh`, following this repo's conventions. + +This skill is **interactive** and runs locally. **Pushing and opening the PR happen ONLY after an +explicit confirmation gate (Phase 4)** — never push or create the PR before the user confirms. + +## Conventions + +**Source of truth: [`.claude/rules/git-rules.md`](../../rules/git-rules.md)** — read it for branch +naming (`feature/`, `bugfix/`, **`tech/`**, `releases/`), the `AND-xxx Description` commit/PR-title +format, and the technical-PR exception (no Jira task → no `AND-xxx` in branch/commit/title). Do not +restate or fork those rules here; follow git-rules.md so this skill can't drift from it. + +This skill only adds what is **not** in git-rules.md: + +| Thing | Rule | +|---|---| +| Default PR base | `develop` (hotfix → the relevant `releases/x.xx`) | +| Protected branches | `develop`, `releases/*` — never commit directly; always branch off (Phase 2) | +| Commit trailer | `Co-Authored-By: Claude Opus 4.8 (1M context) <[REDACTED_EMAIL]>` | +| PR body footer | `🤖 Generated with [Claude Code](https://claude.com/claude-code)` | +| Code comments | **No `AND-xxx`** in code/KDoc (fine in branch/commit/PR) | + +**Dry-run:** if `$ARGUMENTS` contains `--dry-run`, do everything except the writes — no branch +creation, no commit, no push, no `gh pr create`. Print the exact branch name, commit message, file +list, and `gh pr create` command that would run, then stop (see Phase 4D). + +## Phase 0 — Preflight + +Run these and stop with a clear FATAL message if any fails: + +1. `gh auth status` — GitHub CLI must be authenticated. If not: `FATAL: gh is not authenticated. Run 'gh auth login'.` +2. `git rev-parse --abbrev-ref HEAD` — current branch. `git status --porcelain` — working tree. +3. `git remote get-url origin` and the repo's default branch (`gh repo view --json defaultBranchRef -q .defaultBranchRef.name`) for reference. + +**Primary flow (default): branch + commit from existing local changes.** This skill takes the +**current uncommitted working-tree changes**, puts them on the right branch, commits, pushes, and +opens the PR. The target branch is decided by the **task** (Phase 1), not by whichever branch you +happen to be on: +- If the current branch is already the correct branch **for this task** (`feature/AND-xxxxx_…` / + `bugfix/…` / `tech/…` matching the resolved task), commit the pending changes onto it. +- Otherwise — on a protected branch (`develop`/`releases/*`) **or on another task's feature branch** — + create a new branch **off the base** (Phase 5 cuts it from `origin/` so the other branch's + commits don't ride along). Git keeps the uncommitted working-tree changes across this checkout. + +Never leave local changes uncommitted and PR only what was already committed — the pending changes +are the point. + +Fallback (no local changes): if `git status --porcelain` is empty **and** the current branch already +has commits ahead of the base that aren't PR'd, switch to a "PR an existing branch" flow — skip the +commit steps and go straight to push + PR. If the tree is empty and there are no un-PR'd commits +either, there is nothing to open a PR for — stop and say so. + +## Phase 1 — Gather inputs + +Parse `$ARGUMENTS` for an `AND-\d+` task id, a title, and `--base `. Ask only for what's +missing (use `AskUserQuestion` for constrained choices, plain text otherwise): + +- **Task id** (`AND-xxxxx`) — **mandatory** for branch/commit/PR naming. **Always ask the user which + task this PR is for** — never decide it silently. Every PR carries an `AND-xxxxx` **except** an + explicit **Technical PR** (the one no-task exception, described below); do not offer a generic + "no task / standalone" option outside that. You may pre-fill a *suggestion* (from `$ARGUMENTS`, or + an `AND-\d+` found in the current branch name) as the recommended answer, but the user must confirm + or override it. Do not assume the current branch's task id applies to the pending changes — they + are often unrelated (e.g. you're on another task's branch). If the user gives no valid `AND-\d+`, + keep asking — do not proceed without one. + + When asking, also offer a **"Create a new Jira Task"** option. If the user picks it, run the + **`create-jira-task`** skill (it creates the Task from the local changes), then use the newly + created `AND-xxxxx` as this PR's task id and continue. (Offer the Story-equivalent only if the work + clearly warrants a Story; default to a Task.) **In `--dry-run`, do NOT actually run + `create-jira-task`** — it's a real write; instead use a placeholder task id (e.g. `AND-NEW`) and + note that the Task would be created. + + Also offer a **"Technical PR"** option (the one exception to the mandatory-task rule): a chore / + tooling PR with **no Jira task**. If chosen, the change type becomes `tech`, the branch is + `tech/` (no `AND-xxxxx`), and the commit subject + PR title have **no `AND-xxxxx` prefix** + (just the plain English title). + + Options to present: the suggested existing key (if any), **Create a new Jira Task**, **Technical + PR**, and free-text Other for an existing key. Outside of the Technical PR choice, never proceed + without a valid `AND-\d+`. +- **Title** (English, required) — the PR/commit description. If absent, propose one generated from + the staged/working changes (`git diff --stat`, `git log`) and ask the user to approve or edit. + Must be English. +- **Change type** — `feature`, `bugfix`, or `tech` (drives the branch prefix). `tech` is set + automatically when the user chose the **Technical PR** option above. Otherwise infer from the + title/task; default `feature`. +- **Base branch** — default `develop`. Only change for hotfixes (`releases/x.xx`). Ask only if the + current branch is itself a `releases/*` branch (then the base is likely that release line). +- **Files to include** — show `git status --porcelain` and let the user choose. Default to all + tracked changes **except** unrelated submodule pointer bumps and stray edits; call out anything + you exclude. If the user named specific files in `$ARGUMENTS` / the prompt (e.g. via `@path`), + include exactly those. + +## Phase 1b — Classify complexity & choose labels + +Every PR gets exactly **one complexity label**. Count the **files chosen in Phase 1** (the planned +PR contents — not `git diff --cached`, since nothing is staged until Phase 5) and judge the nature of +the change. Propose a level +(via `AskUserQuestion`, recommending the one you judged) and let the user confirm or override: + +| Label | Level | When | File limit | +|---|---|---|---| +| `deep` | 🔴 Red | Complex changes, or touching important/core logic | **≤ 15 files** | +| `complex` | 🟡 Yellow | Not deep and/or does not touch important core logic | **≤ 20 files** | +| `easy` | ⚪ White | Uniform/mechanical changes (rename, package move, formatting) | **no limit** | + +Rules: +1. **Over the limit** → the PR body **must** include an explanation/justification of why the change + could not be split or kept smaller. If the count exceeds the level's limit, ask the user for that + justification and append it to the PR body under a `## Why this exceeds the