From 02b03080584a09cc313362fb90a365c277ab4dce Mon Sep 17 00:00:00 2001 From: magdev Date: Thu, 29 Jan 2026 18:49:29 +0100 Subject: [PATCH] Add Gitea CI/CD release pipeline - Create automated release workflow triggered on version tags (v*) - Validates plugin version matches tag version - Installs production dependencies via Composer - Compiles translation files (.po to .mo) - Builds release package with proper exclusions - Generates SHA256 checksum - Publishes release to Gitea with changelog notes - Document automated release process in README Co-Authored-By: Claude Opus 4.5 --- .gitea/workflows/release.yml | 218 +++++++++++++++++++++++++++++++++++ README.md | 11 ++ 2 files changed, 229 insertions(+) create mode 100644 .gitea/workflows/release.yml diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 0000000..a194375 --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,218 @@ +name: Create Release Package + +on: + push: + tags: + - 'v*' + +jobs: + build-release: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + extensions: mbstring, xml, zip, intl, gettext + tools: composer:v2 + + - name: Get version from tag + id: version + run: | + VERSION=${GITHUB_REF_NAME#v} + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Building version: $VERSION" + + - name: Validate composer.json + run: composer validate --strict + + - name: Configure Composer for private repository + env: + GITEA_TOKEN: ${{ secrets.SRC_GITEA_TOKEN }} + run: | + composer config --global http-basic.src.bundespruefstelle.ch token "${GITEA_TOKEN}" + + - name: Install Composer dependencies (production) + run: | + composer config platform.php 8.3.0 + composer install --no-dev --optimize-autoloader --no-interaction + + - name: Install gettext + run: apt-get update && apt-get install -y gettext + + - name: Compile translations + run: | + for po in languages/*.po; do + if [ -f "$po" ]; then + mo="${po%.po}.mo" + echo "Compiling $po to $mo" + msgfmt -o "$mo" "$po" + fi + done + + - name: Verify plugin version matches tag + run: | + PLUGIN_VERSION=$(grep -oP "Version:\s*\K[0-9]+\.[0-9]+\.[0-9]+" wc-tier-and-package-prices.php | head -1) + TAG_VERSION=${{ steps.version.outputs.version }} + if [ "$PLUGIN_VERSION" != "$TAG_VERSION" ]; then + echo "Error: Plugin version ($PLUGIN_VERSION) does not match tag version ($TAG_VERSION)" + exit 1 + fi + echo "Version verified: $PLUGIN_VERSION" + + - name: Create release directory + run: mkdir -p releases + + - name: Build release package + run: | + VERSION=${{ steps.version.outputs.version }} + PLUGIN_NAME="wc-tier-and-package-prices" + RELEASE_FILE="releases/${PLUGIN_NAME}-${VERSION}.zip" + + cd .. + zip -r "${PLUGIN_NAME}/${RELEASE_FILE}" "${PLUGIN_NAME}" \ + -x "${PLUGIN_NAME}/.git/*" \ + -x "${PLUGIN_NAME}/.gitea/*" \ + -x "${PLUGIN_NAME}/.github/*" \ + -x "${PLUGIN_NAME}/.vscode/*" \ + -x "${PLUGIN_NAME}/.idea/*" \ + -x "${PLUGIN_NAME}/.claude/*" \ + -x "${PLUGIN_NAME}/CLAUDE.md" \ + -x "${PLUGIN_NAME}/wordpress" \ + -x "${PLUGIN_NAME}/wordpress/*" \ + -x "${PLUGIN_NAME}/core" \ + -x "${PLUGIN_NAME}/core/*" \ + -x "${PLUGIN_NAME}/wp-core" \ + -x "${PLUGIN_NAME}/wp-core/*" \ + -x "${PLUGIN_NAME}/releases/*" \ + -x "${PLUGIN_NAME}/composer.lock" \ + -x "${PLUGIN_NAME}/*.log" \ + -x "${PLUGIN_NAME}/logs/*" \ + -x "${PLUGIN_NAME}/.gitignore" \ + -x "${PLUGIN_NAME}/.editorconfig" \ + -x "${PLUGIN_NAME}/phpcs.xml*" \ + -x "${PLUGIN_NAME}/phpunit.xml*" \ + -x "${PLUGIN_NAME}/tests/*" \ + -x "${PLUGIN_NAME}/templates/cache/*" \ + -x "${PLUGIN_NAME}/notes.*" \ + -x "${PLUGIN_NAME}/*.po~" \ + -x "${PLUGIN_NAME}/*.bak" \ + -x "${PLUGIN_NAME}/vendor/*/.git/*" \ + -x "${PLUGIN_NAME}/vendor/*/CLAUDE.md" \ + -x "*.DS_Store" \ + -x "*Thumbs.db" + + cd "${PLUGIN_NAME}" + echo "Created: ${RELEASE_FILE}" + ls -lh "${RELEASE_FILE}" + + - name: Generate checksums + run: | + VERSION=${{ steps.version.outputs.version }} + PLUGIN_NAME="wc-tier-and-package-prices" + RELEASE_FILE="releases/${PLUGIN_NAME}-${VERSION}.zip" + + cd releases + sha256sum "${PLUGIN_NAME}-${VERSION}.zip" > "${PLUGIN_NAME}-${VERSION}.zip.sha256" + echo "SHA256:" + cat "${PLUGIN_NAME}-${VERSION}.zip.sha256" + + - name: Verify package structure + run: | + set +o pipefail + VERSION=${{ steps.version.outputs.version }} + PLUGIN_NAME="wc-tier-and-package-prices" + + echo "Package contents (first 50 entries):" + unzip -l "releases/${PLUGIN_NAME}-${VERSION}.zip" | head -50 || true + + # Verify main plugin file exists + if unzip -l "releases/${PLUGIN_NAME}-${VERSION}.zip" | grep -q "${PLUGIN_NAME}/${PLUGIN_NAME}.php"; then + echo "✓ Main plugin file at correct location" + else + echo "✗ Error: Main plugin file not found at ${PLUGIN_NAME}/${PLUGIN_NAME}.php" + exit 1 + fi + + # Verify vendor directory included + if unzip -l "releases/${PLUGIN_NAME}-${VERSION}.zip" | grep -q "${PLUGIN_NAME}/vendor/"; then + echo "✓ Vendor directory included" + else + echo "✗ Error: Vendor directory not found" + exit 1 + fi + + # Verify excluded files are not present + if unzip -l "releases/${PLUGIN_NAME}-${VERSION}.zip" | grep -qE "CLAUDE\.md|\.claude/|\.git/|wordpress/"; then + echo "✗ Error: Excluded files found in package" + unzip -l "releases/${PLUGIN_NAME}-${VERSION}.zip" | grep -E "CLAUDE\.md|\.claude/|\.git/|wordpress/" + exit 1 + else + echo "✓ No excluded files in package" + fi + + - name: Extract changelog for release notes + id: changelog + run: | + VERSION=${{ steps.version.outputs.version }} + + # Extract release notes from CHANGELOG.md + NOTES=$(sed -n "/^## \[${VERSION}\]/,/^## \[/p" CHANGELOG.md | sed '$ d' | tail -n +2) + if [ -z "$NOTES" ]; then + NOTES="Release version ${VERSION}" + fi + + echo "$NOTES" > release_notes.txt + echo "Release notes extracted" + + - name: Create Gitea Release + env: + GITEA_TOKEN: ${{ secrets.SRC_GITEA_TOKEN }} + run: | + VERSION=${{ steps.version.outputs.version }} + TAG_NAME=${{ github.ref_name }} + PLUGIN_NAME="wc-tier-and-package-prices" + + # Check if this is a prerelease (contains hyphen like v1.0.0-beta) + PRERELEASE="false" + if [[ "$TAG_NAME" == *-* ]]; then + PRERELEASE="true" + fi + + BODY=$(cat release_notes.txt) + + # Create release via Gitea API + RELEASE_RESPONSE=$(curl -s -X POST \ + -H "Authorization: token ${GITEA_TOKEN}" \ + -H "Content-Type: application/json" \ + -d "{\"tag_name\": \"${TAG_NAME}\", \"name\": \"Release ${VERSION}\", \"body\": $(echo "$BODY" | jq -Rs .), \"draft\": false, \"prerelease\": ${PRERELEASE}}" \ + "${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/releases") + + RELEASE_ID=$(echo "$RELEASE_RESPONSE" | jq -r '.id') + + if [ "$RELEASE_ID" == "null" ] || [ -z "$RELEASE_ID" ]; then + echo "Failed to create release:" + echo "$RELEASE_RESPONSE" + exit 1 + fi + + echo "Created release ID: $RELEASE_ID" + + # Upload release assets + for file in "releases/${PLUGIN_NAME}-${VERSION}.zip" "releases/${PLUGIN_NAME}-${VERSION}.zip.sha256"; do + if [ -f "$file" ]; then + FILENAME=$(basename "$file") + echo "Uploading $FILENAME..." + curl -s -X POST \ + -H "Authorization: token ${GITEA_TOKEN}" \ + -H "Content-Type: application/octet-stream" \ + --data-binary "@$file" \ + "${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}/assets?name=${FILENAME}" + echo "Uploaded $FILENAME" + fi + done + + echo "Release created successfully: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/tag/${TAG_NAME}" diff --git a/README.md b/README.md index 819b48e..c0478f5 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,17 @@ A powerful WooCommerce plugin that adds tier pricing and package pricing functio 2. Activate the plugin through the 'Plugins' menu in WordPress 3. Make sure WooCommerce is installed and activated +### Automated Releases + +This project uses a Gitea CI/CD pipeline for automated releases. When a version tag (e.g., `v1.3.2`) is pushed: + +1. The pipeline validates the plugin version matches the tag +2. Composer dependencies are installed (production only) +3. Translation files are compiled +4. A release package is created with proper exclusions +5. SHA256 checksum is generated +6. Release is published to Gitea with changelog notes + ## Configuration ### Global Settings