Build and Release #9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*.*.*' # Official release tags (e.g., v3.1.1) | |
| - 'v*.*.*-beta*' # Beta releases (e.g., v3.1.1-beta1) | |
| - 'v*.*.*-alpha*' # Alpha releases (e.g., v3.1.1-alpha1) | |
| - 'v*.*.*-rc*' # Release candidates (e.g., v3.1.1-rc1) | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version number to build (e.g., v3.1.1 or v3.1.1-beta1). Tag does not need to exist — this is a dry-run: artifacts are saved in the workflow run only, nothing is published.' | |
| required: true | |
| type: string | |
| concurrency: | |
| group: release-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| validate-and-release: | |
| name: Validate Version and Build Release | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write # Required for creating releases and uploading artifacts | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup NDK | |
| uses: nttld/setup-ndk@v1.4.2 | |
| id: setup-ndk | |
| with: | |
| ndk-version: r27c | |
| link-to-sdk: true | |
| add-to-path: true | |
| - name: Install build tools | |
| run: sudo apt-get update && sudo apt-get install -y ninja-build jq rsync binutils unzip | |
| - name: Set up JDK 17 | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: '17' | |
| distribution: 'temurin' | |
| cache: gradle | |
| - name: Cache NDK and CMake builds | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.android/build-cache | |
| library/.cxx | |
| library/build | |
| key: ${{ runner.os }}-ndk-${{ hashFiles('**/*.gradle*', '**/CMakeLists.txt') }} | |
| restore-keys: | | |
| ${{ runner.os }}-ndk- | |
| - name: Grant execute permission for scripts | |
| run: chmod +x gradlew tasks.sh publish.sh | |
| - name: Extract tag version | |
| id: tag_version | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| INPUT_VERSION: ${{ github.event.inputs.version }} | |
| run: | | |
| # Determine if this is a manual trigger or tag push | |
| if [ "$EVENT_NAME" = "workflow_dispatch" ]; then | |
| # Manual trigger - accept tag name (with or without leading v) | |
| RAW_VERSION="$INPUT_VERSION" | |
| RAW_VERSION="${RAW_VERSION#${RAW_VERSION%%[![:space:]]*}}" | |
| RAW_VERSION="${RAW_VERSION%${RAW_VERSION##*[![:space:]]}}" | |
| if [ -z "$RAW_VERSION" ]; then | |
| echo "❌ Version input cannot be empty" | |
| exit 1 | |
| fi | |
| # Accept either "v3.1.1-beta1" or "3.1.1-beta1" | |
| VERSION="${RAW_VERSION#v}" | |
| TAG_NAME="v$VERSION" | |
| IS_MANUAL="true" | |
| IS_PUBLISH="false" | |
| echo "🔧 Dry-run triggered manually (artifacts only, nothing published)" | |
| else | |
| # Tag push - extract from ref | |
| TAG_NAME="${GITHUB_REF#refs/tags/}" | |
| IS_MANUAL="false" | |
| IS_PUBLISH="true" | |
| fi | |
| # Extract and validate version numbers supporting prerelease tags | |
| # e.g., v3.1.1-beta1 -> base=3.1.1, version=3.1.1-beta1 | |
| if [[ $TAG_NAME =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)(-[a-zA-Z0-9\.]+)?$ ]]; then | |
| BASE_VERSION="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}" | |
| PRERELEASE_SUFFIX="${BASH_REMATCH[4]}" | |
| VERSION="${BASE_VERSION}${PRERELEASE_SUFFIX}" | |
| if [ -n "$PRERELEASE_SUFFIX" ]; then | |
| IS_PRERELEASE="true" | |
| echo "🧪 Prerelease detected: $PRERELEASE_SUFFIX" | |
| else | |
| IS_PRERELEASE="false" | |
| fi | |
| else | |
| echo "❌ Invalid tag format: $TAG_NAME" | |
| echo "Tag must be: v{major}.{minor}.{patch}[-prerelease] (e.g., v3.1.1 or v3.1.1-beta1)" | |
| exit 1 | |
| fi | |
| # Validate base version format | |
| if [[ ! $BASE_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | |
| echo "❌ Invalid base version format: $BASE_VERSION" | |
| echo "Version must be in format: \${major}.\${minor}.\${patch} (e.g., 3.1.1)" | |
| exit 1 | |
| fi | |
| echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "base_version=$BASE_VERSION" >> $GITHUB_OUTPUT | |
| echo "is_manual=$IS_MANUAL" >> $GITHUB_OUTPUT | |
| echo "is_publish=$IS_PUBLISH" >> $GITHUB_OUTPUT | |
| echo "is_prerelease=$IS_PRERELEASE" >> $GITHUB_OUTPUT | |
| echo "✅ Valid version: $VERSION (tag: $TAG_NAME, prerelease: $IS_PRERELEASE, manual: $IS_MANUAL, publish: $IS_PUBLISH)" | |
| - name: Validate tag is on master branch (official releases only) | |
| if: steps.tag_version.outputs.is_prerelease == 'false' && steps.tag_version.outputs.is_manual == 'false' | |
| run: | | |
| TAG_NAME="${{ steps.tag_version.outputs.tag_name }}" | |
| echo "🔍 Validating that $TAG_NAME points to a commit on the master branch..." | |
| # Resolve the commit the tag points to (dereference annotated tags) | |
| if ! TAG_COMMIT=$(git rev-parse "${TAG_NAME}^{commit}" 2>/dev/null); then | |
| echo "❌ Could not resolve tag commit for $TAG_NAME — does the tag exist in this repo?" | |
| exit 1 | |
| fi | |
| echo "Tag commit: $TAG_COMMIT" | |
| # Fetch latest master to ensure our ref is up to date (full fetch, no shallow boundary) | |
| if ! git fetch origin master; then | |
| echo "❌ Failed to fetch origin/master. Cannot validate that $TAG_NAME is on the master branch." | |
| exit 1 | |
| fi | |
| # Check whether TAG_COMMIT is reachable from origin/master | |
| if git merge-base --is-ancestor "$TAG_COMMIT" origin/master; then | |
| echo "✅ $TAG_NAME is on the master branch" | |
| else | |
| echo "❌ $TAG_NAME is NOT on the master branch!" | |
| echo "Official release tags must point to a commit that exists in master." | |
| echo "Tag commit : $TAG_COMMIT" | |
| echo "Please create the tag from the master branch and try again." | |
| exit 1 | |
| fi | |
| - name: Validate version matches project version | |
| run: | | |
| PROJECT_VERSION=$(grep -E 'versionName\s*:' build.gradle | sed -E 's/.*versionName\s*:\s*"([^"]+)".*/\1/') | |
| TAG_VERSION="${{ steps.tag_version.outputs.version }}" | |
| BASE_VERSION="${{ steps.tag_version.outputs.base_version }}" | |
| echo "Project version (build.gradle): $PROJECT_VERSION" | |
| echo "Tag full version: $TAG_VERSION" | |
| echo "Tag base version: $BASE_VERSION" | |
| # For prerelease tags (e.g., v3.1.1-beta1), only the base version (3.1.1) | |
| # needs to match build.gradle. This allows tagging prereleases without | |
| # updating build.gradle every time. | |
| if [ "$PROJECT_VERSION" = "$TAG_VERSION" ]; then | |
| echo "✅ Exact version match: $TAG_VERSION" | |
| elif [ "$PROJECT_VERSION" = "$BASE_VERSION" ] && [ "$TAG_VERSION" != "$BASE_VERSION" ]; then | |
| echo "✅ Base version match for prerelease: build.gradle=$PROJECT_VERSION, tag=$TAG_VERSION" | |
| else | |
| echo "❌ Version mismatch!" | |
| echo "build.gradle versionName ($PROJECT_VERSION) does not match tag version ($TAG_VERSION) or base version ($BASE_VERSION)" | |
| echo "Please ensure build.gradle versionName matches the tag's base version." | |
| exit 1 | |
| fi | |
| - name: Setup local.properties for publishing | |
| run: | | |
| # Create local.properties with necessary configurations | |
| mkdir -p /tmp/maven-repo | |
| cat > local.properties << EOF | |
| usingCMakeCompile=true | |
| usingCMakeCompileDebug=false | |
| deployArtifacts=true | |
| localRepoDir=/tmp/maven-repo | |
| EOF | |
| echo "✅ local.properties configured for publishing" | |
| cat local.properties | |
| - name: Build all artifact variants | |
| id: build_variants | |
| run: | | |
| BUILD_START=$(date +%s) | |
| echo "🔨 Building all 4 artifact variants..." | |
| bash -e ./publish.sh | |
| BUILD_END=$(date +%s) | |
| BUILD_TIME=$((BUILD_END - BUILD_START)) | |
| echo "✅ All artifacts built successfully" | |
| echo "⏱️ Build time: $((BUILD_TIME / 60)) minutes $((BUILD_TIME % 60)) seconds" | |
| echo "📦 Generated artifacts:" | |
| find /tmp/maven-repo -type f \( -name "*.aar" -o -name "*.pom" \) | sort | |
| echo "build_time=$BUILD_TIME" >> $GITHUB_OUTPUT | |
| - name: Build demo APK with video module | |
| run: | | |
| echo "🔨 Building demo APK with video module..." | |
| ./tasks.sh --enable-cmake --release --enable-video-module --enable-16kb-page-size --build | |
| # Find and copy the APK (look specifically for release build output) | |
| APK_PATH=$(find "cgeDemo/build/outputs/apk/release" \( -name "*-release.apk" -o -name "*-release-unsigned.apk" \) | head -1) | |
| if [ -z "$APK_PATH" ]; then | |
| # Fallback: search in build directory | |
| APK_PATH=$(find "cgeDemo/build" -path "*/release/*" -name "*.apk" | head -1) | |
| fi | |
| if [ -z "$APK_PATH" ]; then | |
| echo "❌ APK not found!" | |
| echo "Searched locations:" | |
| find "cgeDemo/build" -name "*.apk" || echo "No APK files found" | |
| exit 1 | |
| fi | |
| mkdir -p /tmp/release-artifacts | |
| cp "$APK_PATH" /tmp/release-artifacts/cgeDemo-${{ steps.tag_version.outputs.version }}.apk | |
| echo "✅ Demo APK built successfully" | |
| ls -lh /tmp/release-artifacts/ | |
| - name: Validate APK size and properties | |
| run: | | |
| echo "🔍 Checking APK size and basic properties..." | |
| APK_FILE=$(ls /tmp/release-artifacts/*.apk | head -1) | |
| APK_SIZE=$(stat -c%s "$APK_FILE" 2>/dev/null || stat -f%z "$APK_FILE") | |
| APK_SIZE_MB=$((APK_SIZE / 1024 / 1024)) | |
| echo "📦 APK size: ${APK_SIZE_MB} MB" | |
| # Warn if APK is unusually large | |
| if [ $APK_SIZE -gt 104857600 ]; then # 100MB | |
| echo "::warning::APK size (${APK_SIZE_MB} MB) exceeds 100MB, consider optimization" | |
| fi | |
| # Warn if APK is unusually small (might indicate build issue) | |
| if [ $APK_SIZE -lt 5242880 ]; then # 5MB | |
| echo "::warning::APK size (${APK_SIZE_MB} MB) is unusually small, please verify" | |
| fi | |
| echo "✅ APK validation passed" | |
| - name: Validate native libs max page size (16KB) | |
| run: | | |
| echo "🔍 Validating native library max page size in APK..." | |
| APK_FILE=$(ls /tmp/release-artifacts/*.apk | head -1) | |
| EXTRACT_DIR="/tmp/apk-native-check" | |
| rm -rf "$EXTRACT_DIR" | |
| mkdir -p "$EXTRACT_DIR" | |
| unzip -q "$APK_FILE" "lib/*.so" -d "$EXTRACT_DIR" | |
| SO_COUNT=$(find "$EXTRACT_DIR/lib" -type f -name "*.so" | wc -l | tr -d ' ') | |
| if [ "$SO_COUNT" -eq 0 ]; then | |
| echo "❌ No native libraries found in APK: $APK_FILE" | |
| exit 1 | |
| fi | |
| while IFS= read -r so_file; do | |
| max_align=0 | |
| while IFS= read -r align_hex; do | |
| align_hex=${align_hex#0x} | |
| if [ -z "$align_hex" ]; then | |
| continue | |
| fi | |
| align_dec=$((16#$align_hex)) | |
| if [ "$align_dec" -gt "$max_align" ]; then | |
| max_align="$align_dec" | |
| fi | |
| done < <(readelf -l "$so_file" | awk '/LOAD/ {print $NF}') | |
| if [ "$max_align" -lt 16384 ]; then | |
| echo "❌ Invalid max page size in $(basename "$so_file"): ${max_align} bytes (< 16384)" | |
| readelf -l "$so_file" | |
| exit 1 | |
| fi | |
| printf " ✓ %s max LOAD align: %d bytes\n" "$(basename "$so_file")" "$max_align" | |
| done < <(find "$EXTRACT_DIR/lib" -type f -name "*.so" | sort) | |
| echo "✅ Native library max page size validation passed" | |
| - name: Package AAR artifacts | |
| run: | | |
| echo "📦 Packaging AAR artifacts..." | |
| VERSION="${{ steps.tag_version.outputs.version }}" | |
| MAVEN_REPO="/tmp/maven-repo" | |
| ARTIFACTS_DIR="/tmp/release-artifacts" | |
| # Find and copy all AAR files from the maven repository | |
| # Expected structure: /tmp/maven-repo/org/wysaid/gpuimage-plus/{version}/gpuimage-plus-{version}.aar | |
| while IFS= read -r aar_file; do | |
| if [ -n "$aar_file" ]; then | |
| filename=$(basename "$aar_file") | |
| cp "$aar_file" "$ARTIFACTS_DIR/$filename" | |
| echo " ✓ Packaged: $filename" | |
| fi | |
| done < <(find "$MAVEN_REPO/org/wysaid/gpuimage-plus" -name "*.aar") | |
| # Validate that we have exactly 4 AAR files | |
| AAR_COUNT=$(find "$ARTIFACTS_DIR" -name "*.aar" | wc -l) | |
| if [ "$AAR_COUNT" -ne 4 ]; then | |
| echo "❌ Expected 4 AAR files but found $AAR_COUNT" | |
| exit 1 | |
| fi | |
| echo "✅ All AAR artifacts packaged ($AAR_COUNT files)" | |
| echo "📦 Final artifacts:" | |
| ls -lh "$ARTIFACTS_DIR/" | |
| - name: Generate artifact checksums | |
| run: | | |
| echo "🔐 Generating SHA256 checksums for all artifacts..." | |
| cd /tmp/release-artifacts | |
| # Generate checksums for all files | |
| sha256sum *.apk *.aar > SHA256SUMS.txt 2>/dev/null || shasum -a 256 *.apk *.aar > SHA256SUMS.txt | |
| echo "✅ Checksums generated:" | |
| cat SHA256SUMS.txt | |
| # Also create individual checksum files for convenience | |
| for file in *.apk *.aar; do | |
| if [ -f "$file" ]; then | |
| sha256sum "$file" > "${file}.sha256" 2>/dev/null || shasum -a 256 "$file" > "${file}.sha256" | |
| fi | |
| done | |
| echo "✅ Individual checksum files created" | |
| - name: Sync artifacts to maven repo | |
| if: steps.tag_version.outputs.is_publish == 'true' | |
| id: sync_maven_repo | |
| env: | |
| ARTIFACT_REPO_TOKEN: ${{ secrets.ARTIFACT_REPO_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| VERSION="${{ steps.tag_version.outputs.version }}" | |
| TAG_NAME="${{ steps.tag_version.outputs.tag_name }}" | |
| if [[ -z "${ARTIFACT_REPO_TOKEN:-}" ]]; then | |
| echo "::error::ARTIFACT_REPO_TOKEN is not configured. This secret is required to publish artifacts to the Maven repository." | |
| echo "Please add ARTIFACT_REPO_TOKEN to the repository secrets: Settings → Secrets and variables → Actions → New repository secret" | |
| exit 1 | |
| fi | |
| ARTIFACT_REPO="wysaid/android-gpuimage-plus-maven" | |
| WORKDIR="/tmp/maven-repo-target" | |
| SOURCE_REPO="/tmp/maven-repo" | |
| echo "🔄 Cloning artifact repo..." | |
| git clone --depth 1 "https://${ARTIFACT_REPO_TOKEN}@github.com/${ARTIFACT_REPO}.git" "$WORKDIR" | |
| echo "🚚 Syncing generated Maven artifacts..." | |
| mkdir -p "$WORKDIR/org/wysaid/gpuimage-plus" | |
| if [ ! -d "${SOURCE_REPO}/org/wysaid/gpuimage-plus" ]; then | |
| echo "❌ Source artifacts not found: ${SOURCE_REPO}/org/wysaid/gpuimage-plus" | |
| exit 1 | |
| fi | |
| # Additive sync: keep previously published versions in artifact repo. | |
| rsync -av "${SOURCE_REPO}/org/wysaid/gpuimage-plus/" "$WORKDIR/org/wysaid/gpuimage-plus/" | |
| echo "🧭 Regenerating index pages" | |
| pushd "$WORKDIR" | |
| chmod +x genSites.sh | |
| ./genSites.sh | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git add org/wysaid/gpuimage-plus || true | |
| echo "artifact_commit_url=" >> $GITHUB_OUTPUT | |
| if git diff --cached --quiet; then | |
| echo "ℹ️ No changes to publish; skipping commit." | |
| popd | |
| exit 0 | |
| fi | |
| git commit -m "Publish artifacts ${TAG_NAME}" | |
| # Retry push up to 3 times to handle transient non-fast-forward conflicts | |
| PUSH_ATTEMPTS=0 | |
| until git push origin master; do | |
| PUSH_ATTEMPTS=$((PUSH_ATTEMPTS + 1)) | |
| if [ "$PUSH_ATTEMPTS" -ge 3 ]; then | |
| echo "::error::Maven artifact push failed after $PUSH_ATTEMPTS attempts (possible concurrent push). Re-run the sync step manually for tag $TAG_NAME." | |
| exit 1 | |
| fi | |
| echo "⚠️ Push attempt $PUSH_ATTEMPTS failed; retrying after fetch+rebase..." | |
| git fetch origin master && git rebase origin/master | |
| done | |
| COMMIT_SHA=$(git rev-parse HEAD) | |
| COMMIT_URL="https://github.com/${ARTIFACT_REPO}/commit/${COMMIT_SHA}" | |
| echo "✅ Artifacts pushed to maven repo: $COMMIT_URL" | |
| echo "artifact_commit_url=$COMMIT_URL" >> $GITHUB_OUTPUT | |
| popd | |
| - name: Generate release notes | |
| id: release_notes | |
| run: | | |
| VERSION="${{ steps.tag_version.outputs.version }}" | |
| TAG_NAME="${{ steps.tag_version.outputs.tag_name }}" | |
| cat > /tmp/release_notes.md << EOF | |
| ## 🚀 Android GPUImage Plus $TAG_NAME | |
| ### 📦 Downloads | |
| **Demo APK:** | |
| - \`cgeDemo-$VERSION.apk\` - Demo application with full video features | |
| **AAR Library Artifacts:** | |
| Four variants are available for different use cases: | |
| 1. **gpuimage-plus-$VERSION.aar** | |
| - Page size: 4KB (default) | |
| - Full-featured with FFmpeg bundled | |
| - Architectures: armeabi-v7a, arm64-v8a, x86, x86_64 | |
| 2. **gpuimage-plus-$VERSION-16k.aar** | |
| - Page size: 16KB | |
| - Full-featured with FFmpeg bundled | |
| - Architectures: armeabi-v7a, arm64-v8a, x86, x86_64 | |
| 3. **gpuimage-plus-$VERSION-min.aar** | |
| - Page size: 4KB (default) | |
| - Image-only version (no video features or FFmpeg) | |
| - Architectures: armeabi-v7a, arm64-v8a, x86, x86_64 | |
| 4. **gpuimage-plus-$VERSION-16k-min.aar** | |
| - Page size: 16KB | |
| - Image-only version (no video features or FFmpeg) | |
| - Architectures: armeabi-v7a, arm64-v8a, x86, x86_64 | |
| ### 🔧 Gradle Dependency | |
| \`\`\`gradle | |
| allprojects { | |
| repositories { | |
| maven { | |
| url 'https://maven.wysaid.org/' | |
| } | |
| } | |
| } | |
| dependencies { | |
| // Choose one of the following based on your needs: | |
| // Full-featured with FFmpeg (4KB page size) | |
| implementation 'org.wysaid:gpuimage-plus:$VERSION' | |
| // Full-featured with FFmpeg (16KB page size) | |
| implementation 'org.wysaid:gpuimage-plus:$VERSION-16k' | |
| // Image-only, no video (4KB page size) | |
| implementation 'org.wysaid:gpuimage-plus:$VERSION-min' | |
| // Image-only, no video (16KB page size) | |
| implementation 'org.wysaid:gpuimage-plus:$VERSION-16k-min' | |
| } | |
| \`\`\` | |
| ### 📋 System Requirements | |
| - **Minimum Android SDK**: API 21 (Android 5.0) | |
| - **Target Android SDK**: API 25 | |
| - **NDK Version**: r27c | |
| - **Supported Architectures**: armeabi-v7a, arm64-v8a, x86, x86_64 | |
| ### 📚 Documentation | |
| - **GitHub Repository**: https://github.com/wysaid/android-gpuimage-plus | |
| - **Build & Integration Guide**: https://github.com/wysaid/android-gpuimage-plus/blob/master/docs/build.md | |
| - **Filter Rule Documentation**: https://github.com/wysaid/android-gpuimage-plus/blob/master/docs/filter-rules.md | |
| --- | |
| For complete changelog, see the auto-generated content below. | |
| EOF | |
| echo "✅ Release notes generated" | |
| - name: Create GitHub Release | |
| if: steps.tag_version.outputs.is_publish == 'true' | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ steps.tag_version.outputs.tag_name }} | |
| name: Release ${{ steps.tag_version.outputs.tag_name }} | |
| body_path: /tmp/release_notes.md | |
| files: | | |
| /tmp/release-artifacts/*.apk | |
| /tmp/release-artifacts/*.aar | |
| /tmp/release-artifacts/SHA256SUMS.txt | |
| /tmp/release-artifacts/*.sha256 | |
| draft: true | |
| prerelease: ${{ steps.tag_version.outputs.is_prerelease == 'true' }} | |
| generate_release_notes: true | |
| make_latest: ${{ steps.tag_version.outputs.is_prerelease != 'true' }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Upload artifacts (build-only mode) | |
| if: steps.tag_version.outputs.is_publish != 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: release-artifacts-${{ steps.tag_version.outputs.version }} | |
| path: /tmp/release-artifacts/ | |
| retention-days: 7 | |
| - name: Build-only mode success message | |
| if: steps.tag_version.outputs.is_publish != 'true' | |
| run: | | |
| echo "🎉 ============================================" | |
| echo "🎉 Build completed successfully (artifacts only)!" | |
| echo "🎉 ============================================" | |
| echo "" | |
| echo "📦 Version: ${{ steps.tag_version.outputs.version }}" | |
| echo "📦 Artifacts are available for download from the workflow run." | |
| echo "" | |
| echo "ℹ️ This was a manual dry-run — nothing was published." | |
| echo "ℹ️ To make a real release, push the tag from master:" | |
| echo " git tag ${{ steps.tag_version.outputs.tag_name }} && git push origin ${{ steps.tag_version.outputs.tag_name }}" | |
| echo "" | |
| echo "📦 Built artifacts:" | |
| ls -lh /tmp/release-artifacts/ | |
| - name: Summary | |
| run: | | |
| IS_PUBLISH="${{ steps.tag_version.outputs.is_publish }}" | |
| IS_MANUAL="${{ steps.tag_version.outputs.is_manual }}" | |
| VERSION="${{ steps.tag_version.outputs.version }}" | |
| TAG_NAME="${{ steps.tag_version.outputs.tag_name }}" | |
| if [ "$IS_PUBLISH" != "true" ]; then | |
| echo "## 🔧 Dry-Run Build Completed Successfully!" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Version**: $VERSION" >> $GITHUB_STEP_SUMMARY | |
| echo "**Trigger**: Manual dry-run (workflow_dispatch)" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### ℹ️ Nothing was published" >> $GITHUB_STEP_SUMMARY | |
| echo "Artifacts are retained in this workflow run for **7 days**." >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "To make a real release, push the tag from master:" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY | |
| echo "git tag $TAG_NAME && git push origin $TAG_NAME" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 📦 Built Artifacts (available for download):" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "## 🎉 Release Draft Created Successfully!" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Release**: $TAG_NAME" >> $GITHUB_STEP_SUMMARY | |
| echo "**Version**: $VERSION" >> $GITHUB_STEP_SUMMARY | |
| echo "**Trigger**: Tag push" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### ✅ Version Validation" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ Tag format validated: v\${major}.\${minor}.\${patch}" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ Version matches project version in build.gradle" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 📦 Released Artifacts:" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "**Demo APK:**" >> $GITHUB_STEP_SUMMARY | |
| echo "- cgeDemo-$VERSION.apk (video enabled)" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**AAR Libraries:**" >> $GITHUB_STEP_SUMMARY | |
| echo "- gpuimage-plus-$VERSION.aar (4KB, with video)" >> $GITHUB_STEP_SUMMARY | |
| echo "- gpuimage-plus-$VERSION-16k.aar (16KB, with video)" >> $GITHUB_STEP_SUMMARY | |
| echo "- gpuimage-plus-$VERSION-min.aar (4KB, image-only)" >> $GITHUB_STEP_SUMMARY | |
| echo "- gpuimage-plus-$VERSION-16k-min.aar (16KB, image-only)" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ "$IS_PUBLISH" = "true" ]; then | |
| echo "Review and publish the draft release: ${{ github.server_url }}/${{ github.repository }}/releases" >> $GITHUB_STEP_SUMMARY | |
| echo "(Draft tag: $TAG_NAME)" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**⚠️ Action required**: Go to the releases page, review the draft, then click *Publish release* to make it public." >> $GITHUB_STEP_SUMMARY | |
| fi | |
| ARTIFACT_COMMIT_URL="${{ steps.sync_maven_repo.outputs.artifact_commit_url }}" | |
| if [ -n "$ARTIFACT_COMMIT_URL" ]; then | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 📦 Maven Artifact Repository" >> $GITHUB_STEP_SUMMARY | |
| echo "- Commit: $ARTIFACT_COMMIT_URL" >> $GITHUB_STEP_SUMMARY | |
| echo "- Browse: https://maven.wysaid.org/org/wysaid/gpuimage-plus/" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| # Add build time if available | |
| BUILD_TIME="${{ steps.build_variants.outputs.build_time }}" | |
| if [ -n "$BUILD_TIME" ]; then | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### ⏱️ Build Performance" >> $GITHUB_STEP_SUMMARY | |
| echo "- Total build time: $((BUILD_TIME / 60)) minutes $((BUILD_TIME % 60)) seconds" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| - name: Build failure notification | |
| if: failure() | |
| env: | |
| FAILURE_VERSION: ${{ steps.tag_version.outputs.version || github.event.inputs.version || 'unknown' }} | |
| FAILURE_TAG: ${{ steps.tag_version.outputs.tag_name || github.ref_name || 'unknown' }} | |
| run: | | |
| echo "::error::Release build failed for version ${FAILURE_VERSION}" | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "## ❌ Build Failed" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Version**: ${FAILURE_VERSION}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Tag**: ${FAILURE_TAG}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "Please check the workflow logs for details." >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 🔍 Common Issues" >> $GITHUB_STEP_SUMMARY | |
| echo "- Version mismatch between tag and build.gradle" >> $GITHUB_STEP_SUMMARY | |
| echo "- NDK/CMake configuration issues" >> $GITHUB_STEP_SUMMARY | |
| echo "- Missing dependencies or build tools" >> $GITHUB_STEP_SUMMARY | |
| echo "- Network issues during artifact sync" >> $GITHUB_STEP_SUMMARY |