GitHub ActionsでPaperMCプラグインを“自動”公開するまで

家で マインクラフトでPDCAを回す練習ができる環境を整え、その補助として ホワイトボードプラグインを作りました。

正直、PDCAを回すだけなら配布サイトへの公開は不要です。ただ、せっかく作ったなら 他の人にも使ってもらえるように“公開”してみよう、という発想で配布基盤を整備しました。具体的には、GitHub Actions だけで Hangar(PaperMC公式の配布サイト)へ公開できるようにし、以降は README整備やスクリーンショット作成に注力できる体制を作っています。

目次

仕様ツール/バージョン

要素 バージョン 役割
Java (JDK) 21 Paper 1.20.5以降の必須要件。ローカル/CIともにJDK 21で統一。
Gradle (Wrapper) 9.1.0 Javaのビルド自動化ツール。ビルド&公開を自動化。gradle/wrapper/gradle-wrapper.jar を必ずコミット。
Paper 1.21.9 マインクラフトサーバ
GitHub Javaソース保管・Issue管理・リリース管理。
GitHub Actions 自動ビルド&自動公開(push→Snapshot、tag→Release)。HANGAR_API_TOKEN を Secrets に保存。
Hangar PaperMC公式のプラグイン配布サイト。Project作成/Channel(Snapshotに色必須)/API Key発行を行う。
Hangar API key GithubからHangarへプラグインファイルをアップロードに使用。
GithubリポジトリのSecretsにHANGAR_API_TOKENとして登録。

この記事で得られるもの(やることの全体像)

  • Hangarでプロジェクトを作成し、プラグインの公開
  • Hangarで API Key を発行し、GitHub リポジトリの Secrets に保存
  • Github リポジトリに必要ファイルを配置(plugin.yml の正しい場所、Gradle Wrapper JARをコミット)
  • GitHub Actions で
    • main へ push → Snapshot 自動公開
    • v* タグの push → Release 自動公開

Step 1:Hangar 側の初期設定

  1. プロジェクト作成
    名前と slug を決めて作成(後でGradleの id.set(“") に使う)。
  2. チャネル追加(Snapshot)※初期状態でReleaseチャネルはある
    Projects → Channels → New
    Name: Snapshot、Color を必ず選択(色なしだと API 経由で …noColor で失敗)。
  3. API Key 発行
    Account(アカウント設定) → API Keys → Create
    後で GitHub の Secrets に保存(リポに直書きはNG)。

Step 2:GitHub リポの最小構成

whiteboard/
├─ build.gradle.kts
├─ settings.gradle.kts
├─ gradle/wrapper/gradle-wrapper.jar   ← ★JARも必ずコミット
├─ gradle/wrapper/gradle-wrapper,properties
├─ gradlew / gradlew.bat                             ← gradlewは実行属性(+x)
├─ src/main/java/net/nando256/whiteboard/WhiteboardPlugin.java
└─ src/main/resources/plugin.yml                     ← ★ここに置く(直下はNG)

plugin.yml

// build.gradle.kts(抜粋)
import io.papermc.hangarpublishplugin.model.Platforms

plugins {
    java
    id("io.papermc.hangar-publish-plugin") version "0.1.3"
}

group = "net.nando256"
// CIから -Pversion.override が来たらそれを使い、無指定ならローカル用
version = (findProperty("version.override") as String?) ?: "0.0.0-local"

java { toolchain.languageVersion.set(JavaLanguageVersion.of(21)) }

repositories {
    mavenCentral()
    maven("https://repo.papermc.io/repository/maven-public/")
}

dependencies {
    compileOnly("io.papermc.paper:paper-api:1.21.9-R0.1-SNAPSHOT")
}

// plugin.yml の ${version} を Gradle の version で展開
tasks.processResources {
    filesMatching("plugin.yml") { expand("version" to project.version) }
}

hangarPublish {
    publications.register("plugin") {
        id.set("whiteboard")                         // ← Hangarのproject slug
        version.set(project.version.toString())
        channel.set(providers.gradleProperty("hangar.channel").orElse("Snapshot"))
        apiKey.set(System.getenv("HANGAR_API_TOKEN"))
        platforms {
            register(Platforms.PAPER) {
                jar.set(tasks.jar.flatMap { it.archiveFile })
                platformVersions.set(listOf("1.21.9")) // 複数指定も可
            }
        }
    }
}

Step 4:GitHub Actions(push=Snapshot / tag=Release)

.github/workflows/publish.yml

name: Publish to Hangar

on:
  push:
    branches: [ "main" ]
    tags: [ "v*" ]

jobs:
  build-and-publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: JDK 21
        uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: 21

      - name: Gradle
        uses: gradle/actions/setup-gradle@v4

      - name: Determine channel & version
        id: meta
        run: |
          if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
            echo "channel=Release" >> $GITHUB_OUTPUT
            echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
          else
            echo "channel=Snapshot" >> $GITHUB_OUTPUT
            echo "version=0.0.0-${GITHUB_SHA::7}-SNAPSHOT" >> $GITHUB_OUTPUT
          fi

      - name: Build
        run: ./gradlew -q clean build

      - name: Publish to Hangar
        env:
          HANGAR_API_TOKEN: ${{ secrets.HANGAR_API_TOKEN }}
        run: |
          ./gradlew \
            -Phangar.channel=${{ steps.meta.outputs.channel }} \
            -Pversion.override=${{ steps.meta.outputs.version }} \
            publishPluginPublicationToHangar

Secrets 登録

GitHub → Settings → Secrets and variables → Actions → New repository secret

  • Name: HANGAR_API_TOKEN
  • Value: (Hangarで発行したAPI Key)

運用ルール(覚えるのはこれだけ)

  • 開発中:main に push → Snapshot(0.0.0–SNAPSHOT)で自動公開
  • 配布版:git tag v0.1.0 && git push –tags → Release に自動公開
  • 版名重複:Hangarは チャンネルが違っても同名NG。被ったら タグを上げる or 古い版を削除

よくある失敗と即解決

  • version.new.error.channel.noColor
    → Snapshot チャネルをUIで作成し“色を付ける”
  • version.new.error.duplicateNameAndPlatform
    → 同名の版が既に存在。SnapshotはSHA入り、Releaseはタグ由来にして衝突回避
  • Unable to access … gradle-wrapper.jar
    → Wrapper JAR未コミット。.gitignore見直し→git add -f gradle/wrapper/gradle-wrapper.jar
  • ビルド/起動不可
    → Java 21 前提(ローカル&CIを21に固定)、plugin.yml は src/main/resources/ に

まとめ(公開は“手放し”、創作は“全力”で)

PDCAを回すのに 公開は必須ではありません。でも、作ったものを世に出せば、他の人の学びや遊びにも役立つかもしれない。
本稿の手順で、配布は push/tag だけにして、あとはREADMEやスクショ、機能改善に時間を回せます。やることは少ないのに、効果は大きい——そんな公開基盤づくりでした。