Compare commits

..

No commits in common. "v1.1.0" and "main" have entirely different histories.
v1.1.0 ... main

3 changed files with 128 additions and 23 deletions

View file

@ -1,6 +1,7 @@
# 文派统一插件发布 CI Workflow
# 触发push tag v*
# 运行环境forgejo-ci-php:latest (Alpine + php-cli + git + rsync + zip + node)
# 基于 ci-workflows/wp-release.yml 2026-02-18 版本
name: Release Plugin

on:
@ -17,17 +18,18 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Verify tools
shell: bash
run: |
set -euo pipefail
php -v | head -1
php -v | head -1 || true
git --version
rsync --version | head -1
zip --version | head -2
rsync --version | head -1 || true
zip --version | head -2 || true
jq --version
curl --version | head -1
curl --version | head -1 || true

- name: Extract version from tag
id: version
@ -74,6 +76,58 @@ jobs:
fi
echo "Version consistency check passed: $VERSION"

- name: Generate Changelog
shell: bash
run: |
set -euo pipefail
TAG="${GITHUB_REF#refs/tags/}"

PREV_TAG=$(git tag --sort=-version:refname | grep -E '^v' | grep -v "^${TAG}$" | head -1)

if [ -n "$PREV_TAG" ]; then
echo "Changelog: ${PREV_TAG}..${TAG}"
COMMITS=$(git log "${PREV_TAG}..${TAG}" --no-merges --pretty=format:"%s (%h)" 2>/dev/null || true)
else
echo "Changelog: first release, using all commits"
COMMITS=$(git log --no-merges --pretty=format:"%s (%h)" 2>/dev/null || true)
fi

if [ -z "$COMMITS" ]; then
: > /tmp/changelog.md
echo "No commits found for changelog"
exit 0
fi

FEAT="" FIX="" OTHER=""
while IFS= read -r line; do
case "$line" in
feat:*|feat\(*) FEAT="${FEAT}\n- ${line}" ;;
fix:*|fix\(*) FIX="${FIX}\n- ${line}" ;;
*) OTHER="${OTHER}\n- ${line}" ;;
esac
done <<< "$COMMITS"

CHANGELOG=""
HAS_CATEGORIES=false
if [ -n "$FEAT" ]; then
CHANGELOG="${CHANGELOG}#### New Features${FEAT}\n\n"
HAS_CATEGORIES=true
fi
if [ -n "$FIX" ]; then
CHANGELOG="${CHANGELOG}#### Bug Fixes${FIX}\n\n"
HAS_CATEGORIES=true
fi
if [ -n "$OTHER" ]; then
if [ "$HAS_CATEGORIES" = true ]; then
CHANGELOG="${CHANGELOG}#### Other Changes${OTHER}\n\n"
else
CHANGELOG="${OTHER#\\n}\n\n"
fi
fi

printf '%b' "$CHANGELOG" > /tmp/changelog.md
echo "Changelog generated ($(echo "$COMMITS" | wc -l) commits)"

- name: PHP Lint
shell: bash
run: |
@ -113,8 +167,13 @@ jobs:
--exclude=".gitattributes" \
--exclude=".editorconfig" \
--exclude=".env*" \
--exclude=".agent" \
--exclude=".vscode" \
--exclude="node_modules" \
--exclude="vendor" \
--exclude="tests" \
--exclude="docs" \
--exclude="lib" \
--exclude="phpunit.xml*" \
--exclude="phpcs.xml*" \
--exclude="phpstan.neon*" \
@ -173,7 +232,23 @@ jobs:
SHA256="${{ steps.checksum.outputs.sha256 }}"
API_URL="${GITHUB_SERVER_URL%/}/api/v1/repos/${GITHUB_REPOSITORY}"
AUTH_HEADER="Authorization: token ${AUTH_TOKEN}"
printf -v RELEASE_NOTES '## %s %s\n\n### Checksums\n\n| File | SHA-256 |\n|------|---------|\n| %s | %s |\n' "$SLUG" "$TAG" "$ZIP_NAME" "$SHA256"

{
echo "## ${SLUG} ${TAG}"
echo ""
CHANGELOG_FILE="/tmp/changelog.md"
if [ -f "$CHANGELOG_FILE" ] && [ -s "$CHANGELOG_FILE" ]; then
echo "### What's Changed"
echo ""
cat "$CHANGELOG_FILE"
fi
echo "### Checksums"
echo ""
echo "| File | SHA-256 |"
echo "|------|---------|"
echo "| ${ZIP_NAME} | ${SHA256} |"
} > /tmp/release-notes.md
RELEASE_NOTES=$(cat /tmp/release-notes.md)

echo ">>> Resolving release ${TAG}"
STATUS=$(curl -sS -o /tmp/release.json -w "%{http_code}" \
@ -279,7 +354,6 @@ jobs:
chmod 600 "$KEY_PATH"
ssh-keyscan -t rsa,ecdsa,ed25519 -p "$DEPLOY_PORT" -H "$DEPLOY_HOST" >> "$HOME/.ssh/known_hosts" 2>/dev/null || true

# Run only for this plugin to reduce release-time impact.
if [[ "$DEPLOY_COMMAND_MODE" == "runner" ]]; then
DEPLOY_COMPOSER_SCRIPT="${DEPLOY_COMPOSER_SCRIPT:-/usr/local/sbin/wp-post-release-composer-runner}"
ssh -i "$KEY_PATH" -p "$DEPLOY_PORT" -o BatchMode=yes -o StrictHostKeyChecking=yes "${DEPLOY_USER}@${DEPLOY_HOST}" \

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
vendor/
node_modules/
.env
*.log
.DS_Store

View file

@ -31,7 +31,7 @@ class WenPai_Updater {
*
* @var string
*/
const VERSION = '1.0.0';
const VERSION = '1.1.0';

/**
* 云桥 API 地址。
@ -168,24 +168,50 @@ class WenPai_Updater {

$response = $this->api_request( "plugins/{$this->slug}/info" );

if ( is_wp_error( $response ) ) {
if ( ! is_wp_error( $response ) && ! isset( $response['error'] ) && ! empty( $response['name'] ) ) {
$info = new stdClass();
$info->name = $response['name'];
$info->slug = $response['slug'] ?? $this->slug;
$info->version = $response['version'] ?? '';
$info->author = $response['author'] ?? '';
$info->homepage = $response['homepage'] ?? '';
$info->download_link = $response['download_link'] ?? '';
$info->requires = $response['requires'] ?? '';
$info->tested = $response['tested'] ?? '';
$info->requires_php = $response['requires_php'] ?? '';
$info->last_updated = $response['last_updated'] ?? '';
$info->icons = $response['icons'] ?? [];
$info->banners = $response['banners'] ?? [];
$info->sections = $response['sections'] ?? [];
$info->external = true;

return $info;
}

// API 不可用或插件未注册时,用本地插件头信息兜底
$plugin_path = WP_PLUGIN_DIR . '/' . $this->plugin_file;
if ( ! file_exists( $plugin_path ) ) {
return $result;
}

$info = new stdClass();
$info->name = $response['name'] ?? '';
$info->slug = $response['slug'] ?? $this->slug;
$info->version = $response['version'] ?? '';
$info->author = $response['author'] ?? '';
$info->homepage = $response['homepage'] ?? '';
$info->download_link = $response['download_link'] ?? '';
$info->requires = $response['requires'] ?? '';
$info->tested = $response['tested'] ?? '';
$info->requires_php = $response['requires_php'] ?? '';
$info->last_updated = $response['last_updated'] ?? '';
$info->icons = $response['icons'] ?? [];
$info->banners = $response['banners'] ?? [];
$info->sections = $response['sections'] ?? [];
if ( ! function_exists( 'get_plugin_data' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}

$plugin_data = get_plugin_data( $plugin_path );

$info = new stdClass();
$info->name = $plugin_data['Name'] ?? $this->slug;
$info->slug = $this->slug;
$info->version = $this->version;
$info->author = $plugin_data['AuthorName'] ?? '';
$info->homepage = $plugin_data['PluginURI'] ?? '';
$info->requires = $plugin_data['RequiresWP'] ?? '';
$info->requires_php = $plugin_data['RequiresPHP'] ?? '';
$info->sections = [
'description' => $plugin_data['Description'] ?? '',
];
$info->external = true;

return $info;
}