From 0277c36c9977a535465023d01ec35e59f7f45ae5 Mon Sep 17 00:00:00 2001 From: Nathan Barrett Date: Wed, 4 Mar 2026 18:19:44 -0600 Subject: [PATCH 1/9] Add /trainhop and /trainhop-bump-version skills fixes #3 --- .../skills/trainhop-bump-version/SKILL.md | 100 ++++++++++++++++++ plugins/newtab/skills/trainhop/SKILL.md | 90 ++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100644 plugins/newtab/skills/trainhop-bump-version/SKILL.md create mode 100644 plugins/newtab/skills/trainhop/SKILL.md diff --git a/plugins/newtab/skills/trainhop-bump-version/SKILL.md b/plugins/newtab/skills/trainhop-bump-version/SKILL.md new file mode 100644 index 0000000..5f5d768 --- /dev/null +++ b/plugins/newtab/skills/trainhop-bump-version/SKILL.md @@ -0,0 +1,100 @@ +--- +name: trainhop-bump-version +description: Bumps the newtab version in manifest.json after cutting a train-hop XPI release. Use when explicitly asked to "bump the newtab version after train-hop", "post-train-hop version bump", or "bump minor version for newtab". Optionally pass an existing Bugzilla bug number. Do NOT use for general version bumps or non-train-hop releases. +argument-hint: "[bug-number] (optional)" +disable-model-invocation: true +--- + +# Train-hop: Bump Minor Version + +After a New Tab train-hop XPI release is cut, the version in `browser/extensions/newtab/manifest.json` must be bumped so the next release starts from a clean state. + +## Important + +Do not skip any steps. Complete every step in order before moving to the next. + +## Steps + +### 1. Read current version + +Read `browser/extensions/newtab/manifest.json` and extract the `version` field (format: `MAJOR.MINOR.PATCH`). + +### 2. Read current Nightly version + +Read `browser/config/version.txt` and extract the major version number (e.g. `150` from `150.0a1`). + +### 3. Compute new version + +Compare the manifest MAJOR with the Nightly MAJOR: + +- If they match (still on same Nightly): bump MINOR by 1, keep PATCH as 0 + - e.g. `149.2.0` → `149.3.0` +- If Nightly MAJOR is higher (train moved forward): use Nightly MAJOR, reset MINOR and PATCH to 0 + - e.g. manifest `149.2.0`, Nightly `150` → `150.0.0` + +### 4. Get or file a bug + +If $ARGUMENTS contains a bug number, use it and skip to step 5. + +Otherwise, file a new bug via the Bugzilla REST API: + +```bash +curl -s -X POST https://bugzilla.mozilla.org/rest/bug \ + -H "Content-Type: application/json" \ + -d '{ + "api_key": "'"$BUGZILLA_API_KEY"'", + "product": "Firefox", + "component": "New Tab Page", + "summary": "Bump the minor version number of New Tab from OLD_VERSION to NEW_VERSION", + "version": "Trunk", + "op_sys": "All", + "platform": "All" + }' +``` + +- If `BUGZILLA_API_KEY` is set in the environment, run this automatically and extract the `id` from the response. +- If `BUGZILLA_API_KEY` is not set, print the curl command (with OLD_VERSION and NEW_VERSION substituted) for the user to run, then wait for them to provide the bug number before continuing. + +### 5. Edit manifest.json + +Edit `browser/extensions/newtab/manifest.json`, updating the `version` field to the new version. + +### 6. Lint + +Run the linter on the manifest: + +```bash +./mach lint --fix browser/extensions/newtab/manifest.json +``` + +If linting fails, fix the issue before proceeding. + +### 7. Commit + +Commit the change: + +```bash +git commit browser/extensions/newtab/manifest.json -m "Bug BUG_NUMBER - Bump the newtab manifest version number r?#home-newtab-reviewers" +``` + +### 8. Submit for review + +Run: + +```bash +moz-phab submit -s +``` + +## Troubleshooting + +**`BUGZILLA_API_KEY` not set** +Print the curl command with substituted values for the user to run manually, then ask them to provide the resulting bug number. + +**Lint fails** +Read the error output, fix the issue in `manifest.json`, and re-run the linter before committing. + +**`moz-phab submit` fails with auth error** +Ask the user to run `moz-phab submit` manually. They may need to re-authenticate with `moz-phab self-update` or check their Phabricator token. + +**`moz-phab submit` fails with "no commit found"** +Verify the commit was created in step 7. Run `git log --oneline -3` to confirm. diff --git a/plugins/newtab/skills/trainhop/SKILL.md b/plugins/newtab/skills/trainhop/SKILL.md new file mode 100644 index 0000000..1d9deef --- /dev/null +++ b/plugins/newtab/skills/trainhop/SKILL.md @@ -0,0 +1,90 @@ +--- +name: trainhop +description: Runs the complete New Tab train-hop workflow from start to finish. Use when asked to "run the train-hop", "start a train-hop", "do a train-hop release", or "perform a train-hop". Optionally pass an existing Bugzilla bug number. Do NOT use for individual steps of the train-hop process. +argument-hint: "[bug-number] (optional)" +disable-model-invocation: true +--- + +# Train-hop: Full Workflow + +Orchestrates the complete New Tab train-hop release process by invoking each child skill in sequence. Stop and report to the user if any step fails. + +## Important + +Do not skip any steps. Complete each step fully before moving to the next. If a step is marked "not yet automated", pause and instruct the user to complete it manually before continuing. + +## Steps + +### 1. Update locales + +Invoke `/trainhop-update-locales`. + +### 2. Update metrics + +Invoke `/trainhop-update-metrics`. + +### 3. Build and sign the XPI via ShipIt + +_Not yet automated._ Instruct the user to: +- Sign into the corporate VPN +- Visit https://shipit.mozilla-releng.net/newxpi, select "newtab", enter the GitHub SHA, and create the release +- Coordinate with a second HNT engineer for the two-engineer sign-off +- Copy the Ship task URL once the build completes + +Wait for the user to provide the Ship task URL before continuing. + +### 5. Generate the Nimbus recipe + +Invoke `/trainhop-generate-recipe` passing the Ship task URL provided in step 4. + +### 6. Create Stage Experimenter rollout for QA + +_Not yet automated._ Instruct the user to: +- Sign into the staging version of Experimenter +- Clone the existing QA rollout template +- Set the newtabTrainhopAddon feature value to the recipe from step 5 +- Set min/max Firefox version numbers +- Request rollout approval for QA + +Wait for the user to confirm the stage rollout is live before continuing. + +### 7. File QA ticket + +Invoke `/trainhop-file-qa-ticket` passing $ARGUMENTS (the bug number, if provided). + +### 8. Create Production Experimenter rollouts + +_Not yet automated._ Instruct the user to create three rollouts on the production Experimenter instance: +- **Prior version rollout**: lock to minimum version, exclude from new rollout +- **Release rollout**: new version, start at 25% (or 100% if a prior rollout exists) +- **Beta rollout**: new version, 100% + +Remind the user: do not request approval yet — wait for QA sign-off. + +### 9. Bump minor version + +Invoke `/trainhop-bump-version` passing $ARGUMENTS (the bug number, if provided). + +### 10. Wait for QA sign-off + +Pause and prompt the user to confirm QA has returned a green report before continuing. + +### 11. Ship to Release and Beta + +_Not yet automated._ Instruct the user to: +- Alert `#system-addon-release-process` in Slack with the QA report and rollout link +- Request Release Management approval on the production Release rollout +- Once approved, throttle/end prior rollouts as needed and ramp to 100% over the following days +- Approve the Beta rollout immediately at 100% + +### 12. Find backward-compat shims to clean up + +Invoke `/trainhop-find-compat-shims`. + +## Troubleshooting + +**A child skill is not installed** +Inform the user which skill is missing and that it can be installed via `claude plugin install newtab`. + +**Step fails partway through** +Report which step failed and its error output. Do not attempt to continue past a failed step without explicit user instruction. From 6d6477b4656bc0e1a93875aee60bcfa971b93d9f Mon Sep 17 00:00:00 2001 From: Nathan Barrett Date: Wed, 4 Mar 2026 18:44:55 -0600 Subject: [PATCH 2/9] Add /trainhop-update-metrics skill --- .../skills/trainhop-update-metrics/SKILL.md | 97 +++++++++++++++++++ plugins/newtab/skills/trainhop/SKILL.md | 53 ++++++++-- 2 files changed, 140 insertions(+), 10 deletions(-) create mode 100644 plugins/newtab/skills/trainhop-update-metrics/SKILL.md diff --git a/plugins/newtab/skills/trainhop-update-metrics/SKILL.md b/plugins/newtab/skills/trainhop-update-metrics/SKILL.md new file mode 100644 index 0000000..bc36a23 --- /dev/null +++ b/plugins/newtab/skills/trainhop-update-metrics/SKILL.md @@ -0,0 +1,97 @@ +--- +name: trainhop-update-metrics +description: Updates the New Tab metrics and pings JSON files for a train-hop release. Use when asked to "update train-hop metrics", "run channel-metrics-diff", or "prepare metrics for train-hop". Do NOT use for general metrics changes unrelated to train-hopping. +argument-hint: "[bug-number] (optional)" +disable-model-invocation: true +--- + +# Train-hop: Update Metrics + +Generates updated runtime metrics JSON files for the Beta and Release channels, cleans up stale files, and commits the result. + +## Important + +Do not skip any steps. Complete each step fully before moving to the next. + +## Steps + +### 1. Run channel-metrics-diff for both channels + +Run both commands: + +```bash +./mach newtab channel-metrics-diff --channel beta +./mach newtab channel-metrics-diff --channel release +``` + +### 2. Clean up stale runtime-metrics files + +List the files in `browser/extensions/newtab/webext-glue/metrics/`: + +```bash +ls browser/extensions/newtab/webext-glue/metrics/ +``` + +Read `browser/config/version.txt` to get the current release version major number (e.g. `146` from `146.0`). + +Delete any `runtime-metrics-N.json` file where N is less than the current release major version. Do not delete empty files — a file containing `{"metrics": {}, "pings": {}}` should be kept if its version is current. + +### 3. Review changes + +Show the user a summary of what changed (new files, deleted files, modified files) in `browser/extensions/newtab/webext-glue/metrics/`. + +### 4. Lint + +```bash +./mach lint browser/extensions/newtab/webext-glue/metrics/ +``` + +If linting fails, fix the issue before proceeding. + +### 5. Get or file a bug + +If $ARGUMENTS contains a bug number, use it and skip to step 6. + +Otherwise, file a new bug via the Bugzilla REST API: + +```bash +curl -s -X POST https://bugzilla.mozilla.org/rest/bug \ + -H "Content-Type: application/json" \ + -d '{ + "api_key": "'"$BUGZILLA_API_KEY"'", + "product": "Firefox", + "component": "New Tab Page", + "summary": "Update runtime-metrics for Firefox MAJOR_VERSION train-hop", + "version": "Trunk", + "op_sys": "All", + "platform": "All" + }' +``` + +Replace MAJOR_VERSION with the Nightly major version read in step 2 (e.g. `147`). + +- If `BUGZILLA_API_KEY` is set in the environment, run this automatically and extract the `id` from the response. +- If `BUGZILLA_API_KEY` is not set, print the curl command (with MAJOR_VERSION substituted) for the user to run, then wait for them to provide the bug number before continuing. + +### 6. Commit + +```bash +git commit browser/extensions/newtab/webext-glue/metrics/ -m "Bug BUG_NUMBER - Update New Tab runtime metrics for train-hop r?#home-newtab-reviewers" +``` + +### 7. Submit for review + +```bash +moz-phab submit -s +``` + +## Troubleshooting + +**mach command not found** +Ensure you are running from the root of the Firefox source tree. + +**Lint fails** +Read the error output, fix the issue, and re-run the linter before committing. + +**moz-phab submit fails with auth error** +Ask the user to run `moz-phab submit` manually and check their Phabricator token. diff --git a/plugins/newtab/skills/trainhop/SKILL.md b/plugins/newtab/skills/trainhop/SKILL.md index 1d9deef..a60a1ee 100644 --- a/plugins/newtab/skills/trainhop/SKILL.md +++ b/plugins/newtab/skills/trainhop/SKILL.md @@ -15,6 +15,33 @@ Do not skip any steps. Complete each step fully before moving to the next. If a ## Steps +### 0. Check for Bugzilla API key + +Check for a `BUGZILLA_API_KEY` in the following order: + +1. Check if the environment variable is already set: `echo $BUGZILLA_API_KEY` +2. If not set, check for a `.env` file in the root of the Firefox source tree and look for a `BUGZILLA_API_KEY=` entry + +If a key is found, confirm it is set and continue. + +If no key is found, stop and instruct the user: + +> A Bugzilla API key is required to file bugs automatically during this workflow. +> To create one: +> 1. Go to https://bugzilla.mozilla.org and sign in +> 2. Click your name in the top-right → **Preferences** → **API Keys** +> 3. Enter a description (e.g. "train-hop automation") and click **Generate Key** +> 4. Copy the generated key and add it to your Firefox `.env` file: +> ``` +> BUGZILLA_API_KEY=your-key-here +> ``` +> Or export it in your shell profile (`~/.zshrc`): +> ``` +> export BUGZILLA_API_KEY=your-key-here +> ``` + +Wait for the user to confirm the key is set before continuing. + ### 1. Update locales Invoke `/trainhop-update-locales`. @@ -33,26 +60,32 @@ _Not yet automated._ Instruct the user to: Wait for the user to provide the Ship task URL before continuing. -### 5. Generate the Nimbus recipe +### 4. Generate the Nimbus recipe + +Run: + +```bash +./mach newtab trainhop-recipe +``` -Invoke `/trainhop-generate-recipe` passing the Ship task URL provided in step 4. +Display the full output to the user. They will need `addon_version` and `xpi_download_path` to complete step 5. -### 6. Create Stage Experimenter rollout for QA +### 5. Create Stage Experimenter rollout for QA _Not yet automated._ Instruct the user to: - Sign into the staging version of Experimenter - Clone the existing QA rollout template -- Set the newtabTrainhopAddon feature value to the recipe from step 5 +- Set the newtabTrainhopAddon feature value to the recipe from step 4 - Set min/max Firefox version numbers - Request rollout approval for QA Wait for the user to confirm the stage rollout is live before continuing. -### 7. File QA ticket +### 6. File QA ticket Invoke `/trainhop-file-qa-ticket` passing $ARGUMENTS (the bug number, if provided). -### 8. Create Production Experimenter rollouts +### 7. Create Production Experimenter rollouts _Not yet automated._ Instruct the user to create three rollouts on the production Experimenter instance: - **Prior version rollout**: lock to minimum version, exclude from new rollout @@ -61,15 +94,15 @@ _Not yet automated._ Instruct the user to create three rollouts on the productio Remind the user: do not request approval yet — wait for QA sign-off. -### 9. Bump minor version +### 8. Bump minor version Invoke `/trainhop-bump-version` passing $ARGUMENTS (the bug number, if provided). -### 10. Wait for QA sign-off +### 9. Wait for QA sign-off Pause and prompt the user to confirm QA has returned a green report before continuing. -### 11. Ship to Release and Beta +### 10. Ship to Release and Beta _Not yet automated._ Instruct the user to: - Alert `#system-addon-release-process` in Slack with the QA report and rollout link @@ -77,7 +110,7 @@ _Not yet automated._ Instruct the user to: - Once approved, throttle/end prior rollouts as needed and ramp to 100% over the following days - Approve the Beta rollout immediately at 100% -### 12. Find backward-compat shims to clean up +### 11. Find backward-compat shims to clean up Invoke `/trainhop-find-compat-shims`. From 8340f5947ca3aeb3828c40cb263596cea1a98614 Mon Sep 17 00:00:00 2001 From: Nathan Barrett Date: Wed, 4 Mar 2026 18:52:33 -0600 Subject: [PATCH 3/9] Add /trainhop-update-locales skill --- .../skills/trainhop-update-locales/SKILL.md | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 plugins/newtab/skills/trainhop-update-locales/SKILL.md diff --git a/plugins/newtab/skills/trainhop-update-locales/SKILL.md b/plugins/newtab/skills/trainhop-update-locales/SKILL.md new file mode 100644 index 0000000..2672bb6 --- /dev/null +++ b/plugins/newtab/skills/trainhop-update-locales/SKILL.md @@ -0,0 +1,95 @@ +--- +name: trainhop-update-locales +description: Updates the New Tab locale files for a train-hop release. Use when asked to "update train-hop locales", "run update-locales for train-hop", or "prepare locales for train-hop". Do NOT use for general locale changes unrelated to train-hopping. +argument-hint: "[bug-number] (optional)" +disable-model-invocation: true +--- + +# Train-hop: Update Locales + +Updates the en-US `newtab.ftl` and pulls the latest translations for all supported locales, then commits the result. + +## Important + +Do not skip any steps. Complete each step fully before moving to the next. + +## Steps + +### 1. Read current Nightly version + +Read `browser/config/version.txt` and extract the major version number (e.g. `147` from `147.0a1`). This will be used in the bug summary. + +### 2. Update locales + +```bash +./mach newtab update-locales +``` + +### 3. Review the locales report + +```bash +./mach newtab locales-report +``` + +Display the full report to the user. Call out any locales with **pending** strings — these may require a conversation with Product Management before proceeding, as they could block the train-hop for affected regions. + +Wait for the user to confirm it is safe to continue before proceeding. + +### 4. Get or file a bug + +If $ARGUMENTS contains a bug number, use it and skip to step 5. + +Otherwise, file a new bug via the Bugzilla REST API: + +```bash +curl -s -X POST https://bugzilla.mozilla.org/rest/bug \ + -H "Content-Type: application/json" \ + -d '{ + "api_key": "'"$BUGZILLA_API_KEY"'", + "product": "Firefox", + "component": "New Tab Page", + "summary": "Update locales for Firefox MAJOR_VERSION train-hop", + "version": "Trunk", + "op_sys": "All", + "platform": "All" + }' +``` + +Replace MAJOR_VERSION with the Nightly major version read in step 1 (e.g. `147`). + +- If `BUGZILLA_API_KEY` is set in the environment, run this automatically and extract the `id` from the response. +- If `BUGZILLA_API_KEY` is not set, print the curl command (with MAJOR_VERSION substituted) for the user to run, then wait for them to provide the bug number before continuing. + +### 5. Lint + +```bash +./mach lint browser/extensions/newtab/ +``` + +If linting fails, fix the issue before proceeding. + +### 6. Commit + +```bash +git commit browser/extensions/newtab/ -m "Bug BUG_NUMBER - Update locales for Firefox MAJOR_VERSION train-hop r?#home-newtab-reviewers" +``` + +### 7. Submit for review + +```bash +moz-phab submit +``` + +## Troubleshooting + +**Pending strings in locales report** +Stop and inform the user which locales have pending strings. They should consult Product Management before proceeding, as train-hopping may need to be blocked for affected regions or gated via Nimbus feature flags. + +**mach command not found** +Ensure you are running from the root of the Firefox source tree. + +**Lint fails** +Read the error output, fix the issue, and re-run the linter before committing. + +**moz-phab submit fails with auth error** +Ask the user to run `moz-phab submit` manually and check their Phabricator token. From db2a36580dd4540681aef11550a22814e2f38ef3 Mon Sep 17 00:00:00 2001 From: Nathan Barrett Date: Wed, 4 Mar 2026 19:02:25 -0600 Subject: [PATCH 4/9] Add /trainhop-create-metabug skill --- .../skills/trainhop-bump-version/SKILL.md | 10 ++-- .../skills/trainhop-create-metabug/SKILL.md | 53 +++++++++++++++++++ .../skills/trainhop-update-locales/SKILL.md | 10 ++-- .../skills/trainhop-update-metrics/SKILL.md | 10 ++-- plugins/newtab/skills/trainhop/SKILL.md | 38 +++++++------ 5 files changed, 90 insertions(+), 31 deletions(-) create mode 100644 plugins/newtab/skills/trainhop-create-metabug/SKILL.md diff --git a/plugins/newtab/skills/trainhop-bump-version/SKILL.md b/plugins/newtab/skills/trainhop-bump-version/SKILL.md index 5f5d768..f200919 100644 --- a/plugins/newtab/skills/trainhop-bump-version/SKILL.md +++ b/plugins/newtab/skills/trainhop-bump-version/SKILL.md @@ -1,8 +1,7 @@ --- name: trainhop-bump-version description: Bumps the newtab version in manifest.json after cutting a train-hop XPI release. Use when explicitly asked to "bump the newtab version after train-hop", "post-train-hop version bump", or "bump minor version for newtab". Optionally pass an existing Bugzilla bug number. Do NOT use for general version bumps or non-train-hop releases. -argument-hint: "[bug-number] (optional)" -disable-model-invocation: true +argument-hint: "[meta-bug-number] (optional)" --- # Train-hop: Bump Minor Version @@ -48,12 +47,15 @@ curl -s -X POST https://bugzilla.mozilla.org/rest/bug \ "summary": "Bump the minor version number of New Tab from OLD_VERSION to NEW_VERSION", "version": "Trunk", "op_sys": "All", - "platform": "All" + "platform": "All", + "blocks": [META_BUG_NUMBER] }' ``` +Replace META_BUG_NUMBER with the meta bug number from $ARGUMENTS (omit the `blocks` field if no meta bug number was provided). + - If `BUGZILLA_API_KEY` is set in the environment, run this automatically and extract the `id` from the response. -- If `BUGZILLA_API_KEY` is not set, print the curl command (with OLD_VERSION and NEW_VERSION substituted) for the user to run, then wait for them to provide the bug number before continuing. +- If `BUGZILLA_API_KEY` is not set, print the curl command (with values substituted) for the user to run, then wait for them to provide the bug number before continuing. ### 5. Edit manifest.json diff --git a/plugins/newtab/skills/trainhop-create-metabug/SKILL.md b/plugins/newtab/skills/trainhop-create-metabug/SKILL.md new file mode 100644 index 0000000..166e088 --- /dev/null +++ b/plugins/newtab/skills/trainhop-create-metabug/SKILL.md @@ -0,0 +1,53 @@ +--- +name: trainhop-create-metabug +description: Creates the Bugzilla meta bug for a New Tab train-hop release. Use when asked to "create the train-hop metabug" or "file the train-hop meta bug". Returns the meta bug number for use by other train-hop skills. +--- + +# Train-hop: Create Meta Bug + +Files the Bugzilla meta bug that tracks the full train-hop release. All other bugs filed during the train-hop process should block this meta bug. + +## Important + +Do not skip any steps. Complete each step fully before moving to the next. + +## Steps + +### 1. Read current Nightly version + +Read `browser/config/version.txt` and extract the major version number (e.g. `147` from `147.0a1`). + +### 2. File the meta bug + +```bash +curl -s -X POST https://bugzilla.mozilla.org/rest/bug \ + -H "Content-Type: application/json" \ + -d '{ + "api_key": "'"$BUGZILLA_API_KEY"'", + "product": "Firefox", + "component": "New Tab Page", + "summary": "[meta] Firefox MAJOR_VERSION train-hop metabug", + "version": "Trunk", + "op_sys": "All", + "platform": "All", + "type": "task", + "keywords": ["meta"] + }' +``` + +Replace MAJOR_VERSION with the Nightly major version from step 1 (e.g. `147`). + +- If `BUGZILLA_API_KEY` is set in the environment, run this automatically and extract the `id` from the response. +- If `BUGZILLA_API_KEY` is not set, print the curl command (with MAJOR_VERSION substituted) for the user to run, then wait for them to provide the bug number before continuing. + +### 3. Display the meta bug number + +Print the meta bug number clearly so the user can reference it. All subsequent bugs filed during this train-hop should block this meta bug. + +## Troubleshooting + +**`BUGZILLA_API_KEY` not set** +Print the curl command with MAJOR_VERSION substituted for the user to run manually, then ask them to provide the resulting bug number. + +**API returns an error** +Display the full error response. Common causes: invalid API key, or missing required fields. diff --git a/plugins/newtab/skills/trainhop-update-locales/SKILL.md b/plugins/newtab/skills/trainhop-update-locales/SKILL.md index 2672bb6..6eee567 100644 --- a/plugins/newtab/skills/trainhop-update-locales/SKILL.md +++ b/plugins/newtab/skills/trainhop-update-locales/SKILL.md @@ -1,8 +1,7 @@ --- name: trainhop-update-locales description: Updates the New Tab locale files for a train-hop release. Use when asked to "update train-hop locales", "run update-locales for train-hop", or "prepare locales for train-hop". Do NOT use for general locale changes unrelated to train-hopping. -argument-hint: "[bug-number] (optional)" -disable-model-invocation: true +argument-hint: "[meta-bug-number] (optional)" --- # Train-hop: Update Locales @@ -51,14 +50,15 @@ curl -s -X POST https://bugzilla.mozilla.org/rest/bug \ "summary": "Update locales for Firefox MAJOR_VERSION train-hop", "version": "Trunk", "op_sys": "All", - "platform": "All" + "platform": "All", + "blocks": [META_BUG_NUMBER] }' ``` -Replace MAJOR_VERSION with the Nightly major version read in step 1 (e.g. `147`). +Replace MAJOR_VERSION with the Nightly major version read in step 1 (e.g. `147`), and META_BUG_NUMBER with the meta bug number from $ARGUMENTS (omit the `blocks` field if no meta bug number was provided). - If `BUGZILLA_API_KEY` is set in the environment, run this automatically and extract the `id` from the response. -- If `BUGZILLA_API_KEY` is not set, print the curl command (with MAJOR_VERSION substituted) for the user to run, then wait for them to provide the bug number before continuing. +- If `BUGZILLA_API_KEY` is not set, print the curl command (with values substituted) for the user to run, then wait for them to provide the bug number before continuing. ### 5. Lint diff --git a/plugins/newtab/skills/trainhop-update-metrics/SKILL.md b/plugins/newtab/skills/trainhop-update-metrics/SKILL.md index bc36a23..8378326 100644 --- a/plugins/newtab/skills/trainhop-update-metrics/SKILL.md +++ b/plugins/newtab/skills/trainhop-update-metrics/SKILL.md @@ -1,8 +1,7 @@ --- name: trainhop-update-metrics description: Updates the New Tab metrics and pings JSON files for a train-hop release. Use when asked to "update train-hop metrics", "run channel-metrics-diff", or "prepare metrics for train-hop". Do NOT use for general metrics changes unrelated to train-hopping. -argument-hint: "[bug-number] (optional)" -disable-model-invocation: true +argument-hint: "[meta-bug-number] (optional)" --- # Train-hop: Update Metrics @@ -64,14 +63,15 @@ curl -s -X POST https://bugzilla.mozilla.org/rest/bug \ "summary": "Update runtime-metrics for Firefox MAJOR_VERSION train-hop", "version": "Trunk", "op_sys": "All", - "platform": "All" + "platform": "All", + "blocks": [META_BUG_NUMBER] }' ``` -Replace MAJOR_VERSION with the Nightly major version read in step 2 (e.g. `147`). +Replace MAJOR_VERSION with the Nightly major version read in step 2 (e.g. `147`), and META_BUG_NUMBER with the meta bug number from $ARGUMENTS (omit the `blocks` field if no meta bug number was provided). - If `BUGZILLA_API_KEY` is set in the environment, run this automatically and extract the `id` from the response. -- If `BUGZILLA_API_KEY` is not set, print the curl command (with MAJOR_VERSION substituted) for the user to run, then wait for them to provide the bug number before continuing. +- If `BUGZILLA_API_KEY` is not set, print the curl command (with values substituted) for the user to run, then wait for them to provide the bug number before continuing. ### 6. Commit diff --git a/plugins/newtab/skills/trainhop/SKILL.md b/plugins/newtab/skills/trainhop/SKILL.md index a60a1ee..0e67937 100644 --- a/plugins/newtab/skills/trainhop/SKILL.md +++ b/plugins/newtab/skills/trainhop/SKILL.md @@ -42,15 +42,19 @@ If no key is found, stop and instruct the user: Wait for the user to confirm the key is set before continuing. -### 1. Update locales +### 1. Create meta bug -Invoke `/trainhop-update-locales`. +Invoke `/trainhop-create-metabug`. Note the returned meta bug number — it will be passed to all subsequent skills. -### 2. Update metrics +### 2. Update locales -Invoke `/trainhop-update-metrics`. +Invoke `/trainhop-update-locales` passing the meta bug number from step 1. -### 3. Build and sign the XPI via ShipIt +### 3. Update metrics + +Invoke `/trainhop-update-metrics` passing the meta bug number from step 1. + +### 4. Build and sign the XPI via ShipIt _Not yet automated._ Instruct the user to: - Sign into the corporate VPN @@ -60,7 +64,7 @@ _Not yet automated._ Instruct the user to: Wait for the user to provide the Ship task URL before continuing. -### 4. Generate the Nimbus recipe +### 5. Generate the Nimbus recipe Run: @@ -68,24 +72,24 @@ Run: ./mach newtab trainhop-recipe ``` -Display the full output to the user. They will need `addon_version` and `xpi_download_path` to complete step 5. +Display the full output to the user. They will need `addon_version` and `xpi_download_path` to complete step 6. -### 5. Create Stage Experimenter rollout for QA +### 6. Create Stage Experimenter rollout for QA _Not yet automated._ Instruct the user to: - Sign into the staging version of Experimenter - Clone the existing QA rollout template -- Set the newtabTrainhopAddon feature value to the recipe from step 4 +- Set the newtabTrainhopAddon feature value to the recipe from step 5 - Set min/max Firefox version numbers - Request rollout approval for QA Wait for the user to confirm the stage rollout is live before continuing. -### 6. File QA ticket +### 7. File QA ticket -Invoke `/trainhop-file-qa-ticket` passing $ARGUMENTS (the bug number, if provided). +Invoke `/trainhop-file-qa-ticket` passing the meta bug number from step 1. -### 7. Create Production Experimenter rollouts +### 8. Create Production Experimenter rollouts _Not yet automated._ Instruct the user to create three rollouts on the production Experimenter instance: - **Prior version rollout**: lock to minimum version, exclude from new rollout @@ -94,15 +98,15 @@ _Not yet automated._ Instruct the user to create three rollouts on the productio Remind the user: do not request approval yet — wait for QA sign-off. -### 8. Bump minor version +### 9. Bump minor version -Invoke `/trainhop-bump-version` passing $ARGUMENTS (the bug number, if provided). +Invoke `/trainhop-bump-version` passing the meta bug number from step 1. -### 9. Wait for QA sign-off +### 10. Wait for QA sign-off Pause and prompt the user to confirm QA has returned a green report before continuing. -### 10. Ship to Release and Beta +### 11. Ship to Release and Beta _Not yet automated._ Instruct the user to: - Alert `#system-addon-release-process` in Slack with the QA report and rollout link @@ -110,7 +114,7 @@ _Not yet automated._ Instruct the user to: - Once approved, throttle/end prior rollouts as needed and ramp to 100% over the following days - Approve the Beta rollout immediately at 100% -### 11. Find backward-compat shims to clean up +### 12. Find backward-compat shims to clean up Invoke `/trainhop-find-compat-shims`. From 8e7c4454326d18c4a7522d8f5e124013e90b0d87 Mon Sep 17 00:00:00 2001 From: Reem H <42309026+reemhamz@users.noreply.github.com> Date: Thu, 5 Mar 2026 15:43:57 +1100 Subject: [PATCH 5/9] Moved children skills to be markdown files in new /references/ folder --- plugins/newtab/skills/trainhop/SKILL.md | 18 +++++++++--------- .../references/bump-version.md} | 10 ++-------- .../references/create-metabug.md} | 5 ----- .../references/update-locales.md} | 8 +------- .../references/update-metrics.md} | 10 ++-------- 5 files changed, 14 insertions(+), 37 deletions(-) rename plugins/newtab/skills/{trainhop-bump-version/SKILL.md => trainhop/references/bump-version.md} (82%) rename plugins/newtab/skills/{trainhop-create-metabug/SKILL.md => trainhop/references/create-metabug.md} (86%) rename plugins/newtab/skills/{trainhop-update-locales/SKILL.md => trainhop/references/update-locales.md} (86%) rename plugins/newtab/skills/{trainhop-update-metrics/SKILL.md => trainhop/references/update-metrics.md} (84%) diff --git a/plugins/newtab/skills/trainhop/SKILL.md b/plugins/newtab/skills/trainhop/SKILL.md index 0e67937..65b1069 100644 --- a/plugins/newtab/skills/trainhop/SKILL.md +++ b/plugins/newtab/skills/trainhop/SKILL.md @@ -7,7 +7,7 @@ disable-model-invocation: true # Train-hop: Full Workflow -Orchestrates the complete New Tab train-hop release process by invoking each child skill in sequence. Stop and report to the user if any step fails. +Orchestrates the complete New Tab train-hop release process. Stop and report to the user if any step fails. ## Important @@ -44,15 +44,15 @@ Wait for the user to confirm the key is set before continuing. ### 1. Create meta bug -Invoke `/trainhop-create-metabug`. Note the returned meta bug number — it will be passed to all subsequent skills. +Follow the instructions in `references/create-metabug.md`. Note the returned meta bug number — it will be used in all subsequent steps. ### 2. Update locales -Invoke `/trainhop-update-locales` passing the meta bug number from step 1. +Follow the instructions in `references/update-locales.md`, passing the meta bug number from step 1. ### 3. Update metrics -Invoke `/trainhop-update-metrics` passing the meta bug number from step 1. +Follow the instructions in `references/update-metrics.md`, passing the meta bug number from step 1. ### 4. Build and sign the XPI via ShipIt @@ -87,7 +87,7 @@ Wait for the user to confirm the stage rollout is live before continuing. ### 7. File QA ticket -Invoke `/trainhop-file-qa-ticket` passing the meta bug number from step 1. +_Not yet automated._ Instruct the user to file a QA ticket, linking to the meta bug from step 1. ### 8. Create Production Experimenter rollouts @@ -100,7 +100,7 @@ Remind the user: do not request approval yet — wait for QA sign-off. ### 9. Bump minor version -Invoke `/trainhop-bump-version` passing the meta bug number from step 1. +Follow the instructions in `references/bump-version.md`, passing the meta bug number from step 1. ### 10. Wait for QA sign-off @@ -116,12 +116,12 @@ _Not yet automated._ Instruct the user to: ### 12. Find backward-compat shims to clean up -Invoke `/trainhop-find-compat-shims`. +_Not yet automated._ Instruct the user to search for backward-compatibility shims in the newtab codebase that can now be removed. ## Troubleshooting -**A child skill is not installed** -Inform the user which skill is missing and that it can be installed via `claude plugin install newtab`. +**A reference file is missing** +Inform the user which file is missing and that the skill may need to be reinstalled via `claude plugin install newtab`. **Step fails partway through** Report which step failed and its error output. Do not attempt to continue past a failed step without explicit user instruction. diff --git a/plugins/newtab/skills/trainhop-bump-version/SKILL.md b/plugins/newtab/skills/trainhop/references/bump-version.md similarity index 82% rename from plugins/newtab/skills/trainhop-bump-version/SKILL.md rename to plugins/newtab/skills/trainhop/references/bump-version.md index f200919..db9c141 100644 --- a/plugins/newtab/skills/trainhop-bump-version/SKILL.md +++ b/plugins/newtab/skills/trainhop/references/bump-version.md @@ -1,9 +1,3 @@ ---- -name: trainhop-bump-version -description: Bumps the newtab version in manifest.json after cutting a train-hop XPI release. Use when explicitly asked to "bump the newtab version after train-hop", "post-train-hop version bump", or "bump minor version for newtab". Optionally pass an existing Bugzilla bug number. Do NOT use for general version bumps or non-train-hop releases. -argument-hint: "[meta-bug-number] (optional)" ---- - # Train-hop: Bump Minor Version After a New Tab train-hop XPI release is cut, the version in `browser/extensions/newtab/manifest.json` must be bumped so the next release starts from a clean state. @@ -33,7 +27,7 @@ Compare the manifest MAJOR with the Nightly MAJOR: ### 4. Get or file a bug -If $ARGUMENTS contains a bug number, use it and skip to step 5. +If a meta bug number was provided in the main workflow, use it and skip to step 5. Otherwise, file a new bug via the Bugzilla REST API: @@ -52,7 +46,7 @@ curl -s -X POST https://bugzilla.mozilla.org/rest/bug \ }' ``` -Replace META_BUG_NUMBER with the meta bug number from $ARGUMENTS (omit the `blocks` field if no meta bug number was provided). +Replace META_BUG_NUMBER with the meta bug number from the main workflow (omit the `blocks` field if no meta bug number is available). - If `BUGZILLA_API_KEY` is set in the environment, run this automatically and extract the `id` from the response. - If `BUGZILLA_API_KEY` is not set, print the curl command (with values substituted) for the user to run, then wait for them to provide the bug number before continuing. diff --git a/plugins/newtab/skills/trainhop-create-metabug/SKILL.md b/plugins/newtab/skills/trainhop/references/create-metabug.md similarity index 86% rename from plugins/newtab/skills/trainhop-create-metabug/SKILL.md rename to plugins/newtab/skills/trainhop/references/create-metabug.md index 166e088..feab06c 100644 --- a/plugins/newtab/skills/trainhop-create-metabug/SKILL.md +++ b/plugins/newtab/skills/trainhop/references/create-metabug.md @@ -1,8 +1,3 @@ ---- -name: trainhop-create-metabug -description: Creates the Bugzilla meta bug for a New Tab train-hop release. Use when asked to "create the train-hop metabug" or "file the train-hop meta bug". Returns the meta bug number for use by other train-hop skills. ---- - # Train-hop: Create Meta Bug Files the Bugzilla meta bug that tracks the full train-hop release. All other bugs filed during the train-hop process should block this meta bug. diff --git a/plugins/newtab/skills/trainhop-update-locales/SKILL.md b/plugins/newtab/skills/trainhop/references/update-locales.md similarity index 86% rename from plugins/newtab/skills/trainhop-update-locales/SKILL.md rename to plugins/newtab/skills/trainhop/references/update-locales.md index 6eee567..4cf7c7f 100644 --- a/plugins/newtab/skills/trainhop-update-locales/SKILL.md +++ b/plugins/newtab/skills/trainhop/references/update-locales.md @@ -1,9 +1,3 @@ ---- -name: trainhop-update-locales -description: Updates the New Tab locale files for a train-hop release. Use when asked to "update train-hop locales", "run update-locales for train-hop", or "prepare locales for train-hop". Do NOT use for general locale changes unrelated to train-hopping. -argument-hint: "[meta-bug-number] (optional)" ---- - # Train-hop: Update Locales Updates the en-US `newtab.ftl` and pulls the latest translations for all supported locales, then commits the result. @@ -55,7 +49,7 @@ curl -s -X POST https://bugzilla.mozilla.org/rest/bug \ }' ``` -Replace MAJOR_VERSION with the Nightly major version read in step 1 (e.g. `147`), and META_BUG_NUMBER with the meta bug number from $ARGUMENTS (omit the `blocks` field if no meta bug number was provided). +Replace MAJOR_VERSION with the Nightly major version read in step 1 (e.g. `147`), and META_BUG_NUMBER with the meta bug number from step 1 of the main workflow (omit the `blocks` field if no meta bug number is available). - If `BUGZILLA_API_KEY` is set in the environment, run this automatically and extract the `id` from the response. - If `BUGZILLA_API_KEY` is not set, print the curl command (with values substituted) for the user to run, then wait for them to provide the bug number before continuing. diff --git a/plugins/newtab/skills/trainhop-update-metrics/SKILL.md b/plugins/newtab/skills/trainhop/references/update-metrics.md similarity index 84% rename from plugins/newtab/skills/trainhop-update-metrics/SKILL.md rename to plugins/newtab/skills/trainhop/references/update-metrics.md index 8378326..f91f0ad 100644 --- a/plugins/newtab/skills/trainhop-update-metrics/SKILL.md +++ b/plugins/newtab/skills/trainhop/references/update-metrics.md @@ -1,9 +1,3 @@ ---- -name: trainhop-update-metrics -description: Updates the New Tab metrics and pings JSON files for a train-hop release. Use when asked to "update train-hop metrics", "run channel-metrics-diff", or "prepare metrics for train-hop". Do NOT use for general metrics changes unrelated to train-hopping. -argument-hint: "[meta-bug-number] (optional)" ---- - # Train-hop: Update Metrics Generates updated runtime metrics JSON files for the Beta and Release channels, cleans up stale files, and commits the result. @@ -49,7 +43,7 @@ If linting fails, fix the issue before proceeding. ### 5. Get or file a bug -If $ARGUMENTS contains a bug number, use it and skip to step 6. +If a meta bug number was provided in the main workflow, use it and skip to step 6. Otherwise, file a new bug via the Bugzilla REST API: @@ -68,7 +62,7 @@ curl -s -X POST https://bugzilla.mozilla.org/rest/bug \ }' ``` -Replace MAJOR_VERSION with the Nightly major version read in step 2 (e.g. `147`), and META_BUG_NUMBER with the meta bug number from $ARGUMENTS (omit the `blocks` field if no meta bug number was provided). +Replace MAJOR_VERSION with the Nightly major version read in step 2 (e.g. `147`), and META_BUG_NUMBER with the meta bug number from the main workflow (omit the `blocks` field if no meta bug number is available). - If `BUGZILLA_API_KEY` is set in the environment, run this automatically and extract the `id` from the response. - If `BUGZILLA_API_KEY` is not set, print the curl command (with values substituted) for the user to run, then wait for them to provide the bug number before continuing. From 49306c21d0edb4288fa6356bc47bcc341416ee66 Mon Sep 17 00:00:00 2001 From: Nathan Barrett Date: Thu, 5 Mar 2026 14:53:03 -0600 Subject: [PATCH 6/9] Move most automation to python scripts and add JIRA and confluence automations --- plugins/newtab/skills/trainhop/SKILL.md | 126 +++++--------- .../trainhop/references/bump-version.md | 88 +++------- .../references/create-confluence-page.md | 35 ++++ .../trainhop/references/create-metabug.md | 43 ++--- .../skills/trainhop/references/credentials.md | 23 +++ .../trainhop/references/file-qa-ticket.md | 27 +++ .../trainhop/references/update-locales.md | 70 +++----- .../trainhop/references/update-metrics.md | 72 +++----- .../skills/trainhop/scripts/bump_version.py | 70 ++++++++ .../trainhop/scripts/cleanup_metrics.py | 58 +++++++ .../scripts/create_confluence_page.py | 162 ++++++++++++++++++ .../skills/trainhop/scripts/file_bug.py | 79 +++++++++ .../trainhop/scripts/file_jira_ticket.py | 91 ++++++++++ 13 files changed, 661 insertions(+), 283 deletions(-) create mode 100644 plugins/newtab/skills/trainhop/references/create-confluence-page.md create mode 100644 plugins/newtab/skills/trainhop/references/credentials.md create mode 100644 plugins/newtab/skills/trainhop/references/file-qa-ticket.md create mode 100644 plugins/newtab/skills/trainhop/scripts/bump_version.py create mode 100644 plugins/newtab/skills/trainhop/scripts/cleanup_metrics.py create mode 100644 plugins/newtab/skills/trainhop/scripts/create_confluence_page.py create mode 100644 plugins/newtab/skills/trainhop/scripts/file_bug.py create mode 100644 plugins/newtab/skills/trainhop/scripts/file_jira_ticket.py diff --git a/plugins/newtab/skills/trainhop/SKILL.md b/plugins/newtab/skills/trainhop/SKILL.md index 65b1069..f714c32 100644 --- a/plugins/newtab/skills/trainhop/SKILL.md +++ b/plugins/newtab/skills/trainhop/SKILL.md @@ -1,127 +1,87 @@ --- name: trainhop -description: Runs the complete New Tab train-hop workflow from start to finish. Use when asked to "run the train-hop", "start a train-hop", "do a train-hop release", or "perform a train-hop". Optionally pass an existing Bugzilla bug number. Do NOT use for individual steps of the train-hop process. +description: Runs the New Tab train-hop release workflow for all automated steps: metabug, locales, metrics, Nimbus recipe, QA ticket, Confluence page, and version bump. Use when asked to "run the train-hop", "start a train-hop", or "do a train-hop". Do NOT use for individual steps like bumping the version or updating locales alone — those have their own skills. argument-hint: "[bug-number] (optional)" disable-model-invocation: true --- # Train-hop: Full Workflow -Orchestrates the complete New Tab train-hop release process. Stop and report to the user if any step fails. +## Before Starting -## Important +**Step 1: Ask the user which phase to run** (present as a numbered list): -Do not skip any steps. Complete each step fully before moving to the next. If a step is marked "not yet automated", pause and instruct the user to complete it manually before continuing. +> Which steps would you like to run? +> +> **1. Full workflow** — all automated steps from start to finish +> **2. Prep only** — steps 1–3: create metabug, update locales, update metrics (run before the XPI is cut) +> **3. Post-XPI** — steps 4–6: Nimbus recipe, QA ticket + Confluence page, version bump +> **4. Custom** — specify which numbered steps to include -## Steps +Wait for the user's answer before continuing. + +**Step 2: Collect inputs** — ask for the following based on the selected phase: -### 0. Check for Bugzilla API key +- If the phase includes step 4 (Nimbus recipe): **Ship task URL** from ShipIt +- If the phase includes step 5 (QA ticket + Confluence page): + - **XPI cut date** (e.g. `2026-01-19`) + - **QA handoff date** (e.g. `2026-01-20`) + - **Release date** (e.g. `2026-01-22`) + - **Release Management contact** (check https://whattrainisitnow.com for the release owner) + - **QA contact** (QA engineer assigned to this train-hop) -Check for a `BUGZILLA_API_KEY` in the following order: +**Step 3: Present the plan** — list the steps that will be executed and wait for confirmation before proceeding. -1. Check if the environment variable is already set: `echo $BUGZILLA_API_KEY` -2. If not set, check for a `.env` file in the root of the Firefox source tree and look for a `BUGZILLA_API_KEY=` entry +## Pre-conditions -If a key is found, confirm it is set and continue. +Before running any steps, verify: -If no key is found, stop and instruct the user: +- Working tree is clean: `git status` shows no uncommitted changes +- On `main` branch and up to date: `git pull` +- Bugzilla API key is ready (see `references/credentials.md` if needed) +- Atlassian email and API token are ready (see `references/credentials.md` if needed) -> A Bugzilla API key is required to file bugs automatically during this workflow. -> To create one: -> 1. Go to https://bugzilla.mozilla.org and sign in -> 2. Click your name in the top-right → **Preferences** → **API Keys** -> 3. Enter a description (e.g. "train-hop automation") and click **Generate Key** -> 4. Copy the generated key and add it to your Firefox `.env` file: -> ``` -> BUGZILLA_API_KEY=your-key-here -> ``` -> Or export it in your shell profile (`~/.zshrc`): -> ``` -> export BUGZILLA_API_KEY=your-key-here -> ``` +## Steps -Wait for the user to confirm the key is set before continuing. +Stop and report to the user if any step fails. Do not proceed past a failed step without explicit instruction. ### 1. Create meta bug -Follow the instructions in `references/create-metabug.md`. Note the returned meta bug number — it will be used in all subsequent steps. +Follow `references/create-metabug.md`. Note the returned bug number — pass it to all subsequent steps. ### 2. Update locales -Follow the instructions in `references/update-locales.md`, passing the meta bug number from step 1. +Follow `references/update-locales.md`, passing the meta bug number from step 1. ### 3. Update metrics -Follow the instructions in `references/update-metrics.md`, passing the meta bug number from step 1. - -### 4. Build and sign the XPI via ShipIt - -_Not yet automated._ Instruct the user to: -- Sign into the corporate VPN -- Visit https://shipit.mozilla-releng.net/newxpi, select "newtab", enter the GitHub SHA, and create the release -- Coordinate with a second HNT engineer for the two-engineer sign-off -- Copy the Ship task URL once the build completes +Follow `references/update-metrics.md`, passing the meta bug number from step 1. -Wait for the user to provide the Ship task URL before continuing. - -### 5. Generate the Nimbus recipe - -Run: +### 4. Generate the Nimbus recipe ```bash ./mach newtab trainhop-recipe ``` -Display the full output to the user. They will need `addon_version` and `xpi_download_path` to complete step 6. - -### 6. Create Stage Experimenter rollout for QA - -_Not yet automated._ Instruct the user to: -- Sign into the staging version of Experimenter -- Clone the existing QA rollout template -- Set the newtabTrainhopAddon feature value to the recipe from step 5 -- Set min/max Firefox version numbers -- Request rollout approval for QA - -Wait for the user to confirm the stage rollout is live before continuing. - -### 7. File QA ticket - -_Not yet automated._ Instruct the user to file a QA ticket, linking to the meta bug from step 1. - -### 8. Create Production Experimenter rollouts - -_Not yet automated._ Instruct the user to create three rollouts on the production Experimenter instance: -- **Prior version rollout**: lock to minimum version, exclude from new rollout -- **Release rollout**: new version, start at 25% (or 100% if a prior rollout exists) -- **Beta rollout**: new version, 100% - -Remind the user: do not request approval yet — wait for QA sign-off. - -### 9. Bump minor version - -Follow the instructions in `references/bump-version.md`, passing the meta bug number from step 1. - -### 10. Wait for QA sign-off +Use the Ship task URL collected in the Inputs section. Display the full output. -Pause and prompt the user to confirm QA has returned a green report before continuing. +### 5. File QA ticket and create Confluence page -### 11. Ship to Release and Beta +Follow `references/file-qa-ticket.md`. Note the returned Jira ticket key. -_Not yet automated._ Instruct the user to: -- Alert `#system-addon-release-process` in Slack with the QA report and rollout link -- Request Release Management approval on the production Release rollout -- Once approved, throttle/end prior rollouts as needed and ramp to 100% over the following days -- Approve the Beta rollout immediately at 100% +Then follow `references/create-confluence-page.md`, passing: +- The meta bug number from step 1 +- The QA ticket key from above +- The dates and contacts collected in the Inputs section -### 12. Find backward-compat shims to clean up +### 6. Bump minor version -_Not yet automated._ Instruct the user to search for backward-compatibility shims in the newtab codebase that can now be removed. +Follow `references/bump-version.md`, passing the meta bug number from step 1. ## Troubleshooting **A reference file is missing** -Inform the user which file is missing and that the skill may need to be reinstalled via `claude plugin install newtab`. +The skill may need to be reinstalled: `claude plugin install newtab`. **Step fails partway through** -Report which step failed and its error output. Do not attempt to continue past a failed step without explicit user instruction. +Report which step failed and its error output. Do not continue without explicit user instruction. diff --git a/plugins/newtab/skills/trainhop/references/bump-version.md b/plugins/newtab/skills/trainhop/references/bump-version.md index db9c141..4941cd4 100644 --- a/plugins/newtab/skills/trainhop/references/bump-version.md +++ b/plugins/newtab/skills/trainhop/references/bump-version.md @@ -1,96 +1,48 @@ # Train-hop: Bump Minor Version -After a New Tab train-hop XPI release is cut, the version in `browser/extensions/newtab/manifest.json` must be bumped so the next release starts from a clean state. +Bumps the version in `manifest.json` after the XPI is cut, so Nightly clients prefer the built-in New Tab over the train-hopped one on next update. -## Important +## Pre-condition -Do not skip any steps. Complete every step in order before moving to the next. +Working tree is clean on `main`. The XPI has already been built and signed via ShipIt. ## Steps -### 1. Read current version - -Read `browser/extensions/newtab/manifest.json` and extract the `version` field (format: `MAJOR.MINOR.PATCH`). - -### 2. Read current Nightly version - -Read `browser/config/version.txt` and extract the major version number (e.g. `150` from `150.0a1`). - -### 3. Compute new version - -Compare the manifest MAJOR with the Nightly MAJOR: - -- If they match (still on same Nightly): bump MINOR by 1, keep PATCH as 0 - - e.g. `149.2.0` → `149.3.0` -- If Nightly MAJOR is higher (train moved forward): use Nightly MAJOR, reset MINOR and PATCH to 0 - - e.g. manifest `149.2.0`, Nightly `150` → `150.0.0` - -### 4. Get or file a bug - -If a meta bug number was provided in the main workflow, use it and skip to step 5. - -Otherwise, file a new bug via the Bugzilla REST API: +### 1. Compute and apply new version ```bash -curl -s -X POST https://bugzilla.mozilla.org/rest/bug \ - -H "Content-Type: application/json" \ - -d '{ - "api_key": "'"$BUGZILLA_API_KEY"'", - "product": "Firefox", - "component": "New Tab Page", - "summary": "Bump the minor version number of New Tab from OLD_VERSION to NEW_VERSION", - "version": "Trunk", - "op_sys": "All", - "platform": "All", - "blocks": [META_BUG_NUMBER] - }' +python3 /bump_version.py ``` -Replace META_BUG_NUMBER with the meta bug number from the main workflow (omit the `blocks` field if no meta bug number is available). - -- If `BUGZILLA_API_KEY` is set in the environment, run this automatically and extract the `id` from the response. -- If `BUGZILLA_API_KEY` is not set, print the curl command (with values substituted) for the user to run, then wait for them to provide the bug number before continuing. - -### 5. Edit manifest.json - -Edit `browser/extensions/newtab/manifest.json`, updating the `version` field to the new version. +The script reads `manifest.json` and `browser/config/version.txt`, computes the new version, writes it to `manifest.json`, and prints `OLD_VERSION → NEW_VERSION`. Note both — used in the commit message. -### 6. Lint - -Run the linter on the manifest: +### 2. File a bug ```bash -./mach lint --fix browser/extensions/newtab/manifest.json +python3 /file_bug.py \ + --summary "Bump the minor version number of New Tab from OLD_VERSION to NEW_VERSION" \ + --blocks META_BUG_NUMBER ``` -If linting fails, fix the issue before proceeding. - -### 7. Commit +Omit `--blocks` if no meta bug number is available. Note the printed bug ID. -Commit the change: +### 3. Create a branch, lint, commit, and submit ```bash +git checkout -b bug-BUG_NUMBER-bump-newtab-version-trainhop +./mach lint --fix browser/extensions/newtab/manifest.json git commit browser/extensions/newtab/manifest.json -m "Bug BUG_NUMBER - Bump the newtab manifest version number r?#home-newtab-reviewers" +moz-phab submit -s ``` -### 8. Submit for review +## Expected Result -Run: - -```bash -moz-phab submit -s -``` +`browser/extensions/newtab/manifest.json` `version` field reads `NEW_VERSION`. A Phabricator revision is open for review. `git log --oneline -1` shows the bump commit on the new branch. ## Troubleshooting -**`BUGZILLA_API_KEY` not set** -Print the curl command with substituted values for the user to run manually, then ask them to provide the resulting bug number. - **Lint fails** -Read the error output, fix the issue in `manifest.json`, and re-run the linter before committing. - -**`moz-phab submit` fails with auth error** -Ask the user to run `moz-phab submit` manually. They may need to re-authenticate with `moz-phab self-update` or check their Phabricator token. +Read the error, fix the issue in `manifest.json`, and re-run before committing. -**`moz-phab submit` fails with "no commit found"** -Verify the commit was created in step 7. Run `git log --oneline -3` to confirm. +**moz-phab fails with "no commit found"** +Run `git log --oneline -3` to confirm the commit was created before retrying. diff --git a/plugins/newtab/skills/trainhop/references/create-confluence-page.md b/plugins/newtab/skills/trainhop/references/create-confluence-page.md new file mode 100644 index 0000000..62193a9 --- /dev/null +++ b/plugins/newtab/skills/trainhop/references/create-confluence-page.md @@ -0,0 +1,35 @@ +# Train-hop: Create Confluence Page + +Creates the `HNT VERSION Train Hop` tracking page in the FPS Confluence space. + +## Steps + +### 1. Create the page + +Read the major version from `browser/config/version.txt` (e.g. `147`), then run: + +```bash +python3 /create_confluence_page.py \ + --version MAJOR_VERSION \ + --metabug-url https://bugzilla.mozilla.org/show_bug.cgi?id=META_BUG_NUMBER \ + --qa-ticket QA_TICKET_KEY \ + --xpi-cut XPI_CUT_DATE \ + --qa-handoff QA_HANDOFF_DATE \ + --release-date RELEASE_DATE \ + --relman "REL_MAN_CONTACT" \ + --qa-contact "QA_CONTACT" +``` + +Substitute values from the inputs collected at the start of the workflow. The script prompts for your Atlassian email and API token, then prints the page URL. + +## Expected Result + +The page is accessible at the printed URL under the Train Hops folder in the FPS space, with the summary, timeline, and empty tables pre-populated. The user fills in the "Features being tested" table manually. + +## Troubleshooting + +**HTTP 401** +Check that your email and API token are correct. Get a token at: https://id.atlassian.com/manage-profile/security/api-tokens + +**HTTP 404** +Parent folder ID `1872035972` may have changed. Update `PARENT_PAGE_ID` in `scripts/create_confluence_page.py`. diff --git a/plugins/newtab/skills/trainhop/references/create-metabug.md b/plugins/newtab/skills/trainhop/references/create-metabug.md index feab06c..5f0657c 100644 --- a/plugins/newtab/skills/trainhop/references/create-metabug.md +++ b/plugins/newtab/skills/trainhop/references/create-metabug.md @@ -1,48 +1,27 @@ # Train-hop: Create Meta Bug -Files the Bugzilla meta bug that tracks the full train-hop release. All other bugs filed during the train-hop process should block this meta bug. - -## Important - -Do not skip any steps. Complete each step fully before moving to the next. +Files the Bugzilla meta bug that tracks the full train-hop release. All other bugs filed during the train-hop process block this meta bug. ## Steps -### 1. Read current Nightly version - -Read `browser/config/version.txt` and extract the major version number (e.g. `147` from `147.0a1`). +### 1. File the meta bug -### 2. File the meta bug +Read the major version from `browser/config/version.txt` (e.g. `147` from `147.0a1`), then run: ```bash -curl -s -X POST https://bugzilla.mozilla.org/rest/bug \ - -H "Content-Type: application/json" \ - -d '{ - "api_key": "'"$BUGZILLA_API_KEY"'", - "product": "Firefox", - "component": "New Tab Page", - "summary": "[meta] Firefox MAJOR_VERSION train-hop metabug", - "version": "Trunk", - "op_sys": "All", - "platform": "All", - "type": "task", - "keywords": ["meta"] - }' +python3 /file_bug.py \ + --summary "[meta] Firefox MAJOR_VERSION train-hop metabug" \ + --type task \ + --keywords meta ``` -Replace MAJOR_VERSION with the Nightly major version from step 1 (e.g. `147`). +The script prompts for your Bugzilla API key and prints the new bug ID. Note it — all subsequent bugs in this workflow will block it. -- If `BUGZILLA_API_KEY` is set in the environment, run this automatically and extract the `id` from the response. -- If `BUGZILLA_API_KEY` is not set, print the curl command (with MAJOR_VERSION substituted) for the user to run, then wait for them to provide the bug number before continuing. +## Expected Result -### 3. Display the meta bug number - -Print the meta bug number clearly so the user can reference it. All subsequent bugs filed during this train-hop should block this meta bug. +The meta bug is visible at `https://bugzilla.mozilla.org/show_bug.cgi?id=BUG_ID` with summary `[meta] Firefox MAJOR_VERSION train-hop metabug` and the `meta` keyword. ## Troubleshooting -**`BUGZILLA_API_KEY` not set** -Print the curl command with MAJOR_VERSION substituted for the user to run manually, then ask them to provide the resulting bug number. - **API returns an error** -Display the full error response. Common causes: invalid API key, or missing required fields. +The script prints the full message. Common cause: the `meta` keyword requires special Bugzilla permissions — ask a peer with those permissions to file it manually. diff --git a/plugins/newtab/skills/trainhop/references/credentials.md b/plugins/newtab/skills/trainhop/references/credentials.md new file mode 100644 index 0000000..dd2d64e --- /dev/null +++ b/plugins/newtab/skills/trainhop/references/credentials.md @@ -0,0 +1,23 @@ +# Credential Setup + +The train-hop workflow requires the following credentials. Scripts will prompt for them at runtime — nothing needs to be stored. + +## Bugzilla API Key + +Used to file Bugzilla bugs automatically. + +1. Go to https://bugzilla.mozilla.org and sign in +2. Click your name → **Preferences** → **API Keys** +3. Enter a description (e.g. "train-hop automation") and click **Generate Key** +4. Copy the key — you will be prompted for it when the script runs + +## Atlassian Credentials + +Used to create Jira tickets and Confluence pages. + +**Email**: your Mozilla email address (e.g. `you@mozilla.com`) + +**API Token**: +1. Go to https://id.atlassian.com/manage-profile/security/api-tokens +2. Click **Create API token** +3. Enter a label (e.g. "train-hop") and copy the token diff --git a/plugins/newtab/skills/trainhop/references/file-qa-ticket.md b/plugins/newtab/skills/trainhop/references/file-qa-ticket.md new file mode 100644 index 0000000..edca072 --- /dev/null +++ b/plugins/newtab/skills/trainhop/references/file-qa-ticket.md @@ -0,0 +1,27 @@ +# Train-hop: File QA Ticket + +Creates a Jira ticket in the QA project to notify QA that the train-hop XPI is ready for testing. + +## Steps + +### 1. Create the ticket + +Read the major version from `browser/config/version.txt` (e.g. `147`), then run: + +```bash +python3 /file_jira_ticket.py --version MAJOR_VERSION +``` + +The script prompts for your Atlassian email and API token and prints the ticket key (e.g. `QA-1234`). Note it for the Confluence page. + +## Expected Result + +The ticket is visible at `https://mozilla-hub.atlassian.net/browse/QA-XXXX` with summary `Testing New Tab train-hop for Firefox MAJOR_VERSION Release`. + +## Troubleshooting + +**HTTP 401** +Check that your email and API token are correct. Get a token at: https://id.atlassian.com/manage-profile/security/api-tokens + +**HTTP 400** +Issue type ID `11461` may have changed. Update `ISSUE_TYPE_ID` in `scripts/file_jira_ticket.py`. diff --git a/plugins/newtab/skills/trainhop/references/update-locales.md b/plugins/newtab/skills/trainhop/references/update-locales.md index 4cf7c7f..c7afc5f 100644 --- a/plugins/newtab/skills/trainhop/references/update-locales.md +++ b/plugins/newtab/skills/trainhop/references/update-locales.md @@ -1,89 +1,61 @@ # Train-hop: Update Locales -Updates the en-US `newtab.ftl` and pulls the latest translations for all supported locales, then commits the result. +Updates `newtab.ftl` and pulls the latest translations for all supported locales. -## Important +## Pre-condition -Do not skip any steps. Complete each step fully before moving to the next. +Working tree is clean on `main`. ## Steps -### 1. Read current Nightly version - -Read `browser/config/version.txt` and extract the major version number (e.g. `147` from `147.0a1`). This will be used in the bug summary. - -### 2. Update locales +### 1. Update locales ```bash ./mach newtab update-locales ``` -### 3. Review the locales report +### 2. Review the locales report ```bash ./mach newtab locales-report ``` -Display the full report to the user. Call out any locales with **pending** strings — these may require a conversation with Product Management before proceeding, as they could block the train-hop for affected regions. +Display the full report. Call out any locales with **pending** strings — these may need a conversation with Product Management before proceeding, as they could block the train-hop for affected regions. -Wait for the user to confirm it is safe to continue before proceeding. +Wait for the user to confirm it is safe to continue. -### 4. Get or file a bug +### 3. File a bug -If $ARGUMENTS contains a bug number, use it and skip to step 5. - -Otherwise, file a new bug via the Bugzilla REST API: +Read the major version from `browser/config/version.txt` (e.g. `147`), then run: ```bash -curl -s -X POST https://bugzilla.mozilla.org/rest/bug \ - -H "Content-Type: application/json" \ - -d '{ - "api_key": "'"$BUGZILLA_API_KEY"'", - "product": "Firefox", - "component": "New Tab Page", - "summary": "Update locales for Firefox MAJOR_VERSION train-hop", - "version": "Trunk", - "op_sys": "All", - "platform": "All", - "blocks": [META_BUG_NUMBER] - }' +python3 /file_bug.py \ + --summary "Update locales for Firefox MAJOR_VERSION train-hop" \ + --blocks META_BUG_NUMBER ``` -Replace MAJOR_VERSION with the Nightly major version read in step 1 (e.g. `147`), and META_BUG_NUMBER with the meta bug number from step 1 of the main workflow (omit the `blocks` field if no meta bug number is available). - -- If `BUGZILLA_API_KEY` is set in the environment, run this automatically and extract the `id` from the response. -- If `BUGZILLA_API_KEY` is not set, print the curl command (with values substituted) for the user to run, then wait for them to provide the bug number before continuing. +Omit `--blocks` if no meta bug number is available. Note the printed bug ID. -### 5. Lint +### 4. Create a branch, lint, commit, and submit ```bash +git checkout -b bug-BUG_NUMBER-update-locales-trainhop ./mach lint browser/extensions/newtab/ -``` - -If linting fails, fix the issue before proceeding. - -### 6. Commit - -```bash git commit browser/extensions/newtab/ -m "Bug BUG_NUMBER - Update locales for Firefox MAJOR_VERSION train-hop r?#home-newtab-reviewers" +moz-phab submit ``` -### 7. Submit for review +## Expected Result -```bash -moz-phab submit -``` +A Phabricator revision is open for review. `git log --oneline -1` shows the locales commit on the new branch. ## Troubleshooting **Pending strings in locales report** -Stop and inform the user which locales have pending strings. They should consult Product Management before proceeding, as train-hopping may need to be blocked for affected regions or gated via Nimbus feature flags. - -**mach command not found** -Ensure you are running from the root of the Firefox source tree. +Stop and inform the user which locales are affected. Consult Product Management — the train-hop may need to be blocked for those regions or gated via Nimbus. **Lint fails** -Read the error output, fix the issue, and re-run the linter before committing. +Read the error, fix the issue, and re-run before committing. -**moz-phab submit fails with auth error** +**moz-phab auth error** Ask the user to run `moz-phab submit` manually and check their Phabricator token. diff --git a/plugins/newtab/skills/trainhop/references/update-metrics.md b/plugins/newtab/skills/trainhop/references/update-metrics.md index f91f0ad..434e5b3 100644 --- a/plugins/newtab/skills/trainhop/references/update-metrics.md +++ b/plugins/newtab/skills/trainhop/references/update-metrics.md @@ -1,16 +1,14 @@ # Train-hop: Update Metrics -Generates updated runtime metrics JSON files for the Beta and Release channels, cleans up stale files, and commits the result. +Generates updated runtime metrics JSON files for Beta and Release, cleans up stale files, and commits. -## Important +## Pre-condition -Do not skip any steps. Complete each step fully before moving to the next. +Working tree is clean on `main`. ## Steps -### 1. Run channel-metrics-diff for both channels - -Run both commands: +### 1. Run channel-metrics-diff ```bash ./mach newtab channel-metrics-diff --channel beta @@ -19,73 +17,45 @@ Run both commands: ### 2. Clean up stale runtime-metrics files -List the files in `browser/extensions/newtab/webext-glue/metrics/`: - ```bash -ls browser/extensions/newtab/webext-glue/metrics/ +python3 /cleanup_metrics.py ``` -Read `browser/config/version.txt` to get the current release version major number (e.g. `146` from `146.0`). - -Delete any `runtime-metrics-N.json` file where N is less than the current release major version. Do not delete empty files — a file containing `{"metrics": {}, "pings": {}}` should be kept if its version is current. +The script deletes `runtime-metrics-N.json` files where N is less than the current Nightly major version and reports what was deleted. ### 3. Review changes -Show the user a summary of what changed (new files, deleted files, modified files) in `browser/extensions/newtab/webext-glue/metrics/`. - -### 4. Lint - -```bash -./mach lint browser/extensions/newtab/webext-glue/metrics/ -``` - -If linting fails, fix the issue before proceeding. +Show the user a summary of changed, added, and deleted files in `browser/extensions/newtab/webext-glue/metrics/`. -### 5. Get or file a bug +### 4. File a bug -If a meta bug number was provided in the main workflow, use it and skip to step 6. - -Otherwise, file a new bug via the Bugzilla REST API: +Read the major version from `browser/config/version.txt` (e.g. `147`), then run: ```bash -curl -s -X POST https://bugzilla.mozilla.org/rest/bug \ - -H "Content-Type: application/json" \ - -d '{ - "api_key": "'"$BUGZILLA_API_KEY"'", - "product": "Firefox", - "component": "New Tab Page", - "summary": "Update runtime-metrics for Firefox MAJOR_VERSION train-hop", - "version": "Trunk", - "op_sys": "All", - "platform": "All", - "blocks": [META_BUG_NUMBER] - }' +python3 /file_bug.py \ + --summary "Update runtime-metrics for Firefox MAJOR_VERSION train-hop" \ + --blocks META_BUG_NUMBER ``` -Replace MAJOR_VERSION with the Nightly major version read in step 2 (e.g. `147`), and META_BUG_NUMBER with the meta bug number from the main workflow (omit the `blocks` field if no meta bug number is available). - -- If `BUGZILLA_API_KEY` is set in the environment, run this automatically and extract the `id` from the response. -- If `BUGZILLA_API_KEY` is not set, print the curl command (with values substituted) for the user to run, then wait for them to provide the bug number before continuing. +Omit `--blocks` if no meta bug number is available. Note the printed bug ID. -### 6. Commit +### 5. Create a branch, lint, commit, and submit ```bash +git checkout -b bug-BUG_NUMBER-update-metrics-trainhop +./mach lint browser/extensions/newtab/webext-glue/metrics/ git commit browser/extensions/newtab/webext-glue/metrics/ -m "Bug BUG_NUMBER - Update New Tab runtime metrics for train-hop r?#home-newtab-reviewers" +moz-phab submit -s ``` -### 7. Submit for review +## Expected Result -```bash -moz-phab submit -s -``` +A Phabricator revision is open for review. `git log --oneline -1` shows the metrics commit on the new branch. ## Troubleshooting -**mach command not found** -Ensure you are running from the root of the Firefox source tree. - **Lint fails** -Read the error output, fix the issue, and re-run the linter before committing. +Read the error, fix the issue, and re-run before committing. -**moz-phab submit fails with auth error** +**moz-phab auth error** Ask the user to run `moz-phab submit` manually and check their Phabricator token. diff --git a/plugins/newtab/skills/trainhop/scripts/bump_version.py b/plugins/newtab/skills/trainhop/scripts/bump_version.py new file mode 100644 index 0000000..d485ac1 --- /dev/null +++ b/plugins/newtab/skills/trainhop/scripts/bump_version.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +""" +Computes and applies the next New Tab version for a train-hop release. + +Reads the current version from browser/extensions/newtab/manifest.json and +the current Nightly version from browser/config/version.txt, then: + - If the manifest MAJOR matches Nightly MAJOR: bumps MINOR, resets PATCH to 0 + - If Nightly MAJOR is higher: uses Nightly MAJOR, resets MINOR and PATCH to 0 + +Must be run from the root of the Firefox source tree. +""" + +import json +import sys +from pathlib import Path + + +def main(): + repo_root = Path.cwd() + + # Read current manifest version + manifest_path = repo_root / "browser/extensions/newtab/manifest.json" + if not manifest_path.exists(): + print(f"Error: {manifest_path} not found. Run from the Firefox repo root.", file=sys.stderr) + sys.exit(1) + + with open(manifest_path) as f: + manifest = json.load(f) + + current_version = manifest["version"] + parts = current_version.split(".") + if len(parts) != 3: + print(f"Error: unexpected version format: {current_version}", file=sys.stderr) + sys.exit(1) + + manifest_major, manifest_minor = int(parts[0]), int(parts[1]) + + # Read current Nightly version + version_path = repo_root / "browser/config/version.txt" + if not version_path.exists(): + print(f"Error: {version_path} not found. Run from the Firefox repo root.", file=sys.stderr) + sys.exit(1) + + version_text = version_path.read_text().strip() + nightly_major = int(version_text.split(".")[0]) + + # Compute new version + if manifest_major == nightly_major: + new_version = f"{manifest_major}.{manifest_minor + 1}.0" + elif nightly_major > manifest_major: + new_version = f"{nightly_major}.0.0" + else: + print( + f"Error: manifest MAJOR ({manifest_major}) is ahead of Nightly ({nightly_major}). " + "Something is wrong.", + file=sys.stderr, + ) + sys.exit(1) + + # Write new version + manifest["version"] = new_version + with open(manifest_path, "w") as f: + json.dump(manifest, f, indent=2) + f.write("\n") + + print(f"{current_version} → {new_version}") + + +if __name__ == "__main__": + main() diff --git a/plugins/newtab/skills/trainhop/scripts/cleanup_metrics.py b/plugins/newtab/skills/trainhop/scripts/cleanup_metrics.py new file mode 100644 index 0000000..c7b7ffc --- /dev/null +++ b/plugins/newtab/skills/trainhop/scripts/cleanup_metrics.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +""" +Deletes stale runtime-metrics-N.json files from the New Tab metrics directory. + +Reads the current Nightly major version from browser/config/version.txt and +removes any runtime-metrics-N.json file where N is less than that version, +as those files are no longer needed. + +Must be run from the root of the Firefox source tree. +""" + +import re +import sys +from pathlib import Path + + +def main(): + repo_root = Path.cwd() + + # Read current Nightly version to determine the cutoff + version_path = repo_root / "browser/config/version.txt" + if not version_path.exists(): + print(f"Error: {version_path} not found. Run from the Firefox repo root.", file=sys.stderr) + sys.exit(1) + + version_text = version_path.read_text().strip() + current_major = int(version_text.split(".")[0]) + + metrics_dir = repo_root / "browser/extensions/newtab/webext-glue/metrics" + if not metrics_dir.exists(): + print(f"Error: {metrics_dir} not found. Run from the Firefox repo root.", file=sys.stderr) + sys.exit(1) + + deleted = [] + kept = [] + + for f in sorted(metrics_dir.glob("runtime-metrics-*.json")): + match = re.match(r"runtime-metrics-(\d+)\.json$", f.name) + if not match: + continue + file_version = int(match.group(1)) + if file_version < current_major: + f.unlink() + deleted.append(f.name) + else: + kept.append(f.name) + + if deleted: + print(f"Deleted ({len(deleted)}): {', '.join(deleted)}") + else: + print("No stale files to delete.") + + if kept: + print(f"Kept ({len(kept)}): {', '.join(kept)}") + + +if __name__ == "__main__": + main() diff --git a/plugins/newtab/skills/trainhop/scripts/create_confluence_page.py b/plugins/newtab/skills/trainhop/scripts/create_confluence_page.py new file mode 100644 index 0000000..89f7331 --- /dev/null +++ b/plugins/newtab/skills/trainhop/scripts/create_confluence_page.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python3 +""" +Creates the train-hop tracking page in the Firefox Product Space (FPS) Confluence space. + +Prompts for Atlassian credentials at runtime. +Prints the URL of the created page on success. + +Usage: + python3 create_confluence_page.py \ + --version 147 \ + --metabug-url https://bugzilla.mozilla.org/show_bug.cgi?id=2008783 \ + --qa-ticket QA-4752 \ + --xpi-cut 2026-01-19 \ + --qa-handoff 2026-01-20 \ + --release-date 2026-01-22 \ + --relman "Ryan VanderMeulen" \ + --qa-contact "Valentin Bandac" +""" + +import argparse +import base64 +import getpass +import json +import sys +import urllib.request +import urllib.error + +CONFLUENCE_BASE_URL = "https://mozilla-hub.atlassian.net/wiki" +SPACE_KEY = "FPS" +PARENT_PAGE_ID = "1872035972" # "Train Hops" folder in FPS space +JIRA_BASE_URL = "https://mozilla-hub.atlassian.net/browse" + + +def get_auth_header(email, token): + credentials = base64.b64encode(f"{email}:{token}".encode()).decode() + return f"Basic {credentials}" + + +def build_page_content(args): + qa_ticket_url = f"{JIRA_BASE_URL}/{args.qa_ticket}" + + return f"""

Summary:

+
    +
  • Meta Bug: {args.metabug_url}
  • +
  • QA Bug: {args.qa_ticket}
  • +
  • Timeline: +
      +
    • XPI Cut: {args.xpi_cut}
    • +
    • QA Handoff: {args.qa_handoff}
    • +
    • Release: {args.release_date}
    • +
    +
  • +
  • Rel Man contact: {args.relman}
  • +
  • QA contact: {args.qa_contact}
  • +
+

Helpful Links

+ +
+

Features being tested:

+

These are the experiments/tickets that are planned as part of this release. They can be required or optional.

+ + + + + + + + + + +
Jira Ticket / SummaryProduct OwnerPriority
+

QA Verified Bugs/Patches

+ + + + + + + + + + + +
BugSummaryLanding StatusQA Status
+

Shims added for @backward-compat

+ + + + + + + + + + +
Bug LinkTitleNotes
""" + + +def main(): + parser = argparse.ArgumentParser(description="Create the train-hop Confluence page") + parser.add_argument("--version", required=True, help="Firefox major version (e.g. 147)") + parser.add_argument("--metabug-url", required=True, help="Full Bugzilla metabug URL") + parser.add_argument("--qa-ticket", required=True, help="Jira QA ticket key (e.g. QA-4752)") + parser.add_argument("--xpi-cut", required=True, help="XPI cut date (e.g. 2026-01-19)") + parser.add_argument("--qa-handoff", required=True, help="QA handoff date (e.g. 2026-01-20)") + parser.add_argument("--release-date", required=True, help="Release date (e.g. 2026-01-22)") + parser.add_argument("--relman", required=True, help="Release Management contact name") + parser.add_argument("--qa-contact", required=True, help="QA contact name") + args = parser.parse_args() + + email = input("Atlassian email: ") + token = getpass.getpass("Atlassian API token: ") + + title = f"HNT {args.version} Train Hop" + content = build_page_content(args) + + payload = { + "type": "page", + "title": title, + "space": {"key": SPACE_KEY}, + "ancestors": [{"id": PARENT_PAGE_ID}], + "body": { + "storage": { + "value": content, + "representation": "storage", + } + }, + } + + data = json.dumps(payload).encode("utf-8") + req = urllib.request.Request( + f"{CONFLUENCE_BASE_URL}/rest/api/content", + data=data, + headers={ + "Content-Type": "application/json", + "Authorization": get_auth_header(email, token), + }, + method="POST", + ) + + try: + with urllib.request.urlopen(req) as resp: + result = json.loads(resp.read()) + page_id = result["id"] + page_url = f"{CONFLUENCE_BASE_URL}/spaces/{SPACE_KEY}/pages/{page_id}/{title.replace(' ', '+')}" + print(page_url) + except urllib.error.HTTPError as e: + error_body = e.read().decode() + print(f"Error: HTTP {e.code} {e.reason}", file=sys.stderr) + print(error_body, file=sys.stderr) + sys.exit(1) + except urllib.error.URLError as e: + print(f"Error: {e.reason}", file=sys.stderr) + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/plugins/newtab/skills/trainhop/scripts/file_bug.py b/plugins/newtab/skills/trainhop/scripts/file_bug.py new file mode 100644 index 0000000..59d7aed --- /dev/null +++ b/plugins/newtab/skills/trainhop/scripts/file_bug.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +""" +Files a Bugzilla bug for a New Tab train-hop step. + +Prompts for the Bugzilla API key at runtime. +Prints the new bug ID to stdout on success. + +Usage: + python3 file_bug.py --summary "Update locales for Firefox 147 train-hop" + python3 file_bug.py --summary "..." --blocks 2008783 + python3 file_bug.py --summary "..." --keywords meta --type task +""" + +import argparse +import getpass +import json +import sys +import urllib.error +import urllib.request + + +def main(): + parser = argparse.ArgumentParser(description="File a Bugzilla bug") + parser.add_argument("--summary", required=True, help="Bug summary") + parser.add_argument("--product", default="Firefox") + parser.add_argument("--component", default="New Tab Page") + parser.add_argument("--version", default="Trunk") + parser.add_argument("--type", default="defect") + parser.add_argument("--keywords", nargs="*", default=[], help="Bug keywords (e.g. meta)") + parser.add_argument("--blocks", type=int, help="Bug number that this bug blocks") + args = parser.parse_args() + + api_key = getpass.getpass("Bugzilla API key: ") + + payload = { + "api_key": api_key, + "product": args.product, + "component": args.component, + "summary": args.summary, + "version": args.version, + "op_sys": "All", + "platform": "All", + "type": args.type, + } + + if args.keywords: + payload["keywords"] = args.keywords + + if args.blocks: + payload["blocks"] = [args.blocks] + + data = json.dumps(payload).encode("utf-8") + req = urllib.request.Request( + "https://bugzilla.mozilla.org/rest/bug", + data=data, + headers={"Content-Type": "application/json"}, + method="POST", + ) + + try: + with urllib.request.urlopen(req) as resp: + result = json.loads(resp.read()) + print(result["id"]) + except urllib.error.HTTPError as e: + error_body = e.read().decode() + print(f"Error: HTTP {e.code} {e.reason}", file=sys.stderr) + try: + error_json = json.loads(error_body) + print(f" {error_json.get('message', error_body)}", file=sys.stderr) + except json.JSONDecodeError: + print(f" {error_body}", file=sys.stderr) + sys.exit(1) + except urllib.error.URLError as e: + print(f"Error: {e.reason}", file=sys.stderr) + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/plugins/newtab/skills/trainhop/scripts/file_jira_ticket.py b/plugins/newtab/skills/trainhop/scripts/file_jira_ticket.py new file mode 100644 index 0000000..921f42f --- /dev/null +++ b/plugins/newtab/skills/trainhop/scripts/file_jira_ticket.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +""" +Creates a QA Jira ticket for a New Tab train-hop release. + +Prompts for Atlassian credentials at runtime. +Prints the created ticket key (e.g. QA-1234) on success. + +Usage: + python3 file_jira_ticket.py --version 147 +""" + +import argparse +import base64 +import getpass +import json +import sys +import urllib.request +import urllib.error + +JIRA_BASE_URL = "https://mozilla-hub.atlassian.net" +PROJECT_KEY = "QA" +ISSUE_TYPE_ID = "11461" # Functional +DEFAULT_LABELS = ["QA:Desktop", "QA:High"] + + +def get_auth_header(email, token): + credentials = base64.b64encode(f"{email}:{token}".encode()).decode() + return f"Basic {credentials}" + + +def main(): + parser = argparse.ArgumentParser(description="File a QA Jira ticket for a train-hop release") + parser.add_argument("--version", required=True, help="Firefox major version (e.g. 147)") + args = parser.parse_args() + + email = input("Atlassian email: ") + token = getpass.getpass("Atlassian API token: ") + + summary = f"Testing New Tab train-hop for Firefox {args.version} Release" + description = ( + f"The New Tab team is performing a train-hop for Firefox {args.version}. " + f"Please test the signed XPI on the Release channel using the staging " + f"Experimenter rollout linked in the associated Confluence page." + ) + + payload = { + "fields": { + "project": {"key": PROJECT_KEY}, + "issuetype": {"id": ISSUE_TYPE_ID}, + "summary": summary, + "labels": DEFAULT_LABELS, + "description": { + "type": "doc", + "version": 1, + "content": [ + { + "type": "paragraph", + "content": [{"type": "text", "text": description}], + } + ], + }, + } + } + + data = json.dumps(payload).encode("utf-8") + req = urllib.request.Request( + f"{JIRA_BASE_URL}/rest/api/3/issue", + data=data, + headers={ + "Content-Type": "application/json", + "Authorization": get_auth_header(email, token), + }, + method="POST", + ) + + try: + with urllib.request.urlopen(req) as resp: + result = json.loads(resp.read()) + print(result["key"]) + except urllib.error.HTTPError as e: + error_body = e.read().decode() + print(f"Error: HTTP {e.code} {e.reason}", file=sys.stderr) + print(error_body, file=sys.stderr) + sys.exit(1) + except urllib.error.URLError as e: + print(f"Error: {e.reason}", file=sys.stderr) + sys.exit(1) + + +if __name__ == "__main__": + main() From e0bdc62198dae12ce5e50ed864c724c84debf9e7 Mon Sep 17 00:00:00 2001 From: Maxx Crawford Date: Tue, 17 Mar 2026 16:06:39 -0500 Subject: [PATCH 7/9] Make automation scripts runnable non-interactively - Add BUGZILLA_API_KEY, ATLASSIAN_EMAIL, ATLASSIAN_API_TOKEN, and ATLASSIAN_NAME env var support to file_bug.py and file_jira_ticket.py, falling back to interactive prompts when not set - Expand file_jira_ticket.py with all required QA project fields: meta bug, Confluence URL, due date, feature name, owner, shipping method, engineering team, product, target release, and bugs-filed-at - Output clickable URLs from both scripts instead of bare IDs - Add .gitignore and .env.example for credential management - Update file-qa-ticket.md to document the new arguments --- .gitignore | 2 + .../trainhop/references/file-qa-ticket.md | 8 ++- .../skills/trainhop/scripts/.env.example | 4 ++ .../skills/trainhop/scripts/file_bug.py | 6 ++- .../trainhop/scripts/file_jira_ticket.py | 53 +++++++++++++------ 5 files changed, 53 insertions(+), 20 deletions(-) create mode 100644 .gitignore create mode 100644 plugins/newtab/skills/trainhop/scripts/.env.example diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ee5f8ca --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.env +.claude/ diff --git a/plugins/newtab/skills/trainhop/references/file-qa-ticket.md b/plugins/newtab/skills/trainhop/references/file-qa-ticket.md index edca072..e1be032 100644 --- a/plugins/newtab/skills/trainhop/references/file-qa-ticket.md +++ b/plugins/newtab/skills/trainhop/references/file-qa-ticket.md @@ -9,10 +9,14 @@ Creates a Jira ticket in the QA project to notify QA that the train-hop XPI is r Read the major version from `browser/config/version.txt` (e.g. `147`), then run: ```bash -python3 /file_jira_ticket.py --version MAJOR_VERSION +python3 /file_jira_ticket.py \ + --version MAJOR_VERSION \ + --meta-bug META_BUG_NUMBER \ + --confluence-url CONFLUENCE_PAGE_URL \ + --due-date YYYY-MM-DD ``` -The script prompts for your Atlassian email and API token and prints the ticket key (e.g. `QA-1234`). Note it for the Confluence page. +Credentials are read from env vars `ATLASSIAN_EMAIL`, `ATLASSIAN_API_TOKEN`, and `ATLASSIAN_NAME` (see `references/credentials.md`), falling back to interactive prompts. Prints the ticket key (e.g. `QA-1234`). Note it for the Confluence page. ## Expected Result diff --git a/plugins/newtab/skills/trainhop/scripts/.env.example b/plugins/newtab/skills/trainhop/scripts/.env.example new file mode 100644 index 0000000..cd82460 --- /dev/null +++ b/plugins/newtab/skills/trainhop/scripts/.env.example @@ -0,0 +1,4 @@ +BUGZILLA_API_KEY=your_api_key_here +ATLASSIAN_EMAIL=you@mozilla.com +ATLASSIAN_API_TOKEN=your_api_token_here +ATLASSIAN_NAME=Your Name diff --git a/plugins/newtab/skills/trainhop/scripts/file_bug.py b/plugins/newtab/skills/trainhop/scripts/file_bug.py index 59d7aed..9c90ca3 100644 --- a/plugins/newtab/skills/trainhop/scripts/file_bug.py +++ b/plugins/newtab/skills/trainhop/scripts/file_bug.py @@ -14,6 +14,7 @@ import argparse import getpass import json +import os import sys import urllib.error import urllib.request @@ -30,7 +31,7 @@ def main(): parser.add_argument("--blocks", type=int, help="Bug number that this bug blocks") args = parser.parse_args() - api_key = getpass.getpass("Bugzilla API key: ") + api_key = os.environ.get("BUGZILLA_API_KEY") or getpass.getpass("Bugzilla API key: ") payload = { "api_key": api_key, @@ -60,7 +61,8 @@ def main(): try: with urllib.request.urlopen(req) as resp: result = json.loads(resp.read()) - print(result["id"]) + bug_id = result["id"] + print(f"{bug_id}: https://bugzilla.mozilla.org/show_bug.cgi?id={bug_id}") except urllib.error.HTTPError as e: error_body = e.read().decode() print(f"Error: HTTP {e.code} {e.reason}", file=sys.stderr) diff --git a/plugins/newtab/skills/trainhop/scripts/file_jira_ticket.py b/plugins/newtab/skills/trainhop/scripts/file_jira_ticket.py index 921f42f..7182159 100644 --- a/plugins/newtab/skills/trainhop/scripts/file_jira_ticket.py +++ b/plugins/newtab/skills/trainhop/scripts/file_jira_ticket.py @@ -2,17 +2,20 @@ """ Creates a QA Jira ticket for a New Tab train-hop release. -Prompts for Atlassian credentials at runtime. +Reads credentials from env vars ATLASSIAN_EMAIL, ATLASSIAN_API_TOKEN, and +ATLASSIAN_NAME (for Feature Owners), falling back to interactive prompts. Prints the created ticket key (e.g. QA-1234) on success. Usage: - python3 file_jira_ticket.py --version 147 + python3 file_jira_ticket.py --version 149 --meta-bug 2024043 \ + --confluence-url https://... --due-date 2026-01-22 """ import argparse import base64 import getpass import json +import os import sys import urllib.request import urllib.error @@ -22,6 +25,10 @@ ISSUE_TYPE_ID = "11461" # Functional DEFAULT_LABELS = ["QA:Desktop", "QA:High"] +SHIPPING_METHOD = "System Add-on" +ENGINEERING_TEAM = "New Tab" +PRODUCT = "Desktop" + def get_auth_header(email, token): credentials = base64.b64encode(f"{email}:{token}".encode()).decode() @@ -30,11 +37,15 @@ def get_auth_header(email, token): def main(): parser = argparse.ArgumentParser(description="File a QA Jira ticket for a train-hop release") - parser.add_argument("--version", required=True, help="Firefox major version (e.g. 147)") + parser.add_argument("--version", required=True, help="Firefox major version (e.g. 149)") + parser.add_argument("--meta-bug", required=True, type=int, help="Meta bug number (e.g. 2024043)") + parser.add_argument("--confluence-url", required=True, help="Link to Technical Documentation (Confluence page URL)") + parser.add_argument("--due-date", required=True, help="Due date in YYYY-MM-DD format") args = parser.parse_args() - email = input("Atlassian email: ") - token = getpass.getpass("Atlassian API token: ") + email = os.environ.get("ATLASSIAN_EMAIL") or input("Atlassian email: ") + token = os.environ.get("ATLASSIAN_API_TOKEN") or getpass.getpass("Atlassian API token: ") + owner_name = os.environ.get("ATLASSIAN_NAME") or input("Feature owner name: ") summary = f"Testing New Tab train-hop for Firefox {args.version} Release" description = ( @@ -42,6 +53,14 @@ def main(): f"Please test the signed XPI on the Release channel using the staging " f"Experimenter rollout linked in the associated Confluence page." ) + meta_bug_url = f"https://bugzilla.mozilla.org/show_bug.cgi?id={args.meta_bug}" + + def adf_text(text): + return { + "type": "doc", + "version": 1, + "content": [{"type": "paragraph", "content": [{"type": "text", "text": text}]}], + } payload = { "fields": { @@ -49,16 +68,17 @@ def main(): "issuetype": {"id": ISSUE_TYPE_ID}, "summary": summary, "labels": DEFAULT_LABELS, - "description": { - "type": "doc", - "version": 1, - "content": [ - { - "type": "paragraph", - "content": [{"type": "text", "text": description}], - } - ], - }, + "duedate": args.due_date, + "description": adf_text(description), + "customfield_10137": summary, + "customfield_10138": owner_name, + "customfield_10139": adf_text(args.confluence_url), + "customfield_10151": {"value": SHIPPING_METHOD}, + "customfield_10140": adf_text(meta_bug_url), + "customfield_10155": {"value": f"Fx{args.version}"}, + "customfield_10134": {"value": ENGINEERING_TEAM}, + "customfield_10147": [{"value": PRODUCT}], + "customfield_10749": meta_bug_url, } } @@ -76,7 +96,8 @@ def main(): try: with urllib.request.urlopen(req) as resp: result = json.loads(resp.read()) - print(result["key"]) + key = result["key"] + print(f"{key}: {JIRA_BASE_URL}/browse/{key}") except urllib.error.HTTPError as e: error_body = e.read().decode() print(f"Error: HTTP {e.code} {e.reason}", file=sys.stderr) From a773fba11a3fb42030becc0a711afb6fa4c41e7f Mon Sep 17 00:00:00 2001 From: Maxx Crawford Date: Wed, 20 May 2026 08:43:01 -0500 Subject: [PATCH 8/9] Update skill to use Atlaissian MCP --- plugins/newtab/skills/trainhop/SKILL.md | 72 +++++-- .../references/create-confluence-page.md | 190 ++++++++++++++++-- .../skills/trainhop/references/credentials.md | 60 +++++- .../trainhop/references/file-qa-ticket.md | 97 +++++++-- 4 files changed, 360 insertions(+), 59 deletions(-) diff --git a/plugins/newtab/skills/trainhop/SKILL.md b/plugins/newtab/skills/trainhop/SKILL.md index f714c32..ef4bcec 100644 --- a/plugins/newtab/skills/trainhop/SKILL.md +++ b/plugins/newtab/skills/trainhop/SKILL.md @@ -1,6 +1,6 @@ --- name: trainhop -description: Runs the New Tab train-hop release workflow for all automated steps: metabug, locales, metrics, Nimbus recipe, QA ticket, Confluence page, and version bump. Use when asked to "run the train-hop", "start a train-hop", or "do a train-hop". Do NOT use for individual steps like bumping the version or updating locales alone — those have their own skills. +description: Runs the New Tab train-hop release workflow for all automated steps: metabug, locales, metrics, Nimbus recipe, Confluence page, QA ticket, and version bump. Use when asked to "run the train-hop", "start a train-hop", or "do a train-hop". Do NOT use for individual steps like bumping the version or updating locales alone — those have their own skills. argument-hint: "[bug-number] (optional)" disable-model-invocation: true --- @@ -14,21 +14,23 @@ disable-model-invocation: true > Which steps would you like to run? > > **1. Full workflow** — all automated steps from start to finish -> **2. Prep only** — steps 1–3: create metabug, update locales, update metrics (run before the XPI is cut) -> **3. Post-XPI** — steps 4–6: Nimbus recipe, QA ticket + Confluence page, version bump +> **2. Prep only** — steps 1–3: filings (metabug + Confluence page + QA ticket), update locales, update metrics (run before the XPI is cut) +> **3. Post-XPI** — steps 4–6: Nimbus recipe, update Confluence page with real QA ticket reference, version bump > **4. Custom** — specify which numbered steps to include Wait for the user's answer before continuing. **Step 2: Collect inputs** — ask for the following based on the selected phase: +- If the phase includes step 1 (Confluence page + QA ticket): + - **XPI cut date** (e.g. `2026-05-13`) + - **QA handoff date** (e.g. `2026-05-14`) + - **QA sign-off date** (e.g. `2026-05-18`) — also used as the Jira ticket's due date + - **Release date** (e.g. `2026-05-19`) + - **Release Management contact** — name + Atlassian accountId (check https://whattrainisitnow.com for the release owner; resolve accountId via `mcp__atlassian__lookupJiraAccountId`) + - **QA contact** — name + Atlassian accountId (default: Valentin Bandac, accountId `6310ac8255b0a9e29f1af16d`) + - **Conductor** — name + Atlassian accountId (typically the person running this workflow) - If the phase includes step 4 (Nimbus recipe): **Ship task URL** from ShipIt -- If the phase includes step 5 (QA ticket + Confluence page): - - **XPI cut date** (e.g. `2026-01-19`) - - **QA handoff date** (e.g. `2026-01-20`) - - **Release date** (e.g. `2026-01-22`) - - **Release Management contact** (check https://whattrainisitnow.com for the release owner) - - **QA contact** (QA engineer assigned to this train-hop) **Step 3: Present the plan** — list the steps that will be executed and wait for confirmation before proceeding. @@ -38,24 +40,49 @@ Before running any steps, verify: - Working tree is clean: `git status` shows no uncommitted changes - On `main` branch and up to date: `git pull` -- Bugzilla API key is ready (see `references/credentials.md` if needed) -- Atlassian email and API token are ready (see `references/credentials.md` if needed) +- Bugzilla API key is available (`BUGZILLA_API_KEY` env var or interactive prompt — see `references/credentials.md`) +- The **Atlassian MCP plugin** is installed and authenticated — used for both the Jira ticket and the Confluence page. Install from the official Anthropic marketplace with `/plugin install atlassian@claude-plugins-official` followed by `/reload-plugins`. The plugin runs an OAuth flow on first use; no API token to manage. See `references/credentials.md` for full setup, troubleshooting, and the legacy API-token fallback. ## Steps Stop and report to the user if any step fails. Do not proceed past a failed step without explicit instruction. -### 1. Create meta bug +### 1. File meta bug, Confluence page, and QA ticket + +This is a three-substep flow. Do them in order: + +#### 1a. Create the meta bug Follow `references/create-metabug.md`. Note the returned bug number — pass it to all subsequent steps. +#### 1b. Create the Confluence page (with `QA-TBD` placeholder) + +Follow `references/create-confluence-page.md`, passing: +- The meta bug number from step 1a (full URL form) +- A placeholder for the QA ticket (`QA-TBD`) — the page will be updated in step 5 +- All four dates (XPI Cut, QA Handoff, QA Sign-off, Release) as Unix epoch milliseconds for ADF `date` nodes +- Rel Man, QA, and Conductor as ADF `mention` nodes (name + accountId) + +Note the returned **page ID** and **page URL**. + +#### 1c. File the QA ticket + +Follow `references/file-qa-ticket.md`, passing: +- The meta bug URL from step 1a +- The Confluence page URL from step 1b +- The QA sign-off date (becomes the Jira ticket's due date) +- The QA contact's accountId (for `assignee_account_id`) +- The conductor's name (for `customfield_10138` Feature Owner) + +Note the returned **QA ticket key** (e.g. `QA-5234`). + ### 2. Update locales -Follow `references/update-locales.md`, passing the meta bug number from step 1. +Follow `references/update-locales.md`, passing the meta bug number from step 1a. ### 3. Update metrics -Follow `references/update-metrics.md`, passing the meta bug number from step 1. +Follow `references/update-metrics.md`, passing the meta bug number from step 1a. ### 4. Generate the Nimbus recipe @@ -65,18 +92,13 @@ Follow `references/update-metrics.md`, passing the meta bug number from step 1. Use the Ship task URL collected in the Inputs section. Display the full output. -### 5. File QA ticket and create Confluence page - -Follow `references/file-qa-ticket.md`. Note the returned Jira ticket key. +### 5. Update the Confluence page with the real QA ticket reference -Then follow `references/create-confluence-page.md`, passing: -- The meta bug number from step 1 -- The QA ticket key from above -- The dates and contacts collected in the Inputs section +Use `mcp__atlassian__updateConfluencePage` to replace the `QA-TBD` placeholder on the page from step 1b with a real link to the ticket key from step 1c. Pass `versionMessage: "Fill in QA ticket reference (QA-XXXX)"`. ### 6. Bump minor version -Follow `references/bump-version.md`, passing the meta bug number from step 1. +Follow `references/bump-version.md`, passing the meta bug number from step 1a. ## Troubleshooting @@ -85,3 +107,9 @@ The skill may need to be reinstalled: `claude plugin install newtab`. **Step fails partway through** Report which step failed and its error output. Do not continue without explicit user instruction. + +**MCP call denied by the auto-mode classifier** +Re-prompt the user — these calls (Jira ticket creation, Confluence page creation/update) are intentional and on the user's behalf. + +**Atlassian MCP unavailable** +The `scripts/file_jira_ticket.py` and `scripts/create_confluence_page.py` Python scripts are kept as a legacy fallback. They require `ATLASSIAN_EMAIL`, `ATLASSIAN_API_TOKEN`, and `ATLASSIAN_NAME` env vars and emit the older plain-text Confluence template (no date macros, no `@mention`s, no QA Sign-off, no Conductor row). diff --git a/plugins/newtab/skills/trainhop/references/create-confluence-page.md b/plugins/newtab/skills/trainhop/references/create-confluence-page.md index 62193a9..ca40cb8 100644 --- a/plugins/newtab/skills/trainhop/references/create-confluence-page.md +++ b/plugins/newtab/skills/trainhop/references/create-confluence-page.md @@ -2,34 +2,188 @@ Creates the `HNT VERSION Train Hop` tracking page in the FPS Confluence space. +This step is run **before** the QA ticket is filed (because the QA ticket needs the page URL). Once the QA ticket exists, this page is then updated to swap the `QA-TBD` placeholder for the real ticket link. + +## Constants + +- **Cloud ID**: `mozilla-hub.atlassian.net` +- **FPS space ID**: `12484637` +- **Parent folder ID** ("HNT Train Hop Releases"): `1872035972` + ## Steps -### 1. Create the page +### 1. Create the page via the Atlassian MCP + +Use `mcp__atlassian__createConfluencePage` with `contentFormat: "adf"` so that date macros and `@mention` nodes render natively. Read the major version from `browser/config/version.txt`. + +**Required parameters**: + +- `cloudId`: `mozilla-hub.atlassian.net` +- `spaceId`: `12484637` +- `parentId`: `1872035972` +- `title`: `HNT MAJOR_VERSION Train Hop` +- `contentFormat`: `adf` +- `body`: ADF document (see template below) + +### 2. Body template (ADF) + +Compose an ADF document with this structure. Substitute the placeholders before sending. + +```json +{ + "type": "doc", + "version": 1, + "content": [ + {"type": "heading", "attrs": {"level": 3}, "content": [{"type": "text", "text": "Summary:"}]}, + {"type": "bulletList", "content": [ + {"type": "listItem", "content": [{"type": "paragraph", "content": [ + {"type": "text", "text": "Meta Bug: "}, + {"type": "inlineCard", "attrs": {"url": "METABUG_URL"}} + ]}]}, + {"type": "listItem", "content": [{"type": "paragraph", "content": [ + {"type": "text", "text": "QA Bug: QA-TBD (will update once filed)"} + ]}]}, + {"type": "listItem", "content": [ + {"type": "paragraph", "content": [{"type": "text", "text": "Timeline:"}]}, + {"type": "bulletList", "content": [ + {"type": "listItem", "content": [{"type": "paragraph", "content": [ + {"type": "text", "text": "XPI Cut: "}, + {"type": "date", "attrs": {"timestamp": "XPI_CUT_TIMESTAMP_MS"}} + ]}]}, + {"type": "listItem", "content": [{"type": "paragraph", "content": [ + {"type": "text", "text": "QA Handoff: "}, + {"type": "date", "attrs": {"timestamp": "QA_HANDOFF_TIMESTAMP_MS"}} + ]}]}, + {"type": "listItem", "content": [{"type": "paragraph", "content": [ + {"type": "text", "text": "QA Sign-off: "}, + {"type": "date", "attrs": {"timestamp": "QA_SIGNOFF_TIMESTAMP_MS"}} + ]}]}, + {"type": "listItem", "content": [{"type": "paragraph", "content": [ + {"type": "text", "text": "Release: "}, + {"type": "date", "attrs": {"timestamp": "RELEASE_TIMESTAMP_MS"}} + ]}]} + ]} + ]}, + {"type": "listItem", "content": [{"type": "paragraph", "content": [ + {"type": "text", "text": "Rel Man contact: "}, + {"type": "mention", "attrs": {"id": "RELMAN_ACCOUNT_ID", "text": "@RELMAN_NAME"}} + ]}]}, + {"type": "listItem", "content": [{"type": "paragraph", "content": [ + {"type": "text", "text": "QA contact: "}, + {"type": "mention", "attrs": {"id": "QA_ACCOUNT_ID", "text": "@QA_NAME"}} + ]}]}, + {"type": "listItem", "content": [{"type": "paragraph", "content": [ + {"type": "text", "text": "Conductor: "}, + {"type": "mention", "attrs": {"id": "CONDUCTOR_ACCOUNT_ID", "text": "@CONDUCTOR_NAME"}} + ]}]} + ]}, + {"type": "heading", "attrs": {"level": 4}, "content": [{"type": "text", "text": "Helpful Links"}]}, + {"type": "bulletList", "content": [ + {"type": "listItem", "content": [{"type": "paragraph", "content": [ + {"type": "text", "text": "See documentation: "}, + {"type": "inlineCard", "attrs": {"url": "https://mozilla-hub.atlassian.net/wiki/spaces/FPS/pages/1785135275"}} + ]}]}, + {"type": "listItem", "content": [{"type": "paragraph", "content": [ + {"type": "text", "text": "See check-list: "}, + {"type": "inlineCard", "attrs": {"url": "https://mozilla-hub.atlassian.net/wiki/x/kABgag"}} + ]}]}, + {"type": "listItem", "content": [{"type": "paragraph", "content": [ + {"type": "text", "text": "Real-time Train Hop Adoption Graph", "marks": [{"type": "link", "attrs": {"href": "https://sql.telemetry.mozilla.org/dashboard/new-tab-train-hop-add-on-uptake-dashboard"}}]} + ]}]} + ]}, + {"type": "rule"}, + {"type": "heading", "attrs": {"level": 3}, "content": [{"type": "text", "text": "Features being tested:"}]}, + {"type": "paragraph", "content": [{"type": "text", "text": "These are the experiments/tickets that are planned as part of this release. They can be required or optional."}]}, + {"type": "table", "content": [ + {"type": "tableRow", "content": [ + {"type": "tableHeader", "content": [{"type": "paragraph", "content": [{"type": "text", "text": "Jira Ticket / Summary", "marks": [{"type": "strong"}]}]}]}, + {"type": "tableHeader", "content": [{"type": "paragraph", "content": [{"type": "text", "text": "Product Owner", "marks": [{"type": "strong"}]}]}]}, + {"type": "tableHeader", "content": [{"type": "paragraph", "content": [{"type": "text", "text": "Priority", "marks": [{"type": "strong"}]}]}]} + ]}, + {"type": "tableRow", "content": [ + {"type": "tableCell", "content": [{"type": "paragraph"}]}, + {"type": "tableCell", "content": [{"type": "paragraph"}]}, + {"type": "tableCell", "content": [{"type": "paragraph"}]} + ]} + ]}, + {"type": "heading", "attrs": {"level": 3}, "content": [{"type": "text", "text": "QA Verified Bugs/Patches"}]}, + {"type": "table", "content": [ + {"type": "tableRow", "content": [ + {"type": "tableHeader", "content": [{"type": "paragraph", "content": [{"type": "text", "text": "Bug", "marks": [{"type": "strong"}]}]}]}, + {"type": "tableHeader", "content": [{"type": "paragraph", "content": [{"type": "text", "text": "Summary", "marks": [{"type": "strong"}]}]}]}, + {"type": "tableHeader", "content": [{"type": "paragraph", "content": [{"type": "text", "text": "Landing Status", "marks": [{"type": "strong"}]}]}]}, + {"type": "tableHeader", "content": [{"type": "paragraph", "content": [{"type": "text", "text": "QA Status", "marks": [{"type": "strong"}]}]}]} + ]}, + {"type": "tableRow", "content": [ + {"type": "tableCell", "content": [{"type": "paragraph"}]}, + {"type": "tableCell", "content": [{"type": "paragraph"}]}, + {"type": "tableCell", "content": [{"type": "paragraph"}]}, + {"type": "tableCell", "content": [{"type": "paragraph"}]} + ]} + ]}, + {"type": "heading", "attrs": {"level": 3}, "content": [ + {"type": "text", "text": "Shims added for "}, + {"type": "text", "text": "@backward-compat", "marks": [{"type": "code"}]} + ]}, + {"type": "table", "content": [ + {"type": "tableRow", "content": [ + {"type": "tableHeader", "content": [{"type": "paragraph", "content": [{"type": "text", "text": "Bug Link", "marks": [{"type": "strong"}]}]}]}, + {"type": "tableHeader", "content": [{"type": "paragraph", "content": [{"type": "text", "text": "Title", "marks": [{"type": "strong"}]}]}]}, + {"type": "tableHeader", "content": [{"type": "paragraph", "content": [{"type": "text", "text": "Notes", "marks": [{"type": "strong"}]}]}]} + ]}, + {"type": "tableRow", "content": [ + {"type": "tableCell", "content": [{"type": "paragraph"}]}, + {"type": "tableCell", "content": [{"type": "paragraph"}]}, + {"type": "tableCell", "content": [{"type": "paragraph"}]} + ]} + ]} + ] +} +``` + +### 3. Placeholder substitutions + +- `MAJOR_VERSION` — Firefox major version (e.g. `151`) +- `METABUG_URL` — `https://bugzilla.mozilla.org/show_bug.cgi?id=BUG_ID` +- `*_TIMESTAMP_MS` — Unix epoch milliseconds at UTC midnight for each date. Convert `YYYY-MM-DD` with e.g. `python3 -c "import datetime;print(int(datetime.datetime(YYYY,MM,DD,tzinfo=datetime.timezone.utc).timestamp()*1000))"`. +- `RELMAN_ACCOUNT_ID` / `QA_ACCOUNT_ID` / `CONDUCTOR_ACCOUNT_ID` — Atlassian accountIds; resolve with `mcp__atlassian__lookupJiraAccountId` if not known. +- `*_NAME` — the user's display name (prefixed with `@`, e.g. `@Donal Meehan`). + +Common accountIds (FYI, verify before use): +- Valentin Bandac (QA): `6310ac8255b0a9e29f1af16d` +- Maxx Crawford: `5cd0455cdfe2e60fdd10e002` + +### 4. Note the page ID and URL -Read the major version from `browser/config/version.txt` (e.g. `147`), then run: +The MCP response contains `id` and `_links.webui`. Pass them to the next step (file QA ticket). -```bash -python3 /create_confluence_page.py \ - --version MAJOR_VERSION \ - --metabug-url https://bugzilla.mozilla.org/show_bug.cgi?id=META_BUG_NUMBER \ - --qa-ticket QA_TICKET_KEY \ - --xpi-cut XPI_CUT_DATE \ - --qa-handoff QA_HANDOFF_DATE \ - --release-date RELEASE_DATE \ - --relman "REL_MAN_CONTACT" \ - --qa-contact "QA_CONTACT" +### 5. Update the page after the QA ticket is filed + +Once the QA ticket key is known, use `mcp__atlassian__updateConfluencePage` to replace the `QA-TBD` placeholder with a real link. The simplest approach is to re-send the same ADF body with the placeholder swapped for: + +```json +{"type": "paragraph", "content": [ + {"type": "text", "text": "QA Bug: "}, + {"type": "text", "text": "QA-XXXX: Testing New Tab train-hop for Firefox MAJOR_VERSION Release", "marks": [{"type": "link", "attrs": {"href": "https://mozilla-hub.atlassian.net/browse/QA-XXXX"}}]} +]} ``` -Substitute values from the inputs collected at the start of the workflow. The script prompts for your Atlassian email and API token, then prints the page URL. +Pass `versionMessage: "Fill in QA ticket reference (QA-XXXX)"` so the page history is self-documenting. ## Expected Result -The page is accessible at the printed URL under the Train Hops folder in the FPS space, with the summary, timeline, and empty tables pre-populated. The user fills in the "Features being tested" table manually. +The page is accessible under "HNT Train Hop Releases" in the FPS space with the summary, timeline (using interactive date macros), and contact `@mention`s. The "Features being tested" / "QA Verified Bugs/Patches" / "Shims" tables are empty and filled in by the conductor. ## Troubleshooting -**HTTP 401** -Check that your email and API token are correct. Get a token at: https://id.atlassian.com/manage-profile/security/api-tokens +**MCP returns 404 on `parentId`** +The "HNT Train Hop Releases" folder may have moved. Search with `mcp__atlassian__searchConfluenceUsingCql` for `space = FPS AND title ~ "Train Hop"` and find the folder (type `folder`) — update the constant at the top of this file. + +**Date macros render as plain text** +Confirm `contentFormat: "adf"` was passed. Markdown content cannot express `date` or `mention` nodes; they will be flattened to plain text. + +**Mention shows as `@unknown`** +The accountId is wrong. Resolve via `mcp__atlassian__lookupJiraAccountId` and try again. -**HTTP 404** -Parent folder ID `1872035972` may have changed. Update `PARENT_PAGE_ID` in `scripts/create_confluence_page.py`. +**Legacy fallback** +If the MCP is unavailable, the original Python script (`scripts/create_confluence_page.py`) still works but emits the older plain-text template (no date macros, no `@mention`s, no QA Sign-off, no Conductor row). diff --git a/plugins/newtab/skills/trainhop/references/credentials.md b/plugins/newtab/skills/trainhop/references/credentials.md index dd2d64e..135f64d 100644 --- a/plugins/newtab/skills/trainhop/references/credentials.md +++ b/plugins/newtab/skills/trainhop/references/credentials.md @@ -1,19 +1,67 @@ # Credential Setup -The train-hop workflow requires the following credentials. Scripts will prompt for them at runtime — nothing needs to be stored. +The train-hop workflow has two paths for Jira/Confluence: + +- **Preferred** — the Atlassian MCP plugin (OAuth, no token to manage). See [Atlassian MCP plugin](#atlassian-mcp-plugin) below. +- **Legacy** — direct REST API calls from the Python scripts in `scripts/`, which require an email + API token. See [Atlassian API token (legacy)](#atlassian-api-token-legacy) below. + +Bugzilla still uses a personal API key (no MCP equivalent yet). ## Bugzilla API Key -Used to file Bugzilla bugs automatically. +Used by `scripts/file_bug.py` to file the meta bug. 1. Go to https://bugzilla.mozilla.org and sign in 2. Click your name → **Preferences** → **API Keys** 3. Enter a description (e.g. "train-hop automation") and click **Generate Key** -4. Copy the key — you will be prompted for it when the script runs +4. Copy the key. Either export it as `BUGZILLA_API_KEY` in your shell (recommended: store in an untracked file like `.mozconfig-env` at the repo root and `set -a; source .mozconfig-env; set +a` before running the workflow), or let the script prompt for it interactively. + +## Atlassian MCP plugin + +The Atlassian MCP plugin is published in the **official Anthropic marketplace** (`claude-plugins-official`), which is registered automatically when Claude Code starts. See the [Discover plugins → External integrations](https://code.claude.com/docs/en/discover-plugins#external-integrations) docs for the full list. + +### Install + +From inside Claude Code, run: + +``` +/plugin install atlassian@claude-plugins-official +``` + +Then reload so the new MCP server is picked up: + +``` +/reload-plugins +``` + +If Claude Code reports the plugin is not found, refresh the marketplace first and retry: -## Atlassian Credentials +``` +/plugin marketplace update claude-plugins-official +/plugin install atlassian@claude-plugins-official +``` -Used to create Jira tickets and Confluence pages. +### Authenticate + +On first use, the plugin walks you through an OAuth flow against your Mozilla Atlassian workspace (`mozilla-hub.atlassian.net`). Approve the requested scopes (read/write for Jira and Confluence). No tokens are stored locally — Claude Code manages the OAuth session. + +### Verify + +After install + reload, the `mcp__atlassian__*` tools should be available. A quick smoke test from Claude: + +> List the spaces I can access in Confluence (use `mcp__atlassian__getConfluenceSpaces` with `cloudId: mozilla-hub.atlassian.net`). + +You should see "Firefox Product Space" (key `FPS`, id `12484637`) in the response. + +### Troubleshooting + +- **`mcp__atlassian__*` tools missing after install**: run `/reload-plugins`. If still missing, check `/plugin` → Errors tab. +- **OAuth fails**: confirm you have permission on `mozilla-hub.atlassian.net`. The marketplace plugin's docs (linked from `/plugin` → Discover → atlassian) cover re-auth. +- **MCP call blocked by the auto-mode classifier**: this is a Claude Code permission prompt, not an MCP failure. Approve the call to proceed. + +## Atlassian API token (legacy) + +Only needed if you're falling back to the Python scripts in `scripts/`. The MCP path above is preferred. **Email**: your Mozilla email address (e.g. `you@mozilla.com`) @@ -21,3 +69,5 @@ Used to create Jira tickets and Confluence pages. 1. Go to https://id.atlassian.com/manage-profile/security/api-tokens 2. Click **Create API token** 3. Enter a label (e.g. "train-hop") and copy the token + +Export as `ATLASSIAN_EMAIL`, `ATLASSIAN_API_TOKEN`, and `ATLASSIAN_NAME` (your Feature Owner display name). As with the Bugzilla key, an untracked `.mozconfig-env` file at the repo root works well. diff --git a/plugins/newtab/skills/trainhop/references/file-qa-ticket.md b/plugins/newtab/skills/trainhop/references/file-qa-ticket.md index e1be032..c3fbbe3 100644 --- a/plugins/newtab/skills/trainhop/references/file-qa-ticket.md +++ b/plugins/newtab/skills/trainhop/references/file-qa-ticket.md @@ -2,30 +2,99 @@ Creates a Jira ticket in the QA project to notify QA that the train-hop XPI is ready for testing. +This step is run **after** the Confluence page is created (so the page URL can be linked in the ticket). + ## Steps -### 1. Create the ticket +### 1. Create the ticket via the Atlassian MCP + +Use the `mcp__atlassian__createJiraIssue` tool. Read the major version from `browser/config/version.txt` (e.g. `151`). + +**Required parameters**: + +- `cloudId`: `mozilla-hub.atlassian.net` +- `projectKey`: `QA` +- `issueTypeName`: `Functional` +- `summary`: `Testing New Tab train-hop for Firefox MAJOR_VERSION Release` +- `description`: timeline blurb (see template below) — pass with `contentFormat: "markdown"` +- `assignee_account_id`: the QA contact's Atlassian accountId (use `mcp__atlassian__lookupJiraAccountId` if unknown) +- `additional_fields`: see customfield mapping below + +**Description template** (substitute the QA Handoff weekday and date): + +``` +On {QA_HANDOFF_WEEKDAY}, {QA_HANDOFF_MONTH_DAY}, two days after the Firefox MAJOR_VERSION Release, the New Tab team aims to perform a train-hop. + +Note: We are holding cutting the release for a few different features. If we do not have those features ready, we will shift the entire timeline to accommodate. +``` -Read the major version from `browser/config/version.txt` (e.g. `147`), then run: +**Customfield mapping (`additional_fields`)** — mirrors the QA-4752 / QA-5234 reference tickets: -```bash -python3 /file_jira_ticket.py \ - --version MAJOR_VERSION \ - --meta-bug META_BUG_NUMBER \ - --confluence-url CONFLUENCE_PAGE_URL \ - --due-date YYYY-MM-DD +```json +{ + "labels": ["QA:Desktop", "QA:High"], + "duedate": "QA_SIGNOFF_DATE", + "customfield_10134": {"value": "Front End"}, + "customfield_10137": "Testing New Tab train-hop for Firefox MAJOR_VERSION Release", + "customfield_10138": "FEATURE_OWNER_NAME", + "customfield_10139": { + "type": "doc", "version": 1, + "content": [{"type": "paragraph", "content": [ + {"type": "inlineCard", "attrs": {"url": "CONFLUENCE_PAGE_URL"}} + ]}] + }, + "customfield_10140": { + "type": "doc", "version": 1, + "content": [{"type": "paragraph", "content": [ + {"type": "inlineCard", "attrs": {"url": "CONFLUENCE_PAGE_URL"}}, + {"type": "text", "text": " "}, + {"type": "hardBreak"}, + {"type": "inlineCard", "attrs": {"url": "METABUG_URL"}} + ]}] + }, + "customfield_10147": [{"value": "Desktop"}], + "customfield_10151": {"value": "System Add-on"}, + "customfield_10155": {"value": "FxMAJOR_VERSION"}, + "customfield_10749": "METABUG_URL" +} ``` -Credentials are read from env vars `ATLASSIAN_EMAIL`, `ATLASSIAN_API_TOKEN`, and `ATLASSIAN_NAME` (see `references/credentials.md`), falling back to interactive prompts. Prints the ticket key (e.g. `QA-1234`). Note it for the Confluence page. +Substitute: +- `MAJOR_VERSION` — Firefox major version (e.g. `151`) +- `QA_SIGNOFF_DATE` — `YYYY-MM-DD` of QA sign-off (becomes the ticket's due date) +- `FEATURE_OWNER_NAME` — name of the Feature Owner (typically the train-hop conductor running the workflow) +- `CONFLUENCE_PAGE_URL` — full URL of the Confluence page created in the previous step +- `METABUG_URL` — full Bugzilla URL: `https://bugzilla.mozilla.org/show_bug.cgi?id=BUG_ID` + +### 2. Note the ticket key + +The MCP response contains `key` (e.g. `QA-5234`). Pass it to the next step (Confluence page update). ## Expected Result -The ticket is visible at `https://mozilla-hub.atlassian.net/browse/QA-XXXX` with summary `Testing New Tab train-hop for Firefox MAJOR_VERSION Release`. +The ticket is visible at `https://mozilla-hub.atlassian.net/browse/QA-XXXX` with summary `Testing New Tab train-hop for Firefox MAJOR_VERSION Release`, assigned to the QA contact, and with the Confluence page linked in customfield_10139 (Technical Documentation). + +## Customfield reference + +| Field ID | Purpose | Value shape | +|---|---|---| +| `customfield_10134` | Engineering Team | `{"value": "Front End"}` | +| `customfield_10137` | Test Suite (mirrors summary) | string | +| `customfield_10138` | Feature Owner | string (name) | +| `customfield_10139` | Technical Documentation link | ADF doc with `inlineCard` of Confluence URL | +| `customfield_10140` | Test Plan links | ADF doc with `inlineCard`s of Confluence + metabug | +| `customfield_10147` | Product | `[{"value": "Desktop"}]` | +| `customfield_10151` | Shipping Method | `{"value": "System Add-on"}` | +| `customfield_10155` | Firefox Version | `{"value": "FxXXX"}` | +| `customfield_10749` | Meta Bug | plain URL string | ## Troubleshooting -**HTTP 401** -Check that your email and API token are correct. Get a token at: https://id.atlassian.com/manage-profile/security/api-tokens +**MCP `createJiraIssue` denied by classifier** +Re-prompt the user to authorize the call — the workflow explicitly creates a Jira ticket on the user's behalf. + +**Invalid issue type or customfield** +Issue type ID for Functional is `11461`. If the MCP rejects `issueTypeName: "Functional"`, fall back to passing the ID via `additional_fields.issuetype.id`. If customfield IDs have drifted, fetch a recent reference ticket (e.g. `QA-5234`) via `mcp__atlassian__getJiraIssue` with explicit `fields` to confirm the schema. -**HTTP 400** -Issue type ID `11461` may have changed. Update `ISSUE_TYPE_ID` in `scripts/file_jira_ticket.py`. +**Legacy fallback** +If the MCP is unavailable, the original Python script (`scripts/file_jira_ticket.py`) still works given `ATLASSIAN_EMAIL`, `ATLASSIAN_API_TOKEN`, and `ATLASSIAN_NAME` env vars. From 04aae8705e3b73dba6de2c401114ce03c03b1e89 Mon Sep 17 00:00:00 2001 From: Irene Ni Date: Fri, 10 Jul 2026 12:45:01 -0500 Subject: [PATCH 9/9] Consolidates env handling (_env.py + trainhop.env.example), removes the version-bump step and Jira/Confluence Python scripts in favor of MCP-driven references, and rewrites the Confluence page to HTML time/mention nodes. --- plugins/newtab/skills/trainhop/SKILL.md | 114 ++++----- .../trainhop/references/bump-version.md | 48 ---- .../references/create-confluence-page.md | 232 +++++++----------- .../trainhop/references/create-metabug.md | 6 +- .../skills/trainhop/references/credentials.md | 57 ++--- .../trainhop/references/file-qa-ticket.md | 95 ++++--- .../trainhop/references/update-locales.md | 6 +- .../trainhop/references/update-metrics.md | 52 +++- .../skills/trainhop/scripts/.env.example | 4 - .../newtab/skills/trainhop/scripts/_env.py | 42 ++++ .../skills/trainhop/scripts/bump_version.py | 70 ------ .../trainhop/scripts/cleanup_metrics.py | 59 +++-- .../scripts/create_confluence_page.py | 162 ------------ .../skills/trainhop/scripts/file_bug.py | 32 ++- .../trainhop/scripts/file_jira_ticket.py | 112 --------- .../trainhop/scripts/trainhop.env.example | 14 ++ 16 files changed, 394 insertions(+), 711 deletions(-) delete mode 100644 plugins/newtab/skills/trainhop/references/bump-version.md delete mode 100644 plugins/newtab/skills/trainhop/scripts/.env.example create mode 100644 plugins/newtab/skills/trainhop/scripts/_env.py delete mode 100644 plugins/newtab/skills/trainhop/scripts/bump_version.py delete mode 100644 plugins/newtab/skills/trainhop/scripts/create_confluence_page.py delete mode 100644 plugins/newtab/skills/trainhop/scripts/file_jira_ticket.py create mode 100644 plugins/newtab/skills/trainhop/scripts/trainhop.env.example diff --git a/plugins/newtab/skills/trainhop/SKILL.md b/plugins/newtab/skills/trainhop/SKILL.md index ef4bcec..f03f5e7 100644 --- a/plugins/newtab/skills/trainhop/SKILL.md +++ b/plugins/newtab/skills/trainhop/SKILL.md @@ -1,6 +1,6 @@ --- name: trainhop -description: Runs the New Tab train-hop release workflow for all automated steps: metabug, locales, metrics, Nimbus recipe, Confluence page, QA ticket, and version bump. Use when asked to "run the train-hop", "start a train-hop", or "do a train-hop". Do NOT use for individual steps like bumping the version or updating locales alone — those have their own skills. +description: Runs the New Tab train-hop release workflow for all automated steps: metabug, locales, metrics, Nimbus recipe, Confluence page, and QA ticket. Use when asked to start a train-hop. Do NOT use for individual steps like updating locales alone — those have their own skills. argument-hint: "[bug-number] (optional)" disable-model-invocation: true --- @@ -9,80 +9,61 @@ disable-model-invocation: true ## Before Starting -**Step 1: Ask the user which phase to run** (present as a numbered list): +**Step 1 — Pick the phase.** Ask (numbered list): > Which steps would you like to run? > -> **1. Full workflow** — all automated steps from start to finish -> **2. Prep only** — steps 1–3: filings (metabug + Confluence page + QA ticket), update locales, update metrics (run before the XPI is cut) -> **3. Post-XPI** — steps 4–6: Nimbus recipe, update Confluence page with real QA ticket reference, version bump -> **4. Custom** — specify which numbered steps to include +> **1. Full workflow** — all steps, start to finish +> **2. Prep only** — steps 1–3 (metabug, locales, metrics), run before the XPI is cut +> **3. Post-XPI** — steps 4–5 (Nimbus recipe, Confluence page + QA ticket) +> **4. Custom** — specify which step numbers to include -Wait for the user's answer before continuing. +**Step 2 — Resolve, ask, confirm.** Resolve what you can automatically, ask the user only for the rest, then present the plan and wait for a single confirmation. -**Step 2: Collect inputs** — ask for the following based on the selected phase: +*Resolve automatically:* +- **`TARGET_VERSION`** — read the Nightly major from `browser/config/version.txt`; the release target is `Nightly − 2` (e.g. `154` → `152`). This labels the meta bug, per-step bugs, QA ticket, and Confluence title — **not** the Nightly version. Use it everywhere; don't re-derive it per step. +- **Conductor** — defaults to the signed-in user (`${MCP}atlassianUserInfo`). +- **QA contact** — defaults to Valentin Bandac (`6310ac8255b0a9e29f1af16d`). +- **accountIds** — resolve names → accountIds with `${MCP}lookupJiraAccountId`. -- If the phase includes step 1 (Confluence page + QA ticket): - - **XPI cut date** (e.g. `2026-05-13`) - - **QA handoff date** (e.g. `2026-05-14`) - - **QA sign-off date** (e.g. `2026-05-18`) — also used as the Jira ticket's due date - - **Release date** (e.g. `2026-05-19`) - - **Release Management contact** — name + Atlassian accountId (check https://whattrainisitnow.com for the release owner; resolve accountId via `mcp__atlassian__lookupJiraAccountId`) - - **QA contact** — name + Atlassian accountId (default: Valentin Bandac, accountId `6310ac8255b0a9e29f1af16d`) - - **Conductor** — name + Atlassian accountId (typically the person running this workflow) -- If the phase includes step 4 (Nimbus recipe): **Ship task URL** from ShipIt +*Ask the user (only what the chosen phase needs):* +- **Target version** — confirm the computed `Nightly − 2` default, or take an override. +- If step 4 is included — **Ship task URL** (from ShipIt). +- If step 5 is included: + - **Dates**: XPI cut, QA handoff, QA sign-off (= the Jira due date), and the staged **Release** dates — 50% and 100% (usually consecutive days). + - **Rel Man** — name only (check https://whattrainisitnow.com/release/?version=release if unknown). + - **Conductor & QA contact** — default to you (the signed-in user) and Valentin Bandac; confirm, or name someone else. -**Step 3: Present the plan** — list the steps that will be executed and wait for confirmation before proceeding. +Then show the resolved target version and the exact steps to run, and wait for one confirmation before proceeding. ## Pre-conditions -Before running any steps, verify: +Run these checks at the start — don't ask the user to verify them. If something is off, explain it in plain language and wait. -- Working tree is clean: `git status` shows no uncommitted changes -- On `main` branch and up to date: `git pull` -- Bugzilla API key is available (`BUGZILLA_API_KEY` env var or interactive prompt — see `references/credentials.md`) -- The **Atlassian MCP plugin** is installed and authenticated — used for both the Jira ticket and the Confluence page. Install from the official Anthropic marketplace with `/plugin install atlassian@claude-plugins-official` followed by `/reload-plugins`. The plugin runs an OAuth flow on first use; no API token to manage. See `references/credentials.md` for full setup, troubleshooting, and the legacy API-token fallback. +1. **In the Firefox checkout.** Confirm `browser/config/version.txt` exists in the working directory. If not, the workflow is running from the wrong place — ask the user to start it from their local Firefox source checkout (every step operates there). +2. **Clean tree on `main`.** Run `git status --porcelain` and `git rev-parse --abbrev-ref HEAD`. If there are uncommitted changes or the branch isn't `main`, stop and say so plainly (e.g. "there are unsaved changes in the Firefox repo" / "you're on branch X, not `main`") and ask how to proceed — do not run on a dirty tree. Once clean and on `main`, run `git pull` to get up to date. +3. **Bugzilla API key.** The key must be a non-empty `BUGZILLA_API_KEY` line in `~/.mozbuild/trainhop.env`. Check with: + ```bash + grep -qE '^BUGZILLA_API_KEY=.+' ~/.mozbuild/trainhop.env && echo ok + ``` + If that prints `ok`, continue. If not (file missing or value empty), the key isn't set up: point the user to the setup doc — https://mozilla-hub.atlassian.net/wiki/x/QoA4qg — and **stop** until they've created the file in their own terminal, then re-check. **Never ask for the key in the chat, prompt for it, or write it yourself** — the key must never enter the Claude session. You only verify it's present. +4. **Atlassian MCP** (only needed for step 5). The Atlassian MCP plugin must be installed and authenticated: `/plugin install atlassian@claude-plugins-official` then `/reload-plugins` (OAuth on first use, no token). See `references/credentials.md` for setup and the `${MCP}` tool-prefix note. ## Steps Stop and report to the user if any step fails. Do not proceed past a failed step without explicit instruction. -### 1. File meta bug, Confluence page, and QA ticket - -This is a three-substep flow. Do them in order: - -#### 1a. Create the meta bug +### 1. Create meta bug Follow `references/create-metabug.md`. Note the returned bug number — pass it to all subsequent steps. -#### 1b. Create the Confluence page (with `QA-TBD` placeholder) - -Follow `references/create-confluence-page.md`, passing: -- The meta bug number from step 1a (full URL form) -- A placeholder for the QA ticket (`QA-TBD`) — the page will be updated in step 5 -- All four dates (XPI Cut, QA Handoff, QA Sign-off, Release) as Unix epoch milliseconds for ADF `date` nodes -- Rel Man, QA, and Conductor as ADF `mention` nodes (name + accountId) - -Note the returned **page ID** and **page URL**. - -#### 1c. File the QA ticket - -Follow `references/file-qa-ticket.md`, passing: -- The meta bug URL from step 1a -- The Confluence page URL from step 1b -- The QA sign-off date (becomes the Jira ticket's due date) -- The QA contact's accountId (for `assignee_account_id`) -- The conductor's name (for `customfield_10138` Feature Owner) - -Note the returned **QA ticket key** (e.g. `QA-5234`). - ### 2. Update locales -Follow `references/update-locales.md`, passing the meta bug number from step 1a. +Follow `references/update-locales.md`, passing the meta bug number from step 1. ### 3. Update metrics -Follow `references/update-metrics.md`, passing the meta bug number from step 1a. +Follow `references/update-metrics.md`, passing the meta bug number from step 1. ### 4. Generate the Nimbus recipe @@ -92,13 +73,34 @@ Follow `references/update-metrics.md`, passing the meta bug number from step 1a. Use the Ship task URL collected in the Inputs section. Display the full output. -### 5. Update the Confluence page with the real QA ticket reference +### 5. Create Confluence page and file QA ticket + +This is a three-substep flow. Do them in order: + +#### 5a. Create the Confluence page (with `QA-TBD` placeholder) + +Follow `references/create-confluence-page.md`, passing: +- The meta bug number from step 1 (full URL form) +- A placeholder for the QA ticket (`QA-TBD`) — the page will be updated in step 5c +- The dates (XPI Cut, QA Handoff, QA Sign-off, Release 50%/100%) as `YYYY-MM-DD` for HTML `