Skip to content

chore(skills): add release-widget skill - #2370

Open
yordan-st wants to merge 14 commits into
mainfrom
skill/release-widget
Open

chore(skills): add release-widget skill#2370
yordan-st wants to merge 14 commits into
mainfrom
skill/release-widget

Conversation

@yordan-st

Copy link
Copy Markdown
Contributor

Summary

  • Adds `.agents/skills/release-widget/SKILL.md` — automates widget/module release pipeline (version bump → GitHub draft release → OSS clearance → Marketplace publish)
  • Previously ran as private trial (untracked); opening as draft for team feedback before promoting to shared skill set

Test plan

  • Used successfully for image-web v1.6.0 and charts-web v6.3.2 releases

@yordan-st
yordan-st marked this pull request as ready for review August 4, 2026 09:30
@yordan-st
yordan-st requested a review from a team as a code owner August 4, 2026 09:30
@github-actions

This comment has been minimized.

Comment thread .agents/skills/release-widget/SKILL.md Outdated
Comment thread .agents/skills/release-widget/SKILL.md Outdated
@yordan-st
yordan-st force-pushed the skill/release-widget branch 2 times, most recently from fbe06a0 to 7773a8b Compare August 21, 2026 13:57
@github-actions

This comment has been minimized.

@yordan-st
yordan-st force-pushed the skill/release-widget branch from 74a8e99 to cce0a0d Compare September 7, 2026 12:36
@github-actions

This comment has been minimized.

Comment thread .agents/skills/release-widget/SKILL.md Outdated
Comment thread .agents/skills/release-widget/SKILL.md Outdated
Comment thread .agents/skills/release-widget/SKILL.md Outdated
Comment thread .agents/skills/release-widget/SKILL.md Outdated
Comment thread .agents/skills/release-widget/SKILL.md Outdated
Comment thread .agents/skills/release-widget/SKILL.md Outdated
Comment thread .agents/skills/release-widget/SKILL.md Outdated
Comment thread .agents/skills/release-widget/SKILL.md Outdated
Comment thread .agents/skills/release-widget/SKILL.md Outdated
Comment thread .agents/skills/release-widget/SKILL.md Outdated
Comment thread .agents/skills/release-widget/SKILL.md Outdated
- **Running `rui-package-info` / `rui-bump-version` without `cd`-ing into the widget/module dir first** — they read `process.cwd()`, not a path argument.
- **Treating `appNumber` presence via grep instead of reading the schema** — a module-wrapped widget's package.json simply omits the `marketplace.appNumber` key; check for `null`/undefined/`-1` via `rui-package-info`, don't grep for the string `"appNumber"` (unreliable — the field can exist with value `-1` too, which also means "not independently published").
- **Publishing before the asset gate passes** — this is the exact mistake pattern that caused the 409 double-trigger risk. Never call `gh release edit --draft=false` without first confirming both MPK and READMEOSS assets are attached.
- **Escalating a 409 without checking run history first** — many past "failures" are actually the second of two triggers for an already-successful publish. Always check `gh run list` history for the tag before treating a 409 as a real incident.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

many past "failures" are actually the second of two triggers for an already-successful publish

How would this happen?

Comment thread .agents/skills/release-widget/SKILL.md Outdated
Comment thread .agents/skills/release-widget/SKILL.md Outdated
Comment thread .agents/skills/release-widget/SKILL.md Outdated

Find the run matching this tag/branch.

- `conclusion: success` → the workflow succeeded, but that only means the API call didn't error — it's not proof the version is live. There's no packaged helper to query the Marketplace programmatically (`createDraft`/`publishDraft` are write-only, no idempotency or read-back check), so confirm manually: ask the user to open Marketplace → package page → Manage Versions, and check `<version>` is listed. Don't declare the release done until they confirm.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is marketplace-mcp that we can use for this.

Comment thread .agents/skills/release-widget/SKILL.md Outdated
@github-actions

This comment has been minimized.

Comment thread .agents/skills/release-widget/SKILL.md Outdated

```bash
cd $RELEASE_PATH
pnpm exec rui-bump-version <version>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can use global pnpm exec rui-bump-version <npm-package-name> <version>. And this script should check if the package is releasable by its own, and should give an error if not. Bump should be from the containing package.

Possibly extracting changelogs can use the same principle, by package name. This gives less room for error. maybe the same guard for usage on releasable packages only

await bumpXml(path, version);
} catch {
xmlBumped = false; // modules have no package.xml
if (info.mxpackage.type === "module") {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Charts widgets is a widget but still has dependencies.

  Automates widget/module release pipeline: version bump, GitHub draft
  release, OSS clearance SBOM, Marketplace publish. Sharing for team
  feedback before promoting out of private trial.
@yordan-st
yordan-st force-pushed the skill/release-widget branch from 50fbf1e to 1ac50b0 Compare September 8, 2026 13:34
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Comment on lines 223 to 228
hasUnreleasedLogs(): boolean {
return this.changelog.content[0].sections.length !== 0;
const [unreleased] = this.changelog.content;
// Module changelogs usually carry their entries under subcomponents
// (per wrapped widget), with no module level sections at all.
return unreleased.sections.length !== 0 || unreleased.subcomponents.length !== 0;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This never happens, subcomponents entries added during release. So it is never a case where there is an unreleased section with subcomponents.

const dependencyPath = await resolvePackagePath(dependencyName);

await bumpPackage(dependencyPath, version);
bumpedPackages.push(shortName(dependencyName));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we strip @mendix here? If we get package name with @mendix, we should also return back the same format.

}

function resolveVersion(bumpType: string, previousVersion: string): string {
const version = getNewVersion(bumpType, previousVersion);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like getNewVersion already does what Version class is capable of. We should use Version math instead of using manual math done in getNewVersion.


`appName` is the Marketplace display name (e.g. `Maps`). The draft release is titled `<appName> v<version>`, which is what the OSS helpers match SBOM/READMEOSS filenames against — they derive it from the tag themselves.

- `appNumber` is a positive number → **standalone release** (a widget, or a module published directly). Keep this `info`, Phase 2 and 3 reuse it — no re-fetching.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

appNumber is not used in Phase 2 as far as I can tell.

- `appNumber` is a positive number → **standalone release** (a widget, or a module published directly). Keep this `info`, Phase 2 and 3 reuse it — no re-fetching.
- `appNumber` is `null`/absent/`-1` → widget is module-wrapped, not published on its own. Find the owning module:
```bash
grep -l "\"@mendix/<widget>\"" packages/modules/*/package.json

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fail for charts widget, this doesn't live in modules folder.


```bash
echo "== SBOM jar =="; ls "${SBOM_GENERATOR_JAR:-$HOME/SBOM_Generator.jar}" 2>&1
echo "== rui helpers =="; pnpm exec which rui-package-info 2>&1 | tail -1

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to check for that?


If the SBOM jar is missing, say what's missing and how to fix it (where to get `SBOM_Generator.jar`, or point `SBOM_GENERATOR_JAR` at it) — don't proceed past a missing prereq.

If a helper doesn't resolve (`Command "rui-package-info" not found`), the bins aren't linked yet — `pnpm install` at the repo root, then re-check. Don't work around it by calling `ts-node bin/<helper>.ts` all run.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a misconfigured local setup, no need to check for it.

It refuses to run and exits non-zero when:

- `<npm-package-name>` isn't independently releasable (no positive `marketplace.appNumber`) — Phase 0 pointed at the wrong package, go back and recheck.
- the argument is neither a bump type nor an `x.y.z` version.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not make it possible to pass bump type, only version in the first place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants