[v3] feat: publish npm packages and the Gradle plugin, rename runner to @plugwright/runner - #55
Merged
Merged
Conversation
auth-authme and console-rcon sat at 1.0.0 while the runner they are written against had moved on several versions, because the bump script only ever knew about runner-package. Nothing said which runner a given plugin package was built for. They now share one version. A plugin package is not useful without the runner, so a version pair that has to be looked up is a cost with nothing on the other side of it.
The plugin only went to the Gradle Plugin Portal, which is unreachable from a network that does not let builds out to the internet. Such an organisation had no supported way to get the plugin at all. `publishAllPublicationsToPlugwrightRepository` now deploys both the plugin jar and its marker to whatever repository `plugwright.publish.url` names, with credentials from `plugwright.publish.user` and `.password`. All three also read from PLUGWRIGHT_PUBLISH_URL, _USER and _PASSWORD, which is the shape a CI job already has its secrets in. None of the three appear in this repository. A URL here would tie a public build to one company's servers; a password here would be a password in version control. With no URL set the repository is not declared at all, so a build that does not opt in publishes exactly where it did before.
…oosing The release workflow published one of the three packages, and only to npmjs. The other two — the AuthMe and RCON reference plugins — had no publish path at all, and an organisation that mirrors its dependencies had none either. `npm run publish:packages` now sends all three wherever it is pointed. Given no configuration that is npmjs, which is what a release is; given a registry and credentials in the environment it is that registry instead. The two cases differ only in where the request goes and how it is authenticated, so they share a script rather than each growing one. Nothing about a private registry is written into the packages. A `publishConfig.registry` in a package.json would send the public release there too, so the URL and the credentials come from the environment, and the credentials go into a temporary npm config outside the working tree that is deleted whether the publish worked or not.
…optional
The plugin could already go to the Gradle Plugin Portal or to a maven repository
of the build's choosing, but the two were reached by tasks that look nothing
alike — `publishPlugins` against
`publishAllPublicationsToPlugwrightRepository`. Documenting a release meant
documenting two vocabularies.
`publishToPublicRepository` and `publishToPrivateRepository` wrap what was
already there. Neither destination is mandatory, and neither being available is
a failure: the private one is off until `plugwright.publish.url` names a
repository, and without one the task succeeds, publishes nothing and says why.
Most checkouts have no private repository, so a build script or a CI job can name
the task unconditionally instead of guarding every call.
Either can also be switched off outright, for when the implicit rule gets it
wrong — a fork that publishes only inside a company wants the public one off, and
a machine that holds the private URL for *resolving* may still want to publish
nowhere:
plugwright.publish.public.enabled default true
plugwright.publish.private.enabled default: on when a URL is set
The switch goes on the wrapped task rather than the wrapper. `onlyIf` skips the
task it is set on and nothing it depends on, so a wrapper that skipped itself
would still have run the publish underneath it.
The workflow published `@drownek/plugwright` and stopped there, so `@plugwright/auth-authme` and `@plugwright/console-rcon` — which a build asks for by name as soon as it declares an AuthMe or RCON plugin — were never on npmjs at all. Anyone following the docs got a 404 from `npm install`. It now runs the same `npm run publish:packages` a maintainer would run locally, which covers all three and keeps provenance on. The gradle step moves to `publishToPublicRepository`, which is `publishPlugins` under the name the docs use.
The registry URL and its credentials are deliberately not in any package.json or build script, which leaves nowhere that says they exist. `.env.example` is that place: it lists every variable both publish paths read, and says which of them a public release needs, which is none of them. `.env` itself is ignored, along with `*.local.md` for notes kept next to the checked-in docs.
Neither destination was written down anywhere. The release workflow was the only record of how a public release happens, and the private path — which exists precisely so an organisation can run one without the public registries — had no record at all beyond the environment variables the code reads. `docs/publishing.mdx` covers both, alongside what carries a version and why the tag comes before the publish.
The two reference plugins publish under `@plugwright`, so leaving the runtime they load into on `@drownek/plugwright` splits the project across two npm scopes for a reason no user could reconstruct. The org exists now, and 3.0 is already a breaking release with build scripts being edited anyway, so this is the cheapest moment to move. Only the npm name changes. The Gradle plugin id stays `io.github.drownek.plugwright`, the Kotlin package stays `me.drownek.plugwright`, and `repository.url` still points at `Drownek/plugwright`, so provenance is unaffected. `@drownek/plugwright` keeps its 2.x releases and wants an `npm deprecate` pointing at the new name once 3.0 ships.
Every `npm { }` example routes `@drownek` to a private mirror, a scope that stops
holding anything the moment the runner moves. `@plugwright` keeps the illustration
true: mirroring the project's own packages is the setup these examples are for.
A trusted publisher is configured per package, and every name under the new scope is unpublished, so there is nothing for OIDC to authenticate against on the first release. The publish step reads `NODE_AUTH_TOKEN` from an `NPM_TOKEN` secret — a granular token scoped to the org — and the block comes out once each package exists and `npm trust` can take over. Provenance is unaffected: `--provenance` and `id-token: write` stay where they are, and the attestation is signed from the job's OIDC token whichever credential does the publishing.
Owner
|
Merged, will try to publish dev.0 release and will bump to dev.1 afterwards |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Sixth and last PR in the series (#46), on top of #52. Rebased onto
v3-devat1dbef83.Kotlin compiles (
plugwright-bundle:compileKotlin), andtsc --noEmitis clean inrunner-package,auth-authme-packageandconsole-rcon-package.This wires up the four artifacts the project ships — three npm packages and the Gradle
plugin — for an actual release, and finishes the scope decision from #48: the runner moves
from
@drownek/plugwrightto@plugwright/runner.What ships
Lockstep versioning.
scripts/bump-version.jsnow bumps all three npm packages, not justrunner-package, and refreshes the plugin packages' lockfiles afterward —npm versionwriteseach package's own version but doesn't touch a linked dependency's version as it's recorded in
a lockfile, so an install is needed to pick up the runner's new number everywhere it's copied.
npm publishing.
scripts/publish.jspublishes all three packages in dependency order(runner first, so a consumer resolving a plugin package finds the runner already there). It
reaches npmjs.com by default and a private registry when
PLUGWRIGHT_NPM_REGISTRY(or--registry) is set — the registry and its credentials live in the environment rather than ina package manifest, so pointing at a private mirror for one run doesn't leak into the public
release.
release.ymlruns it with--provenanceagainst npmjs.com.Gradle plugin publishing.
plugwright-bundle/build.gradle.ktsgetspublishToPublicRepository(Gradle Plugin Portal, on by default) and
publishToPrivateRepository(an arbitrary Mavenrepository, on only once
plugwright.publish.url/PLUGWRIGHT_PUBLISH_URLis set). Both areswitches on the underlying publish task rather than wrappers that skip themselves, since a
wrapper skipping itself still lets whatever it
dependsOnrun.Fixed alongside: the bundle module had
implementation(project(":plugwright-core"))etc. for-core,-localand-external, which Gradle writes into the published POM as runtimedependencies on Maven coordinates that exist in no repository. Every consumer resolving the
plugin from a repository — public or private — got
Could not find io.github.drownek:plugwright-core.They're
compileOnlynow, matchingplugwright-api, since all four are merged into thebundle's own jar and none is published separately.
.env.exampledocuments every variable both scripts read, anddocs/publishing.mdxcoversthe two publish paths end to end — public release and pointing everything at a private registry.
The rename.
@drownek/plugwright→@plugwright/runner, everywhere: both packages'package.json/lockfiles, every import across the runner, the two plugins, the docs, and theexample. The Gradle plugin id stays
io.github.drownek.plugwright, the Kotlin package staysme.drownek.plugwright, andrepository.urlstill points atDrownek/plugwright— this isonly about the npm name.
README.mdgets an upgrade note for anyone still on 2.x.Needs from you before merge
Two things from the #48 discussion that are still open and now block this PR's own CI job:
NPM_TOKENGitHub secret.release.ymlwires it asNODE_AUTH_TOKENfor the firstpublish of each
@plugwrightpackage, per the plan from [v3] feat: reference plugin packages, and the runner surface they need #48 — a granular token scoped tothe org, since a trusted publisher can't be configured for a package name that doesn't
exist yet. Without it the release workflow's npm step fails outright on the first tag push.
npm deprecate @drownek/plugwright, pointing at@plugwright/runner, once 3.0actually publishes. Not urgent for this merge, but easy to lose track of once the new name
is live and the old one just goes quiet instead of pointing anywhere.
Both are on your side — I don't have publish access to either scope.
Testing
npm run publish:packages -- --dry-runpacks and validates all three without sending anything../gradlew publishToPublicRepositoryandpublishToPrivateRepositorywere exercised against athrowaway local Maven repo (
plugwright.publish.url=file://...) to confirm the POM resolvesnow that the three inner modules are
compileOnly.Merging
This is the last PR in the series — squash and merge is fine here, unlike the previous five.
After this
Opened two follow-up issues from the #46 discussion: #53 (replacing player reuse with
environment-scoped identity and
describe.serial()) and #54 (the three bugs you foundreviewing #52). I'll start on both once this merges.