# docs https://github.com/marketplace/actions/create-release # docs https://github.com/ncipollo/release-action # docs https://docs.github.com/en/actions/using-jobs/choosing-the-runner-for-a-job#choosing-github-hosted-runners # # Architecture: build jobs upload workflow artifacts only. A single # finalize-release job creates the GitHub release with all assets + body. # If ANY build job fails, finalize-release is skipped and no release appears. name: release on: push: tags: - 'v*' env: HUSKY: '0' jobs: preflight: runs-on: ubuntu-22.04 permissions: contents: read steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Node.js v22 uses: actions/setup-node@v4 with: node-version: 22 cache: 'yarn' - name: Install dependencies run: | for i in 1 2 3; do echo "yarn install attempt $i" yarn install --frozen-lockfile --ignore-engines --network-timeout 100000 --network-concurrency 1 && break sleep 5 [ "$i" = "3" ] && exit 1 done - name: Run Vitest run: yarn test --run - name: Lint run: yarn lint - name: Type check run: yarn type-check - name: Build React app run: CI='' NODE_ENV=production yarn build - name: Run React Doctor run: yarn doctor - name: Install Chromium for smoke tests run: npx playwright install --with-deps chromium - name: Smoke test built web app run: node scripts/smoke-web-app.js --start-preview linux: strategy: fail-fast: false matrix: arch: [x64, arm64] runs-on: ubuntu-22.04 needs: preflight permissions: contents: read steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Node.js v22 uses: actions/setup-node@v4 with: node-version: 22 cache: 'yarn' - name: Install dependencies run: | for i in 1 2 3; do echo "yarn install attempt $i" yarn install --frozen-lockfile --ignore-engines --network-timeout 100000 --network-concurrency 1 && break sleep 5 [ "$i" = "3" ] && exit 1 done - name: Download IPFS and set permissions run: BUILD_ARCH=${{ matrix.arch }} node electron/download-ipfs && sudo chmod +x bin/linux/ipfs - name: Build React app run: CI='' NODE_ENV=production yarn build - name: Build Electron app for Linux (arm64) if: matrix.arch == 'arm64' run: yarn electron:build:linux:arm64 - name: Build Electron app for Linux (x64) if: matrix.arch == 'x64' run: yarn electron:build:linux:x64 - name: Stage release artifacts run: | mkdir -p release-assets cp out/make/AppImage/**/*.AppImage release-assets/ - name: Create static HTML release archive if: matrix.arch == 'x64' run: | VERSION=$(node -e "console.log(require('./package.json').version)") HTML_ARCHIVE_DIR="5chan-html-$VERSION" rm -rf "$HTML_ARCHIVE_DIR" cp -R build "$HTML_ARCHIVE_DIR" zip -r "release-assets/${HTML_ARCHIVE_DIR}.zip" "$HTML_ARCHIVE_DIR" rm -rf "$HTML_ARCHIVE_DIR" - name: List release assets run: ls -la release-assets - uses: actions/upload-artifact@v4 with: name: release-linux-${{ matrix.arch }} path: release-assets/ mac: strategy: fail-fast: false matrix: include: - runner: macos-15-intel # Intel x64 arch: x64 - runner: macos-latest # Apple Silicon arm64 arch: arm64 runs-on: ${{ matrix.runner }} needs: preflight permissions: contents: read steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Node.js v22 uses: actions/setup-node@v4 with: node-version: 22 cache: 'yarn' - name: Setup Python 3.12 uses: actions/setup-python@v5 with: python-version: '3.12' - run: pip install setuptools - name: Install dependencies run: | for i in 1 2 3; do echo "yarn install attempt $i" yarn install --frozen-lockfile --ignore-engines --network-timeout 100000 --network-concurrency 1 && break sleep 5 [ "$i" = "3" ] && exit 1 done - name: Download IPFS and set permissions run: node electron/download-ipfs && sudo chmod +x bin/mac/ipfs - name: Build React app run: CI='' NODE_ENV=production yarn build - name: Build Electron app for Mac env: CSC_IDENTITY_AUTO_DISCOVERY: 'false' run: | if [ "${{ matrix.arch }}" = "arm64" ]; then yarn electron:build:mac:arm64 else yarn electron:build:mac:x64 fi - name: Rename DMG with architecture suffix run: | for f in out/make/*.dmg; do [ -f "$f" ] || continue base=$(basename "$f" .dmg) mv "$f" "out/make/${base}-${{ matrix.arch }}.dmg" done - name: Stage release artifacts run: | mkdir -p release-assets cp out/make/*.dmg release-assets/ 2>/dev/null || true find out/make/zip -name '*.zip' -exec cp {} release-assets/ \; 2>/dev/null || true - name: List release assets run: ls -la release-assets - uses: actions/upload-artifact@v4 with: name: release-mac-${{ matrix.arch }} path: release-assets/ windows: runs-on: windows-2022 needs: preflight permissions: contents: read steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Node.js v22 uses: actions/setup-node@v4 with: node-version: 22 cache: 'yarn' - name: Install dependencies shell: bash run: | for i in 1 2 3; do echo "yarn install attempt $i" yarn install --frozen-lockfile --ignore-engines --network-timeout 100000 --network-concurrency 1 && break sleep 5 [ "$i" = "3" ] && exit 1 done - name: Build React app run: npx cross-env NODE_ENV=production yarn build - name: Build Electron app for Windows (x64) run: yarn electron:build:windows - name: Stage release artifacts shell: bash run: | mkdir -p release-assets cp out/make/squirrel.windows/x64/*.exe release-assets/ - name: List release assets shell: bash run: ls -la release-assets - uses: actions/upload-artifact@v4 with: name: release-windows path: release-assets/ android: runs-on: ubuntu-22.04 needs: preflight permissions: contents: read steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: '17' - uses: actions/setup-node@v4 with: node-version: 22 cache: 'yarn' - run: sudo apt-get install -y apksigner zipalign - name: Install dependencies run: | for i in 1 2 3; do echo "yarn install attempt $i" yarn install --frozen-lockfile --ignore-engines --network-timeout 100000 --network-concurrency 1 && break sleep 5 [ "$i" = "3" ] && exit 1 done - name: Build React app run: CI='' NODE_ENV=production yarn build - name: Set Android versionCode and versionName run: | sed -i "s/versionCode 1/versionCode $(git tag | wc -l)/" ./android/app/build.gradle sed -i "s/versionName \"1.0\"/versionName \"$(node -e "console.log(require('./package.json').version)")\"/" ./android/app/build.gradle cat ./android/app/build.gradle - name: Sync Capacitor run: npx cap sync android - name: Build APK run: | for i in 1 2 3; do echo "gradlew assembleRelease attempt $i" (cd android && ./gradlew assembleRelease --stacktrace) && break sleep 10 [ "$i" = "3" ] && exit 1 done - name: Optimize APK run: cd android/app/build/outputs/apk/release && zipalign 4 app-release-unsigned.apk app-release-unsigned-zip.apk - name: Sign APK run: cd android/app/build/outputs/apk/release && apksigner sign --ks ../../../../../plebbit.keystore --ks-pass pass:${{ secrets.PLEBBIT_REACT_KEYSTORE_PASSWORD }} --ks-key-alias release --out app-release-signed.apk app-release-unsigned-zip.apk - name: Stage release artifacts run: | mkdir -p release-assets VERSION=$(node -e "console.log(require('./package.json').version)") mv android/app/build/outputs/apk/release/app-release-signed.apk "release-assets/5chan-${VERSION}.apk" - name: List release assets run: ls -la release-assets - uses: actions/upload-artifact@v4 with: name: release-android path: release-assets/ finalize-release: runs-on: ubuntu-22.04 needs: [linux, mac, windows, android] permissions: contents: write steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Node.js v22 uses: actions/setup-node@v4 with: node-version: 22 cache: 'yarn' - name: Install dependencies run: | for i in 1 2 3; do echo "yarn install attempt $i" yarn install --frozen-lockfile --ignore-engines --network-timeout 100000 --network-concurrency 1 && break sleep 5 [ "$i" = "3" ] && exit 1 done - name: Download all release artifacts uses: actions/download-artifact@v4 with: pattern: release-* path: release-assets merge-multiple: true - name: List all release assets run: ls -la release-assets - name: Populate dist for release-body script run: | mkdir -p dist cp release-assets/* dist/ - name: Generate release body env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPOSITORY: ${{ github.repository }} GITHUB_REF_NAME: ${{ github.ref_name }} run: node scripts/release-body > release-body.txt - name: Create GitHub release uses: ncipollo/release-action@v1 with: artifacts: 'release-assets/*' bodyFile: "release-body.txt" token: ${{ secrets.GITHUB_TOKEN }}