Appearance
11. Plugin Updater
AppelTools ships a built-in plugin updater that can check, download, and install updates from six providers. The commands /atp updater and /atv updater expose the same surface on both Paper and Velocity.
11.1 Public API (common/.../Utils/PluginUpdater.java)
java
public class PluginUpdater {
public static CompletableFuture<PluginUpdateInfo> checkForUpdate(PluginUpdateConfig config);
public static CompletableFuture<Void> downloadAndReplace(PluginUpdateInfo info, Path pluginDir);
}PluginUpdateInfo (@Data):
| Field | Type |
|---|---|
provider | Provider |
currentVersion | String |
latestVersion | String |
downloadUrl | String |
fileName | String |
size | long |
sha256 | String (optional) |
Provider enum: JENKINS, SPIGOT, MODRINTH, HANGAR, GITHUB, GEYSER.
11.2 Configuration
Configured in config.yml under plugins:. The key of an entry is the name of the plugin:
yaml
plugins:
my-plugin:
provider: "modrinth"
project-id: "abc123"
other-plugin:
provider: "github"
owner: "octocat"
name: "hello-world"
luckperms:
provider: "jenkins"
api-url: "https://ci.lucko.me/job/LuckPerms"
artifact-prefix: "LuckPerms-Bukkit-"The keys that an entry needs depend on its provider:
| Provider | The keys it needs |
|---|---|
jenkins | api-url, artifact-prefix |
spigotmc | resource-id |
modrinth | project-id |
hangar | platform, owner, name |
github | owner, name (or repo) |
geyser | project |
Optional are plugin-name, artifact-prefix, version-pattern, current-version-pattern, prerelease and repo. The version that is installed is read out of the jar of the plugin, so current-version is not a setting.
11.3 Providers
Each provider is an inner class of PluginUpdater that implements a uniform interface:
java
interface ProviderImpl {
String getLatestVersion(PluginUpdateConfig config);
String getDownloadUrl(PluginUpdateConfig config, String version);
String getFileName(PluginUpdateConfig config, String version);
}11.3.1 Jenkins
- HTTP
GET {baseUrl}/job/{jobName}/lastSuccessfulBuild/api/json. - Parses
artifacts[0].fileNameandartifacts[0].relativePath. - Download URL:
{baseUrl}/job/{jobName}/lastSuccessfulBuild/artifact/{relativePath}.
Options:
jenkins-base-url(e.g.https://ci.example.com)jenkins-job-namejenkins-username+jenkins-api-tokenfor basic auth (optional).
11.3.2 SpigotMC
- POST to
https://api.spiget.org/v2/resources/{resourceId}/versions/latestwithUser-Agent: AppelTools/2.0. - Download URL:
https://api.spiget.org/v2/resources/{resourceId}/download. - Reads file size from
Content-Length.
Options:
spigot-resource-id.
11.3.3 Modrinth
- GET
https://api.modrinth.com/v2/project/{id|slug}/version?game_versions=[...]&loaders=[...]. - Filters by
minecraft-versionandloader. - Returns the latest matching version's primary file URL.
Options:
modrinth-project-idormodrinth-slug.minecraft-version.loader("paper", "velocity", "folia", etc.).
11.3.4 Hangar (PaperMC)
- GET
https://hangar.papermc.io/api/v1/projects/{slug}/versions?channel=Release&limit=1. - Returns the latest version's
download.url.
Options:
hangar-project-slug.hangar-channel("Release", "Beta", "Snapshot").hangar-platform("PAPER", "VELOCITY", "WATERFALL").
11.3.5 GitHub
- GET
https://api.github.com/repos/{owner}/{repo}/releases/latest. - Iterates
assets[]to find one matchingasset-pattern(glob). - Download URL is
asset.browser_download_url.
Options:
github-repo(owner/repo).asset-pattern(glob like*-all.jar).
11.3.6 Geyser (MCBE compatibility)
- Same HTTP shape as SpigotMC, but using Geyser's update endpoint.
- Reserved for Geyser plugin update checks.
Options:
geyser-project-name(defaults to "Geyser").
11.4 Download and Replace
java
PluginUpdater.downloadAndReplace(info, pluginDir)
.thenAccept(v -> logger.info("Updated " + info.id()));Steps:
- Download to
{pluginDir}/{fileName}.tmp. - Validate ZIP magic
0x50 0x4B(i.e. file starts withPK\x03\x04). If not a valid JAR, abort and delete.tmp. - Delete the old file
{pluginDir}/{oldFileName}(the plugin name is detected by listing*.jarinpluginDir). - If the provider is SpigotMC, the downloaded file is renamed to match the existing filename (Spigot always returns the same name). For all other providers, the new filename is kept.
- Rename
.tmp→ final.
The download is done with java.net.http.HttpClient (no external dependency). For Modrinth and Hangar, an Authorization header is set if a token is in config.
11.5 Commands
/atp updater list
Lists all configured plugins with their current and latest versions.
/atp updater get <plugin>
Shows current vs latest for a single plugin.
/atp updater update <plugin>
Downloads and replaces. Requires Permissions.Command.Admin.UPDATER.
The /atv versions on Velocity expose the same surface.
11.6 Reliability
- HTTP timeouts: 10s connect, 30s read.
- Failures return a
PluginUpdateExceptionwith the underlying cause.
11.7 Note on Restart
After downloadAndReplace, the plugin is not auto-reloaded. The user is informed to restart the proxy or paper node at their convenience. (For Paper, the bootstrap detects missing listeners at startup; for Velocity, the proxy must be restarted.)