Skip to content

fix(commands): migrate GreetCommand to BaseCommandExecutor for UltiTools 6.3.0 (#4) - #5

Merged
wisdommen merged 12 commits into
masterfrom
fix/p17-w0-api-630
Sep 21, 2026
Merged

wisdommen merged 12 commits into
masterfrom
fix/p17-w0-api-630

Conversation

@wisdommen

Copy link
Copy Markdown
Member

Summary

Moves this example onto UltiTools-API 6.3.0 and Paper. GreetCommand extended AbstractCommandExecutor, which 6.3.0 removed, so the plugin loaded but no /ultiext sub-command registered (#4). It now extends BaseCommandExecutor. The pom builds on UltiTools-API 6.3.0-SNAPSHOT and paper-api 1.21.11-R0.1-SNAPSHOT, the repository gains its first tests (15) and its first CI workflow, and the UAT checklist is corrected so its rows give the right verdict on a real server.

本 PR 将示例迁移到 UltiTools-API 6.3.0 与 Paper:GreetCommand 改为继承 BaseCommandExecutor(旧基类已在 6.3.0 移除,导致 /ultiext 子命令全部无法注册,#4),新增 15 个测试与首个 CI 工作流,并修正 UAT 清单。

Issue closure

Closes #4

Superseded pull requests

Both open pull requests are reused, not rewritten. Their commits were cherry-picked onto the latest master with git cherry-pick -x, keeping the original author and author date. Both applied cleanly and compiled against 6.3.0-SNAPSHOT when measured.

PR Original commit Commit in this PR Change
#2 1cbbd55 066bc59 pin UltiTools-API 6.3.0-SNAPSHOT, add central-snapshots
#1 e128f2f 9cb2317 GreetCommand extends BaseCommandExecutor

PR #2's branch already contained PR #1's commit, so these two commits are everything in both. They are kept verbatim to preserve authorship, and two sentences in 9cb2317's message are no longer true where it now sits:

  • It says AbstractCommandExecutor was "deprecated". 6.3.0 removed it.
  • It says it "compiles against the existing released UltiTools-API 6.2.2 pin". In this branch it sits on 066bc59 and compiles against 6.3.0-SNAPSHOT.

066bc59's pom comment ("no CI workflow") is corrected by later commits. Both pull requests will be closed with a comment pointing here.

Checklist rows amended

UAT-CHECKLIST.md:

  • Conventions:
    • Build under test: a jar built before the migration still loads but registers no /ultiext sub-command. Because the jar records no source commit, the executor compares the installed jar's SHA-256 with the build hand-off's.
    • Persistent records: join-created and persisted visitor records outlive the rows that made them, so rows check record state instead of assuming it.
    • Console commands: the permission convention no longer says only one row uses the console.
  • ultitools-example.greet.hello: JoinListener sends the identical line on join, so the row now requires a new line after the command and no unknown-command reply. Before, it could pass with no command registered.
  • ultitools-example.data.visitors.neg-empty:
    • An empty store is established and checked from the console, and the step runs from the console.
    • A follow-up visit/visitors proves the store is readable.
    • The row cleans up after itself.
  • ultitools-example.data.visitors: <n> must equal the lines printed, and the list must include probe and the executor's own join record.
  • ultitools-example.data.visit, ultitools-example.data.delvisitor.neg-not-found, ultitools-example.data.persistence, ultitools-example.join.on-join: preconditions check the record state with /ultiext visitors and say how to reach it.
  • ultitools-example.join.on-join.neg-rejoin: says when to read N.

FEATURES.md: GreetCommand source line numbers updated (@CmdExecutor 46; @CmdMapping 56/62/69/99/118). The "no comment names our annotations" claim is replaced with measured counts. AbstractDataEntity is described as removed, not deprecated.

Red-when-reverted evidence

  • UltiTools-External-Example-4-RED.log / UltiTools-External-Example-4-GREEN.log: with the migration commit reverted, the build fails to compile (cannot find symbol AbstractCommandExecutor, GreetCommand.java lines 6 and 51); at the head, GreetCommandTest runs 14 tests, 0 failures. The RED is a compile error, so it proves the migration is required to build, not that the assertions catch a regression. The next log does that.
  • UltiTools-External-Example-4-MUTATION-registration-RED.log: behaviour-level RED. The copy has GreetCommand not extending BaseCommandExecutor. GreetCommandRegistrationTest fails because /ultiext is not registered: a test failure, not a compile error. That test runs GreetCommand through the framework's own code: the container steps of PluginManager#registerExternal, the real PluginManager.validateCommandExecutorContracts, and the real CommandManager#registerAllExternal / unregisterAllExternal against a real Bukkit SimpleCommandMap. Only UltiTools.getInstance() and Bukkit's static accessors are stubbed. End-to-end registration on a server is then covered by the real-machine row ultitools-example.greet.hello.

Behaviour changes

From CHANGELOG.md, verbatim:

Fixed

Changed

(The Chinese entries follow each in the file.)

Known limitation

README.md is unchanged. It still pins 6.2.2 in the dependency snippet, says "Requires UltiTools-API 6.2.2+", and describes "any standard Bukkit/Spigot/Paper plugin". The 6.2.2+ runtime claim still holds: every framework member the compiled classes use exists with the same signature in 6.2.2. Refreshing the version claims, and saying that the host server must be Paper, belongs to the 6.3.0 release package, together with UltiKits/UltiRecipe#19.

CI

.github/workflows/maven-ci.yml is new, so its first run is on this pull request. It is the modules' workflow (same pinned actions, JDK 21, mvn -B verify) with one deliberate change: the job is named Test & package (JDK 21) instead of Test, coverage gate & package (JDK 21), because this repository has no coverage gate and the check should not promise one. No publish or release workflow is added, and the project version is unchanged.

Gates

  • Gate 1, own code review: independent deep review. 0 blockers, 5 warnings and 7 info findings, all dispositioned; the warnings were fixed in 48227ea, 6354f3a, 9f8b843 and b1a4380.
  • Gate 2, third-party review: this repository is not onboarded to Codacy, so gate 2 is the Codex review.
  • Gate 3, real-machine UAT: pending, in the wave-0 integration session.
  • Gate 4, CI: the Test & package (JDK 21) check on the final head.

Verification

mvn -B clean verify on this head: Tests run: 15, Failures: 0, Errors: 0, Skipped: 0, BUILD SUCCESS (GreetCommandTest 14, GreetCommandRegistrationTest 1).

Checklist

  • Targets master
  • Line endings preserved per file. pom.xml and GreetCommand.java stay CRLF; the markdown files and template stay LF. The two new test files are CRLF to match every src/main/java file.
  • Comments, javadoc, workflow comments, and this PR's title and body are English-first with Chinese as a supplement
  • FEATURES.md and UAT-CHECKLIST.md updated

🤖 Generated with Claude Code

https://claude.ai/code/session_017BD9mGr6EsyRsEv3d2BizL

wisdommen and others added 11 commits September 17, 2026 21:30
…pshots

- Bump the UltiTools-API dependency from the released 6.2.2 to the
  6.3.0-SNAPSHOT lineage (phase 9, MOD-01/MOD-02), ahead of the 6.3.0
  release.
- Add the central-snapshots repository entry; without it the snapshot
  coordinate cannot be resolved at all.
- Record, in the pom near the build section, that this repository is
  deliberately out of scope for the module coverage gate: it has no
  CI workflow to run one in, and it demonstrates the External Plugin
  API rather than shipping as a UltiToolsPlugin module.
- Module version and line endings unchanged.

(cherry picked from commit 1cbbd55)
)

- Replace spigot-api 1.20.4 and the SpigotMC repository with paper-api
  1.21.11-R0.1-SNAPSHOT from the PaperMC repository, the same pin and
  repository the UltiKits modules use. UltiTools-API 6.3.0 is a Paper
  framework (Adventure types throughout), so Spigot is not a supported
  build target.
- Add JUnit 5.10.0, Mockito 5.5.0, AssertJ 3.24.2 and MockBukkit
  (org.mockbukkit.mockbukkit:mockbukkit-v1.21:4.101.0) as test
  dependencies, and maven-surefire-plugin 3.1.2, with the coordinates
  and versions the modules already declare.
- Correct the phase-9 scope comment: it said the repository has no CI
  workflow, which stops being true in this change set. The coverage gate
  stays out of scope.
- Project version unchanged; line endings preserved (CRLF).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017BD9mGr6EsyRsEv3d2BizL
…I 6.3.0 (#4)

GreetCommandTest covers the three things an external plugin's command
needs on 6.3.0:

- Registration contract read by CommandManager#registerAllExternal: the
  class is a Bukkit CommandExecutor (BaseCommandExecutor) and carries
  @cmdexecutor with aliases ultiext/uext, permission ultiext.greet, and
  manualRegister=false; getMappings() holds all five sub-commands.
- Dispatch through BaseCommandExecutor#onCommand on a MockBukkit server
  (permitted player and console), including <name> parameter binding.
- Each mapped method's sent messages and DataOperator calls (insert,
  update, failed update, getAll, del, uninitialised operator), plus help.

RED at this commit: GreetCommand still extends the AbstractCommandExecutor
that 6.3.0 deleted, so the main sources do not compile.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017BD9mGr6EsyRsEv3d2BizL
Swap the deprecated AbstractCommandExecutor for the current
BaseCommandExecutor (import + extends only). All @CmdTarget,
@cmdexecutor, @CmdMapping and @CmdParam annotations are preserved
verbatim, and the existing handleHelp(CommandSender) override is
kept unchanged, satisfying BaseCommandExecutor's protected abstract
contract with no stub.

Compiles against the existing released UltiTools-API 6.2.2 pin,
no snapshot repository added (D-10 round 1).

(cherry picked from commit e128f2f)
…mmand (#4)

- Add an English-first class javadoc (Chinese supplement) walking a
  reader through the path this example exists to teach:
  UltiToolsAPI.connect -> package scan and @Autowired injection ->
  CommandManager#registerAllExternal -> BaseCommandExecutor#onCommand
  (mapping match, @CmdTarget and permission checks, parameter binding,
  next-tick execution), and why commands extend BaseCommandExecutor now
  that 6.3.0 removed AbstractCommandExecutor.
- FEATURES.md: shift the GreetCommand positive-control line numbers by
  the 25 javadoc lines (@cmdexecutor 21->46; @CmdMapping 31/37/44/74/93
  -> 56/62/69/99/118); replace the claim that no comment names the
  repository's own annotations - already false on master, where the
  connect comment in UltiToolsExtExample names @cmdexecutor and
  @eventlistener - with the measured unanchored counts; say
  AbstractDataEntity was removed in 6.3.0, not deprecated.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017BD9mGr6EsyRsEv3d2BizL
…cklist (#4)

Follow-up to the reused migration commit (cherry-picked from PR #1), which
cannot carry these files without rewriting it:

- CHANGELOG.md (new, Keep a Changelog 1.1.0, English first):
  ### Fixed - /ultiext sub-commands register again on UltiTools-API
  6.3.0 (symptom as measured in #4: plugin and join listener work, every
  sub-command gets Bukkit's unknown-command reply);
  ### Changed - builds on UltiTools-API 6.3.0-SNAPSHOT and paper-api
  1.21.11 instead of 6.2.2 and spigot-api 1.20.4.
- UAT-CHECKLIST.md: a "Build under test" convention. No row names the
  removed base class or a 6.2.x API, so no row changes; the twelve rows
  Phase 10 could not run need only a jar built after this migration, and
  the convention makes a stale jar a setup error rather than a row
  failure.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017BD9mGr6EsyRsEv3d2BizL
- .github/workflows/maven-ci.yml copied byte-for-byte from UltiWorlds
  (same pinned actions/checkout and actions/setup-java SHAs, JDK 21
  temurin, `mvn -B verify` on every push and pull request), so this
  repository's pull requests get a real build-and-test check. The
  repository had no workflow before this.
- No publish or release workflow is added.
- The copied job name says "coverage gate"; this repository has no
  JaCoCo check (phase-9 scope decision in pom.xml), so here the job runs
  the tests and packages the jar. Kept verbatim so the file stays
  identical to the modules' copy.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017BD9mGr6EsyRsEv3d2BizL
…tration (#4)

Gate-1 review WR-01: GreetCommandTest proved the registration contract by
reading annotations, but never ran the code that registers the command.

- GreetCommandRegistrationTest repeats the container steps
  PluginManager#registerExternal performs for UltiToolsAPI.connect (plugin
  class loader, JavaPlugin type, package scan, refresh), calls the real
  package-private PluginManager.validateCommandExecutorContracts, then the
  real CommandManager#registerAllExternal against a real Bukkit
  SimpleCommandMap. It asserts /ultiext and /uext resolve to one
  PluginCommand with permission ultiext.greet whose executor is the
  scanned GreetCommand with GreetService injected, and that
  unregisterAllExternal removes both. Only UltiTools.getInstance() and
  Bukkit's static accessors are stubbed.
- Behaviour-level RED: in a throwaway copy where GreetCommand does not
  extend BaseCommandExecutor, registerAllExternal skips it without error
  and the /ultiext assertion fails (a test failure, not a compile error).
- Test sources converted to CRLF to match every src/main/java file
  (review IN-06); GreetCommandTest's content is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017BD9mGr6EsyRsEv3d2BizL
…'s no-CI claim (#4)

- maven-ci.yml (gate-1 review WR-02): the job copied from the modules was
  named "Test, coverage gate & package" and its comment described a
  jacoco:check step. This repository has no JaCoCo plugin and no coverage
  threshold, so a green check promised a gate that does not exist. The job
  is now "Test & package (JDK ${{ matrix.java-version }})", rendered as
  "Test & package (JDK 21)", and the comment says only what `mvn -B verify`
  runs. Pinned actions, triggers and the command are unchanged; the file
  is no longer byte-identical to the modules' copy, deliberately.
- pull_request_template.md (WR-03): the Issue closure comment said the
  repository has no workflows and no CI. It now says the only workflow is
  maven-ci.yml, which builds and tests and closes nothing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017BD9mGr6EsyRsEv3d2BizL
Gate-1 review IN-04:
- The coverage-gate comment said "sixteen product modules"; there are
  fifteen active UltiKits product modules. It also carried internal
  planning codes, which mean nothing to a reader of this public example;
  the comment now states the facts in words.
- The central-snapshots comment carried planning codes and said the other
  repositories "serve releases only", which stopped being true when the
  PaperMC repository started serving the paper-api snapshot; it now says
  the PaperMC repository does not host UltiTools-API.
Comments only; no dependency, repository or version change; CRLF kept.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017BD9mGr6EsyRsEv3d2BizL
…ed records (#4)

Gate-1 review WR-04, WR-05 and the same-class sweep:

- Build under test (WR-04): the jar records no source commit (manifest
  and plugin.yml version are identical before and after the migration),
  so the convention now has the executor compare the installed jar's
  SHA-256 with the build hand-off's.
- data.visitors.neg-empty (WR-05): JoinListener creates a record for every
  joining player, including the executor, and records survive restarts,
  so "delete what earlier rows created" left records behind and a correct
  build failed the row. The empty store is now established and checked
  from the console, the step runs from the console, and a follow-up
  visit/visitors pair proves the store is readable, so the empty reply
  cannot pass on a broken store; the row cleans up after itself.
- Sweep, same class (an expectation or precondition that ignores state the
  session or an earlier dispatch creates):
  - greet.hello: the join greeting is the identical line, so the row
    could pass with no command registered at all - exactly #4's broken
    build. It now requires a new line after the command and no
    unknown-command reply.
  - data.visitors: "<n> matches the actual stored count" was not
    observable; now <n> must equal the lines printed, which must include
    probe and the executor's own join record.
  - data.visit, data.delvisitor.neg-not-found, data.persistence,
    join.on-join: preconditions now check the record state with
    /ultiext visitors and say how to reach it, instead of assuming no
    earlier dispatch left a record.
  - join.on-join.neg-rejoin: says when to read N.
  - A convention bullet states why, and the permission convention no
    longer claims only one row uses the console.
- Unchanged: greet.hello.neg-console, greet.info, data.delvisitor,
  data.visit.neg-repeat. Row order check: no precondition cites a later
  row.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017BD9mGr6EsyRsEv3d2BizL
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 17, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-17T12:04:44.168995Z c90aa13 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@wisdommen

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

Reviewed commit: b1a4380e77

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

…og (#4)

The comment rewritten in 9f8b843 said the PaperMC repository does not
host UltiTools-API and that the snapshot could not be resolved without
central-snapshots. The first CI run on this pull request disproves both:
Maven downloaded UltiTools-API-6.3.0-20260917.005350-20.pom and .jar from
repo.papermc.io/repository/maven-public, whose group proxies Central's
snapshots. The comment now says what the entry is (the repository the
framework snapshot is published to) and that the build declares it rather
than relying on PaperMC's proxy. Comment only; CRLF kept.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017BD9mGr6EsyRsEv3d2BizL
@wisdommen

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: c90aa13a8f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@wisdommen
wisdommen merged commit 24c0e39 into master Sep 21, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GreetCommand still extends the removed AbstractCommandExecutor, so every /ultiext subcommand silently fails to register

1 participant