Breaking/2026 stack modernization #253
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
| # Dual-stack CI: auto-detects Java 8 (develop) vs Java 21 (breaking/) based | |
| # on whether dev.cljs.edn exists in the checkout. After breaking/ merges to | |
| # develop, the Java 8 path becomes dead code and can be removed. | |
| name: CI | |
| on: | |
| push: | |
| branches: [develop, main] | |
| pull_request: | |
| branches: [develop, main] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| checks: write | |
| jobs: | |
| detect-stack: | |
| name: Detect Stack | |
| runs-on: ubuntu-latest | |
| outputs: | |
| java-version: ${{ steps.detect.outputs.java-version }} | |
| java-distribution: ${{ steps.detect.outputs.java-distribution }} | |
| lein-version: ${{ steps.detect.outputs.lein-version }} | |
| cljs-command: ${{ steps.detect.outputs.cljs-command }} | |
| needs-datomic-pro: ${{ steps.detect.outputs.needs-datomic-pro }} | |
| stack-label: ${{ steps.detect.outputs.stack-label }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Detect stack from project files | |
| id: detect | |
| run: | | |
| # dev.cljs.edn is the figwheel-main build config — only exists on | |
| # breaking/2026-stack-modernization (Java 21, Datomic Pro, fig:build). | |
| if [ -f "dev.cljs.edn" ]; then | |
| echo "Detected: figwheel-main stack (Java 21, Datomic Pro)" | |
| echo "java-version=21" >> $GITHUB_OUTPUT | |
| echo "java-distribution=temurin" >> $GITHUB_OUTPUT | |
| echo "lein-version=2.11.2" >> $GITHUB_OUTPUT | |
| echo "cljs-command=fig:build" >> $GITHUB_OUTPUT | |
| echo "needs-datomic-pro=true" >> $GITHUB_OUTPUT | |
| echo "stack-label=Java 21 / figwheel-main / Datomic Pro" >> $GITHUB_OUTPUT | |
| else | |
| echo "Detected: legacy stack (Java 8, Datomic Free)" | |
| echo "java-version=8" >> $GITHUB_OUTPUT | |
| echo "java-distribution=zulu" >> $GITHUB_OUTPUT | |
| echo "lein-version=2.9.10" >> $GITHUB_OUTPUT | |
| echo "cljs-command=cljsbuild once dev" >> $GITHUB_OUTPUT | |
| echo "needs-datomic-pro=false" >> $GITHUB_OUTPUT | |
| echo "stack-label=Java 8 / cljsbuild / Datomic Free" >> $GITHUB_OUTPUT | |
| fi | |
| test: | |
| name: Test & Lint (${{ needs.detect-stack.outputs.stack-label }}) | |
| runs-on: ubuntu-latest | |
| needs: detect-stack | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up JDK ${{ needs.detect-stack.outputs.java-version }} | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: ${{ needs.detect-stack.outputs.java-distribution }} | |
| java-version: ${{ needs.detect-stack.outputs.java-version }} | |
| - name: Set up Leiningen | |
| uses: DeLaGuardo/setup-clojure@12.5 | |
| with: | |
| lein: ${{ needs.detect-stack.outputs.lein-version }} | |
| - name: Cache Maven dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.m2/repository | |
| key: ${{ runner.os }}-maven-j${{ needs.detect-stack.outputs.java-version }}-${{ hashFiles('project.clj') }} | |
| restore-keys: | | |
| ${{ runner.os }}-maven-j${{ needs.detect-stack.outputs.java-version }}- | |
| - name: Load local libs (pdfbox) | |
| run: | | |
| mkdir -p ~/.m2/repository/org/ | |
| cp -rv ./lib/org/* ~/.m2/repository/org/ | |
| # Datomic Pro jars are not committed to git. Download and maven-install | |
| # them the same way .devcontainer/post-create.sh does. | |
| - name: Install Datomic Pro | |
| if: needs.detect-stack.outputs.needs-datomic-pro == 'true' | |
| run: | | |
| DATOMIC_VERSION=1.0.7482 | |
| TARGET_DIR="lib/com/datomic/datomic-pro/${DATOMIC_VERSION}" | |
| ZIP_PATH="/tmp/datomic-pro-${DATOMIC_VERSION}.zip" | |
| DOWNLOAD_URL="https://datomic-pro-downloads.s3.amazonaws.com/${DATOMIC_VERSION}/datomic-pro-${DATOMIC_VERSION}.zip" | |
| echo "Downloading Datomic Pro ${DATOMIC_VERSION}..." | |
| curl --fail --location --silent --show-error -o "$ZIP_PATH" "$DOWNLOAD_URL" | |
| mkdir -p "${TARGET_DIR}" | |
| unzip -q "$ZIP_PATH" -d "${TARGET_DIR}" | |
| # Flatten nested directory if present (zip contains datomic-pro-VERSION/ subdir) | |
| TOP_SUBDIR=$(find "${TARGET_DIR}" -mindepth 1 -maxdepth 1 -type d -print -quit || true) | |
| if [ -n "${TOP_SUBDIR}" ] && [ -z "$(find "${TARGET_DIR}" -maxdepth 1 -type f -print -quit)" ]; then | |
| mv "${TOP_SUBDIR}"/* "${TARGET_DIR}/" | |
| rmdir "${TOP_SUBDIR}" | |
| fi | |
| # Populate ~/.m2 with Datomic Pro artifacts | |
| (cd "${TARGET_DIR}" && bash bin/maven-install) | |
| echo "Datomic Pro ${DATOMIC_VERSION} installed to local Maven repo" | |
| - name: Install dependencies | |
| run: lein deps | |
| - name: Run linter | |
| id: lint | |
| run: | | |
| echo "## Lint Results" >> $GITHUB_STEP_SUMMARY | |
| if lein lint 2>&1 | tee lint-output.txt; then | |
| echo "**Lint passed** - no errors" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "**Lint failed**" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| cat lint-output.txt >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| exit 1 | |
| fi | |
| - name: Run tests | |
| id: test | |
| run: | | |
| echo "## Test Results" >> $GITHUB_STEP_SUMMARY | |
| if lein test 2>&1 | tee test-output.txt; then | |
| SUMMARY=$(grep -E "^Ran [0-9]+ tests" test-output.txt || echo "Tests completed") | |
| echo "**Tests passed**" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "**Tests failed**" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| tail -50 test-output.txt >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| exit 1 | |
| fi | |
| - name: Build ClojureScript | |
| id: cljs | |
| run: | | |
| echo "## ClojureScript Build" >> $GITHUB_STEP_SUMMARY | |
| if lein ${{ needs.detect-stack.outputs.cljs-command }} 2>&1 | tee cljs-output.txt; then | |
| echo "**CLJS build succeeded**" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "**CLJS build failed**" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| tail -50 cljs-output.txt >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| exit 1 | |
| fi | |
| - name: Post PR comment with results | |
| if: github.event_name == 'pull_request' && always() | |
| continue-on-error: true # Fork PRs get read-only GITHUB_TOKEN | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const lintOutput = fs.existsSync('lint-output.txt') ? fs.readFileSync('lint-output.txt', 'utf8') : 'No output'; | |
| const testOutput = fs.existsSync('test-output.txt') ? fs.readFileSync('test-output.txt', 'utf8') : 'No output'; | |
| const cljsOutput = fs.existsSync('cljs-output.txt') ? fs.readFileSync('cljs-output.txt', 'utf8') : 'No output'; | |
| const lintOk = '${{ steps.lint.outcome }}' === 'success'; | |
| const testOk = '${{ steps.test.outcome }}' === 'success'; | |
| const cljsOk = '${{ steps.cljs.outcome }}' === 'success'; | |
| const allOk = lintOk && testOk && cljsOk; | |
| const stackLabel = '${{ needs.detect-stack.outputs.stack-label }}'; | |
| const testMatch = testOutput.match(/Ran (\d+) tests containing (\d+) assertions/); | |
| const testSummary = testMatch ? `${testMatch[1]} tests, ${testMatch[2]} assertions` : 'See logs'; | |
| const status = allOk ? 'All checks passed' : 'Some checks failed'; | |
| const body = [ | |
| `## ${status}`, | |
| '', | |
| '| Check | Status | Details |', | |
| '|-------|--------|---------|', | |
| `| Lint | ${lintOk ? 'Pass' : 'Fail'} | ${lintOk ? 'No errors' : 'See workflow logs'} |`, | |
| `| Tests | ${testOk ? 'Pass' : 'Fail'} | ${testOk ? testSummary : 'See workflow logs'} |`, | |
| `| CLJS Build | ${cljsOk ? 'Pass' : 'Fail'} | ${cljsOk ? 'Compiled' : 'See workflow logs'} |`, | |
| '', | |
| `**Stack**: ${stackLabel}`, | |
| '', | |
| '<details>', | |
| '<summary>Full test output</summary>', | |
| '', | |
| '```', | |
| testOutput.slice(-2000), | |
| '```', | |
| '', | |
| '</details>', | |
| '', | |
| '---', | |
| `*[Workflow run](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})*` | |
| ].join('\n'); | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number | |
| }); | |
| const botComment = comments.find(c => | |
| c.user.type === 'Bot' && (c.body.includes('All checks passed') || c.body.includes('Some checks failed')) | |
| ); | |
| if (botComment) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body: body | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: body | |
| }); | |
| } | |
| - name: Upload artifacts on failure | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ci-failure-logs | |
| path: | | |
| lint-output.txt | |
| test-output.txt | |
| cljs-output.txt | |
| retention-days: 7 |