mcpField
M
minecraft-ci-release

minecraft-ci-release

github.com/jahrome907云与 DevOps192139 次安装2 周前更新
代码仓库

关于 minecraft-ci-release

面向 Minecraft 模组和 Paper 插件项目的 CI/CD 与发布管理技能,提供工作流、版本和发布流程指导。内容涵盖 GitHub Release、构建检查、依赖更新及安全处理密钥,并区分不同 Minecraft 版本的 Java 要求。

主要功能

  1. 01CI 构建与测试工作流
  2. 02GitHub Release 配置
  3. 03版本标签与制品校验
  4. 04发布密钥安全处理
  5. 05工作流片段验证

适用场景

  1. 01为 Fabric 和 NeoForge 模组设置构建流程
  2. 02为 Paper 插件配置 CI
  3. 03检查版本号与 Git 标签是否匹配
  4. 04发布前验证工作流片段

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jahrome907/minecraft-agent-skills --skill minecraft-ci-release

安装后在 Claude Code 中输入/minecraft-ci-release确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
publishing-gradle.md
scripts/
validate-workflow-snippets.sh
scripts/vendor/
js-yaml.min.cjs
LICENSE.js-yaml

详细介绍

Minecraft CI / Release 技能

路由边界

  • Use when:任务涉及 CI/CD 流水线、制品发布、版本管理或发行管理。
  • Do not use when:任务涉及游戏玩法或插件实现(minecraft-modding、minecraft-plugin-dev 或 minecraft-datapack)。
  • Do not use when:任务涉及服务端运行时操作或基础设施调优(minecraft-server-admin)。

发行设置

保留每个仓库现有的发行目标和审批政策。标签可以构建制品并创建 GitHub Release,而不发布到 Modrinth 或 CurseForge。仅当项目已经使用发布工具,或用户提出要求时,才添加发布工具。切勿将令牌添加到已提交的文件中。

对于 Minecraft 26.x,使用 Java 25,并在工作流标签 和示例中注明。旧版 Minecraft 1.21.x 项目继续使用 Java 21;保留其自身的 加载器和 Gradle 约定,不要机械地更改其版本。

在受保护的工作流中使用不可变的 GitHub Action 修订版本。以下引用于 2026-09-04 根据上游标签验证;有意升级某个 Action 前, 请从上游标签重新获取并确认:

actions/[email protected]             3d3c42e5aac5ba805825da76410c181273ba90b1
actions/[email protected]           dd06d9cba3e5552c54d9f8ea23572deb30010f7c
gradle/actions/[email protected]  9c971963bec38e04b3d30dcc455b5382be2fdbfb
actions/[email protected]      043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
softprops/[email protected]  efb35369e0ad2afab669f228072c1b0d510eae64

版本与标签约定

Minecraft 模组版本格式为:{mod_version}+{mc_version}

1.0.0+26.2  ← mod 1.0.0 for MC 26.2
1.2.3+26.2
2.0.0+26.2

Git 标签使用不带游戏版本后缀的发行版本;如果项目采用该约定,则在制品版本中保留 Minecraft 版本:

mod_version: 1.2.3
project/artifact version: 1.2.3+26.2
tag: v1.2.3

发行工作流必须在构建前验证 v1.2.3 与 mod_version=1.2.3 是否匹配。不要根据标签覆盖 mod_version,因为这样会掩盖不匹配的问题。 Gradle 任务和安全提取更新日志的方法见 发布参考。


核心 CI 工作流(NeoForge + Fabric)

这是 Minecraft 26.x / Java 25 的示例。添加下方测试任务后,显示的检查名称为 Build / Build (fabric)、Build / Build (neoforge) 和 Build / Test。首次拉取请求成功后,将 GitHub 显示的确切名称复制到分支保护设置中;重命名工作流或任务 会更改必需检查的上下文。

.github/workflows/build.yml
name: Build

on:
  push:
    branches: ["main", "develop"]
  pull_request:
    branches: ["main"]

permissions:
  contents: read

jobs:
  build:
    name: Build (${{ matrix.platform }})
    runs-on: ubuntu-latest
    strategy:
      matrix:
        platform: [neoforge, fabric]
      fail-fast: false

    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1

      - name: Set up Java 25
        uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c
        with:
          java-version: "25"
          distribution: "temurin"

      - name: Setup Gradle
        uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb
        with:
          cache-read-only: ${{ github.event_name == 'pull_request' }}

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew

      - name: Build (${{ matrix.platform }})
        run: ./gradlew :${{ matrix.platform }}:build --no-daemon

      - name: Upload artifacts
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
        with:
          name: mod-${{ matrix.platform }}-${{ github.sha }}
          path: ${{ matrix.platform }}/build/libs/*.jar
          if-no-files-found: error

  test:
    name: Test
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
      - name: Set up Java 25
        uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c
        with:
          distribution: temurin
          java-version: "25"
      - name: Set up Gradle
        uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb
      - name: Run tests
        run: ./gradlew test --no-daemon

带标签的 GitHub Release

.github/workflows/release.yml
name: Release

on:
  push:
    tags:
      - "v*"

permissions:
  contents: write      # for creating GitHub releases

jobs:
  release:
    name: Release
    runs-on: ubuntu-latest

    steps:
      - name: Checkout tagged source
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1

      - name: Set up Java 25
        uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c
        with:
          java-version: "25"
          distribution: "temurin"

      - name: Setup Gradle
        uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew

      - name: Validate tag and build
        env:
          MOD_VERSION: ${{ github.ref_name }}
        run: |
          MOD_VERSION="${MOD_VERSION#v}"
          ./gradlew verifyReleaseVersion build --no-daemon \
            -PreleaseModVersion="$MOD_VERSION"

      - name: Select release artifacts
        env:
          RELEASE_TAG: ${{ github.ref_name }}
        run: |
          mkdir -p release-artifacts
          shopt -s nullglob
          select_primary() {
            local loader="$1"; shift
            local matches=( "$@" )
            if (( ${#matches[@]} != 1 )); then
              printf 'Expected one %s primary JAR, found %s: %s\n' \
                "$loader" "${#matches[@]}" "${matches[*]:-none}" >&2
              exit 1
            fi
            cp "${matches[0]}" "release-artifacts/${loader}-${RELEASE_TAG}.jar"
          }
          select_primary fabric fabric/build/libs/*-fabric.jar
          select_primary neoforge neoforge/build/libs/*-neoforge.jar

      - name: Create GitHub Release
        uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64
        with:
          files: |
            release-artifacts/fabric-${{ github.ref_name }}.jar
            release-artifacts/neoforge-${{ github.ref_name }}.jar
          fail_on_unmatched_files: true
          generate_release_notes: true
          prerelease: ${{ contains(github.ref_name, '-alpha') || contains(github.ref_name, '-beta') || contains(github.ref_name, '-rc') }}

此工作流仅创建 GitHub Release。它要求有一个主要 Fabric JAR 和 一个主要 NeoForge JAR,且两者的名称能区分加载器。在项目构建中配置这些分类器;如果命名约定不同,则同时修改两种匹配模式。 选择步骤在匹配结果为零个或多个时会失败,并复制为不同的发行名称,以防意外覆盖或部分发行。只有当目标范围包含特定发布目标时,才在版本验证后添加项目专用的发布工具。


Paper 插件 CI

.github/workflows/build.yml(插件)
name: Build

on:
  push:
    branches: ["main"]
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
      - uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c
        with:
          java-version: "25"
          distribution: "temurin"
      - uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb
      - run: chmod +x gradlew
      - run: ./gradlew build --no-daemon
      - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
        with:
          name: plugin-${{ github.sha }}
          path: build/libs/*.jar
          if-no-files-found: error

  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
      - uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c
        with:
          java-version: "25"
          distribution: "temurin"
      - uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb
      - run: ./gradlew test --no-daemon

发布与更新日志详情

仅当项目发布到 Modrinth 或 CurseForge 时,才阅读发布参考。其中包括当前插件版本、 26.x 的 jar 选择、旧版 Loom 的明确 remapJar 指南、版本验证,以及在缺少预期更新日志标题时会失败的解析器。


gradle.properties 密钥模式

切勿硬编码令牌。请从环境变量中读取:

# gradle.properties (committed)
mod_id=mymod
mod_version=1.0.0
minecraft_version=26.2
modrinth_project_id=AABBCCDD
curseforge_project_id=123456

# DO NOT commit tokens
# Set these as GitHub repo secrets:
# MODRINTH_TOKEN, CURSEFORGE_TOKEN

模组的语义化版本控制

更改版本变更
新功能,无破坏性更改次版本:1.1.0
仅修复缺陷修订版本:1.0.1
API/配置存在破坏性更改主版本:2.0.0
Minecraft 版本更新保持模组版本不变,更改 +26.2 后缀
预发行版1.0.0-beta.1、1.0.0-rc.1

CHANGELOG.md 约定

# Changelog

## [1.1.0] — 2025-06-01
### Added
- New `/kit` command
- PDC-based kill tracker

### Fixed
- Death message not appearing on Paper 26.2

## [1.0.0] — 2025-05-01
### Added
- Initial release

发布参考按 mod_version 提取此部分;如果缺少预期标题,则会清楚地报告失败。


Dependabot 配置

.github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "gradle"
    directory: "/"
    schedule:
      interval: "weekly"
    groups:
      gradle-plugins:
        patterns:
          - "com.gradleup.shadow"
          - "dev.architectury.loom"
          - "com.modrinth.minotaur"
          - "net.darkhax.curseforgegradle"

  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"

构建缓存最佳实践

# In all workflow jobs:
- name: Setup Gradle
  uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb
  with:
    # Read-only cache on PRs, read-write on main
    cache-read-only: ${{ github.event_name == 'pull_request' }}

分支保护 + 必需检查

建议为 main 配置以下 GitHub 分支保护:

  • 要求通过以下观察到的检查:Build / Build (fabric)、Build / Build (neoforge) 和 Build / Test
  • 要求保持线性历史(使用 squash/rebase 合并)
  • 要求提交签名(可选,但建议用于发布工作流)

标签和发布脚本

#!/usr/bin/env bash
# scripts/release.sh <mod-version>
set -euo pipefail

VERSION="${1:?Usage: release.sh <mod-version>}"
REMOTE="${RELEASE_REMOTE:-origin}"
BRANCH="${RELEASE_BRANCH:-main}"
EXPECTED_REMOTE_URL="${RELEASE_REMOTE_URL:?Set RELEASE_REMOTE_URL to the expected push URL}"
git diff --check
[[ -z "$(git status --porcelain=v1 --untracked-files=all)" ]] \
  || { echo "Working tree contains staged, unstaged, or untracked files." >&2; exit 1; }
[[ "$(git branch --show-current)" == "$BRANCH" ]] \
  || { echo "Release must start from branch $BRANCH." >&2; exit 1; }
mapfile -t PUSH_URLS < <(git remote get-url --push --all "$REMOTE")
[[ ${#PUSH_URLS[@]} -eq 1 && "${PUSH_URLS[0]}" == "$EXPECTED_REMOTE_URL" ]] \
  || { echo "Remote $REMOTE must have one expected push URL." >&2; exit 1; }
! git rev-parse --verify --quiet "refs/tags/v${VERSION}" >/dev/null \
  || { echo "Local tag v${VERSION} already exists." >&2; exit 1; }
set +e
git ls-remote --exit-code --tags "$EXPECTED_REMOTE_URL" "refs/tags/v${VERSION}" >/dev/null
REMOTE_TAG_STATUS=$?
set -e
case "$REMOTE_TAG_STATUS" in
  0) echo "Remote tag v${VERSION} already exists." >&2; exit 1 ;;
  2) ;;
  *) echo "Could not verify remote tag v${VERSION}." >&2; exit "$REMOTE_TAG_STATUS" ;;
esac
./gradlew verifyReleaseVersion --no-daemon -PreleaseModVersion="$VERSION"
git tag --annotate "v${VERSION}" --message "Release v${VERSION}"
git push "$REMOTE" "HEAD:refs/heads/${BRANCH}"
git push "$REMOTE" "refs/tags/v${VERSION}"

运行此脚本前,请更新并验证版本/变更日志文件,然后为该发布提交打标签。为目标发布分支和确切的推送 URL 设置 RELEASE_BRANCH、RELEASE_REMOTE 和 RELEASE_REMOTE_URL。未经明确授权,请勿强制推送或重新标记已发布的版本。

工作流片段验证器

从已安装的 minecraft-ci-release 技能目录运行捆绑的验证器:

# Run from the installed skill directory:
./scripts/validate-workflow-snippets.sh --root .

# Strict mode treats warnings as failures:
./scripts/validate-workflow-snippets.sh --root . --strict

此验证器随附且自包含。可从复制的 .agents/、.codex/ 或 .claude/ minecraft-ci-release 技能目录运行,无需依赖仓库根目录下的 node_modules。

它会验证符合工作流格式的 YAML、未解析的占位符、工作流密钥文档,以及固定到完整提交 SHA 的远程 uses: 引用。本地操作(./...)和 Docker 操作(docker://...)有意不纳入 SHA 要求。它只读取此技能的 SKILL.md:不会验证项目的 .github/workflows 文件或 Gradle 任务。正式发布前,请检查项目生成的制品、运行 verifyReleaseVersion,并审查确切的工作流差异和配置的发布目标。


参考资料

评论

支持 Markdown