Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 0 additions & 160 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ permissions:
actions: read
packages: read
pull-requests: write
issues: write

jobs:
codec:
uses: ./.github/workflows/build_and_test.yml
Expand Down Expand Up @@ -306,161 +304,3 @@ jobs:
with:
module: main
module_id: anvillib

# ── Roseau summary comment ─────────────────────────────────────

roseau-summary:
needs:
- codec-roseau
- collision-roseau
- config-roseau
- font-roseau
- integration-roseau
- moveable-entity-block-roseau
- multiblock-roseau
- network-roseau
- recipe-roseau
- registrum-roseau
- rendering-roseau
- space-select-roseau
- sync-roseau
- util-roseau
- wheel-roseau
- main-roseau
if: always()
runs-on: ubuntu-latest
env:
CODEC_BC: ${{ needs.codec-roseau.outputs.has_bc }}
CODEC_N: ${{ needs.codec-roseau.outputs.bc_count }}
COLLISION_BC: ${{ needs.collision-roseau.outputs.has_bc }}
COLLISION_N: ${{ needs.collision-roseau.outputs.bc_count }}
CONFIG_BC: ${{ needs.config-roseau.outputs.has_bc }}
CONFIG_N: ${{ needs.config-roseau.outputs.bc_count }}
FONT_BC: ${{ needs.font-roseau.outputs.has_bc }}
FONT_N: ${{ needs.font-roseau.outputs.bc_count }}
INTEGRATION_BC: ${{ needs.integration-roseau.outputs.has_bc }}
INTEGRATION_N: ${{ needs.integration-roseau.outputs.bc_count }}
MEB_BC: ${{ needs.moveable-entity-block-roseau.outputs.has_bc }}
MEB_N: ${{ needs.moveable-entity-block-roseau.outputs.bc_count }}
MULTIBLOCK_BC: ${{ needs.multiblock-roseau.outputs.has_bc }}
MULTIBLOCK_N: ${{ needs.multiblock-roseau.outputs.bc_count }}
NETWORK_BC: ${{ needs.network-roseau.outputs.has_bc }}
NETWORK_N: ${{ needs.network-roseau.outputs.bc_count }}
RECIPE_BC: ${{ needs.recipe-roseau.outputs.has_bc }}
RECIPE_N: ${{ needs.recipe-roseau.outputs.bc_count }}
REGISTRUM_BC: ${{ needs.registrum-roseau.outputs.has_bc }}
REGISTRUM_N: ${{ needs.registrum-roseau.outputs.bc_count }}
RENDERING_BC: ${{ needs.rendering-roseau.outputs.has_bc }}
RENDERING_N: ${{ needs.rendering-roseau.outputs.bc_count }}
SPACESELECT_BC: ${{ needs.space-select-roseau.outputs.has_bc }}
SPACESELECT_N: ${{ needs.space-select-roseau.outputs.bc_count }}
SYNC_BC: ${{ needs.sync-roseau.outputs.has_bc }}
SYNC_N: ${{ needs.sync-roseau.outputs.bc_count }}
UTIL_BC: ${{ needs.util-roseau.outputs.has_bc }}
UTIL_N: ${{ needs.util-roseau.outputs.bc_count }}
WHEEL_BC: ${{ needs.wheel-roseau.outputs.has_bc }}
WHEEL_N: ${{ needs.wheel-roseau.outputs.bc_count }}
MAIN_BC: ${{ needs.main-roseau.outputs.has_bc }}
MAIN_N: ${{ needs.main-roseau.outputs.bc_count }}
steps:
- name: Download Roseau reports
uses: actions/download-artifact@v4
with:
pattern: roseau-*
path: roseau-reports

- name: Generate and post PR comment
run: |
row() {
local name=$1 bc=$2 count=$3
if [ -z "$bc" ]; then
echo "| ${name} | ⚪ Skipped | — |"
elif [ "$bc" = "true" ]; then
echo "| ${name} | 🔴 BC detected | ${count} |"
else
echo "| ${name} | ✅ Compatible | 0 |"
fi
}

{
echo "## 🌿 Roseau API Breaking Change Report"
echo ""
echo "| Module | Status | Breaking Changes |"
echo "|--------|--------|-----------------|"
row "codec" "$CODEC_BC" "$CODEC_N"
row "collision" "$COLLISION_BC" "$COLLISION_N"
row "config" "$CONFIG_BC" "$CONFIG_N"
row "font" "$FONT_BC" "$FONT_N"
row "integration" "$INTEGRATION_BC" "$INTEGRATION_N"
row "moveable-entity-block" "$MEB_BC" "$MEB_N"
row "multiblock" "$MULTIBLOCK_BC" "$MULTIBLOCK_N"
row "network" "$NETWORK_BC" "$NETWORK_N"
row "recipe" "$RECIPE_BC" "$RECIPE_N"
row "registrum" "$REGISTRUM_BC" "$REGISTRUM_N"
row "rendering" "$RENDERING_BC" "$RENDERING_N"
row "space-select" "$SPACESELECT_BC" "$SPACESELECT_N"
row "sync" "$SYNC_BC" "$SYNC_N"
row "util" "$UTIL_BC" "$UTIL_N"
row "wheel" "$WHEEL_BC" "$WHEEL_N"
row "main" "$MAIN_BC" "$MAIN_N"
echo ""
} > /tmp/roseau-body.md

# Append breaking change details for each affected module
append_details() {
local mod=$1 bc=$2 count=$3
if [ "$bc" != "true" ]; then return; fi
local csv="roseau-reports/roseau-${mod}/report.csv"
if [ ! -f "$csv" ]; then return; fi
{
echo "### 🔴 ${mod} — ${count} breaking change(s)"
echo ""
while IFS=';' read -r type symbol kind nature location newSymbol binaryBreaking sourceBreaking; do
echo "#### \`${location}\`"
echo '```'
echo "${type}"
echo "${symbol}"
echo "${kind}"
[ "$binaryBreaking" = "true" ] && echo "✗ binary-breaking" || echo "✓ binary-compatible"
[ "$sourceBreaking" = "true" ] && echo "✗ source-breaking" || echo "✓ source-compatible"
echo '```'
echo ""
done < <(tail -n +2 "$csv")
} >> /tmp/roseau-body.md
}

append_details "codec" "$CODEC_BC" "$CODEC_N"
append_details "collision" "$COLLISION_BC" "$COLLISION_N"
append_details "config" "$CONFIG_BC" "$CONFIG_N"
append_details "font" "$FONT_BC" "$FONT_N"
append_details "integration" "$INTEGRATION_BC" "$INTEGRATION_N"
append_details "moveable-entity-block" "$MEB_BC" "$MEB_N"
append_details "multiblock" "$MULTIBLOCK_BC" "$MULTIBLOCK_N"
append_details "network" "$NETWORK_BC" "$NETWORK_N"
append_details "recipe" "$RECIPE_BC" "$RECIPE_N"
append_details "registrum" "$REGISTRUM_BC" "$REGISTRUM_N"
append_details "rendering" "$RENDERING_BC" "$RENDERING_N"
append_details "space-select" "$SPACESELECT_BC" "$SPACESELECT_N"
append_details "sync" "$SYNC_BC" "$SYNC_N"
append_details "util" "$UTIL_BC" "$UTIL_N"
append_details "wheel" "$WHEEL_BC" "$WHEEL_N"
append_details "main" "$MAIN_BC" "$MAIN_N"

echo "> Full CSVs: see the *Artifacts* section of [this workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})." >> /tmp/roseau-body.md

- name: Find existing Roseau comment
id: find-comment
uses: peter-evans/find-comment@v3
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: anvil-craft
body-includes: Roseau API Breaking Change Report

- name: Create or update PR comment
uses: peter-evans/create-or-update-comment@v4
with:
token: ${{ secrets.PAT_TOKEN }}
comment-id: ${{ steps.find-comment.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body-path: /tmp/roseau-body.md
edit-mode: replace
150 changes: 150 additions & 0 deletions .github/workflows/roseau_comment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
name: Roseau PR Comment

on:
workflow_run:
workflows:
- Pull Request Check
types:
- completed

permissions:
contents: read
actions: read
pull-requests: write

jobs:
comment:
if: ${{ github.event.workflow_run.conclusion != 'skipped' }}
runs-on: ubuntu-latest
steps:
- name: Download Roseau reports
uses: actions/download-artifact@v4
with:
pattern: roseau-*
path: roseau-reports
run-id: ${{ github.event.workflow_run.id }}

- name: Find PR number
id: pr
run: |
HEAD_BRANCH="${{ github.event.workflow_run.head_branch }}"
HEAD_SHA="${{ github.event.workflow_run.head_sha }}"
PR_NUMBER=$(gh pr list \
--head "$HEAD_BRANCH" \
--state open \
--json number \
--jq '.[0].number')
if [ -z "$PR_NUMBER" ]; then
PR_NUMBER=$(gh pr list \
--search "$HEAD_SHA" \
--state open \
--json number \
--jq '.[0].number')
fi
if [ -z "$PR_NUMBER" ]; then
echo "::warning::Could not find PR number for branch=$HEAD_BRANCH sha=$HEAD_SHA"
fi
echo "number=$PR_NUMBER" >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Generate report body
run: |
row() {
local name=$1 dir=$2
local csv="${dir}/report.csv"
if [ -f "$csv" ] && [ "$(wc -l < "$csv")" -gt 1 ]; then
local count=$(($(wc -l < "$csv") - 1))
echo "| ${name} | 🔴 BC detected | ${count} |"
elif [ -f "$csv" ]; then
echo "| ${name} | ✅ Compatible | 0 |"
else
echo "| ${name} | ⚪ Skipped | — |"
fi
}

{
echo "## 🌿 Roseau API Breaking Change Report"
echo ""
echo "| Module | Status | Breaking Changes |"
echo "|--------|--------|-----------------|"
row "codec" "roseau-reports/roseau-codec"
row "collision" "roseau-reports/roseau-collision"
row "config" "roseau-reports/roseau-config"
row "font" "roseau-reports/roseau-font"
row "integration" "roseau-reports/roseau-integration"
row "moveable-entity-block" "roseau-reports/roseau-moveable-entity-block"
row "multiblock" "roseau-reports/roseau-multiblock"
row "network" "roseau-reports/roseau-network"
row "recipe" "roseau-reports/roseau-recipe"
row "registrum" "roseau-reports/roseau-registrum"
row "rendering" "roseau-reports/roseau-rendering"
row "space-select" "roseau-reports/roseau-space-select"
row "sync" "roseau-reports/roseau-sync"
row "util" "roseau-reports/roseau-util"
row "wheel" "roseau-reports/roseau-wheel"
row "main" "roseau-reports/roseau-main"
echo ""
} > /tmp/roseau-body.md

append_details() {
local name=$1 dir=$2
local csv="${dir}/report.csv"
if [ ! -f "$csv" ]; then return; fi
local count=$(($(wc -l < "$csv") - 1))
if [ "$count" -le 0 ]; then return; fi
{
echo "### 🔴 ${name} — ${count} breaking change(s)"
echo ""
while IFS=';' read -r type symbol kind nature location newSymbol binaryBreaking sourceBreaking; do
echo "#### \`${location}\`"
echo '```'
echo "${type}"
echo "${symbol}"
echo "${kind}"
[ "$binaryBreaking" = "true" ] && echo "✗ binary-breaking" || echo "✓ binary-compatible"
[ "$sourceBreaking" = "true" ] && echo "✗ source-breaking" || echo "✓ source-compatible"
echo '```'
echo ""
done < <(tail -n +2 "$csv")
} >> /tmp/roseau-body.md
}

append_details "codec" "roseau-reports/roseau-codec"
append_details "collision" "roseau-reports/roseau-collision"
append_details "config" "roseau-reports/roseau-config"
append_details "font" "roseau-reports/roseau-font"
append_details "integration" "roseau-reports/roseau-integration"
append_details "moveable-entity-block" "roseau-reports/roseau-moveable-entity-block"
append_details "multiblock" "roseau-reports/roseau-multiblock"
append_details "network" "roseau-reports/roseau-network"
append_details "recipe" "roseau-reports/roseau-recipe"
append_details "registrum" "roseau-reports/roseau-registrum"
append_details "rendering" "roseau-reports/roseau-rendering"
append_details "space-select" "roseau-reports/roseau-space-select"
append_details "sync" "roseau-reports/roseau-sync"
append_details "util" "roseau-reports/roseau-util"
append_details "wheel" "roseau-reports/roseau-wheel"
append_details "main" "roseau-reports/roseau-main"

echo "> Full CSVs: see the *Artifacts* section of [this workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }})." >> /tmp/roseau-body.md

- name: Find existing Roseau comment
id: find-comment
if: steps.pr.outputs.number != ''
uses: peter-evans/find-comment@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ steps.pr.outputs.number }}
comment-author: anvil-craft
body-includes: Roseau API Breaking Change Report

- name: Create or update PR comment
if: steps.pr.outputs.number != ''
uses: peter-evans/create-or-update-comment@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
comment-id: ${{ steps.find-comment.outputs.comment-id }}
issue-number: ${{ steps.pr.outputs.number }}
body-path: /tmp/roseau-body.md
edit-mode: replace
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

import java.lang.reflect.AccessFlag;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Set;

@Slf4j
Expand All @@ -35,11 +37,17 @@ static <B extends ByteBuf, T extends IPacket> PacketData<B, T> find(Class<T> pac
) {
continue;
}
Class<?> declaringClass = field.getType();
if (declaringClass.isAssignableFrom(CustomPacketPayload.Type.class)) {
Class<?> fieldType = field.getType();
if (CustomPacketPayload.Type.class.isAssignableFrom(fieldType)) {
if (!isMatchingTypeArgument(field.getGenericType(), 0, packetClass)) {
continue;
}
field.setAccessible(true);
type = (CustomPacketPayload.Type<T>) field.get(null);
} else if (declaringClass.isAssignableFrom(StreamCodec.class)) {
} else if (StreamCodec.class.isAssignableFrom(fieldType)) {
if (!isMatchingTypeArgument(field.getGenericType(), 1, packetClass)) {
continue;
}
field.setAccessible(true);
codec = (StreamCodec<B, T>) field.get(null);
}
Expand Down Expand Up @@ -77,4 +85,27 @@ static <B extends ByteBuf, T extends IPacket> PacketData<B, T> find(Class<T> pac
}
return new PacketData<>(type, codec, direction, handler);
}

/**
* 检查字段的参数化类型中,指定索引的类型实参是否与期望的类匹配。
* 如果字段类型不是参数化类型、类型实参不足、或类型不匹配,返回 false。
*/
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private static boolean isMatchingTypeArgument(
Type genericType,
int typeArgIndex,
Class<?> expectedClass
) {
if (!(genericType instanceof ParameterizedType pt)) {
return false;
}
Type[] typeArgs = pt.getActualTypeArguments();
if (typeArgs.length <= typeArgIndex) {
return false;
}
if (!(typeArgs[typeArgIndex] instanceof Class<?> typeArg)) {
return false;
}
return typeArg.isAssignableFrom(expectedClass);
}
}
Loading