ci: add plugin build and release pipeline
This commit is contained in:
@@ -0,0 +1,40 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: temurin
|
||||||
|
java-version: 17
|
||||||
|
cache: gradle
|
||||||
|
|
||||||
|
- name: Validate conventional commits
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
run: |
|
||||||
|
npx -y \
|
||||||
|
-p @commitlint/cli \
|
||||||
|
-p @commitlint/config-conventional \
|
||||||
|
commitlint --from "${{ github.event.pull_request.base.sha }}" --to "${{ github.sha }}" \
|
||||||
|
--extends @commitlint/config-conventional
|
||||||
|
|
||||||
|
- name: Build and test
|
||||||
|
run: ./gradlew clean check jar
|
||||||
|
|
||||||
|
- name: Upload development artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: spigot-creeper-fear-${{ github.sha }}
|
||||||
|
path: build/libs/*.jar
|
||||||
|
if-no-files-found: error
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
|
||||||
|
- name: Set up Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: temurin
|
||||||
|
java-version: 17
|
||||||
|
cache: gradle
|
||||||
|
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Build and test before release
|
||||||
|
run: ./gradlew clean check
|
||||||
|
|
||||||
|
- name: Capture previous tag
|
||||||
|
id: previous_tag
|
||||||
|
run: |
|
||||||
|
if git describe --tags --abbrev=0 >/dev/null 2>&1; then
|
||||||
|
echo "value=$(git describe --tags --abbrev=0)" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "value=" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Run semantic-release
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
run: |
|
||||||
|
npx -y \
|
||||||
|
-p semantic-release@24.2.9 \
|
||||||
|
-p @semantic-release/commit-analyzer@13.0.1 \
|
||||||
|
-p @semantic-release/release-notes-generator@14.1.0 \
|
||||||
|
semantic-release \
|
||||||
|
--branches main \
|
||||||
|
--plugins @semantic-release/commit-analyzer,@semantic-release/release-notes-generator
|
||||||
|
|
||||||
|
- name: Capture current tag
|
||||||
|
id: current_tag
|
||||||
|
run: |
|
||||||
|
if git describe --tags --exact-match HEAD >/dev/null 2>&1; then
|
||||||
|
echo "value=$(git describe --tags --exact-match HEAD)" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "value=" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Resolve release
|
||||||
|
id: release
|
||||||
|
env:
|
||||||
|
PREVIOUS_TAG: ${{ steps.previous_tag.outputs.value }}
|
||||||
|
CURRENT_TAG: ${{ steps.current_tag.outputs.value }}
|
||||||
|
run: |
|
||||||
|
if [ -n "$CURRENT_TAG" ] && [ "$CURRENT_TAG" != "$PREVIOUS_TAG" ]; then
|
||||||
|
echo "created=true" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "tag=$CURRENT_TAG" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "version=${CURRENT_TAG#v}" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "created=false" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Build versioned plugin
|
||||||
|
if: steps.release.outputs.created == 'true'
|
||||||
|
env:
|
||||||
|
VERSION: ${{ steps.release.outputs.version }}
|
||||||
|
run: ./gradlew clean jar -PreleaseVersion="$VERSION"
|
||||||
|
|
||||||
|
- name: Upload release workflow artifact
|
||||||
|
if: steps.release.outputs.created == 'true'
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: spigot-creeper-fear-${{ steps.release.outputs.version }}
|
||||||
|
path: build/libs/spigot-creeper-fear-${{ steps.release.outputs.version }}.jar
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
- name: Create Gitea release and upload plugin
|
||||||
|
if: steps.release.outputs.created == 'true'
|
||||||
|
env:
|
||||||
|
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
GITEA_SERVER_URL: ${{ github.server_url }}
|
||||||
|
REPOSITORY: ${{ github.repository }}
|
||||||
|
TAG: ${{ steps.release.outputs.tag }}
|
||||||
|
VERSION: ${{ steps.release.outputs.version }}
|
||||||
|
PREVIOUS_TAG: ${{ steps.previous_tag.outputs.value }}
|
||||||
|
run: |
|
||||||
|
api_url="${GITEA_SERVER_URL}/api/v1"
|
||||||
|
jar="build/libs/spigot-creeper-fear-${VERSION}.jar"
|
||||||
|
export RELEASE_BODY
|
||||||
|
if [ -n "$PREVIOUS_TAG" ]; then
|
||||||
|
RELEASE_BODY=$(git log --pretty='format:- %s (%h)' "${PREVIOUS_TAG}..HEAD")
|
||||||
|
else
|
||||||
|
RELEASE_BODY=$(git log --pretty='format:- %s (%h)' HEAD)
|
||||||
|
fi
|
||||||
|
payload=$(node -e '
|
||||||
|
process.stdout.write(JSON.stringify({
|
||||||
|
tag_name: process.env.TAG,
|
||||||
|
name: process.env.TAG,
|
||||||
|
body: process.env.RELEASE_BODY,
|
||||||
|
draft: false,
|
||||||
|
prerelease: false
|
||||||
|
}));
|
||||||
|
')
|
||||||
|
response=$(curl --fail-with-body --silent --show-error \
|
||||||
|
-X POST \
|
||||||
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
"${api_url}/repos/${REPOSITORY}/releases" \
|
||||||
|
--data "$payload")
|
||||||
|
release_id=$(printf '%s' "$response" | node -e '
|
||||||
|
let input = "";
|
||||||
|
process.stdin.on("data", chunk => input += chunk);
|
||||||
|
process.stdin.on("end", () => {
|
||||||
|
const response = JSON.parse(input);
|
||||||
|
if (!response.id) process.exit(1);
|
||||||
|
process.stdout.write(String(response.id));
|
||||||
|
});
|
||||||
|
')
|
||||||
|
curl --fail-with-body --silent --show-error \
|
||||||
|
-X POST \
|
||||||
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
|
-H "Content-Type: application/octet-stream" \
|
||||||
|
--data-binary "@${jar}" \
|
||||||
|
"${api_url}/repos/${REPOSITORY}/releases/${release_id}/assets?name=spigot-creeper-fear-${VERSION}.jar"
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
# Spigot Creeper Fear
|
||||||
|
|
||||||
|
A Spigot 26.2 plugin that lets players earn six Creeper Aura ranks. Once unlocked, an aura prevents creeper explosions that hit the player from breaking blocks, trading that protection for rank-dependent player damage.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Spigot 26.2
|
||||||
|
- Java 17 or newer
|
||||||
|
|
||||||
|
## Progression
|
||||||
|
|
||||||
|
Players earn one current-tier point when they kill a creeper directly, through a projectile, or through an owned tameable. A self-destructing creeper also awards one point to every player its explosion hits. Each tier defaults to 100 points and resets progress to zero when unlocked.
|
||||||
|
|
||||||
|
| Rank | Creeper damage | Block damage |
|
||||||
|
| --- | ---: | --- |
|
||||||
|
| Locked | 1× | Normal |
|
||||||
|
| I | 3× | Prevented |
|
||||||
|
| II | 2× | Prevented |
|
||||||
|
| III | 1.5× | Prevented |
|
||||||
|
| IV | 1× | Prevented |
|
||||||
|
| V | 0.5× | Prevented |
|
||||||
|
| VI | Cancelled | Prevented |
|
||||||
|
|
||||||
|
Progress is stored by player UUID in `plugins/CreeperFear/player-progress.sqlite3`. Database work runs away from the server thread.
|
||||||
|
|
||||||
|
After each point, a temporary boss bar shows current-tier progress. Unlocking a rank displays a full-screen title. Rank VI players no longer receive a progress bar.
|
||||||
|
|
||||||
|
## Build and install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew clean check jar
|
||||||
|
cp build/libs/spigot-creeper-fear-0.1.0-SNAPSHOT.jar /path/to/server/plugins/
|
||||||
|
```
|
||||||
|
|
||||||
|
Restart the server after copying the JAR. The plugin creates its configuration and SQLite database under `plugins/CreeperFear/`.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
| Command | Description | Permission |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `/creeperaura progress` | Show personal progress | `creeperfear.progress` |
|
||||||
|
| `/creeperaura progress <player>` | Inspect a known online or offline player | `creeperfear.admin.inspect` |
|
||||||
|
| `/creeperaura set <player> <progress>` | Set current-tier progress | `creeperfear.admin.modify` |
|
||||||
|
| `/creeperaura add <player> <amount>` | Adjust current-tier progress | `creeperfear.admin.modify` |
|
||||||
|
| `/creeperaura rank <player> <rank>` | Set rank and reset tier progress | `creeperfear.admin.modify` |
|
||||||
|
| `/creeperaura threshold <rank> <points>` | Persist a rank requirement | `creeperfear.admin.configure` |
|
||||||
|
| `/creeperaura reload` | Reload validated configuration | `creeperfear.admin.configure` |
|
||||||
|
|
||||||
|
The personal progress permission defaults to everyone. Administrative permissions default to server operators. Administrative changes are recorded in the server log.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
progression:
|
||||||
|
requirements:
|
||||||
|
I: 100
|
||||||
|
II: 100
|
||||||
|
III: 100
|
||||||
|
IV: 100
|
||||||
|
V: 100
|
||||||
|
VI: 100
|
||||||
|
|
||||||
|
aura:
|
||||||
|
damage-multipliers:
|
||||||
|
I: 3.0
|
||||||
|
II: 2.0
|
||||||
|
III: 1.5
|
||||||
|
IV: 1.0
|
||||||
|
V: 0.5
|
||||||
|
VI: 0.0
|
||||||
|
|
||||||
|
feedback:
|
||||||
|
progress-bar-seconds: 5
|
||||||
|
rank-up-title: "Creeper Aura %rank%"
|
||||||
|
rank-up-subtitle: "Unlocked!"
|
||||||
|
```
|
||||||
|
|
||||||
|
Requirements must be positive integers. Multipliers must be finite and non-negative. Invalid reloads are rejected while the last valid runtime settings remain active. Requirement changes preserve current rank and tier progress; a subsequent qualifying point can unlock at most one rank.
|
||||||
|
|
||||||
|
## Releases
|
||||||
|
|
||||||
|
Gitea Actions builds and tests every push and pull request and uploads a development JAR. Pull requests also validate conventional commit messages.
|
||||||
|
|
||||||
|
Pushes to `main` run semantic-release:
|
||||||
|
|
||||||
|
- `fix:` creates a patch release;
|
||||||
|
- `feat:` creates a minor release;
|
||||||
|
- a breaking-change footer or `!` creates a major release.
|
||||||
|
|
||||||
|
A successful release attaches a versioned JAR to the corresponding Gitea release. The repository must define a `RELEASE_TOKEN` secret with repository contents write permission.
|
||||||
|
|
||||||
|
For a local versioned artifact:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew clean check jar -PreleaseVersion=1.2.3
|
||||||
|
```
|
||||||
|
|
||||||
|
## Design
|
||||||
|
|
||||||
|
The [OKF design bundle](design/index.md) contains the architecture and completed user stories.
|
||||||
@@ -14,3 +14,4 @@ This bundle documents a Spigot plugin in which players earn Creeper Aura ranks b
|
|||||||
- [User stories](user-stories/index.md)
|
- [User stories](user-stories/index.md)
|
||||||
- [Plugin architecture](architecture.md)
|
- [Plugin architecture](architecture.md)
|
||||||
- [Design log](log.md)
|
- [Design log](log.md)
|
||||||
|
- [Project README](../README.md)
|
||||||
|
|||||||
@@ -20,3 +20,4 @@ description: Chronological record of material changes to the Spigot Creeper Fear
|
|||||||
- Completed US-004 with an asynchronous self-service progress command, ordinary-player permission, completion output, and command metadata.
|
- Completed US-004 with an asynchronous self-service progress command, ordinary-player permission, completion output, and command metadata.
|
||||||
- Completed US-005 with UUID-backed offline inspection, atomic progress and rank administration, separate permissions, online-state refresh, and audit logging.
|
- Completed US-005 with UUID-backed offline inspection, atomic progress and rank administration, separate permissions, online-state refresh, and audit logging.
|
||||||
- Completed US-006 with validated per-rank requirements and multipliers, configurable feedback, persistent threshold administration, and safe reload behavior.
|
- Completed US-006 with validated per-rank requirements and multipliers, configurable feedback, persistent threshold administration, and safe reload behavior.
|
||||||
|
- Completed US-007 with Java 17/Spigot 26.2 Gradle builds, project documentation, Gitea CI, conventional-commit checks, semantic versioning, and release artifact publication.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
type: User Story
|
type: User Story
|
||||||
title: "US-007: Build and release the plugin"
|
title: "US-007: Build and release the plugin"
|
||||||
description: Give maintainers repeatable Java builds, automated verification, and versioned Gitea releases.
|
description: Give maintainers repeatable Java builds, automated verification, and versioned Gitea releases.
|
||||||
status: backlog
|
status: done
|
||||||
---
|
---
|
||||||
|
|
||||||
# US-007: Build and release the plugin
|
# US-007: Build and release the plugin
|
||||||
@@ -11,14 +11,14 @@ As a **plugin maintainer**, I want automated builds and releases so that tested,
|
|||||||
|
|
||||||
## Acceptance criteria
|
## Acceptance criteria
|
||||||
|
|
||||||
- [ ] The Gradle project compiles with Java 17 against Spigot API 26.2.
|
- [x] The Gradle project compiles with Java 17 against Spigot API 26.2.
|
||||||
- [ ] Automated tests run as part of the Gradle `check` lifecycle.
|
- [x] Automated tests run as part of the Gradle `check` lifecycle.
|
||||||
- [ ] Pushes and pull requests build and test the plugin in Gitea Actions.
|
- [x] Pushes and pull requests build and test the plugin in Gitea Actions.
|
||||||
- [ ] Pull requests validate conventional commit messages.
|
- [x] Pull requests validate conventional commit messages.
|
||||||
- [ ] CI stores a development JAR as a workflow artifact.
|
- [x] CI stores a development JAR as a workflow artifact.
|
||||||
- [ ] Main-branch conventional commits drive semantic versioning.
|
- [x] Main-branch conventional commits drive semantic versioning.
|
||||||
- [ ] A successful release builds a versioned JAR and attaches it to the corresponding Gitea release.
|
- [x] A successful release builds a versioned JAR and attaches it to the corresponding Gitea release.
|
||||||
- [ ] Build, installation, command, permission, configuration, and release procedures are documented.
|
- [x] Build, installation, command, permission, configuration, and release procedures are documented.
|
||||||
|
|
||||||
## Related
|
## Related
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user