Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
139 commits
Select commit Hold shift + click to select a range
169bf6a
feat(gradle): split plugin into api/core modules and add config.json …
monikon22 Aug 15, 2026
7694c60
refactor(runner): replace module singletons with Session, add Environ…
monikon22 Aug 15, 2026
1371293
feat(gradle): add mode registry, move LocalMode to plugwright-local
monikon22 Aug 15, 2026
525d921
feat(matrix): add PlugwrightMatrixTask, JSON+JUnit reports, requires/…
monikon22 Aug 15, 2026
9141210
feat(runner): add plugin host with hooks, fixtures, matchers, inherit…
monikon22 Aug 15, 2026
cdac6b5
feat(gradle): thread plugin configs and cleanup journal through confi…
monikon22 Aug 15, 2026
a574308
feat(external): add ExternalMode with account pool, console channels,…
monikon22 Aug 15, 2026
4af068f
feat(bundle): split published plugin id into its own module registeri…
monikon22 Aug 15, 2026
b8675bf
feat(runner): add account pool, external environment, admin-bot conso…
monikon22 Aug 15, 2026
2aaf4c1
fix(gradle): give mode-registered tasks the shared Node setup
monikon22 Aug 15, 2026
410fdfe
fix(runner): keep secrets lazy and report ping/cleanup exit codes
monikon22 Aug 15, 2026
2db8b3c
fix(session): throttle bot error logging instead of logging every pac…
monikon22 Aug 16, 2026
da65879
feat(gradle): keep the IntelliJ sync trigger through the module split
monikon22 Aug 20, 2026
86fd6fb
fix(gradle): wire the IDEA sync trigger when idea applies late
monikon22 Aug 22, 2026
5bdcc6d
build(gradle): load kotlin-dsl once for all subprojects
monikon22 Aug 22, 2026
266ed8c
Merge pull request #47 from monikon22/pr/1-mode-architecture
Drownek Aug 23, 2026
e89bde6
chore: bump to 3.0.0-dev.0
Drownek Aug 23, 2026
e8461ad
feat(console-rcon): add @plugwright/console-rcon package
monikon22 Aug 15, 2026
3522191
feat(auth-authme): add reference AuthMe authentication plugin
monikon22 Aug 15, 2026
0977204
feat(gradle): install the npm packages an environment declares
monikon22 Aug 15, 2026
3be6e8e
fix(runner): resolve optional packages from the test project
monikon22 Aug 15, 2026
0ac3064
feat(gradle): let any mode declare runner plugins
monikon22 Aug 15, 2026
2b213ce
feat(gradle): write the runtime reference a third-party mode needs
monikon22 Aug 15, 2026
5074f67
fix(runner): authenticate before waiting for the spawn
monikon22 Aug 15, 2026
2e1054a
feat(runner): run op and command sync through a console that answers
monikon22 Aug 15, 2026
7c2cdc8
feat(runner): let a test require a specific capability value
monikon22 Aug 15, 2026
71d68ef
chore(runner): expose the CLI as a bin entry
monikon22 Aug 15, 2026
276692f
feat(auth-authme): answer the prompt the server actually sent
monikon22 Aug 15, 2026
20057c6
docs: document environments, external servers, plugins and modes
monikon22 Aug 15, 2026
fdcdef4
test(example): run the suite against a second, hand-started server
monikon22 Aug 15, 2026
9489557
feat(runner): let a caller keep part of a chat message out of the log
monikon22 Aug 20, 2026
90213fb
fix(auth-authme): keep the password out of the run log
monikon22 Aug 20, 2026
7e5204a
fix(external): stop pinning the RCON console package to a range it ca…
monikon22 Aug 23, 2026
67e78ce
Merge pull request #48 from monikon22/pr/2-plugin-packages
Drownek Aug 23, 2026
bd5ce7d
feat(gradle): give the workspace a fixed directory layout
monikon22 Aug 16, 2026
3b9fa83
feat(init): scaffold the layout, gitignore included
monikon22 Aug 16, 2026
0c293a5
refactor(example): move the example onto the new layout
monikon22 Aug 16, 2026
8b31c29
docs: document the workspace layout
monikon22 Aug 16, 2026
f7e4d5b
refactor(example): move message-buffer.spec.ts onto the new layout
monikon22 Aug 23, 2026
579fefc
chore(example): refresh the workspace lockfile
monikon22 Aug 23, 2026
6f9726c
fix(core): stop stripping tsconfig.json comments on migration rewrite
monikon22 Aug 24, 2026
8e1ad36
Merge pull request #49 from monikon22/pr/3-workspace-layout
Drownek Aug 24, 2026
4028a87
feat(gradle): describe npm registries in the build script
monikon22 Aug 16, 2026
7544da7
feat(gradle): write the .npmrc before installing
monikon22 Aug 16, 2026
0062204
feat(init): scaffold a workspace that knows about .npmrc
monikon22 Aug 16, 2026
ef98b10
docs: document custom npm registries
monikon22 Aug 16, 2026
9cd7472
feat(gitignore): update patterns to ignore plugin binaries and add Co…
monikon22 Aug 16, 2026
0bd0922
fix(npm): stop cmd eating the caret in a runner package range
monikon22 Aug 16, 2026
e9e12b2
Merge pull request #50 from monikon22/pr/4-npm-registries
Drownek Aug 24, 2026
cdd721f
fix(npm): don't cut git/URL package specs at the last @
monikon22 Aug 24, 2026
1ff9119
fix(npm): insert call after cmd /c to stop it eating outer quotes
monikon22 Aug 24, 2026
f457e44
feat(runner): reuse a connected player across test boundaries
monikon22 Aug 16, 2026
44110b5
feat(reuse): let a reused player leave the server between tests
monikon22 Aug 16, 2026
c8cead6
feat(reuse): add reuseTest pool-initialization hooks
monikon22 Aug 16, 2026
702d9ee
feat(reuse): run reuseTest as a reported dependency of its trigger test
monikon22 Aug 16, 2026
6950497
docs(writing-tests): document reuseTest
monikon22 Aug 16, 2026
9a095c4
feat(reuse): give reuseTest the full TestOptions scope of a regular test
monikon22 Aug 16, 2026
b02d4be
docs(writing-tests): document reuseTest's full TestOptions scope
monikon22 Aug 16, 2026
76ffb24
fix(reuse): clear a stayed player's chat history on checkout
monikon22 Aug 20, 2026
1dbef83
Merge pull request #52 from monikon22/pr/5-player-reuse
Drownek Aug 25, 2026
3bb591d
[v3] feat: publish npm packages and the Gradle plugin, rename runner …
monikon22 Aug 27, 2026
562467f
chore: bump to 3.0.0-dev.1
Drownek Aug 27, 2026
535f8c6
fix(authme): hardcode joinIndex to 0 to avoid missing login prompt
monikon22 Aug 27, 2026
fc2cdb8
fix(local-mode): write configured port to server.properties
monikon22 Aug 27, 2026
6bfd120
fix(stand-reset): use player.deOp() to clear tracked ability state
monikon22 Aug 27, 2026
8c0f793
Merge pull request #56 from monikon22/fix/54-stand-bugs
Drownek Aug 27, 2026
f55ee81
refactor: drop player reuse
monikon22 Aug 27, 2026
eb47179
feat(accounts): let a name come from the environment, not a counter
monikon22 Aug 27, 2026
8cdd38e
feat(runner): add describe.serial() for tests that share state on pur…
monikon22 Aug 27, 2026
d3df705
feat(example): reset balance and kit cooldowns on the stand
monikon22 Aug 27, 2026
2091ee0
docs: replace the reuse pages with describe.serial
monikon22 Aug 27, 2026
3a8f2bd
fix(example): exclude the named-bot test on the stand
monikon22 Aug 27, 2026
a8f7ca7
Merge pull request #59 from monikon22/feat/53-serial-identity
Drownek Aug 28, 2026
0dc2115
build(deps): add idea-ext dependency to plugwright-bundle
Drownek Aug 28, 2026
b47d1af
ci: trigger example plugin tests on v3-dev branch
Drownek Aug 28, 2026
6fae90d
fix(auth-authme): fall back to login on a missing prompt (#60)
monikon22 Aug 28, 2026
6eab226
feat(auth-authme): add failOnMissingPrompt to opt back into strict pr…
monikon22 Aug 28, 2026
dd0122c
build(example-plugin): track a stand start.sh launcher outside genera…
monikon22 Aug 28, 2026
2592328
ci(#61): run the stand environment suite after LocalMode
monikon22 Aug 28, 2026
8797621
ci(#61): install JDK 21 before starting the stand server
monikon22 Aug 28, 2026
2ab3e7d
ci(#61): split stand into its own parallel job
monikon22 Aug 28, 2026
1051650
ci(#61): install console-rcon before pinging the stand server
monikon22 Aug 28, 2026
41d7173
ci(#61): fix duplicate gradle-args key from the previous commit
monikon22 Aug 28, 2026
b40398b
feat(auth-authme): replace missing-prompt guess with sessionResumedPa…
monikon22 Aug 28, 2026
ede3dda
test(example): cover authme session-resume, enable AuthMe sessions
monikon22 Aug 28, 2026
1e58e04
Merge pull request #63 from monikon22/feat/61-stand-ci-testing
Drownek Aug 28, 2026
9b81ac6
build: use npm ci instead of npm install for packages
Drownek Aug 28, 2026
ebf256a
ci: use java 21 directly in plugwright-action
Drownek Aug 28, 2026
f9f8357
Merge pull request #62 from monikon22/feat/authme-fail-on-missing-prompt
Drownek Aug 29, 2026
a8bfbe7
ci: replace gradle ping loop with log tail and disable daemon
Drownek Aug 29, 2026
bf056c8
feat(runner): let createPlayer take a password for a named bot
monikon22 Aug 30, 2026
ffecdc3
test(example): unname the second bot, run multi-bot and Cross-bot on …
monikon22 Aug 30, 2026
1823e82
fix(runner): read the console log from a cursor instead of clearing it
monikon22 Aug 30, 2026
b71620d
feat(runner): add concurrency option to test() and describe.serial
monikon22 Aug 30, 2026
de4e9cf
test(example): add e2e coverage for concurrent test execution
monikon22 Aug 30, 2026
405caac
docs: document the concurrency option and its report shape
monikon22 Aug 30, 2026
647d3d8
fix(example): skip the server-log concurrency test where console outp…
monikon22 Aug 30, 2026
1ef3232
feat(runner): show instance pass counts in the report
monikon22 Aug 30, 2026
1909b71
fix(authme): make Microsoft login-wall skip opt-in
monikon22 Aug 30, 2026
4415fc9
docs(authme): drop 'AuthMe never prompts microsoft accounts' claim
monikon22 Aug 30, 2026
a31adb8
Merge pull request #66 from monikon22/feat/58-createplayer-password
Drownek Sep 2, 2026
dcc5ef8
fix(session): stop disconnectAllBots from losing bots added mid-teardown
monikon22 Sep 3, 2026
7109b6b
fix(test-runner): disconnect bots whose join() failed
monikon22 Sep 3, 2026
a529bb5
fix(test-registry): reject concurrency on tests inside describe.serial
monikon22 Sep 3, 2026
37fc104
fix(runner): load main/suite spec files after preflight runs
monikon22 Sep 3, 2026
f7b7cd8
fix(test-runner): recognize a rejoined bot as the scope's own
monikon22 Sep 3, 2026
9e423ef
fix(authme): wait for authentication confirmation on session resume
Drownek Sep 3, 2026
ce619d5
test(example): format concurrency test and remove /say
Drownek Sep 3, 2026
6743acb
Merge pull request #67 from monikon22/feat/64-concurrent-test-execution
Drownek Sep 3, 2026
5060eec
Merge pull request #68 from monikon22/fix/65-authme-microsoft-login-wall
Drownek Sep 3, 2026
c93ed74
docs: document HolyWorld integration in README
Drownek Sep 3, 2026
e774c5d
docs: remove publishing instructions from README
Drownek Sep 3, 2026
08dc6e9
docs: clarify server log assertions and isolation under concurrency
Drownek Sep 4, 2026
60f31ca
fix(runner): return command output instead of sync marker in executeA…
Drownek Sep 4, 2026
5547b1f
feat(runner): add player.clearInventory method with state polling
Drownek Sep 4, 2026
9b5bc5b
refactor(plugins): adopt player.clearInventory and poll console confi…
Drownek Sep 4, 2026
d2213ce
fix(runner): fix TCP chunk splitting by keeping a remainder across ch…
Drownek Sep 4, 2026
8dfbafe
fix(runner): fix test pattern matching bug against absolute paths
Drownek Sep 4, 2026
5647e3c
fix(rcon): add buffer underflow guard when decoding packets
Drownek Sep 4, 2026
2935edc
fix(rcon): implement standard RCON sentinel strategy for fragmented r…
Drownek Sep 4, 2026
15ea876
fix(runner): ensure proper TCP chunk boundary handling across packets
Drownek Sep 5, 2026
a14a032
fix(gradle-plugin): make publish aggregate private and public repos
monikon22 Sep 6, 2026
0ec8621
Merge pull request #71 from monikon22/fix/bundle-publish-task
Drownek Sep 6, 2026
bea8b60
[v3] fix: MS profile caching, RCON queue & runner exit code
monikon22 Sep 6, 2026
16116f2
refactor: streamline v3 architecture, unify RCON execution, and remov…
Drownek Sep 8, 2026
433f57c
feat(runner): support Minecraft 26.1.1 and 26.1.2 versions
Drownek Sep 8, 2026
c0578ca
docs: sync supported versions, CI example, and links from master
Drownek Sep 8, 2026
03d8f03
fix(gradle-plugin): redownload server.jar on Minecraft version change
Drownek Sep 8, 2026
a48636b
ci: add workflow_dispatch trigger with selectable Minecraft and Java …
Drownek Sep 8, 2026
35f7d11
merge: absorb master into v3-dev keeping v3 state
Drownek Sep 8, 2026
b9d2758
feat(runner): log bot name on chat and harden RCON socket lifecycle
Drownek Sep 8, 2026
e4bbe18
style(runner): apply unified cyan prefix to bot log outputs
Drownek Sep 8, 2026
4ad5d19
style(runner): unify remaining bot log prefixes with cyan [Bot username]
Drownek Sep 8, 2026
2392986
test(e2e): set creative mode in multi-bot teleportation test to preve…
Drownek Sep 8, 2026
bfe6eb6
refactor(runner): clean up console types, return promise in rcon exec…
Drownek Sep 9, 2026
5f3c04d
docs: add individual migration guide, expand api-reference
Drownek Sep 10, 2026
5864823
docs: update quickstart to use environments
Drownek Sep 10, 2026
a9aa27a
refactor(runner)!: remove deprecated GUI API and fix RCON edge cases
Drownek Sep 12, 2026
3902881
chore: bump to 3.0.0
Drownek Sep 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Settings for publishing to a registry other than the public ones. Copy to `.env` and fill
# in what applies; `.env` is ignored by git so the passwords stay out of the repository.
#
# None of this is needed for a public release. `npm run publish:packages` with nothing set
# publishes to npmjs.com, and `./gradlew publishToPublicRepository` publishes the plugin to
# the Gradle Plugin Portal using the credentials that plugin already looks for
# (GRADLE_PUBLISH_KEY and GRADLE_PUBLISH_SECRET).

# --- npm packages -------------------------------------------------------------------------
# Where `npm run publish:packages` sends @plugwright/runner and the plugin packages.
# Leave the registry unset to publish to npmjs.com instead.
PLUGWRIGHT_NPM_REGISTRY=https://registry.example.com/repository/npm-hosted/
PLUGWRIGHT_NPM_USER=
PLUGWRIGHT_NPM_PASSWORD=

# Optional. The dist-tag to publish under, and the npm access level.
# PLUGWRIGHT_NPM_TAG=latest
# PLUGWRIGHT_NPM_ACCESS=public

# --- gradle plugin ------------------------------------------------------------------------
# Where `./gradlew publishToPrivateRepository` sends the plugin. The same three values can be
# given as gradle properties instead: plugwright.publish.url, .user and .password.
# Leave the user and password empty for a repository that accepts anonymous deploys.
#
# Naming a URL here is what turns private publishing on. Without one the task succeeds and
# publishes nothing, so leaving this whole section blank is a valid setup.
PLUGWRIGHT_PUBLISH_URL=https://repo.example.com/repository/maven-releases/
PLUGWRIGHT_PUBLISH_USER=
PLUGWRIGHT_PUBLISH_PASSWORD=

# Optional. Force either destination off, whatever the rest of this file says.
# PLUGWRIGHT_PUBLISH_PUBLIC_ENABLED=false
# PLUGWRIGHT_PUBLISH_PRIVATE_ENABLED=false
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.sh text eol=lf
105 changes: 100 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,116 @@ on:
- 'docs/**'
- 'docs.json'
- '**/*.md'
workflow_dispatch:
inputs:
mc_version:
description: 'Minecraft version to test'
required: true
default: '1.21.11'
type: choice
options:
- '1.21.11'
- '26.1.2'
java_version:
description: 'Java version'
required: true
default: '21'
type: choice
options:
- '21'
- '26'
run_stand:
description: 'Run external stand server tests'
required: true
default: true
type: boolean

jobs:
test-example-plugin:
if: "!contains(github.event.head_commit.message, 'skip-ci')"
runs-on: ubuntu-latest
env:
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
MC_VERSION: ${{ inputs.mc_version || '1.21.11' }}
JAVA_VERSION: ${{ inputs.java_version || '21' }}

steps:
- uses: actions/checkout@v4
- name: Build runner-package
# The example links all three by path, and npm cannot build a linked package: it packs
# the directory into a staging copy that never gets its dev dependencies.
- name: Build the local npm packages
run: |
cd runner-package
npm install
npm run build
npm run install:packages
npm run build:packages
- uses: drownek/plugwright-action@v1
with:
java-version: "21"
java-version: ${{ inputs.java_version || '21' }}
node-version: "24"
working-directory: "./example_plugin"

test-example-plugin-stand:
if: "!contains(github.event.head_commit.message, 'skip-ci') && (inputs.run_stand == null || inputs.run_stand == true)"
runs-on: ubuntu-latest
env:
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
MC_VERSION: ${{ inputs.mc_version || '1.21.11' }}
JAVA_VERSION: ${{ inputs.java_version || '21' }}
# Test-only credentials for the Paper server this job starts and tears down itself.
PLUGWRIGHT_RCON_PASSWORD: plugwright
PLUGWRIGHT_BOT_PASSWORD: plugwright

steps:
- uses: actions/checkout@v4
# Same duplicated build as test-example-plugin: this job runs on its own runner, in
# parallel with it, so it can't share that job's npm install/build output.
- name: Build the local npm packages
run: |
npm run install:packages
npm run build:packages
# Running in parallel with test-example-plugin means this job can't reuse its
# generated/local/run/ either - provision the same Paper server here instead of just
# running plugwrightTest, which would also run (and duplicate) the local suite.
# plugwrightCompileTests is the other half: plugwrightPingStand/plugwrightTestStand
# don't depend on it themselves (ExternalMode assumes the stand is already up, nothing
# to provision - see registerTasks in ExternalMode.kt), they just expect node_modules
# to already have what npm(...) plugin refs and console { rcon {} } need.
- uses: drownek/plugwright-action@v1
with:
java-version: ${{ inputs.java_version || '21' }}
node-version: "24"
working-directory: "./example_plugin"
gradle-args: plugwrightProvisionLocal plugwrightCompileTests
# generated/ is gitignored, so start.sh - the launcher example_plugin/README.md tells
# developers to hand-write - never made it into the provisioned run dir. Copy in the
# tracked copy.
- name: Start the stand Paper server
working-directory: ./example_plugin/src/test/e2e/generated/local/run
run: |
cp "$GITHUB_WORKSPACE/example_plugin/src/test/e2e/stand-run/start.sh" .
chmod +x start.sh
nohup ./start.sh > stand-server.log 2>&1 &
echo $! > stand-server.pid
- name: Wait for the stand server
working-directory: ./example_plugin/src/test/e2e/generated/local/run
timeout-minutes: 2
run: tail -n +1 -f stand-server.log | grep -q -m 1 'Done'
- name: Verify authentication (Ping)
working-directory: ./example_plugin
run: ./gradlew plugwrightPingStand
- name: Run the stand suite
working-directory: ./example_plugin
run: ./gradlew plugwrightTestStand
- name: Stop the stand Paper server
if: always()
working-directory: ./example_plugin/src/test/e2e/generated/local/run
run: |
[ -f stand-server.pid ] && kill "$(cat stand-server.pid)" 2>/dev/null || true
- name: Upload stand server log
if: failure()
uses: actions/upload-artifact@v4
with:
name: stand-server-log
path: |
example_plugin/src/test/e2e/generated/local/run/stand-server.log
example_plugin/build/reports/plugwright/stand.*
if-no-files-found: ignore
20 changes: 14 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: write # for creating GitHub releases
id-token: write # required for OIDC trusted publishing
id-token: write # signs the provenance attestation
steps:
- name: Checkout repository
uses: actions/checkout@v4
Expand All @@ -31,11 +31,19 @@ jobs:
- name: Upgrade npm
run: npm install -g npm@11.5.1

- name: Publish NPM package
working-directory: runner-package
# The plugin packages link the runner through `file:../runner-package`, so they are
# installed together rather than one directory at a time. Each package builds itself
# from `prepublishOnly`, and the script publishes all three.
- name: Publish NPM packages
env:
# A trusted publisher is configured per package, and no name under @plugwright
# exists yet, so there is nothing for OIDC to authenticate against on the first
# release. A granular token scoped to the org carries it; once all three names
# exist, `npm trust` takes over and this block comes out.
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
npm ci
npm publish --access public --provenance
npm run install:packages
npm run publish:packages -- --provenance

- name: Publish Gradle plugin
working-directory: gradle-plugin
Expand All @@ -44,5 +52,5 @@ jobs:
GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_PUBLISH_SECRET }}
run: |
chmod +x gradlew
./gradlew publishPlugins
./gradlew publish

18 changes: 12 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ gradle-app.setting
!gradle-wrapper.jar
*.class
gradle.properties
/gradle-plugin/bin/
/example_plugin/bin/
**/bin/

# IDE
.idea/
Expand All @@ -32,6 +31,9 @@ gradle.properties
Thumbs.db
desktop.ini

# Code Graph index
.codegraph/

# Logs
*.log
logs/
Expand All @@ -40,7 +42,8 @@ logs/
*.tsbuildinfo
dist/

# Test server runtime
# Test server runtime — plugwright writes it under <testsDir>/generated/<environment>
generated/
run/
test-server/
**/server.properties
Expand All @@ -62,9 +65,6 @@ test-server/
**/spigot.jar
server.jar

# Compiled test files
**/e2e/dist/

# Temporary files
*.tmp
*.temp
Expand All @@ -81,3 +81,9 @@ release.properties
dependency-reduced-pom.xml

.serena/

# Publishing credentials for a private registry. See .env.example.
.env

# Local, per-developer notes kept beside the checked-in docs.
*.local.md
Loading
Loading