Release on version.js update #222
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: Release on version.js update | |
| on: | |
| workflow_run: | |
| workflows: ["Bump version and sync Changelog to Docker Repo"] | |
| types: [completed] | |
| branches: [master] | |
| workflow_dispatch: | |
| inputs: | |
| ref: | |
| description: "Ref (branch/sha) to build from (default: master)" | |
| required: false | |
| version: | |
| description: "Explicit version tag to release (e.g., v1.8.12). If empty, parse from public/js/version.js." | |
| required: false | |
| permissions: | |
| contents: write | |
| jobs: | |
| release: | |
| runs-on: ubuntu-latest | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') | |
| concurrency: | |
| group: release-${{ github.event_name }}-${{ github.run_id }} | |
| cancel-in-progress: false | |
| steps: | |
| - name: Resolve source ref | |
| id: pickref | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | |
| if [[ -n "${{ github.event.inputs.ref }}" ]]; then | |
| REF_IN="${{ github.event.inputs.ref }}" | |
| else | |
| REF_IN="master" | |
| fi | |
| if git ls-remote --exit-code --heads https://github.com/${{ github.repository }}.git "$REF_IN" >/dev/null 2>&1; then | |
| REF="$REF_IN" | |
| else | |
| REF="$REF_IN" | |
| fi | |
| elif [[ "${{ github.event_name }}" == "workflow_run" ]]; then | |
| # Use the branch tip (includes the version.js bump commit created by the upstream workflow). | |
| REF="${{ github.event.workflow_run.head_branch }}" | |
| else | |
| REF="${{ github.sha }}" | |
| fi | |
| echo "ref=$REF" >> "$GITHUB_OUTPUT" | |
| echo "Using ref=$REF" | |
| - name: Checkout chosen ref (full history + tags, no persisted token) | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ steps.pickref.outputs.ref }} | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Determine version | |
| id: ver | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| if [[ -n "${{ github.event.inputs.version || '' }}" ]]; then | |
| VER="${{ github.event.inputs.version }}" | |
| else | |
| if [[ ! -f public/js/version.js ]]; then | |
| echo "public/js/version.js not found; cannot auto-detect version." >&2 | |
| exit 1 | |
| fi | |
| VER="$(grep -Eo "APP_VERSION\s*=\s*['\"]v[^'\"]+['\"]" public/js/version.js | sed -E "s/.*['\"](v[^'\"]+)['\"].*/\1/")" | |
| if [[ -z "$VER" ]]; then | |
| echo "Could not parse APP_VERSION from public/js/version.js" >&2 | |
| exit 1 | |
| fi | |
| fi | |
| echo "version=$VER" >> "$GITHUB_OUTPUT" | |
| echo "Detected version: $VER" | |
| - name: Skip if tag already exists | |
| id: tagcheck | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| if git rev-parse -q --verify "refs/tags/${{ steps.ver.outputs.version }}" >/dev/null; then | |
| echo "exists=true" >> "$GITHUB_OUTPUT" | |
| echo "Tag ${{ steps.ver.outputs.version }} already exists. Skipping release." | |
| else | |
| echo "exists=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Prepare stamp script | |
| if: steps.tagcheck.outputs.exists == 'false' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| sed -i 's/\r$//' scripts/stamp-assets.sh || true | |
| chmod +x scripts/stamp-assets.sh | |
| - name: Build stamped staging tree | |
| if: steps.tagcheck.outputs.exists == 'false' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| VER="${{ steps.ver.outputs.version }}" | |
| rm -rf staging | |
| rsync -a \ | |
| --exclude '.git' --exclude '.github' \ | |
| --exclude 'resources' \ | |
| --exclude '.dockerignore' --exclude '.gitattributes' --exclude '.gitignore' \ | |
| ./ staging/ | |
| bash ./scripts/stamp-assets.sh "${VER}" "$(pwd)/staging" | |
| # --- PHP + Composer for vendor/ (production) --- | |
| - name: Setup PHP | |
| if: steps.tagcheck.outputs.exists == 'false' | |
| id: php | |
| uses: shivammathur/setup-php@v2 | |
| with: | |
| php-version: '8.3' | |
| tools: composer:v2 | |
| extensions: mbstring, json, curl, dom, fileinfo, openssl, zip | |
| coverage: none | |
| ini-values: memory_limit=-1 | |
| - name: Cache Composer downloads | |
| if: steps.tagcheck.outputs.exists == 'false' | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.composer/cache | |
| ~/.cache/composer | |
| key: composer-${{ runner.os }}-php-${{ steps.php.outputs.php-version }}-${{ hashFiles('**/composer.lock') }} | |
| restore-keys: | | |
| composer-${{ runner.os }}-php-${{ steps.php.outputs.php-version }}- | |
| - name: Install PHP dependencies into staging | |
| if: steps.tagcheck.outputs.exists == 'false' | |
| env: | |
| COMPOSER_MEMORY_LIMIT: -1 | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| pushd staging >/dev/null | |
| if [[ -f composer.json ]]; then | |
| composer install \ | |
| --no-dev \ | |
| --prefer-dist \ | |
| --no-interaction \ | |
| --no-progress \ | |
| --optimize-autoloader \ | |
| --classmap-authoritative | |
| test -f vendor/autoload.php || (echo "Composer install did not produce vendor/autoload.php" >&2; exit 1) | |
| else | |
| echo "No composer.json in staging; skipping vendor install." | |
| fi | |
| popd >/dev/null | |
| # --- end Composer --- | |
| - name: Verify placeholders removed (skip vendor/) | |
| if: steps.tagcheck.outputs.exists == 'false' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| ROOT="$(pwd)/staging" | |
| if grep -R -n -E "{{APP_QVER}}|{{APP_VER}}" "$ROOT" \ | |
| --exclude-dir=vendor --exclude-dir=vendor-bin \ | |
| --include='*.html' --include='*.php' --include='*.css' --include='*.js' 2>/dev/null; then | |
| echo "Unreplaced placeholders found in staging." >&2 | |
| exit 1 | |
| fi | |
| echo "OK: No unreplaced placeholders." | |
| - name: Zip artifact (includes vendor/) | |
| if: steps.tagcheck.outputs.exists == 'false' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| VER="${{ steps.ver.outputs.version }}" | |
| (cd staging && zip -r "../FileRise-${VER}.zip" . >/dev/null) | |
| - name: Compute SHA-256 | |
| if: steps.tagcheck.outputs.exists == 'false' | |
| id: sum | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| ZIP="FileRise-${{ steps.ver.outputs.version }}.zip" | |
| SHA=$(shasum -a 256 "$ZIP" | awk '{print $1}') | |
| echo "$SHA $ZIP" > "${ZIP}.sha256" | |
| echo "sha=$SHA" >> "$GITHUB_OUTPUT" | |
| echo "Computed SHA-256: $SHA" | |
| - name: Extract notes from CHANGELOG (optional) | |
| if: steps.tagcheck.outputs.exists == 'false' | |
| id: notes | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| NOTES_PATH="" | |
| if [[ -f CHANGELOG.md ]]; then | |
| awk ' | |
| BEGIN{found=0} | |
| /^## / && !found {found=1} | |
| found && /^---$/ {exit} | |
| found {print} | |
| ' CHANGELOG.md > CHANGELOG_SNIPPET.md || true | |
| sed -i -e :a -e '/^\n*$/{$d;N;ba' -e '}' CHANGELOG_SNIPPET.md || true | |
| if [[ -s CHANGELOG_SNIPPET.md ]]; then | |
| NOTES_PATH="CHANGELOG_SNIPPET.md" | |
| fi | |
| fi | |
| echo "path=$NOTES_PATH" >> "$GITHUB_OUTPUT" | |
| - name: Compute previous tag (for Full Changelog link) | |
| if: steps.tagcheck.outputs.exists == 'false' | |
| id: prev | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| VER="${{ steps.ver.outputs.version }}" | |
| PREV=$(git tag --list "v*" --sort=-v:refname | grep -v -F "$VER" | head -n1 || true) | |
| if [[ -z "$PREV" ]]; then | |
| PREV=$(git rev-list --max-parents=0 HEAD | tail -n1) | |
| fi | |
| echo "prev=$PREV" >> "$GITHUB_OUTPUT" | |
| echo "Previous tag/baseline: $PREV" | |
| - name: Build release body | |
| if: steps.tagcheck.outputs.exists == 'false' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| VER="${{ steps.ver.outputs.version }}" | |
| PREV="${{ steps.prev.outputs.prev }}" | |
| REPO="${GITHUB_REPOSITORY}" | |
| COMPARE_URL="https://github.com/${REPO}/compare/${PREV}...${VER}" | |
| ZIP="FileRise-${VER}.zip" | |
| SHA="${{ steps.sum.outputs.sha }}" | |
| { | |
| echo | |
| if [[ -s CHANGELOG_SNIPPET.md ]]; then | |
| cat CHANGELOG_SNIPPET.md | |
| echo | |
| fi | |
| echo "## ${VER}" | |
| echo "### Full Changelog" | |
| echo "[${PREV} β ${VER}](${COMPARE_URL})" | |
| echo | |
| echo "### SHA-256 (zip)" | |
| echo '```' | |
| echo "${SHA} ${ZIP}" | |
| echo '```' | |
| } > RELEASE_BODY.md | |
| sed -n '1,200p' RELEASE_BODY.md | |
| - name: Create GitHub Release | |
| if: steps.tagcheck.outputs.exists == 'false' | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ steps.ver.outputs.version }} | |
| target_commitish: ${{ steps.pickref.outputs.ref }} | |
| name: ${{ steps.ver.outputs.version }} | |
| body_path: RELEASE_BODY.md | |
| generate_release_notes: false | |
| files: | | |
| FileRise-${{ steps.ver.outputs.version }}.zip | |
| FileRise-${{ steps.ver.outputs.version }}.zip.sha256 |