From 7ffc6a963655d599ec1d06f8901290daa1ab4bfb Mon Sep 17 00:00:00 2001 From: its-mitesh-kumar Date: Fri, 3 Jul 2026 20:26:35 +0530 Subject: [PATCH 1/4] feat: add raise-pr skill for automated PR workflows (v0.7.0) Signed-off-by: its-mitesh-kumar --- .claude-plugin/marketplace.json | 4 +- .claude-plugin/plugin.json | 2 +- README.md | 6 + pyproject.toml | 2 +- skills/raise-pr/SKILL.md | 201 ++++++++++++++++++++ skills/raise-pr/references/repo-profiles.md | 67 +++++++ uv.lock | 2 +- 7 files changed, 279 insertions(+), 5 deletions(-) create mode 100644 skills/raise-pr/SKILL.md create mode 100644 skills/raise-pr/references/repo-profiles.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 14efd96..f5016f9 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -5,14 +5,14 @@ }, "metadata": { "description": "Orchestrator skill for RHDH plugin development - onboard, update, and maintain plugins in the Extensions Catalog", - "version": "0.6.1" + "version": "0.7.0" }, "plugins": [ { "name": "rhdh", "source": "./", "description": "Skills for RHDH plugin lifecycle management", - "version": "0.6.1", + "version": "0.7.0", "strict": true } ] diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index ec8a1cd..f4ba7f1 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "rhdh", "description": "All-in-one toolkit for Red Hat Developer Hub (RHDH). Covers plugin development, overlay management, environment setup, version compatibility, CI/CD, and RHDH ecosystem navigation.", - "version": "0.6.1", + "version": "0.7.0", "author": { "name": "RHDH Store Manager" }, diff --git a/README.md b/README.md index 13766c3..106d411 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,12 @@ Track work across the four RHDH Jira projects. - **[to-issue](./skills/rhdh-jira/references/to-issue.md)** — Create a Story, Task, Bug, or Spike with automatic type inference. Grills on implementation details and story points. - **[update-jira-status](./skills/rhdh-jira/references/update-jira-status.md)** — Update an issue with session progress. Detects the related issue, adds a status comment, proposes transitions, and checks upward cascade to parent Epic/Feature. +### PR Workflow + +Automate the full PR lifecycle — build, changeset, commit, push, and create — for plugin monorepos. + +- **[raise-pr](./skills/raise-pr/SKILL.md)** — Full PR workflow for `rhdh-plugins` and `community-plugins`: detect workspace from staged changes, run build/validation, generate changesets, commit with sign-off, push, and create the GitHub PR. Auto-detects which repo you're in. Supports `--a` auto-approve mode to skip all approval gates. + ### PR Review - **[rhdh-pr-review](./skills/rhdh-pr-review/SKILL.md)** — PR code review with inline comments (GitHub, GitLab planned) and live cluster testing for rhdh-operator PRs. Layered architecture: fetch → analyze → post. diff --git a/pyproject.toml b/pyproject.toml index f76fce1..e50f84b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "rhdh-skill" -version = "0.6.1" +version = "0.7.0" description = "Claude Code skill for RHDH plugin development" readme = "README.md" license = "Apache-2.0" diff --git a/skills/raise-pr/SKILL.md b/skills/raise-pr/SKILL.md new file mode 100644 index 0000000..1d48815 --- /dev/null +++ b/skills/raise-pr/SKILL.md @@ -0,0 +1,201 @@ +--- +name: raise-pr +description: > + Automate the full PR workflow for rhdh-plugins and community-plugins monorepos: + detect workspace, build, generate changeset, commit, push, and create the GitHub PR. + Auto-detects which repo you're in. Supports --a auto-approve mode to skip all + approval gates. Use when asked to "raise a PR", "create a PR", "submit a PR", + "open a PR", "push my changes", "make a PR for this plugin", or "PR workflow". + Also use when user says "raise pr", "/pr", or mentions creating a pull request + in rhdh-plugins or community-plugins. +--- + + + + +Pre-build cleanup uses `rm -rf plugins/*/dist packages/*/dist` scoped to the workspace directory. If permission errors occur, escalate to `sudo`. Never use `find -name dist` or any broad recursive search — that deletes `dist/` inside `node_modules` and breaks everything. + + + +Only plugins under `plugins/*` with published-source changes need changesets. Always ignore `packages/*` — those are private app/backend packages that are never published. Within each plugin, only include it if changes touch `src/` or other published paths (root `index.ts`, `config.d.ts`, `package.json`). Changes only in `dev/`, `tests/`, `__fixtures__/`, or storybook stories do not require a changeset. + + + +Capture `git status --porcelain` before builds as the baseline. After builds, only stage files that are new relative to that baseline. Pre-existing dirty files (local config overrides, dev fixtures) must never be staged. + + + + +## Mode: check for `--a` flag + +Check if the user invoked this skill with `--a` (auto-approve mode). + +- **`--a` present:** All approval gates (Steps 4, 8, and 9) are skipped — proceed automatically. +- **`--a` absent (default):** Approval gates require user confirmation before proceeding. + +--- + +## Step 1 — Detect repo profile + +Read `references/repo-profiles.md` and follow the detection logic. Run `git remote -v`, match the remote URLs, and load the matching profile (upstream repo, npm scope, PR body template, changeset docs link). + +If no profile matches, ask the user which repo they are targeting before proceeding. + +Store the profile values for use in Steps 5, 6, and 10. + +--- + +## Step 2 — Detect workspace(s) from staged changes + +1. Run `git diff --cached --name-only` to list all staged files. +2. If no files are staged, stop: "No staged changes found. Stage your changes with `git add` before running this command." +3. Extract workspace names from staged file paths. The workspace is the second path segment (e.g., `workspaces/bulk-import/plugins/foo/src/index.ts` → workspace `bulk-import`, path `workspaces/bulk-import`). +4. If staged files span **multiple** workspaces, inform the user: "Changes detected in **N** workspace(s): ``. Proceed? (Yes/No)". Wait for confirmation. If declined, stop. +5. Store the workspace names and paths for later steps. + +--- + +## Step 3 — Capture baseline snapshot + +Run `git status --porcelain` and save the full output as the **baseline snapshot**. This captures all files that were already dirty or untracked before any build commands run. Used in Step 7 to filter out pre-existing changes. + +--- + +## Step 4 — Create branch (only if on `main`) [APPROVAL GATE] + +1. Run `git branch --show-current`. +2. **If on `main`:** + a. Analyze the staged diff (`git diff --cached`) to understand the changes. + b. Generate a branch name: `feat/-` (use `fix/` for bug fixes). For multiple workspaces, use a general description. + c. **If NOT auto-approve:** present the proposed branch name and a one-line summary. Wait for approval. **If auto-approve:** proceed immediately. + d. Run `git checkout -b `. +3. **If NOT on `main`:** skip branch creation. Inform the user: "Already on branch ``, skipping branch creation." + +--- + +## Step 5 — Build and validate each workspace + +For **each** workspace from Step 2, run the following commands **sequentially** inside the workspace directory (e.g., `workspaces/bulk-import`). If any command fails, **stop immediately** and report the error with the failing command, workspace, and output. + +### 5.0 — Pre-build cleanup + +Remove stale `dist/` directories that may contain root-owned files from previous Docker or sudo builds: + +``` +rm -rf plugins/*/dist packages/*/dist +``` + +If this fails with a permission error (`EACCES`), escalate to: + +``` +sudo rm -rf plugins/*/dist packages/*/dist +``` + +### 5.1–5.6 — Build pipeline + +Run in order: + +1. `yarn` — install dependencies +2. `yarn prettier:fix` — format code +3. `yarn tsc:full` — full TypeScript type check +4. `yarn build:all` — build all packages +5. `yarn test --watchAll=false` — run tests (disable Jest watch mode) +6. `yarn build:api-reports:only` — generate/update API reports + +--- + +## Step 6 — Generate changeset per workspace + +For **each** workspace from Step 2, generate a changeset programmatically. Use the npm scope from the detected repo profile (Step 1). + +1. From the staged diff (`git diff --cached`), determine: + - Which **plugins** under this workspace are affected (look at `plugins/*` only — **ignore `packages/*`**). + - Within each plugin, only include it if changes touch published paths (`src/`, root `index.ts`, `config.d.ts`, `package.json`). Skip plugins with changes only in `dev/`, `tests/`, `__fixtures__/`, or stories. + - Read each affected plugin's `package.json` for its npm package name. + - Infer the semver bump: `patch` for fixes, `minor` for features, `major` for breaking changes. + - **If no plugins have published-source changes, skip changeset generation for this workspace.** +2. Generate a short summary (1-2 sentences). +3. Generate a random changeset ID: `--` pattern, lowercase, 5-8 chars per word. Each workspace gets a unique ID. +4. Write the changeset file to `/.changeset/.md`: + +``` +--- +'': +--- + + +``` + +If multiple packages are affected, list each on its own YAML line. + +**Do NOT run `yarn changeset` interactively.** Create files programmatically. + +--- + +## Step 7 — Identify build-generated files + +1. Run `git status --porcelain` for the **current snapshot**. +2. Compare against the **baseline snapshot** from Step 3. +3. Files only in the current snapshot are build-generated (created by Step 5 builds or Step 6 changesets). +4. Files already in the baseline are pre-existing — exclude them from staging. + +--- + +## Step 8 — Stage build-generated files [APPROVAL GATE] + +1. Present the filtered list of build-generated files from Step 7. +2. **If NOT auto-approve:** ask the user for approval before staging. **If auto-approve:** stage all automatically. +3. Run `git add` for each approved file. + +--- + +## Step 9 — Commit [APPROVAL GATE] + +1. Run `git diff --cached --stat` to review all staged changes. +2. Generate a commit message in conventional commit format: `(): ` (e.g., `feat(bulk-import): add batch repository import support`). +3. **If NOT auto-approve:** present the commit message and staged file summary. Wait for approval. **If auto-approve:** commit immediately. +4. Commit with the **`-s` flag** (Signed-off-by): + +``` +git commit -s -m "" +``` + +--- + +## Step 10 — Push and create PR + +1. Push the branch: + +``` +git push -u origin HEAD +``` + +2. Generate a PR title from the commit message. +3. Create the PR using `gh pr create` with the repo-appropriate template from the detected profile (Step 1). Use the upstream repo value for `--repo` and `main` for `--base`. Pass the body via HEREDOC: + +``` +gh pr create --repo --base main --title "" --body "$(cat <<'EOF' +<PR body from detected profile — fill in generated description> +EOF +)" +``` + +4. Display the PR URL as the final output. + +--- + +## Gotchas + +- **Fork workflows:** The user may have `origin` pointing to their fork and `upstream` to the canonical repo. Detection checks all remotes, not just `origin`. The `--repo` flag on `gh pr create` targets the canonical upstream regardless of which remote `origin` points to. +- **Multiple workspaces:** Each workspace gets its own build cycle (Step 5) and changeset (Step 6). The commit (Step 9) bundles everything into one commit. If the user prefers separate PRs per workspace, they should stage and run the skill once per workspace. +- **Changeset ID collisions:** Each workspace must get a unique random ID. If generating for multiple workspaces in one run, track used IDs and avoid duplicates. + +<reference_index> + +## Reference Index + +| Reference | Load when... | +|-----------|-------------| +| `references/repo-profiles.md` | Always — at the start of every invocation (Step 1) | + +</reference_index> diff --git a/skills/raise-pr/references/repo-profiles.md b/skills/raise-pr/references/repo-profiles.md new file mode 100644 index 0000000..325c877 --- /dev/null +++ b/skills/raise-pr/references/repo-profiles.md @@ -0,0 +1,67 @@ +# Repo Profiles + +Auto-detect which repository you are in and load the matching profile. Read this file at the start of every `raise-pr` invocation. + +## Detection + +Run `git remote -v` and inspect all remote URLs (fetch lines). Match against the patterns below. If multiple remotes exist (e.g. `origin` pointing to a fork and `upstream` pointing to the canonical repo), prefer the canonical match. + +| URL pattern | Profile | +|-------------|---------| +| Contains `rhdh-plugins` (but NOT `community-plugins`) | **rhdh-plugins** | +| Contains `community-plugins` | **community-plugins** | +| Neither matches | Ask the user: "Which repo are you targeting? (1) rhdh-plugins (2) community-plugins" | + +## Profile: rhdh-plugins + +| Field | Value | +|-------|-------| +| Upstream repo | `redhat-developer/rhdh-plugins` | +| npm scope | `@red-hat-developer-hub` | +| Changeset `fixed` group | `["@red-hat-developer-hub/*"]` | +| Changeset docs link | `https://github.com/redhat-developer/rhdh-plugins/blob/main/CONTRIBUTING.md#creating-changesets` | +| PR base branch | `main` | +| Commit signing | `-s` (Signed-off-by) | + +### PR body template (rhdh-plugins) + +``` +## Description +<generated description — 2-4 sentences explaining what changed and why> + +## Fixed +- <Jira link — ask the user, or leave as TODO> + +## Checklist +- [x] A changeset describing the change and affected packages. ([more info](https://github.com/redhat-developer/rhdh-plugins/blob/main/CONTRIBUTING.md#creating-changesets)) +- [ ] Added or Updated documentation +- [ ] Tests for new functionality and regression tests for bug fixes +- [ ] Screenshots attached (for UI changes) +``` + +## Profile: community-plugins + +| Field | Value | +|-------|-------| +| Upstream repo | `backstage/community-plugins` | +| npm scope | `@backstage-community` | +| Changeset `fixed` group | `[]` (no fixed versioning) | +| Changeset docs link | `https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md#creating-changesets` | +| PR base branch | `main` | +| Commit signing | `-s` (Signed-off-by — DCO required) | + +### PR body template (community-plugins) + +``` +## Hey, I just made a Pull Request! + +<generated description — 2-4 sentences explaining what changed and why> + +#### Checklist + +- [x] A changeset describing the change and affected packages. ([more info](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md#creating-changesets)) +- [ ] Added or updated documentation +- [ ] Tests for new functionality and regression tests for bug fixes +- [ ] Screenshots attached (for UI changes) +- [x] All your commits have a `Signed-off-by` line in the message. ([more info](https://github.com/backstage/backstage/blob/master/CONTRIBUTING.md#developer-certificate-of-origin)) +``` diff --git a/uv.lock b/uv.lock index 8d77fb0..86223f5 100644 --- a/uv.lock +++ b/uv.lock @@ -195,7 +195,7 @@ wheels = [ [[package]] name = "rhdh-skill" -version = "0.5.0" +version = "0.7.0" source = { virtual = "." } [package.optional-dependencies] From 273e47af2f17067ce62fb481866d74943172b725 Mon Sep 17 00:00:00 2001 From: its-mitesh-kumar <itsmiteshkumar98@gmail.com> Date: Sat, 4 Jul 2026 02:44:27 +0530 Subject: [PATCH 2/4] addign bugfix skill Signed-off-by: its-mitesh-kumar <itsmiteshkumar98@gmail.com> --- README.md | 8 +- skills/bug-fix/SKILL.md | 230 +++++++++++++++++++ skills/bug-fix/references/e2e-patterns.md | 196 ++++++++++++++++ skills/bug-fix/references/video-recording.md | 143 ++++++++++++ skills/bug-fix/references/workspace-map.md | 81 +++++++ skills/raise-pr/SKILL.md | 137 ++++++++++- skills/raise-pr/references/jira-input.md | 129 +++++++++++ skills/raise-pr/references/repo-profiles.md | 18 +- 8 files changed, 927 insertions(+), 15 deletions(-) create mode 100644 skills/bug-fix/SKILL.md create mode 100644 skills/bug-fix/references/e2e-patterns.md create mode 100644 skills/bug-fix/references/video-recording.md create mode 100644 skills/bug-fix/references/workspace-map.md create mode 100644 skills/raise-pr/references/jira-input.md diff --git a/README.md b/README.md index 106d411..46ecd67 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,13 @@ Track work across the four RHDH Jira projects. Automate the full PR lifecycle — build, changeset, commit, push, and create — for plugin monorepos. -- **[raise-pr](./skills/raise-pr/SKILL.md)** — Full PR workflow for `rhdh-plugins` and `community-plugins`: detect workspace from staged changes, run build/validation, generate changesets, commit with sign-off, push, and create the GitHub PR. Auto-detects which repo you're in. Supports `--a` auto-approve mode to skip all approval gates. +- **[raise-pr](./skills/raise-pr/SKILL.md)** — Full PR workflow for `rhdh-plugins` and `community-plugins`: detect workspace from staged changes, run build/validation, generate changesets, commit with sign-off, push, and create the GitHub PR. Auto-detects which repo you're in. Supports `--a` auto-approve mode to skip all approval gates. Accepts an optional Jira key or URL to link the PR — adds Web Link, comment, and transitions the issue to Review. + +### Bug Fix + +Reproduce, diagnose, fix, and PR RHDH plugin bugs from Jira tickets with automated Playwright-based before/after screen recordings. + +- **[bug-fix](./skills/bug-fix/SKILL.md)** — End-to-end bug fix workflow: fetch Jira issue, map component to workspace, write Playwright reproduction test with video recording, diagnose root cause, apply fix, verify, and create PR with before/after recordings embedded. Chains into `raise-pr` for the full PR lifecycle including post-PR Jira updates. ### PR Review diff --git a/skills/bug-fix/SKILL.md b/skills/bug-fix/SKILL.md new file mode 100644 index 0000000..00914ca --- /dev/null +++ b/skills/bug-fix/SKILL.md @@ -0,0 +1,230 @@ +--- +name: bug-fix +description: > + Reproduce, diagnose, fix, and PR RHDH plugin bugs from Jira tickets using + Playwright e2e tests with before/after screen recordings. Accepts a Jira key + (RHDHBUGS-1934), Jira URL (redhat.atlassian.net/browse/...), or a request to + "fix this bug", "reproduce and fix", "/bug-fix". Chains into raise-pr for the + full PR lifecycle including post-PR Jira updates (Web Link, comment, transition + to Review). +--- + +<essential_principles> + +<principle name="repro_test_is_temporary"> +The reproduction test (`_repro-<KEY>.test.ts`) is a diagnostic tool, not a deliverable. It is deleted before staging. It must never appear in the PR. +</principle> + +<principle name="runtime_discovery"> +Do not hardcode workspace internals. Discover each workspace's e2e infrastructure at runtime by reading its `playwright.config.ts`, `e2e-tests/utils/`, and `plugins/*/src/translations/ref.ts`. The `references/workspace-map.md` maps Jira components to workspace directories, but everything else is discovered dynamically. +</principle> + +<principle name="video_evidence"> +Every bug fix PR must include before/after visual evidence. Playwright video recording captures the bug in action (before) and the fix working (after). These are converted to GIFs and embedded in the PR description. +</principle> + +</essential_principles> + +## Prerequisites + +- Working checkout of `rhdh-plugins` (or `community-plugins`) +- `yarn` available on PATH +- `ffmpeg` available on PATH (for video conversion; fall back to raw `.webm` if absent) +- Jira auth configured (`.jira-token` next to `acli` binary, or Jira MCP in Cursor) + +--- + +## Step 1 — Fetch Jira issue and parse details + +Read `references/workspace-map.md` for the Jira component-to-workspace mapping. + +1. Parse the Jira reference from the user's input. Follow the parsing rules in `raise-pr/references/jira-input.md`: + - Bare key: `RHDHBUGS-1934` + - Browse URL: `https://redhat.atlassian.net/browse/RHDHBUGS-1934` + - URL without scheme: `redhat.atlassian.net/browse/RHIDP-15252` +2. Fetch the full issue details using the Jira REST API or MCP (`read_jira_issue`): + - Summary, description, steps to reproduce + - Component field (maps to workspace) + - Status (for post-PR transition) + - Attachments/screenshots (visual reference for reproduction) +3. Store: `jira_key`, `jira_url`, `jira_summary`, `jira_description`, `jira_component`, `jira_status` + +**If the description has no clear steps to reproduce**: ask the user to provide reproduction steps before proceeding. + +--- + +## Step 2 — Identify workspace and discover e2e infrastructure + +1. Map the Jira **Component** field to a workspace directory using `references/workspace-map.md`. + - If no component is set or the component is unknown: ask the user which workspace to target. +2. Navigate to the workspace: `cd workspaces/<workspace-dir>` +3. **Discover e2e infrastructure dynamically**: + - Read `playwright.config.ts` for port configuration, locale list, start commands, and `APP_MODE` support. + - Scan `e2e-tests/utils/` to discover available helper functions (translations, navigation, API mocking, accessibility). + - Read `plugins/*/src/translations/ref.ts` for translation key structure (used for i18n-safe selectors). + - Read `plugins/*/src/components/` to build a component-to-source-file map. +4. Run `yarn install` if `node_modules` is missing or stale. + +**If the workspace has no `playwright.config.ts`**: fall back to a screenshot-only approach — skip video recording and use DOM assertions or manual screenshots instead. + +Read `references/e2e-patterns.md` for shared Playwright patterns across all rhdh-plugins workspaces. + +--- + +## Step 3 — Write reproduction test with video recording + +Read `references/e2e-patterns.md` for test patterns and `references/video-recording.md` for video configuration. + +1. Create a temporary test file: `e2e-tests/_repro-<JIRA-KEY>.test.ts` + - The `_` prefix signals this file is temporary and should not be committed. +2. The test must: + - Import workspace-specific helpers discovered in Step 2. + - Use i18n-safe selectors (via translation keys) where available. + - Configure video recording per-test: + ```typescript + test.use({ + video: { mode: 'on', size: { width: 1280, height: 720 } }, + }); + ``` + - Encode the "steps to reproduce" from the Jira description as Playwright actions. + - Assert the **expected** behavior (the assertion should fail when the bug is present). +3. Run the test against the `en` locale in legacy mode: + ``` + APP_MODE=legacy npx playwright test e2e-tests/_repro-<KEY>.test.ts --project=en + ``` +4. The test should **fail** — confirming the bug is reproduced. + +**If the test passes** (bug not reproduced): re-read the Jira description, adjust the test, and retry. If still not reproducible after 2 attempts, report findings and ask the user for guidance. + +--- + +## Step 4 — Capture "before" recording + +1. After the failed test run (Step 3), locate the video file in `test-results/`. + - Playwright saves videos at `test-results/<test-title>/video.webm`. +2. Copy the video to a stable path: + ``` + mkdir -p e2e-tests/_repro-artifacts + cp test-results/*/video.webm e2e-tests/_repro-artifacts/before-fix.webm + ``` +3. Store the path for later conversion (Step 7). + +--- + +## Step 5 — Diagnose and fix + +1. **Diagnose**: trace from the failing Playwright selector back to the source: + - Identify which React component renders the UI element under test. + - Read the component source code (`plugins/*/src/components/`). + - Identify the root cause (e.g., MUI prop misconfiguration, missing state update, CSS issue, accessibility gap, i18n key mismatch). +2. **Apply the fix** in the source code. +3. **Validate**: + - `yarn tsc:full` — type check passes. + - `yarn test --watchAll=false` — unit tests pass. + +**Confidence gates** — ask the user before proceeding if: +- Multiple possible root causes exist — present options and let the user choose. +- The fix touches more than 3 files — show the plan and get approval. +- The fix changes API surface or public types — this may need a minor version bump. + +--- + +## Step 6 — Capture "after" recording + +1. Re-run the reproduction test: + ``` + APP_MODE=legacy npx playwright test e2e-tests/_repro-<KEY>.test.ts --project=en + ``` +2. The test should **pass** — confirming the fix works. +3. Copy the video: + ``` + cp test-results/*/video.webm e2e-tests/_repro-artifacts/after-fix.webm + ``` +4. Optionally run in NFS mode as well to check for mode-specific regressions: + ``` + APP_MODE=nfs npx playwright test e2e-tests/_repro-<KEY>.test.ts --project=en + ``` + +**If the test still fails after the fix**: re-examine the diagnosis and iterate. + +--- + +## Step 7 — Convert videos for PR embedding + +Read `references/video-recording.md` for conversion details. + +1. Check if `ffmpeg` is available on PATH. +2. **If available**: convert `.webm` to `.gif`: + ``` + ffmpeg -i e2e-tests/_repro-artifacts/before-fix.webm -vf "fps=10,scale=800:-1" -loop 0 e2e-tests/_repro-artifacts/before-fix.gif + ffmpeg -i e2e-tests/_repro-artifacts/after-fix.webm -vf "fps=10,scale=800:-1" -loop 0 e2e-tests/_repro-artifacts/after-fix.gif + ``` +3. **If `ffmpeg` is not available**: keep the `.webm` files and note that they will be uploaded as PR comment attachments instead of inline GIFs. + +--- + +## Step 8 — Clean up and create PR + +### 8.1 — Delete temporary files + +Remove the reproduction test and artifacts — these must not appear in the PR: + +``` +rm e2e-tests/_repro-<KEY>.test.ts +rm -rf test-results/ +``` + +Keep `e2e-tests/_repro-artifacts/` temporarily (needed for PR image upload). + +### 8.2 — Stage fix files + +Stage only the code fix (not the repro test or artifacts): + +``` +git add <fixed-source-files> +``` + +### 8.3 — Chain into raise-pr + +Invoke `raise-pr --a` with the following caller context: + +| Field | Value | +|-------|-------| +| `jira_key` | The resolved Jira key from Step 1 | +| `jira_url` | `https://redhat.atlassian.net/browse/<jira_key>` | +| `jira_summary` | Issue summary from Step 1 | +| `recordings` | `{ before: "e2e-tests/_repro-artifacts/before-fix.gif", after: "e2e-tests/_repro-artifacts/after-fix.gif" }` | +| `pr_description_extra` | `**Root cause:** <diagnosis from Step 5>` | + +`raise-pr` handles: repo detection, build, changeset, commit (with `Fixes:` trailer), push, PR creation (with `## UI before/after changes`), and post-PR Jira updates (Web Link, comment, transition to Review). + +### 8.4 — Final cleanup + +After the PR is created, delete the artifacts directory: + +``` +rm -rf e2e-tests/_repro-artifacts/ +``` + +--- + +## When NOT to Use + +- **Backend-only bugs** — if the bug has no UI component, there is nothing to video-record. Use standard debugging and fix workflows instead. +- **Bugs requiring live backend data** — if reproduction depends on real API responses that cannot be mocked via the workspace's e2e test infrastructure. +- **Cross-workspace bugs** — if the fix requires changes across multiple workspaces, handle each workspace separately or use `raise-pr` directly. +- **Non-RHDH Jira projects** — this skill's workspace mapping is specific to `rhdh-plugins` workspaces and RHDH Jira projects (RHIDP, RHDHBUGS, RHDHPLAN, RHDHSUPP). + +<reference_index> + +## Reference Index + +| Reference | Load when... | +|-----------|-------------| +| `references/workspace-map.md` | Always — at the start of every invocation (Step 1-2) | +| `references/e2e-patterns.md` | When writing the reproduction test (Step 3) | +| `references/video-recording.md` | When configuring video capture (Step 3) and converting videos (Step 7) | +| `raise-pr/references/jira-input.md` | When parsing Jira keys/URLs (Step 1) — shared with raise-pr | +| `raise-pr/references/repo-profiles.md` | Loaded by raise-pr during Step 8.3 chain | + +</reference_index> diff --git a/skills/bug-fix/references/e2e-patterns.md b/skills/bug-fix/references/e2e-patterns.md new file mode 100644 index 0000000..e8c616f --- /dev/null +++ b/skills/bug-fix/references/e2e-patterns.md @@ -0,0 +1,196 @@ +# E2E Patterns: Shared Playwright Infrastructure + +Common patterns across all `rhdh-plugins` workspaces. Reference this when writing reproduction tests (Step 3). + +## Shared Architecture + +All workspaces with e2e tests follow the same structure: + +``` +workspaces/<workspace>/ +├── playwright.config.ts # Multi-locale, dual-mode config +├── e2e-tests/ +│ ├── *.test.ts # Test files +│ └── utils/ +│ ├── translations.ts # i18n helper +│ ├── *Helpers.ts # Workspace-specific helpers +│ ├── accessibility.ts # a11y testing +│ └── localeSkip.ts # Locale skip logic +├── app-config.yaml # Base Backstage config +└── e2e-tests/test_yamls/ # Per-locale test configs +``` + +## Multi-Locale Setup + +All workspaces use the same 6 locales: + +```typescript +const LOCALES = ['en', 'de', 'es', 'fr', 'it', 'ja'] as const; +``` + +Each locale gets its own frontend and backend port: + +```typescript +const FRONTEND_PORT_BASE = 3000; // en=3000, de=3001, es=3002, ... +const BACKEND_PORT_BASE = 7007; // en=7007, de=7008, es=7009, ... +``` + +**For reproduction tests**: always run against `en` only (fastest feedback): + +``` +APP_MODE=legacy npx playwright test e2e-tests/_repro-<KEY>.test.ts --project=en +``` + +## Dual-Mode (APP_MODE) + +All workspaces support two frontend modes via the `APP_MODE` environment variable: + +- `legacy` (default) — uses `packages/app-legacy` or `yarn start:legacy` +- `nfs` — uses the New Frontend System via `packages/app` or `yarn start` + +The `playwright.config.ts` reads this: + +```typescript +const appMode = process.env.APP_MODE || 'legacy'; +const startCommand = appMode === 'legacy' ? 'yarn start:legacy' : 'yarn start'; +``` + +**For reproduction**: run legacy first. After the fix, verify both modes. + +## Translation Helpers + +Most workspaces have a `getTranslations()` helper that loads the plugin's translation keys for the current locale. Use these for i18n-safe selectors: + +```typescript +import { getTranslations, type InsightsMessages } from './utils/translations.js'; + +test.beforeAll(async ({ browser }) => { + const translations = getTranslations(locale); + // Use translations.header.title instead of hardcoded "Adoption Insights" +}); +``` + +**Why**: hardcoded English strings break in non-`en` locales. Always use translation keys when available. + +## Common Playwright Selectors + +Prefer accessibility-first selectors: + +```typescript +// Role-based (best) +page.getByRole('button', { name: 'Submit' }) +page.getByRole('combobox') +page.getByRole('listbox') +page.getByRole('tab', { name: translations.tabs.overview }) + +// Text-based (good for translated text) +page.getByText(translations.header.dateRange.defaultLabel) + +// Test ID (fallback) +page.getByTestId('date-range-select') + +// CSS selector (last resort) +page.locator('.MuiSelect-root') +``` + +## Waiting Patterns + +```typescript +// Wait for navigation to complete +await page.waitForURL('**/adoption-insights'); + +// Wait for network idle +await page.waitForLoadState('networkidle'); + +// Wait for specific element +await expect(page.getByRole('heading', { name: title })).toBeVisible(); + +// Custom wait for data flush +await waitForDataFlush(); // workspace-specific helper +``` + +## MUI Component Patterns + +Many rhdh-plugins use Material-UI. Common interaction patterns: + +```typescript +// MUI Select (dropdown) +const select = page.getByText(translations.header.dateRange.defaultLabel).first(); +await select.click(); +const listbox = page.getByRole('listbox'); +await expect(listbox).toBeVisible(); + +// MUI Select with keyboard +await page.keyboard.press('ArrowDown'); +const focused = listbox.locator(':focus'); +await expect(focused).toHaveCount(1); +await page.keyboard.press('Enter'); + +// MUI Tab +await page.getByRole('tab', { name: 'Details' }).click(); + +// MUI Table +const rows = page.getByRole('row'); +await expect(rows).toHaveCount(expectedCount); +``` + +## Repro Test Template + +Use this skeleton for reproduction tests: + +```typescript +import { test, expect, Page, BrowserContext } from '@playwright/test'; + +test.use({ + video: { mode: 'on', size: { width: 1280, height: 720 } }, +}); + +test.describe('Repro: <JIRA-KEY> — <short description>', () => { + let page: Page; + let context: BrowserContext; + + test.beforeAll(async ({ browser }) => { + context = await browser.newContext(); + page = await context.newPage(); + // Navigate to the relevant page + }); + + test.afterAll(async () => { + await context.close(); + }); + + test('<expected behavior that currently fails>', async () => { + // Steps to reproduce from Jira + // ... + // Assertion that should pass when the bug is fixed + }); +}); +``` + +## Running a Single Test + +```bash +# Legacy mode, en locale only (fastest for reproduction) +APP_MODE=legacy npx playwright test e2e-tests/_repro-<KEY>.test.ts --project=en + +# NFS mode (for verification after fix) +APP_MODE=nfs npx playwright test e2e-tests/_repro-<KEY>.test.ts --project=en + +# With headed browser (for debugging) +APP_MODE=legacy npx playwright test e2e-tests/_repro-<KEY>.test.ts --project=en --headed + +# With trace (for detailed debugging) +APP_MODE=legacy npx playwright test e2e-tests/_repro-<KEY>.test.ts --project=en --trace on +``` + +## Common yarn Scripts + +All workspaces follow the same script naming: + +```bash +yarn test:e2e:legacy # APP_MODE=legacy playwright test +yarn test:e2e:nfs # APP_MODE=nfs playwright test +yarn test:e2e:all # Run both modes +yarn tsc:full # Full TypeScript type check +yarn test --watchAll=false # Unit tests (no watch mode) +``` diff --git a/skills/bug-fix/references/video-recording.md b/skills/bug-fix/references/video-recording.md new file mode 100644 index 0000000..cbc5ed5 --- /dev/null +++ b/skills/bug-fix/references/video-recording.md @@ -0,0 +1,143 @@ +# Video Recording: Playwright Capture & Conversion + +How to capture before/after screen recordings for bug fix PRs. Reference this in Steps 3, 4, 6, and 7. + +## Playwright Video Configuration + +Configure video recording per-test using `test.use()`: + +```typescript +test.use({ + video: { + mode: 'on', + size: { width: 1280, height: 720 }, + }, +}); +``` + +- **`mode: 'on'`** — record every test run (not `retain-on-failure`, because we want the "before" video even though the test fails). +- **`size`** — 1280x720 gives good quality at reasonable file size. Matches most laptop viewports. + +All rhdh-plugins workspaces use `@playwright/test` >= 1.60.0, which supports this config. + +## Where Videos Land + +Playwright saves videos to the `test-results/` directory inside the workspace: + +``` +workspaces/<workspace>/test-results/ +└── <test-describe-title>-<test-title>-<browser>/ + └── video.webm +``` + +The exact path depends on the test title. After running, find the video: + +```bash +find test-results -name "video.webm" -type f +``` + +## Capturing Before/After Videos + +### Before fix (Step 4) + +After the reproduction test **fails** (bug is present): + +```bash +mkdir -p e2e-tests/_repro-artifacts +cp test-results/*/video.webm e2e-tests/_repro-artifacts/before-fix.webm +``` + +### After fix (Step 6) + +Clean the test results first, then re-run: + +```bash +rm -rf test-results/ +APP_MODE=legacy npx playwright test e2e-tests/_repro-<KEY>.test.ts --project=en +cp test-results/*/video.webm e2e-tests/_repro-artifacts/after-fix.webm +``` + +## Converting to GIF + +GitHub PR descriptions support inline images (PNG, GIF, JPEG) but NOT inline `.webm` video. Convert to GIF for embedding. + +### With ffmpeg (recommended) + +```bash +ffmpeg -i e2e-tests/_repro-artifacts/before-fix.webm \ + -vf "fps=10,scale=800:-1" -loop 0 \ + e2e-tests/_repro-artifacts/before-fix.gif + +ffmpeg -i e2e-tests/_repro-artifacts/after-fix.webm \ + -vf "fps=10,scale=800:-1" -loop 0 \ + e2e-tests/_repro-artifacts/after-fix.gif +``` + +Options explained: +- `fps=10` — 10 frames per second (balances smoothness vs file size) +- `scale=800:-1` — scale width to 800px, maintain aspect ratio +- `-loop 0` — loop the GIF infinitely + +### Check if ffmpeg is available + +```bash +which ffmpeg >/dev/null 2>&1 && echo "available" || echo "not found" +``` + +### Without ffmpeg (fallback) + +If `ffmpeg` is not installed: + +1. Keep the `.webm` files as-is. +2. After the PR is created, upload the `.webm` files as PR comment attachments. +3. Reference them in the PR body as download links rather than inline images. +4. Inform the user: "Install `ffmpeg` for inline GIF previews in PRs: `brew install ffmpeg` (macOS) or `sudo apt install ffmpeg` (Linux)." + +## Embedding in PR Description + +### With GIFs (inline preview) + +After creating the PR with placeholder text, upload the GIFs. Two approaches: + +**Approach A — GitHub drag-and-drop URL** + +1. Create the PR with placeholder image references. +2. Open the PR in a browser. +3. Drag the GIF files into the PR description editor. +4. GitHub uploads them to `user-images.githubusercontent.com` and generates URLs. +5. The PR body is updated with the real URLs. + +**Approach B — PR comment with images** + +1. Create the PR with the description text (no images). +2. Add a PR comment with the GIFs: + ``` + gh pr comment <PR_NUMBER> --body "## Recordings + + ### Before fix + (drag before-fix.gif here) + + ### After fix + (drag after-fix.gif here)" + ``` + +**Approach A is preferred** because images are directly in the PR description. + +### Without GIFs (webm attachments) + +```markdown +## UI before changes +[Download before-fix.webm](link-to-attachment) + +## UI after changes +[Download after-fix.webm](link-to-attachment) +``` + +## Cleanup + +After the PR is created and images are uploaded, remove all temporary artifacts: + +```bash +rm -rf e2e-tests/_repro-artifacts/ +rm -rf test-results/ +``` diff --git a/skills/bug-fix/references/workspace-map.md b/skills/bug-fix/references/workspace-map.md new file mode 100644 index 0000000..c9cb18f --- /dev/null +++ b/skills/bug-fix/references/workspace-map.md @@ -0,0 +1,81 @@ +# Workspace Map: Jira Components to rhdh-plugins Workspaces + +Maps Jira issue **Component** fields to workspace directories in `rhdh-plugins`. Used in Step 2 to identify which workspace a bug belongs to. + +## Component-to-Workspace Mapping + +| Jira Component | Workspace Directory | Has E2E Tests | E2E Modes | +|----------------|-------------------|---------------|-----------| +| Adoption Insights | `adoption-insights` | Yes | legacy + nfs | +| Bulk Import | `bulk-import` | Yes | legacy + nfs | +| Extensions | `extensions` | Yes | legacy + nfs | +| Homepage | `homepage` | Yes | legacy + nfs | +| Lightspeed | `lightspeed` | Yes | legacy + nfs | +| Global Header | `global-header` | Yes | legacy only | +| Quickstart | `quickstart` | Yes | legacy + nfs | +| Scorecard | `scorecard` | Yes | legacy + nfs | +| Localization | `translations` | Yes | unknown | +| DCM | `dcm` | Config only | n/a | +| Orchestrator | `orchestrator` | No | n/a | +| MCP | `mcp-integrations` | No | n/a | + +### Workspaces without Jira component mapping + +These workspaces exist in `rhdh-plugins` but may not have a direct Jira Component match. If the Jira issue's Component doesn't match the table above, ask the user which workspace to target. + +- `ai-integrations`, `app-defaults`, `augment`, `boost`, `cost-management` +- `install-dynamic-plugins`, `konflux`, `noop`, `repo-tools`, `theme`, `x2a` + +## Runtime Discovery + +After identifying the workspace directory, discover its e2e infrastructure dynamically. Do not hardcode workspace-specific details in this file. + +### Step 1: Read Playwright config + +``` +workspaces/<dir>/playwright.config.ts +``` + +Extract: +- `LOCALES` array (typically `['en', 'de', 'es', 'fr', 'it', 'ja']`) +- `FRONTEND_PORT_BASE` and `BACKEND_PORT_BASE` +- `APP_MODE` support (look for `process.env.APP_MODE`) +- `startCommand` (legacy vs nfs) +- `webServer` configuration + +### Step 2: Scan e2e helpers + +``` +workspaces/<dir>/e2e-tests/utils/ +``` + +Common files across workspaces: +- `translations.ts` — `getTranslations()` helper for i18n-safe selectors +- `insightsHelpers.ts` / `testHelper.ts` / `helpers.ts` — workspace-specific navigation and interaction helpers +- `accessibility.ts` — accessibility testing utilities +- `localeSkip.ts` — locale-specific test skipping logic +- `events.ts` / `apiUtils.ts` — API mocking and data seeding + +### Step 3: Read translation keys + +``` +workspaces/<dir>/plugins/*/src/translations/ref.ts +``` + +Contains the full translation key structure. Use these keys with `getTranslations()` to build i18n-safe Playwright selectors like `page.getByText(translations.header.dateRange.defaultLabel)`. + +### Step 4: Map components to source files + +``` +workspaces/<dir>/plugins/*/src/components/ +``` + +Scan the component directory tree to understand which React components render which UI elements. This mapping is used during diagnosis (Step 5) to trace from a failing Playwright selector back to the source code. + +## Fuzzy Matching + +Jira Component names don't always match workspace directory names exactly. Apply these rules: + +1. Lowercase and hyphenate the component name: "Adoption Insights" → `adoption-insights` +2. Check for known aliases (e.g., "Localization" → `translations`) +3. If no match, list all workspace directories and ask the user to pick one diff --git a/skills/raise-pr/SKILL.md b/skills/raise-pr/SKILL.md index 1d48815..e1fb846 100644 --- a/skills/raise-pr/SKILL.md +++ b/skills/raise-pr/SKILL.md @@ -4,10 +4,11 @@ description: > Automate the full PR workflow for rhdh-plugins and community-plugins monorepos: detect workspace, build, generate changeset, commit, push, and create the GitHub PR. Auto-detects which repo you're in. Supports --a auto-approve mode to skip all - approval gates. Use when asked to "raise a PR", "create a PR", "submit a PR", - "open a PR", "push my changes", "make a PR for this plugin", or "PR workflow". - Also use when user says "raise pr", "/pr", or mentions creating a pull request - in rhdh-plugins or community-plugins. + approval gates. Accepts an optional Jira key or URL to link the PR to a Jira issue + (adds Web Link, comment, and transitions to Review). Use when asked to "raise a PR", + "create a PR", "submit a PR", "open a PR", "push my changes", "make a PR for this + plugin", or "PR workflow". Also use when user says "raise pr", "/pr", or mentions + creating a pull request in rhdh-plugins or community-plugins. --- <essential_principles> @@ -45,6 +46,31 @@ Store the profile values for use in Steps 5, 6, and 10. --- +## Step 1.5 — Resolve Jira context + +Read `references/jira-input.md` for parsing rules and REST API patterns. + +Resolve a Jira issue from one of these sources (in priority order): + +1. **Caller context** — another skill (e.g., `bug-fix`) passes `jira_key`, `jira_url`, and `jira_summary` directly. Skip detection. +2. **Argument** — the user passed a Jira key or URL as an argument (e.g., `raise-pr RHDHBUGS-1934` or `raise-pr https://redhat.atlassian.net/browse/RHIDP-15252`). +3. **Branch name** — if the current branch contains a Jira key (e.g., `fix/RHDHBUGS-1934-keyboard-nav`), extract it. +4. **Prompt** — ask: "Jira issue key or URL? (enter to skip)". + +**Parsing rules** (from `references/jira-input.md`): + +- If input matches `(RHIDP|RHDHBUGS|RHDHPLAN|RHDHSUPP)-\d+` anywhere in the string, extract that as the key. +- If input contains `atlassian.net/browse/`, extract everything after `/browse/` as the key. +- Construct: `jira_url = https://redhat.atlassian.net/browse/<jira_key>` + +**Fetch issue summary** (if key resolved and summary not provided by caller): + +Use the Jira REST API per `references/jira-input.md` to fetch the issue summary. If auth is not configured or the fetch fails, store `jira_summary = null` and continue — the key and URL are still usable. + +Store: `jira_key`, `jira_url`, `jira_summary` (all nullable). If no Jira reference was resolved, all three are null and Jira-specific behavior in later steps is skipped. + +--- + ## Step 2 — Detect workspace(s) from staged changes 1. Run `git diff --cached --name-only` to list all staged files. @@ -66,7 +92,9 @@ Run `git status --porcelain` and save the full output as the **baseline snapshot 1. Run `git branch --show-current`. 2. **If on `main`:** a. Analyze the staged diff (`git diff --cached`) to understand the changes. - b. Generate a branch name: `feat/<workspace>-<short-description>` (use `fix/` for bug fixes). For multiple workspaces, use a general description. + b. Generate a branch name: + - **If `jira_key` is set:** `fix/<workspace>-<JIRA-KEY>-<short-slug>` (e.g., `fix/adoption-insights-RHDHBUGS-1934-keyboard-nav-dropdown`). This matches the existing repo convention and enables auto-linking in the Jira Development panel. + - **If no Jira key:** `feat/<workspace>-<short-description>` (use `fix/` for bug fixes). For multiple workspaces, use a general description. c. **If NOT auto-approve:** present the proposed branch name and a one-line summary. Wait for approval. **If auto-approve:** proceed immediately. d. Run `git checkout -b <branch-name>`. 3. **If NOT on `main`:** skip branch creation. Inform the user: "Already on branch `<name>`, skipping branch creation." @@ -153,12 +181,22 @@ If multiple packages are affected, list each on its own YAML line. 1. Run `git diff --cached --stat` to review all staged changes. 2. Generate a commit message in conventional commit format: `<type>(<workspace>): <short description>` (e.g., `feat(bulk-import): add batch repository import support`). -3. **If NOT auto-approve:** present the commit message and staged file summary. Wait for approval. **If auto-approve:** commit immediately. -4. Commit with the **`-s` flag** (Signed-off-by): +3. **If `jira_url` is set**, append a `Fixes:` trailer in the commit body: + +``` +fix(adoption-insights): enable keyboard navigation in header date-range dropdown +Fixes: https://redhat.atlassian.net/browse/RHDHBUGS-1934 ``` -git commit -s -m "<message>" + +4. **If NOT auto-approve:** present the commit message and staged file summary. Wait for approval. **If auto-approve:** commit immediately. +5. Commit with the **`-s` flag** (Signed-off-by): + ``` +git commit -s -m "<subject>" -m "Fixes: <jira_url>" +``` + +If no `jira_url`, omit the second `-m` flag. --- @@ -170,17 +208,75 @@ git commit -s -m "<message>" git push -u origin HEAD ``` -2. Generate a PR title from the commit message. -3. Create the PR using `gh pr create` with the repo-appropriate template from the detected profile (Step 1). Use the upstream repo value for `--repo` and `main` for `--base`. Pass the body via HEREDOC: +2. Generate a PR title from the commit subject line. +3. Build the PR body from the detected repo profile template (Step 1). The body has conditional sections: + - **`## Fixed`** — include only if `jira_key` is set. Format: `- [<JIRA-KEY>](<jira_url>) — <jira_summary>`. + - **`## UI before changes` / `## UI after changes`** — include only if `recordings` are provided in caller context. Embed the before/after GIF URLs. + - **`pr_description_extra`** — if provided by caller context (e.g., root cause analysis from `bug-fix`), insert it after the generated description paragraph. + - **`## Checklist`** — always present. +4. Create the PR using `gh pr create` with the repo-appropriate template. Use the upstream repo value for `--repo` and `main` for `--base`. Pass the body via HEREDOC: ``` gh pr create --repo <upstream-repo> --base main --title "<title>" --body "$(cat <<'EOF' -<PR body from detected profile — fill in generated description> +<assembled PR body> EOF )" ``` -4. Display the PR URL as the final output. +5. Capture and store the PR URL for Step 11. +6. Display the PR URL. + +--- + +## Step 11 — Post-PR Jira updates + +**Skip this step entirely if `jira_key` is null.** + +Read `references/jira-input.md` for REST API patterns and auth setup. + +### 11.1 — Add Web Link on Jira issue + +Add the PR as a Web Link on the Jira issue using the REST API: + +``` +POST /rest/api/3/issue/<jira_key>/remotelink +Body: { "object": { "url": "<PR_URL>", "title": "PR: <PR_title>" } } +``` + +### 11.2 — Add comment + +Add a comment documenting the PR submission: + +``` +acli jira workitem comment add --key <jira_key> --comment "PR submitted: <PR_URL>" --yes +``` + +If `acli` is not available, use the REST API: + +``` +POST /rest/api/3/issue/<jira_key>/comment +Body: { "body": { "type": "doc", "version": 1, "content": [{"type": "paragraph", "content": [{"type": "text", "text": "PR submitted: <PR_URL>"}]}] } } +``` + +### 11.3 — Transition to Review + +Always attempt the transition — the user explicitly linked a Jira issue, so the intent is to move it to Review. + +1. Query available transitions: + +``` +GET /rest/api/3/issue/<jira_key>/transitions +``` + +2. Find the transition whose `to.name` is `"Review"` (case-insensitive match). +3. **If found**: execute it: + +``` +POST /rest/api/3/issue/<jira_key>/transitions +Body: { "transition": { "id": "<transition_id>" } } +``` + +4. **If "Review" is not in the available transitions**: warn the user — "Issue `<jira_key>` is in status `<current_status>`. Cannot transition directly to Review. Available transitions: `<list>`. Move to the required status first." --- @@ -190,6 +286,22 @@ EOF - **Multiple workspaces:** Each workspace gets its own build cycle (Step 5) and changeset (Step 6). The commit (Step 9) bundles everything into one commit. If the user prefers separate PRs per workspace, they should stage and run the skill once per workspace. - **Changeset ID collisions:** Each workspace must get a unique random ID. If generating for multiple workspaces in one run, track used IDs and avoid duplicates. +## Caller Context (optional) + +When another skill chains into `raise-pr`, it may provide a **caller context** with pre-resolved values. If present, these override the defaults — skip detection for any field that is already provided. + +| Field | Type | Used in | Description | +|-------|------|---------|-------------| +| `jira_key` | string | Steps 1.5, 4, 9, 10, 11 | Pre-resolved Jira issue key (skip Step 1.5 detection) | +| `jira_url` | string | Steps 9, 10, 11 | Full Jira browse URL | +| `jira_summary` | string | Step 10 | Issue summary for the PR body `## Fixed` section | +| `recordings` | object | Step 10 | `{ before: "<path>", after: "<path>" }` — GIF paths for `## UI before/after changes` | +| `pr_description_extra` | string | Step 10 | Extra text inserted after the description (e.g., root cause analysis) | + +Skills that chain into `raise-pr`: + +- **`bug-fix`** — provides all five fields after reproducing and fixing a Jira bug with Playwright video recordings. + <reference_index> ## Reference Index @@ -197,5 +309,6 @@ EOF | Reference | Load when... | |-----------|-------------| | `references/repo-profiles.md` | Always — at the start of every invocation (Step 1) | +| `references/jira-input.md` | When resolving Jira context (Step 1.5) and performing post-PR Jira updates (Step 11) | </reference_index> diff --git a/skills/raise-pr/references/jira-input.md b/skills/raise-pr/references/jira-input.md new file mode 100644 index 0000000..ddad896 --- /dev/null +++ b/skills/raise-pr/references/jira-input.md @@ -0,0 +1,129 @@ +# Jira Input Parsing & REST API Patterns + +Shared reference for resolving Jira issue keys from user input and performing Jira REST API operations. Used by `raise-pr` (Step 1.5, Step 11) and `bug-fix` (Step 1). + +## Parsing Jira References + +Accept any of these formats and normalize to a key + URL pair: + +| Input format | Example | Extraction | +|-------------|---------|------------| +| Bare key | `RHDHBUGS-1934` | Match directly | +| Browse URL | `https://redhat.atlassian.net/browse/RHDHBUGS-1934` | Extract after `/browse/` | +| URL without scheme | `redhat.atlassian.net/browse/RHIDP-15252` | Extract after `/browse/` | +| URL with query params | `https://redhat.atlassian.net/browse/RHIDP-15252?focusedId=123` | Extract key between `/browse/` and `?` | + +### Extraction rules + +1. If the input contains `atlassian.net/browse/`, extract the path segment immediately after `/browse/` (strip any query string or fragment). +2. Otherwise, scan the full input string for a match against the pattern `(RHIDP|RHDHBUGS|RHDHPLAN|RHDHSUPP)-\d+`. +3. If neither matches, the input is invalid — ask the user to provide a valid key or URL. + +### Normalization + +Once the key is extracted: + +``` +jira_key = "RHDHBUGS-1934" +jira_url = "https://redhat.atlassian.net/browse/RHDHBUGS-1934" +``` + +Always construct `jira_url` from the key — do not store the user's raw URL (it may have query params or fragments). + +## Authentication + +All REST API calls use the `.jira-token` file. Locate it next to the `acli` binary: + +```bash +ACLI_PATH="$(readlink -f "$(which acli)" 2>/dev/null || which acli)" +TOKEN_FILE="$(dirname "$ACLI_PATH")/.jira-token" +AUTH="$(cat "$TOKEN_FILE")" +``` + +The file contains `email:api_token` in a single line. **Never read the token into the conversation context** — only use it in shell commands via variable substitution. + +If `acli` is not on PATH or `.jira-token` does not exist, warn the user: "Jira REST API auth not configured. Run `rhdh-jira setup` or see rhdh-jira skill for setup instructions." Continue without Jira operations. + +## REST API Patterns + +Base URL: `https://redhat.atlassian.net` + +### Fetch issue summary + +```bash +curl -s -u "$AUTH" \ + "https://redhat.atlassian.net/rest/api/3/issue/$JIRA_KEY?fields=summary,status" | \ + python3 -c "import json,sys; d=json.load(sys.stdin); print(d['fields']['summary'])" +``` + +### Add Web Link (remote link) + +```bash +curl -s -X POST \ + -u "$AUTH" \ + -H "Content-Type: application/json" \ + -d "{\"object\": {\"url\": \"$PR_URL\", \"title\": \"$PR_TITLE\"}}" \ + "https://redhat.atlassian.net/rest/api/3/issue/$JIRA_KEY/remotelink" +``` + +Returns `201 Created` on success with `{"id": ..., "self": "..."}`. + +### Add comment + +Prefer `acli` when available: + +```bash +acli jira workitem comment add --key "$JIRA_KEY" --comment "PR submitted: $PR_URL" --yes +``` + +REST API fallback (requires ADF format): + +```bash +curl -s -X POST \ + -u "$AUTH" \ + -H "Content-Type: application/json" \ + -d '{ + "body": { + "type": "doc", + "version": 1, + "content": [{"type": "paragraph", "content": [{"type": "text", "text": "PR submitted: '"$PR_URL"'"}]}] + } + }' \ + "https://redhat.atlassian.net/rest/api/3/issue/$JIRA_KEY/comment" +``` + +### Query available transitions + +```bash +curl -s -u "$AUTH" \ + "https://redhat.atlassian.net/rest/api/3/issue/$JIRA_KEY/transitions" | \ + python3 -c " +import json, sys +data = json.load(sys.stdin) +for t in data.get('transitions', []): + print(f\"{t['id']:>5} {t['to']['name']}\") +" +``` + +### Execute transition + +```bash +curl -s -X POST \ + -u "$AUTH" \ + -H "Content-Type: application/json" \ + -d "{\"transition\": {\"id\": \"$TRANSITION_ID\"}}" \ + "https://redhat.atlassian.net/rest/api/3/issue/$JIRA_KEY/transitions" +``` + +Returns `204 No Content` on success. + +## Error Handling + +| HTTP Status | Meaning | Action | +|-------------|---------|--------| +| 200/201/204 | Success | Continue | +| 400 | Bad request | Check payload format. For transitions, the requested transition may not be valid from the current status. | +| 401 | Unauthorized | `.jira-token` is missing, malformed, or expired. Warn user. | +| 403 | Forbidden | User lacks permission on this issue. Warn user. | +| 404 | Not found | Issue key is wrong or issue does not exist. Warn user. | +| 429 | Rate limited | Wait 5 seconds, retry once. | diff --git a/skills/raise-pr/references/repo-profiles.md b/skills/raise-pr/references/repo-profiles.md index 325c877..7f88d4d 100644 --- a/skills/raise-pr/references/repo-profiles.md +++ b/skills/raise-pr/references/repo-profiles.md @@ -25,12 +25,22 @@ Run `git remote -v` and inspect all remote URLs (fetch lines). Match against the ### PR body template (rhdh-plugins) +The template has conditional sections. Include or omit them based on the resolved Jira context and caller context from Step 1.5. + ``` ## Description <generated description — 2-4 sentences explaining what changed and why> -## Fixed -- <Jira link — ask the user, or leave as TODO> +<pr_description_extra — if provided by caller context, insert here (e.g., root cause analysis)> + +## Fixed ← include only if jira_key is set +- [<JIRA-KEY>](<jira_url>) — <jira_summary> + +## UI before changes ← include only if recordings provided by caller +![Before fix](<before-gif-url>) + +## UI after changes ← include only if recordings provided by caller +![After fix](<after-gif-url>) ## Checklist - [x] A changeset describing the change and affected packages. ([more info](https://github.com/redhat-developer/rhdh-plugins/blob/main/CONTRIBUTING.md#creating-changesets)) @@ -39,6 +49,10 @@ Run `git remote -v` and inspect all remote URLs (fetch lines). Match against the - [ ] Screenshots attached (for UI changes) ``` +**When no Jira key is set**: omit `## Fixed` entirely. +**When no recordings provided**: omit both `## UI before changes` and `## UI after changes`. +**When both are absent**: the template reduces to `## Description` + `## Checklist` (the minimal form). + ## Profile: community-plugins | Field | Value | From 21ca63cc8390e5a4c1a28487a0ad9d96cccd26a3 Mon Sep 17 00:00:00 2001 From: its-mitesh-kumar <itsmiteshkumar98@gmail.com> Date: Sat, 4 Jul 2026 03:59:03 +0530 Subject: [PATCH 3/4] updating the skills Signed-off-by: its-mitesh-kumar <itsmiteshkumar98@gmail.com> --- skills/bug-fix/SKILL.md | 25 ++++++++++++++++++++++--- skills/raise-pr/SKILL.md | 13 ++++++++++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/skills/bug-fix/SKILL.md b/skills/bug-fix/SKILL.md index 00914ca..737e07a 100644 --- a/skills/bug-fix/SKILL.md +++ b/skills/bug-fix/SKILL.md @@ -23,6 +23,21 @@ Do not hardcode workspace internals. Discover each workspace's e2e infrastructur Every bug fix PR must include before/after visual evidence. Playwright video recording captures the bug in action (before) and the fix working (after). These are converted to GIFs and embedded in the PR description. </principle> +<principle name="step_echo_banners"> +Before executing each numbered Step, echo a clearly visible banner to the terminal so the user can track progress: +``` +echo "================ Step N — <Step title> ===========" +``` +</principle> + +<principle name="preflight_port_cleanup"> +Before running any Playwright test, check whether the dev-server port (from `playwright.config.ts`) is already in use. If it is, kill the process occupying it: +``` +lsof -ti:<PORT> | xargs kill -9 2>/dev/null || true +``` +A stale dev server from a prior session will cause the test to connect to the wrong app and time out. +</principle> + </essential_principles> ## Prerequisites @@ -88,11 +103,15 @@ Read `references/e2e-patterns.md` for test patterns and `references/video-record ``` - Encode the "steps to reproduce" from the Jira description as Playwright actions. - Assert the **expected** behavior (the assertion should fail when the bug is present). -3. Run the test against the `en` locale in legacy mode: +3. **Pre-flight: kill stale dev server** — before running the test, ensure the dev-server port (read from `playwright.config.ts` `webServer.url`) is free: + ``` + lsof -ti:<PORT> | xargs kill -9 2>/dev/null || true + ``` +4. Run the test against the `en` locale in legacy mode: ``` APP_MODE=legacy npx playwright test e2e-tests/_repro-<KEY>.test.ts --project=en ``` -4. The test should **fail** — confirming the bug is reproduced. +5. The test should **fail** — confirming the bug is reproduced. **If the test passes** (bug not reproduced): re-read the Jira description, adjust the test, and retry. If still not reproducible after 2 attempts, report findings and ask the user for guidance. @@ -194,7 +213,7 @@ Invoke `raise-pr --a` with the following caller context: | `jira_url` | `https://redhat.atlassian.net/browse/<jira_key>` | | `jira_summary` | Issue summary from Step 1 | | `recordings` | `{ before: "e2e-tests/_repro-artifacts/before-fix.gif", after: "e2e-tests/_repro-artifacts/after-fix.gif" }` | -| `pr_description_extra` | `**Root cause:** <diagnosis from Step 5>` | +| `pr_description_extra` | `### Root cause\n<diagnosis from Step 5>` | `raise-pr` handles: repo detection, build, changeset, commit (with `Fixes:` trailer), push, PR creation (with `## UI before/after changes`), and post-PR Jira updates (Web Link, comment, transition to Review). diff --git a/skills/raise-pr/SKILL.md b/skills/raise-pr/SKILL.md index e1fb846..131c290 100644 --- a/skills/raise-pr/SKILL.md +++ b/skills/raise-pr/SKILL.md @@ -14,7 +14,7 @@ description: > <essential_principles> <principle name="scoped_dist_cleanup"> -Pre-build cleanup uses `rm -rf plugins/*/dist packages/*/dist` scoped to the workspace directory. If permission errors occur, escalate to `sudo`. Never use `find -name dist` or any broad recursive search — that deletes `dist/` inside `node_modules` and breaks everything. +Pre-build cleanup uses `rm -rf plugins/*/dist packages/*/dist` scoped to the workspace directory. If permission errors occur (root-owned files from a prior Docker build), use a disposable Docker container to remove them — never use `sudo`. Never use `find -name dist` or any broad recursive search — that deletes `dist/` inside `node_modules` and breaks everything. </principle> <principle name="changesets_skip_packages"> @@ -25,6 +25,13 @@ Only plugins under `plugins/*` with published-source changes need changesets. Al Capture `git status --porcelain` before builds as the baseline. After builds, only stage files that are new relative to that baseline. Pre-existing dirty files (local config overrides, dev fixtures) must never be staged. </principle> +<principle name="step_echo_banners"> +Before executing each numbered Step, echo a clearly visible banner to the terminal so the user can track progress: +``` +echo "================ Step N — <Step title> ===========" +``` +</principle> + </essential_principles> ## Mode: check for `--a` flag @@ -113,10 +120,10 @@ Remove stale `dist/` directories that may contain root-owned files from previous rm -rf plugins/*/dist packages/*/dist ``` -If this fails with a permission error (`EACCES`), escalate to: +If this fails with a permission error (`EACCES`), use a disposable Docker container to remove them (avoids needing `sudo` on the host): ``` -sudo rm -rf plugins/*/dist packages/*/dist +docker run --rm -v "$(pwd)":/workspace alpine sh -c "rm -rf /workspace/plugins/*/dist /workspace/packages/*/dist" ``` ### 5.1–5.6 — Build pipeline From 309542f7f51dbd6902a93b94f8d0bf8b99cab584 Mon Sep 17 00:00:00 2001 From: its-mitesh-kumar <itsmiteshkumar98@gmail.com> Date: Sat, 4 Jul 2026 05:31:12 +0530 Subject: [PATCH 4/4] improving the skill Signed-off-by: its-mitesh-kumar <itsmiteshkumar98@gmail.com> --- skills/bug-fix/SKILL.md | 43 +++++++++--- skills/bug-fix/references/video-recording.md | 23 ++++-- skills/raise-pr/SKILL.md | 73 ++++++++++++++++---- 3 files changed, 111 insertions(+), 28 deletions(-) diff --git a/skills/bug-fix/SKILL.md b/skills/bug-fix/SKILL.md index 737e07a..f541188 100644 --- a/skills/bug-fix/SKILL.md +++ b/skills/bug-fix/SKILL.md @@ -11,6 +11,14 @@ description: > <essential_principles> +<principle name="skill_entry_banner"> +As the very first action when the skill is invoked, echo a skill entry banner to the terminal: +``` +echo "================ Using Bug Fix Skill ===========" +``` +This must happen before any other work (reading references, MCP calls, etc.). +</principle> + <principle name="repro_test_is_temporary"> The reproduction test (`_repro-<KEY>.test.ts`) is a diagnostic tool, not a deliverable. It is deleted before staging. It must never appear in the PR. </principle> @@ -24,10 +32,11 @@ Every bug fix PR must include before/after visual evidence. Playwright video rec </principle> <principle name="step_echo_banners"> -Before executing each numbered Step, echo a clearly visible banner to the terminal so the user can track progress: +Before executing each numbered Step, echo a clearly visible banner to the terminal so the user can track progress — even if the step's actual work is done via MCP tools or file reads rather than shell commands: ``` echo "================ Step N — <Step title> ===========" ``` +This applies to ALL steps including Step 1. Run the echo command in a Shell tool call before doing anything else for that step. </principle> <principle name="preflight_port_cleanup"> @@ -38,6 +47,14 @@ lsof -ti:<PORT> | xargs kill -9 2>/dev/null || true A stale dev server from a prior session will cause the test to connect to the wrong app and time out. </principle> +<principle name="preflight_system_limits"> +Before running any Playwright test, ensure the system file descriptor limit is raised and always use `required_permissions: ["all"]` on the shell command to avoid sandbox restrictions on browser launch: +``` +ulimit -n 65536 2>/dev/null || true +``` +Without this, webpack's file watcher (Watchpack) may hit `EMFILE: too many open files` and crash Chrome/Chromium. +</principle> + </essential_principles> ## Prerequisites @@ -93,23 +110,31 @@ Read `references/e2e-patterns.md` for test patterns and `references/video-record 1. Create a temporary test file: `e2e-tests/_repro-<JIRA-KEY>.test.ts` - The `_` prefix signals this file is temporary and should not be committed. 2. The test must: - - Import workspace-specific helpers discovered in Step 2. + - Import workspace-specific helpers discovered in Step 2 **only for navigation/setup** (e.g., API mocking, translations). - Use i18n-safe selectors (via translation keys) where available. - - Configure video recording per-test: + - **Always create its own browser context with video recording** — do NOT rely on workspace bootstrap helpers for the context, as they may not enable video. Use the `browser` fixture directly: ```typescript - test.use({ - video: { mode: 'on', size: { width: 1280, height: 720 } }, + test('repro', async ({ browser }) => { + const context = await browser.newContext({ + recordVideo: { dir: 'test-results/', size: { width: 1280, height: 720 } }, + }); + const page = await context.newPage(); + + // ... test steps using page ... + + await context.close(); // finalizes the video file }); ``` + This guarantees video recording regardless of how the workspace's own e2e infrastructure manages contexts. - Encode the "steps to reproduce" from the Jira description as Playwright actions. - Assert the **expected** behavior (the assertion should fail when the bug is present). 3. **Pre-flight: kill stale dev server** — before running the test, ensure the dev-server port (read from `playwright.config.ts` `webServer.url`) is free: ``` lsof -ti:<PORT> | xargs kill -9 2>/dev/null || true ``` -4. Run the test against the `en` locale in legacy mode: +4. Run the test against the `en` locale in legacy mode. **Always** prefix with `ulimit -n 65536` and use `required_permissions: ["all"]` on the Shell tool call: ``` - APP_MODE=legacy npx playwright test e2e-tests/_repro-<KEY>.test.ts --project=en + ulimit -n 65536 && APP_MODE=legacy npx playwright test e2e-tests/_repro-<KEY>.test.ts --project=en ``` 5. The test should **fail** — confirming the bug is reproduced. @@ -150,9 +175,9 @@ Read `references/e2e-patterns.md` for test patterns and `references/video-record ## Step 6 — Capture "after" recording -1. Re-run the reproduction test: +1. Re-run the reproduction test (with `ulimit` and `required_permissions: ["all"]`): ``` - APP_MODE=legacy npx playwright test e2e-tests/_repro-<KEY>.test.ts --project=en + ulimit -n 65536 && APP_MODE=legacy npx playwright test e2e-tests/_repro-<KEY>.test.ts --project=en ``` 2. The test should **pass** — confirming the fix works. 3. Copy the video: diff --git a/skills/bug-fix/references/video-recording.md b/skills/bug-fix/references/video-recording.md index cbc5ed5..d1ddbe2 100644 --- a/skills/bug-fix/references/video-recording.md +++ b/skills/bug-fix/references/video-recording.md @@ -4,22 +4,31 @@ How to capture before/after screen recordings for bug fix PRs. Reference this in ## Playwright Video Configuration -Configure video recording per-test using `test.use()`: +The reproduction test must **always create its own browser context** with `recordVideo` to guarantee video capture regardless of how the workspace's e2e infrastructure manages contexts: ```typescript -test.use({ - video: { - mode: 'on', - size: { width: 1280, height: 720 }, - }, +test('repro', async ({ browser }) => { + const context = await browser.newContext({ + recordVideo: { dir: 'test-results/', size: { width: 1280, height: 720 } }, + }); + const page = await context.newPage(); + + // ... test steps ... + + await context.close(); // finalizes the video file }); ``` -- **`mode: 'on'`** — record every test run (not `retain-on-failure`, because we want the "before" video even though the test fails). +- **`recordVideo.dir`** — directory where Playwright saves the `.webm` file. - **`size`** — 1280x720 gives good quality at reasonable file size. Matches most laptop viewports. +- **`context.close()`** — MUST be called to finalize the video. Without it the file may be incomplete. All rhdh-plugins workspaces use `@playwright/test` >= 1.60.0, which supports this config. +### Why not `test.use({ video: ... })`? + +`test.use()` only applies to Playwright's auto-created contexts. Many rhdh-plugins workspaces (e.g., `lightspeed`) manually create contexts in `beforeAll` helpers, which bypasses `test.use()` entirely. By always creating our own context with `recordVideo`, we avoid this pitfall. + ## Where Videos Land Playwright saves videos to the `test-results/` directory inside the workspace: diff --git a/skills/raise-pr/SKILL.md b/skills/raise-pr/SKILL.md index 131c290..f53fdfb 100644 --- a/skills/raise-pr/SKILL.md +++ b/skills/raise-pr/SKILL.md @@ -13,8 +13,16 @@ description: > <essential_principles> +<principle name="skill_entry_banner"> +As the very first action when the skill is invoked, echo a skill entry banner to the terminal: +``` +echo "================ Using Raise PR Skill ===========" +``` +This must happen before any other work (reading references, detecting repo profile, etc.). +</principle> + <principle name="scoped_dist_cleanup"> -Pre-build cleanup uses `rm -rf plugins/*/dist packages/*/dist` scoped to the workspace directory. If permission errors occur (root-owned files from a prior Docker build), use a disposable Docker container to remove them — never use `sudo`. Never use `find -name dist` or any broad recursive search — that deletes `dist/` inside `node_modules` and breaks everything. +Pre-build cleanup uses `rm -rf plugins/*/dist packages/*/dist` scoped to the workspace directory. If permission errors occur (root-owned files from a prior Docker build), **skip only `yarn build:all`** and warn the user to run `sudo chown -R $(whoami) .` to fix ownership permanently. Never use `sudo` in the skill itself. Never use `find -name dist` or any broad recursive search — that deletes `dist/` inside `node_modules` and breaks everything. </principle> <principle name="changesets_skip_packages"> @@ -120,12 +128,13 @@ Remove stale `dist/` directories that may contain root-owned files from previous rm -rf plugins/*/dist packages/*/dist ``` -If this fails with a permission error (`EACCES`), use a disposable Docker container to remove them (avoids needing `sudo` on the host): - +**If `EACCES` permission error occurs:** Set a flag `SKIP_BUILD_ALL=true`. Log a warning with the permanent fix: ``` -docker run --rm -v "$(pwd)":/workspace alpine sh -c "rm -rf /workspace/plugins/*/dist /workspace/packages/*/dist" +echo "⚠️ Skipping yarn build:all — dist/ has root-owned files. Run 'sudo chown -R $(whoami) .' to fix ownership, then re-run." ``` +Never use `sudo` in the skill itself — just tell the user how to fix it. + ### 5.1–5.6 — Build pipeline Run in order: @@ -133,9 +142,9 @@ Run in order: 1. `yarn` — install dependencies 2. `yarn prettier:fix` — format code 3. `yarn tsc:full` — full TypeScript type check -4. `yarn build:all` — build all packages +4. `yarn build:all` — build all packages. **Skip this step if `SKIP_BUILD_ALL=true`** (from 5.0 fallback). 5. `yarn test --watchAll=false` — run tests (disable Jest watch mode) -6. `yarn build:api-reports:only` — generate/update API reports +6. `yarn build:api-reports:only` — generate/update API reports (depends on `tsc:full`, always runs) --- @@ -241,25 +250,49 @@ EOF Read `references/jira-input.md` for REST API patterns and auth setup. +For each sub-step below, try methods in priority order. If one method fails (auth error, tool not available, network error), move to the next. Log which methods succeeded/failed so the user knows the final state. + ### 11.1 — Add Web Link on Jira issue -Add the PR as a Web Link on the Jira issue using the REST API: +Add the PR as a Web Link on the Jira issue. Try in order: + +**Method A — Jira MCP `add_jira_comment` with link (if `add_remote_link` MCP tool exists):** +``` +Use CallMcpTool: server="user-jira", toolName="add_remote_link" +``` +**Method B — REST API:** ``` POST /rest/api/3/issue/<jira_key>/remotelink Body: { "object": { "url": "<PR_URL>", "title": "PR: <PR_title>" } } ``` +**Method C — `acli` CLI:** +``` +acli jira issue link add --key <jira_key> --url <PR_URL> --title "PR: <PR_title>" +``` + +**If all methods fail:** Log a warning and continue. The Web Link is desirable but not blocking: +``` +echo "⚠️ Could not add Web Link to <jira_key>. Add manually: <PR_URL>" +``` + ### 11.2 — Add comment -Add a comment documenting the PR submission: +Add a comment documenting the PR submission. Try in order: +**Method A — Jira MCP:** ``` -acli jira workitem comment add --key <jira_key> --comment "PR submitted: <PR_URL>" --yes +Use CallMcpTool: server="user-jira", toolName="add_jira_comment" +Arguments: { "issueKey": "<jira_key>", "comment": "PR submitted: <PR_URL>" } ``` -If `acli` is not available, use the REST API: +**Method B — `acli` CLI:** +``` +acli jira workitem comment add --key <jira_key> --comment "PR submitted: <PR_URL>" --yes +``` +**Method C — REST API:** ``` POST /rest/api/3/issue/<jira_key>/comment Body: { "body": { "type": "doc", "version": 1, "content": [{"type": "paragraph", "content": [{"type": "text", "text": "PR submitted: <PR_URL>"}]}] } } @@ -269,15 +302,21 @@ Body: { "body": { "type": "doc", "version": 1, "content": [{"type": "paragraph", Always attempt the transition — the user explicitly linked a Jira issue, so the intent is to move it to Review. -1. Query available transitions: +**Method A — Jira MCP (if `transition_jira_issue` tool exists):** +``` +Use CallMcpTool: server="user-jira", toolName="transition_jira_issue" +Arguments: { "issueKey": "<jira_key>", "transitionName": "Review" } +``` + +**Method B — REST API:** +1. Query available transitions: ``` GET /rest/api/3/issue/<jira_key>/transitions ``` 2. Find the transition whose `to.name` is `"Review"` (case-insensitive match). 3. **If found**: execute it: - ``` POST /rest/api/3/issue/<jira_key>/transitions Body: { "transition": { "id": "<transition_id>" } } @@ -285,6 +324,16 @@ Body: { "transition": { "id": "<transition_id>" } } 4. **If "Review" is not in the available transitions**: warn the user — "Issue `<jira_key>` is in status `<current_status>`. Cannot transition directly to Review. Available transitions: `<list>`. Move to the required status first." +**Method C — `acli` CLI:** +``` +acli jira issue transition --key <jira_key> --transition "Review" --yes +``` + +**If all methods fail for transition:** Log a warning and continue — the PR has been created successfully: +``` +echo "⚠️ Could not transition <jira_key> to Review. Transition it manually." +``` + --- ## Gotchas