Bump version to 1.10.1 #63
Workflow file for this run
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*' | |
| permissions: | |
| contents: write | |
| jobs: | |
| # Tests must pass before any release artifacts are built | |
| test: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Check formatting | |
| run: npm run format:check | |
| - name: Run linter | |
| run: npm run lint | |
| - name: Security audit | |
| run: npm audit --audit-level=high | |
| - name: Run tests | |
| run: npm run test:run | |
| - name: Verify build | |
| run: npm run build | |
| # Validate release type - full releases require existing prerelease | |
| validate: | |
| needs: test | |
| runs-on: ubuntu-latest | |
| outputs: | |
| is_prerelease: ${{ steps.check.outputs.is_prerelease }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Determine release type | |
| id: check | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| TAG="${GITHUB_REF#refs/tags/}" | |
| VERSION="${TAG#v}" | |
| # Extract base version (strip prerelease suffix) | |
| BASE_VERSION=$(echo "$VERSION" | sed 's/-.*//') | |
| # Check if this is a prerelease tag (contains -alpha, -beta, -rc, etc.) | |
| if [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-.+ ]]; then | |
| echo "is_prerelease=true" >> $GITHUB_OUTPUT | |
| echo "This is a PRE-RELEASE: $TAG" | |
| else | |
| echo "is_prerelease=false" >> $GITHUB_OUTPUT | |
| echo "This is a FULL RELEASE: $TAG" | |
| # Check if a prerelease exists for this version | |
| PRERELEASES=$(gh release list --limit 100 | grep -E "${BASE_VERSION}-(alpha|beta|rc)" || true) | |
| if [ -z "$PRERELEASES" ]; then | |
| echo "::error::No pre-release found for version $BASE_VERSION. Create a pre-release first (e.g., v${BASE_VERSION}-beta.1)" | |
| exit 1 | |
| else | |
| echo "Found pre-releases for this version:" | |
| echo "$PRERELEASES" | |
| fi | |
| fi | |
| # Clean up invalid releases - delete tag if validation failed | |
| cleanup-invalid: | |
| needs: [test, validate] | |
| if: failure() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Delete invalid tag | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| TAG="${GITHUB_REF#refs/tags/}" | |
| echo "Cleaning up invalid release: $TAG" | |
| # Delete the release if it exists | |
| gh release delete "$TAG" --repo "$GITHUB_REPOSITORY" --yes 2>/dev/null || echo "No release to delete" | |
| # Delete the tag | |
| git push --delete origin "$TAG" 2>/dev/null || echo "No remote tag to delete" | |
| echo "" | |
| echo "Invalid release $TAG has been deleted." | |
| # Verify package.json version matches tag | |
| verify-version: | |
| needs: validate | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Verify version match | |
| run: | | |
| TAG="${GITHUB_REF#refs/tags/}" | |
| TAG_VERSION="${TAG#v}" | |
| # Extract base version (strip prerelease suffix) | |
| TAG_BASE=$(echo "$TAG_VERSION" | sed 's/-.*//') | |
| PKG_VERSION=$(node -p "require('./package.json').version") | |
| echo "Tag version: $TAG_VERSION (base: $TAG_BASE)" | |
| echo "Package.json version: $PKG_VERSION" | |
| if [ "$TAG_BASE" != "$PKG_VERSION" ]; then | |
| echo "::error::Version mismatch! Tag ($TAG_BASE) does not match package.json ($PKG_VERSION)" | |
| exit 1 | |
| fi | |
| echo "Version verified: $PKG_VERSION" | |
| # Create the GitHub release first (so builds can upload to it) | |
| create-release: | |
| needs: [validate, verify-version] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Create GitHub Release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| TAG="${GITHUB_REF#refs/tags/}" | |
| IS_PRERELEASE="${{ needs.validate.outputs.is_prerelease }}" | |
| NOTES="## Installation | |
| **macOS:** Open Terminal and run: \`xattr -cr /Applications/Graph\\ Core.app\` then open the app. | |
| **Windows:** Run the installer. Click \"More info\" then \"Run anyway\" if you see a SmartScreen warning. | |
| **Linux:** Make the AppImage executable: \`chmod +x Graph-Core-*.AppImage\`" | |
| if [ "$IS_PRERELEASE" = "true" ]; then | |
| gh release create "$TAG" --repo "$GITHUB_REPOSITORY" --draft --prerelease --generate-notes --notes "$NOTES" | |
| echo "Created draft prerelease: $TAG" | |
| else | |
| gh release create "$TAG" --repo "$GITHUB_REPOSITORY" --draft --generate-notes --notes "$NOTES" | |
| echo "Created draft release: $TAG" | |
| fi | |
| # Build release artifacts and upload to the release | |
| build: | |
| needs: [validate, verify-version, create-release] | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [macos-latest, windows-latest, ubuntu-latest] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Build app | |
| run: npm run build | |
| - name: Build Electron (macOS) | |
| if: matrix.os == 'macos-latest' | |
| run: npx electron-builder --mac --publish never | |
| env: | |
| CSC_IDENTITY_AUTO_DISCOVERY: false | |
| - name: Build Electron (Windows) | |
| if: matrix.os == 'windows-latest' | |
| run: npx electron-builder --win --publish never | |
| - name: Build Electron (Linux) | |
| if: matrix.os == 'ubuntu-latest' | |
| run: npx electron-builder --linux --publish never | |
| - name: Upload artifacts to release | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| TAG="${GITHUB_REF#refs/tags/}" | |
| echo "Uploading artifacts to release $TAG" | |
| # Upload all release files except blockmap and debug yml files | |
| for file in release/*; do | |
| if [ -f "$file" ]; then | |
| filename=$(basename "$file") | |
| # Skip blockmap and builder-debug.yml, but include latest*.yml for auto-updates | |
| if [[ "$filename" != *.blockmap && "$filename" != "builder-debug.yml" ]]; then | |
| echo "Uploading: $filename" | |
| gh release upload "$TAG" "$file" --repo "$GITHUB_REPOSITORY" --clobber | |
| fi | |
| fi | |
| done | |
| # Publish the release (remove draft status) | |
| publish-release: | |
| needs: [validate, build] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Publish release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| TAG="${GITHUB_REF#refs/tags/}" | |
| IS_PRERELEASE="${{ needs.validate.outputs.is_prerelease }}" | |
| echo "Publishing release: $TAG" | |
| if [ "$IS_PRERELEASE" = "true" ]; then | |
| gh release edit "$TAG" --repo "$GITHUB_REPOSITORY" --draft=false --prerelease | |
| echo "Published prerelease: $TAG" | |
| else | |
| gh release edit "$TAG" --repo "$GITHUB_REPOSITORY" --draft=false --prerelease=false | |
| echo "Published release: $TAG" | |
| fi | |
| # Upload release assets to R2 (full releases only) | |
| upload-r2: | |
| needs: [validate, publish-release] | |
| if: needs.validate.outputs.is_prerelease == 'false' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download release assets | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| mkdir -p assets | |
| gh release download "${{ github.ref_name }}" --repo "${{ github.repository }}" --dir assets | |
| - name: Upload to R2 | |
| env: | |
| RCLONE_CONFIG_R2_TYPE: s3 | |
| RCLONE_CONFIG_R2_PROVIDER: Cloudflare | |
| RCLONE_CONFIG_R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }} | |
| RCLONE_CONFIG_R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }} | |
| RCLONE_CONFIG_R2_ENDPOINT: https://78836246513c4e18ead5fd9349aea200.r2.cloudflarestorage.com | |
| run: | | |
| curl -s https://rclone.org/install.sh | sudo bash | |
| # Generate index.html | |
| cat > assets/index.html << 'EOF' | |
| <!DOCTYPE html> | |
| <html><head><title>Graph Core Downloads</title> | |
| <style>body{font-family:system-ui;max-width:800px;margin:2rem auto;padding:1rem} | |
| a{display:block;padding:0.5rem 0}</style></head> | |
| <body><h1>Graph Core Downloads</h1> | |
| EOF | |
| for f in assets/*; do | |
| [ -f "$f" ] && echo "<a href=\"$(basename "$f")\">$(basename "$f")</a>" >> assets/index.html | |
| done | |
| echo "</body></html>" >> assets/index.html | |
| echo "Files to upload:" | |
| ls -la assets/ | |
| # First upload new files (copy doesn't delete anything) | |
| rclone copy assets/ r2:binaries/graph-core/ -v | |
| # Verify upload succeeded by checking a file exists in R2 | |
| if rclone ls r2:binaries/graph-core/ | head -1 | grep -q .; then | |
| echo "Upload verified, cleaning up old versions..." | |
| # Now safe to sync (deletes old files since new ones exist) | |
| rclone sync assets/ r2:binaries/graph-core/ -v | |
| else | |
| echo "::error::Upload verification failed - keeping old files" | |
| exit 1 | |
| fi | |
| # Trigger website to update download links | |
| trigger-website: | |
| needs: upload-r2 | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Trigger sorenwacker.net update | |
| env: | |
| PAT_TOKEN: ${{ secrets.WEBSITE_DISPATCH_TOKEN }} | |
| run: | | |
| curl -X POST \ | |
| -H "Accept: application/vnd.github+json" \ | |
| -H "Authorization: Bearer $PAT_TOKEN" \ | |
| https://api.github.com/repos/sorenwacker/sorenwacker.net/dispatches \ | |
| -d '{"event_type":"graph-core-release","client_payload":{"version":"${{ github.ref_name }}"}}' |