Skip to content

Migrate CI from GitHub Actions to Buildkite#48

Open
z8dn wants to merge 13 commits into
mainfrom
migrate-to-buildkite
Open

Migrate CI from GitHub Actions to Buildkite#48
z8dn wants to merge 13 commits into
mainfrom
migrate-to-buildkite

Conversation

@z8dn
Copy link
Copy Markdown
Owner

@z8dn z8dn commented Apr 18, 2026

Summary

  • Adds .buildkite/pipeline.yml — main CI pipeline (build → test + verify in parallel → release draft on main)
  • Adds .buildkite/pipeline.release.yml — publishes plugin to JetBrains Marketplace on tag push, opens changelog PR
  • Adds .buildkite/pipeline.ui-tests.yml — manual UI test matrix across Linux, macOS, and Windows agents
  • Adds .buildkite/pipeline.qodana.yml — Qodana code quality scan, skips doc-only changes

The existing .github/workflows/ files are left intact so GitHub Actions keeps running during the transition. Once Buildkite pipelines are wired up and validated, those can be removed in a follow-up.

Migration notes for reviewers

Concept GitHub Actions Buildkite
Artifact upload actions/upload-artifact artifact_paths:
Step outputs ${{ steps.x.outputs.y }} buildkite-agent meta-data set/get
Job deps needs: depends_on:
Branch filter branches: [main] branches: "main" on step
Secrets secrets.* Agent env vars (set in Buildkite pipeline settings)

Required secrets to configure in Buildkite:

  • GITHUB_TOKEN — release draft + changelog PR
  • PUBLISH_TOKEN, CERTIFICATE_CHAIN, PRIVATE_KEY, PRIVATE_KEY_PASSWORD — JetBrains Marketplace publish
  • QODANA_TOKEN — Qodana scan

Agent requirements: Java 21 (Zulu) pre-installed; adjust JAVA_HOME paths in each pipeline to match your agent OS images. Windows UI test step uses gradlew.bat and cmd syntax.

Test plan

  • Trigger pipeline.yml on a test branch push and verify build/test/verify steps all pass
  • Confirm release draft step is skipped on PR builds and runs only on main
  • Manually trigger pipeline.ui-tests.yml and verify IDE health check passes on at least Linux
  • Verify pipeline.qodana.yml skips correctly when only doc files are changed
  • Trigger pipeline.release.yml on a test tag and confirm Marketplace publish + changelog PR creation

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Added automated Qodana code scanning as part of CI
    • Added cross-platform UI testing pipeline for Linux, macOS, and Windows
    • Configured automated release workflow for publishing plugin distributions and changelog updates
    • Updated platform configuration to "AI"

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 18, 2026

Warning

Rate limit exceeded

@z8dn has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 43 minutes and 16 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 43 minutes and 16 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 51be2b63-585d-4e7b-92db-c92604a6864b

📥 Commits

Reviewing files that changed from the base of the PR and between 0f11d0b and 4f257bd.

📒 Files selected for processing (1)
  • build.gradle.kts
📝 Walkthrough

Walkthrough

Adds several Buildkite pipeline configurations for CI, release, UI tests, and Qodana scanning, and updates Gradle settings (platformType and plugin verification JVM args). Changes are configuration-only and introduce automated release and scanning steps.

Changes

Cohort / File(s) Summary
Buildkite Pipelines
.buildkite/pipeline.yml, .buildkite/pipeline.qodana.yml, .buildkite/pipeline.release.yml, .buildkite/pipeline.ui-tests.yml
Adds CI pipeline (test, build, verify, draft release), Qodana scan step with changed-files filtering and Docker execution, a release pipeline that runs Gradle publish and automates GitHub release + changelog PRs, and manual OS-specific UI test pipelines with background IDE startup and readiness polling. Artifacts declared for tests, verifier, Qodana report, and distributions.
Gradle Configuration
gradle.properties, build.gradle.kts
Adds platformType = AI to gradle.properties and removes a hardcoded gradleVersion property; adds pluginVerification { freeArgs = listOf("-Xmx1g") } to configure verifier JVM heap.

Sequence Diagram(s)

sequenceDiagram
    participant Buildkite
    participant Docker as "Docker / Gradle"
    participant GitHub
    participant Qodana as "Qodana Cloud"
    Buildkite->>Docker: run build/publish/verify UI tests or qodana container
    Docker->>Buildkite: produce artifacts (zips, reports, verifier results, test reports)
    Buildkite->>GitHub: create/update draft release, upload artifacts, open PRs (release changelog)
    Buildkite->>Qodana: (for qodana step) invoke scan image with token & endpoint, store report artifacts
    Qodana-->>Buildkite: write scan report -> collected as artifacts
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I hopped through YAML fields tonight,

Scanning, building by CI light.
Qodana peeks, releases take flight,
Tests awake on Linux, Mac, and Win — delight!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Migrate CI from GitHub Actions to Buildkite' accurately describes the primary change in the PR, which adds four new Buildkite pipeline configuration files while retaining GitHub Actions workflows.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch migrate-to-buildkite

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 18, 2026

Qodana for JVM

It seems all right 👌

No new problems were found according to the checks applied

☁️ View the detailed Qodana report

Contact Qodana team

Contact us at qodana-support@jetbrains.com

@z8dn z8dn marked this pull request as ready for review April 18, 2026 14:59
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.buildkite/pipeline.qodana.yml:
- Around line 16-18: Update the CHANGED assignment to diff the full PR range
instead of only the last commit by using git diff --name-only origin/main...HEAD
(fetch origin/main first and fallback to HEAD~1 HEAD only if necessary) and make
the NON_DOC pipeline tolerant of no matches by appending "|| true" to the grep
commands; specifically modify the CHANGED variable and the NON_DOC pipeline (the
lines that set CHANGED and NON_DOC) so CHANGED is populated from
origin/main...HEAD and NON_DOC uses "grep -vE
'^(CHANGELOG|CONTRIBUTING|CODE_OF_CONDUCT|README)\.md$' | grep -v '^img/' ||
true" to avoid failing under errexit when there are no non-doc files, leaving
the subsequent if [ -z "$NON_DOC" ] check unchanged.
- Around line 10-12: The pipeline currently escapes QODANA_TOKEN as
$${QODANA_TOKEN?} which prevents Buildkite from interpolating the secret at
upload time; change the env entry to use unescaped ${QODANA_TOKEN?} so Buildkite
will substitute the actual token during pipeline upload (or alternatively remove
the env entry and configure QODANA_TOKEN to be injected at runtime via Buildkite
agent secrets); update the env block referencing QODANA_TOKEN (and keep
QODANA_ENDPOINT as-is) to apply the fix.

In @.buildkite/pipeline.release.yml:
- Around line 21-25: The pipeline currently assumes TAG is set and will run gh
release view/upload with an empty identifier; add a guard right after the
TAG="$$BUILDKITE_TAG" assignment to fail fast if TAG is empty (e.g., check [ -z
"$$TAG" ]) and exit with a non-zero status and clear error message, before any
usage of RELEASE_BODY or calls to gh release view / gh release upload so the
script never calls gh with an invalid release identifier.
- Around line 6-20: The Docker plugin block fails to pass GITHUB_TOKEN into the
container and the chosen image (gradle:8-jdk21) does not include the GitHub CLI,
causing gh commands to be missing or unauthenticated; update the docker plugin
configuration used in the pipeline (the docker#v5.12.0 plugin block) to add
GITHUB_TOKEN to the environment list and either switch the image to one that
bundles Gradle 8 + JDK 21 + gh or add an install step that installs GitHub CLI
(so gh is available) before any commands that call gh; ensure the environment
entry name exactly matches GITHUB_TOKEN and that subsequent commands rely on
that token for authentication.

In @.buildkite/pipeline.ui-tests.yml:
- Around line 18-28: The readiness loops currently fall through and always run
./gradlew test even when the IDE never becomes ready; introduce a READY guard:
initialize READY=false before each loop, set READY=true inside the curl success
branch (where it currently echoes "IDE is ready" and breaks), and after the loop
check READY and if still false exit with a non-zero status (e.g., exit 1) before
invoking ./gradlew test; apply this same READY pattern to the macOS and Windows
blocks that contain the for i in $(seq ...) / curl checks and the subsequent
./gradlew test invocation.

In @.buildkite/pipeline.yml:
- Around line 49-51: The current pipeline command uses "gh api
repos/{owner}/{repo}/releases" piped to "select(.draft == true) | .id" and xargs
DELETE which removes all draft releases; change it to only delete the draft
whose tag matches the release being regenerated (v$$VERSION) by filtering
releases for both .draft == true and .tag_name == "v$VERSION" before extracting
.id, and then DELETE only that ID (keep the same gh api ... DELETE flow but
narrow the jq filter to include tag_name == "v$VERSION" so unrelated drafts are
not removed).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ae5a57e4-9cd7-4c89-9ee7-61c322f262d9

📥 Commits

Reviewing files that changed from the base of the PR and between e0141bc and 22ae847.

📒 Files selected for processing (5)
  • .buildkite/pipeline.qodana.yml
  • .buildkite/pipeline.release.yml
  • .buildkite/pipeline.ui-tests.yml
  • .buildkite/pipeline.yml
  • gradle.properties

Comment on lines +10 to +12
env:
QODANA_TOKEN: $${QODANA_TOKEN?}
QODANA_ENDPOINT: "https://qodana.cloud"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Buildkite pipeline YAML env variable interpolation escaped dollar signs in env blocks

💡 Result:

In Buildkite pipeline YAML files, particularly when using buildkite-agent pipeline upload, environment variable interpolation occurs using $VAR or ${VAR} syntax. To prevent interpolation during upload (so the variable is evaluated at runtime instead), escape the dollar sign with $$ or $ in commands, env blocks, or other strings. Example from official docs: - command: "deploy.sh $$SERVER" env: SERVER: "server-a" Here, $$SERVER becomes $SERVER at runtime, allowing the job's environment to interpolate it. This applies to env blocks in steps. Top-level env in pipeline.yml sets variables for subsequent steps and is available for interpolation in further uploads. For literal dollars without interpolation, use $$ or $. Use --no-interpolation flag on pipeline upload to disable entirely (agent v3.1.1+). Sources confirm this behavior consistently across docs and GitHub issues.

Citations:


Do not escape QODANA_TOKEN with double dollar signs in the env: block.

Using $${QODANA_TOKEN?} prevents Buildkite's upload-time interpolation, leaving ${QODANA_TOKEN?} as a literal environment variable value that Docker receives instead of the actual token. Either use unescaped ${QODANA_TOKEN?} to interpolate the secret during pipeline upload, or configure the token to be injected at runtime through Buildkite's agent secrets mechanism.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.buildkite/pipeline.qodana.yml around lines 10 - 12, The pipeline currently
escapes QODANA_TOKEN as $${QODANA_TOKEN?} which prevents Buildkite from
interpolating the secret at upload time; change the env entry to use unescaped
${QODANA_TOKEN?} so Buildkite will substitute the actual token during pipeline
upload (or alternatively remove the env entry and configure QODANA_TOKEN to be
injected at runtime via Buildkite agent secrets); update the env block
referencing QODANA_TOKEN (and keep QODANA_ENDPOINT as-is) to apply the fix.

Comment on lines +16 to +18
CHANGED="$$(git diff --name-only HEAD~1 HEAD 2>/dev/null || git diff --name-only origin/main...HEAD)"
NON_DOC="$$(echo "$$CHANGED" | grep -vE '^(CHANGELOG|CONTRIBUTING|CODE_OF_CONDUCT|README)\.md$$' | grep -v '^img/')"
if [ -z "$$NON_DOC" ]; then
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Diff the full PR range before deciding to skip Qodana.

HEAD~1 HEAD only inspects the last commit, so a PR with source changes followed by a docs-only commit can incorrectly skip the scan. Also make the grep filter tolerant of “no non-doc files” under errexit.

Proposed fix
-        CHANGED="$$(git diff --name-only HEAD~1 HEAD 2>/dev/null || git diff --name-only origin/main...HEAD)"
-        NON_DOC="$$(echo "$$CHANGED" | grep -vE '^(CHANGELOG|CONTRIBUTING|CODE_OF_CONDUCT|README)\.md$$' | grep -v '^img/')"
+        if [ "$${BUILDKITE_PULL_REQUEST:-false}" != "false" ]; then
+          CHANGED="$$(git diff --name-only origin/main...HEAD)"
+        else
+          CHANGED="$$(git diff --name-only HEAD~1 HEAD 2>/dev/null || git diff --name-only origin/main...HEAD)"
+        fi
+        NON_DOC="$$(echo "$$CHANGED" | grep -vE '^(CHANGELOG|CONTRIBUTING|CODE_OF_CONDUCT|README)\.md$$' | grep -v '^img/' || true)"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.buildkite/pipeline.qodana.yml around lines 16 - 18, Update the CHANGED
assignment to diff the full PR range instead of only the last commit by using
git diff --name-only origin/main...HEAD (fetch origin/main first and fallback to
HEAD~1 HEAD only if necessary) and make the NON_DOC pipeline tolerant of no
matches by appending "|| true" to the grep commands; specifically modify the
CHANGED variable and the NON_DOC pipeline (the lines that set CHANGED and
NON_DOC) so CHANGED is populated from origin/main...HEAD and NON_DOC uses "grep
-vE '^(CHANGELOG|CONTRIBUTING|CODE_OF_CONDUCT|README)\.md$' | grep -v '^img/' ||
true" to avoid failing under errexit when there are no non-doc files, leaving
the subsequent if [ -z "$NON_DOC" ] check unchanged.

Comment on lines +6 to +20
env:
PUBLISH_TOKEN: $${PUBLISH_TOKEN?}
CERTIFICATE_CHAIN: $${CERTIFICATE_CHAIN?}
PRIVATE_KEY: $${PRIVATE_KEY?}
PRIVATE_KEY_PASSWORD: $${PRIVATE_KEY_PASSWORD?}
GITHUB_TOKEN: $${GITHUB_TOKEN?}
plugins:
- docker#v5.12.0:
image: "gradle:8-jdk21"
environment:
- PUBLISH_TOKEN
- CERTIFICATE_CHAIN
- PRIVATE_KEY
- PRIVATE_KEY_PASSWORD
commands:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Checks whether the release container image has GitHub CLI available.
docker run --rm --entrypoint sh gradle:8-jdk21 -lc 'command -v gh && gh --version'

Repository: z8dn/advanced-android-project-view

Length of output: 124


🏁 Script executed:

cat -n .buildkite/pipeline.release.yml

Repository: z8dn/advanced-android-project-view

Length of output: 2321


🏁 Script executed:

# Search for uses of gh command and GITHUB_TOKEN in the codebase
rg 'gh ' --type yaml
rg 'GITHUB_TOKEN' --type yaml

Repository: z8dn/advanced-android-project-view

Length of output: 60


🏁 Script executed:

# Check if there are other buildkite pipeline files or docs
fd 'pipeline' --type f

Repository: z8dn/advanced-android-project-view

Length of output: 60


🏁 Script executed:

# Look for Dockerfile, docker-compose, or other Docker configs
fd -e Dockerfile -e dockerfile
fd -e 'docker-compose*'

Repository: z8dn/advanced-android-project-view

Length of output: 60


🏁 Script executed:

# Check if there are any scripts that set up the environment
fd -e 'sh' -e 'bash' | head -20

Repository: z8dn/advanced-android-project-view

Length of output: 60


🏁 Script executed:

# Search for any setup steps or gh installation references
rg 'gh ' -A 2 -B 2 --type yaml --type sh
rg 'docker' .buildkite/ -i

Repository: z8dn/advanced-android-project-view

Length of output: 444


Add GITHUB_TOKEN to Docker container environment and ensure GitHub CLI is available in the release image.

The GITHUB_TOKEN variable is defined in env (line 11) but is not included in the Docker plugin's environment list (lines 15-19). The commands on lines 25, 36, 47, and 51 call gh (GitHub CLI), which neither exists in gradle:8-jdk21 nor will authenticate without the token. The release step will fail with "command not found" or authentication errors.

Add GITHUB_TOKEN to the Docker plugin environment and switch to an image that includes both Gradle 8, JDK 21, and GitHub CLI, or install gh in the container entrypoint.

Proposed fix
     plugins:
       - docker#v5.12.0:
-          image: "gradle:8-jdk21"
+          image: "<image-with-gradle-jdk21-and-gh>"
           environment:
             - PUBLISH_TOKEN
             - CERTIFICATE_CHAIN
             - PRIVATE_KEY
             - PRIVATE_KEY_PASSWORD
+            - GITHUB_TOKEN
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.buildkite/pipeline.release.yml around lines 6 - 20, The Docker plugin block
fails to pass GITHUB_TOKEN into the container and the chosen image
(gradle:8-jdk21) does not include the GitHub CLI, causing gh commands to be
missing or unauthenticated; update the docker plugin configuration used in the
pipeline (the docker#v5.12.0 plugin block) to add GITHUB_TOKEN to the
environment list and either switch the image to one that bundles Gradle 8 + JDK
21 + gh or add an install step that installs GitHub CLI (so gh is available)
before any commands that call gh; ensure the environment entry name exactly
matches GITHUB_TOKEN and that subsequent commands rely on that token for
authentication.

Comment on lines +21 to +25
- |
TAG="$$BUILDKITE_TAG"

if [ -z "$$RELEASE_BODY" ]; then
RELEASE_BODY="$$(gh release view "$$TAG" --json body -q '.body')"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fail fast when the release pipeline is not running for a tag.

TAG can be empty outside tag builds, which makes the following gh release view/upload calls operate with an invalid release identifier.

Proposed fix
-        TAG="$$BUILDKITE_TAG"
+        TAG="$${BUILDKITE_TAG:?Release pipeline must run on a tag build}"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- |
TAG="$$BUILDKITE_TAG"
if [ -z "$$RELEASE_BODY" ]; then
RELEASE_BODY="$$(gh release view "$$TAG" --json body -q '.body')"
- |
TAG="$${BUILDKITE_TAG:?Release pipeline must run on a tag build}"
if [ -z "$$RELEASE_BODY" ]; then
RELEASE_BODY="$$(gh release view "$$TAG" --json body -q '.body')"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.buildkite/pipeline.release.yml around lines 21 - 25, The pipeline currently
assumes TAG is set and will run gh release view/upload with an empty identifier;
add a guard right after the TAG="$$BUILDKITE_TAG" assignment to fail fast if TAG
is empty (e.g., check [ -z "$$TAG" ]) and exit with a non-zero status and clear
error message, before any usage of RELEASE_BODY or calls to gh release view / gh
release upload so the script never calls gh with an invalid release identifier.

Comment on lines +18 to +28
- |
# Wait for IDE to be ready (equivalent to url-health-check-action)
for i in $$(seq 1 15); do
if curl -sf http://127.0.0.1:8082 > /dev/null 2>&1; then
echo "IDE is ready"
break
fi
echo "Attempt $$i/15 — waiting 30s..."
sleep 30
done
- ./gradlew test
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fail the UI step when the IDE never becomes ready.

All three readiness loops fall through after 15 failed attempts and still run tests. Add an explicit timeout failure before invoking test.

Proposed fix
         # Wait for IDE to be ready (equivalent to url-health-check-action)
+        READY=0
         for i in $$(seq 1 15); do
           if curl -sf http://127.0.0.1:8082 > /dev/null 2>&1; then
             echo "IDE is ready"
+            READY=1
             break
           fi
           echo "Attempt $$i/15 — waiting 30s..."
           sleep 30
         done
+        if [ "$$READY" -ne 1 ]; then
+          echo "IDE did not become ready after 15 attempts"
+          exit 1
+        fi

Apply the same READY guard to the macOS block, and for Windows:

         for /L %%i in (1,1,15) do (
           curl -sf http://127.0.0.1:8082 >nul 2>&1 && (echo IDE is ready & goto :ready)
           echo Attempt %%i/15 - waiting 30s...
           timeout /t 30 /nobreak >nul
         )
+        echo IDE did not become ready after 15 attempts
+        exit /b 1
         :ready

Also applies to: 42-51, 65-72

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.buildkite/pipeline.ui-tests.yml around lines 18 - 28, The readiness loops
currently fall through and always run ./gradlew test even when the IDE never
becomes ready; introduce a READY guard: initialize READY=false before each loop,
set READY=true inside the curl success branch (where it currently echoes "IDE is
ready" and breaks), and after the loop check READY and if still false exit with
a non-zero status (e.g., exit 1) before invoking ./gradlew test; apply this same
READY pattern to the macOS and Windows blocks that contain the for i in $(seq
...) / curl checks and the subsequent ./gradlew test invocation.

Comment thread .buildkite/pipeline.yml
Comment on lines +49 to +51
gh api repos/{owner}/{repo}/releases \
--jq '.[] | select(.draft == true) | .id' \
| xargs -I '{}' gh api -X DELETE repos/{owner}/{repo}/releases/{}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Lists the draft releases the current command would delete.
gh api repos/{owner}/{repo}/releases \
  --jq '.[] | select(.draft == true) | [.id, .tag_name, .name] | `@tsv`'

Repository: z8dn/advanced-android-project-view

Length of output: 101


🏁 Script executed:

cat -n .buildkite/pipeline.yml | sed -n '40,60p'

Repository: z8dn/advanced-android-project-view

Length of output: 822


Limit draft deletion to the release tag being regenerated.

This deletes every draft release in the repository (line 49-51) before creating v$$VERSION. Any other manual draft releases in the repository would be silently removed, causing data loss. This is particularly risky in CI where it could destroy unrelated draft releases created by other processes or developers.

Safer tag-scoped deletion
-        gh api repos/{owner}/{repo}/releases \
-          --jq '.[] | select(.draft == true) | .id' \
-          | xargs -I '{}' gh api -X DELETE repos/{owner}/{repo}/releases/{}
+        DRAFT_ID="$$(gh api repos/{owner}/{repo}/releases \
+          --jq ".[] | select(.draft == true and .tag_name == \"v$$VERSION\") | .id")"
+        if [ -n "$$DRAFT_ID" ]; then
+          gh api -X DELETE "repos/{owner}/{repo}/releases/$$DRAFT_ID"
+        fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
gh api repos/{owner}/{repo}/releases \
--jq '.[] | select(.draft == true) | .id' \
| xargs -I '{}' gh api -X DELETE repos/{owner}/{repo}/releases/{}
DRAFT_ID="$$(gh api repos/{owner}/{repo}/releases \
--jq ".[] | select(.draft == true and .tag_name == \"v$$VERSION\") | .id")"
if [ -n "$$DRAFT_ID" ]; then
gh api -X DELETE "repos/{owner}/{repo}/releases/$$DRAFT_ID"
fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.buildkite/pipeline.yml around lines 49 - 51, The current pipeline command
uses "gh api repos/{owner}/{repo}/releases" piped to "select(.draft == true) |
.id" and xargs DELETE which removes all draft releases; change it to only delete
the draft whose tag matches the release being regenerated (v$$VERSION) by
filtering releases for both .draft == true and .tag_name == "v$VERSION" before
extracting .id, and then DELETE only that ID (keep the same gh api ... DELETE
flow but narrow the jq filter to include tag_name == "v$VERSION" so unrelated
drafts are not removed).

z8dn and others added 9 commits April 19, 2026 23:53
Adds four Buildkite pipeline files under .buildkite/ that replace the
existing GitHub Actions workflows:

- pipeline.yml         → build.yml (build, test, verify, release draft)
- pipeline.release.yml → release.yml (publish to JetBrains Marketplace)
- pipeline.ui-tests.yml→ run-ui-tests.yml (manual UI test matrix)
- pipeline.qodana.yml  → qodana_code_quality.yml (code quality scan)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove the hardcoded /usr/lib/jvm/zulu-21-amd64 JAVA_HOME from all steps
in pipeline.yml and pipeline.release.yml — the path didn't exist on the
agent. Java is available via PATH; let the agent environment handle it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Buildkite agents have no Java pre-installed. Switch all Gradle steps
to run inside the official gradle:8.13-jdk21 Docker image via the
docker#v5.11.0 plugin, with a shared Gradle cache mounted at /tmp/.gradle.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Gradle daemon was OOM-killed during buildSearchableOptions. Switch all
Gradle invocations to --no-daemon --max-workers=2 to stay within agent
memory limits. Also remove the now-unused GRADLE_OPTS env from the Docker
plugin config since it was redundant with the CLI flags.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use gradle command directly (not ./gradlew), docker#v3.5.0 plugin, and
gradle:8-jdk21 image — matching the pattern from the Buildkite template
at https://buildkite.com/organizations/zayden-fung/pipelines/new?tid=kotlin-gradle

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This task starts a full IntelliJ IDE process to build plugin marketplace
search indexes. It's not needed for build correctness and consistently
OOM-kills the Gradle daemon on standard CI agents.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fixes "plugin docker-buildkite-plugin command hook exited with status 1"
error caused by outdated plugin version.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@z8dn z8dn force-pushed the migrate-to-buildkite branch from 22ae847 to 3b86d09 Compare April 19, 2026 16:54
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (6)
.buildkite/pipeline.yml (1)

49-51: ⚠️ Potential issue | 🔴 Critical

Limit draft deletion to the release tag being regenerated.

This still deletes every draft release in the repository before creating v$$VERSION. Filter by both draft == true and tag_name == "v$$VERSION" so unrelated drafts are not removed.

Safer tag-scoped deletion
         gh api repos/{owner}/{repo}/releases \
-          --jq '.[] | select(.draft == true) | .id' \
-          | xargs -I '{}' gh api -X DELETE repos/{owner}/{repo}/releases/{}
+          --jq ".[] | select(.draft == true and .tag_name == \"v$$VERSION\") | .id" \
+          | xargs -r -I '{}' gh api -X DELETE repos/{owner}/{repo}/releases/{}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.buildkite/pipeline.yml around lines 49 - 51, The current pipeline command
deletes all draft releases; change the jq filter used against gh api
repos/{owner}/{repo}/releases to select only items where .draft == true AND
.tag_name == "v$$VERSION" (i.e., use a combined predicate like .[] |
select(.draft == true and .tag_name == "v$$VERSION") | .id) so that the xargs
deletion that calls gh api -X DELETE repos/{owner}/{repo}/releases/{} only
removes the draft release matching the tag being regenerated.
.buildkite/pipeline.qodana.yml (2)

10-12: ⚠️ Potential issue | 🟠 Major

Do not escape QODANA_TOKEN in the env: assignment.

$${QODANA_TOKEN?} can leave ${QODANA_TOKEN?} as the literal value passed to Docker instead of requiring/injecting the actual token. Use upload-time ${QODANA_TOKEN?} or remove this assignment and inject the secret through Buildkite agent secrets. Buildkite interpolation docs: https://buildkite.com/docs/agent/cli/reference/pipeline

Proposed fix
     env:
-      QODANA_TOKEN: $${QODANA_TOKEN?}
+      QODANA_TOKEN: ${QODANA_TOKEN?}
       QODANA_ENDPOINT: "https://qodana.cloud"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.buildkite/pipeline.qodana.yml around lines 10 - 12, The env assignment for
QODANA_TOKEN currently uses an extra escape ($${QODANA_TOKEN?}) which can pass
the literal string into Docker; change the value to use Buildkite interpolation
${QODANA_TOKEN?} (no extra $) so the secret is injected at upload time, or
remove the QODANA_TOKEN env line entirely and inject the secret via Buildkite
agent secrets; update the env key named QODANA_TOKEN accordingly in the pipeline
configuration.

16-18: ⚠️ Potential issue | 🟠 Major

Diff the full PR range before deciding to skip Qodana.

HEAD~1 HEAD only checks the last commit, so a PR with source changes followed by a docs-only commit can incorrectly skip the scan. Also make the non-doc filter safe when no files remain after filtering.

Proposed fix
-        CHANGED="$$(git diff --name-only HEAD~1 HEAD 2>/dev/null || git diff --name-only origin/main...HEAD)"
-        NON_DOC="$$(echo "$$CHANGED" | grep -vE '^(CHANGELOG|CONTRIBUTING|CODE_OF_CONDUCT|README)\.md$$' | grep -v '^img/')"
+        git fetch origin main --depth=1
+        if [ "$${BUILDKITE_PULL_REQUEST:-false}" != "false" ]; then
+          CHANGED="$$(git diff --name-only origin/main...HEAD)"
+        else
+          CHANGED="$$(git diff --name-only HEAD~1 HEAD 2>/dev/null || git diff --name-only origin/main...HEAD)"
+        fi
+        NON_DOC="$$(echo "$$CHANGED" | grep -vE '^(CHANGELOG|CONTRIBUTING|CODE_OF_CONDUCT|README)\.md$$' | grep -v '^img/' || true)"
         if [ -z "$$NON_DOC" ]; then
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.buildkite/pipeline.qodana.yml around lines 16 - 18, The current CHANGED
calculation only diffs the last commit (git diff --name-only HEAD~1 HEAD) which
misses earlier PR commits, and NON_DOC can fail if grep returns no matches;
update CHANGED to prefer the full PR range (e.g., CHANGED="$(git diff
--name-only origin/main...HEAD 2>/dev/null || git diff --name-only HEAD~1 HEAD
2>/dev/null)") and make NON_DOC resilient by capturing the filtered output with
a fallback so grep exit status doesn't break the script (e.g., NON_DOC="$(echo
"$CHANGED" | grep -vE '^(CHANGELOG|CONTRIBUTING|CODE_OF_CONDUCT|README)\.md$' |
grep -v '^img/' || true)"), then keep the same check if [ -z "$NON_DOC" ] to
decide skipping Qodana.
.buildkite/pipeline.release.yml (2)

21-25: ⚠️ Potential issue | 🟠 Major

Fail fast when the release pipeline is not running for a tag.

TAG can be empty outside tag builds, causing gh release view/upload to run with an invalid release identifier.

Proposed fix
-        TAG="$$BUILDKITE_TAG"
+        TAG="$${BUILDKITE_TAG:?Release pipeline must run on a tag build}"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.buildkite/pipeline.release.yml around lines 21 - 25, The pipeline uses TAG
(set via TAG="$$BUILDKITE_TAG") which can be empty for non-tag builds, causing
subsequent gh release view/upload calls to run with an invalid identifier; add
an early validation after TAG is set to check if TAG is empty and if so print an
error and exit non-zero, and apply the same guard before any gh release view or
gh release upload usage (refer to the TAG and RELEASE_BODY variables and the gh
release view/upload commands) so the job fails fast when not running for a tag.

6-20: ⚠️ Potential issue | 🔴 Critical

Fix secret interpolation, pass GITHUB_TOKEN, and use the project Gradle version.

The Docker step calls gh, but GITHUB_TOKEN is not forwarded into the container and the gradle:8-jdk21 image may not include GitHub CLI. It also bypasses the project wrapper (gradle-wrapper.properties uses Gradle 9.4.1) and the escaped env: assignments can become literal placeholder values. Use runtime secret injection or unescaped required variables, forward GITHUB_TOKEN, and align the container/wrapper/tooling. Buildkite Docker plugin env docs: https://buildkite.com/resources/plugins/buildkite-plugins/docker-buildkite-plugin/

Proposed fix direction
     env:
-      PUBLISH_TOKEN: $${PUBLISH_TOKEN?}
-      CERTIFICATE_CHAIN: $${CERTIFICATE_CHAIN?}
-      PRIVATE_KEY: $${PRIVATE_KEY?}
-      PRIVATE_KEY_PASSWORD: $${PRIVATE_KEY_PASSWORD?}
-      GITHUB_TOKEN: $${GITHUB_TOKEN?}
+      PUBLISH_TOKEN: ${PUBLISH_TOKEN?}
+      CERTIFICATE_CHAIN: ${CERTIFICATE_CHAIN?}
+      PRIVATE_KEY: ${PRIVATE_KEY?}
+      PRIVATE_KEY_PASSWORD: ${PRIVATE_KEY_PASSWORD?}
+      GITHUB_TOKEN: ${GITHUB_TOKEN?}
     plugins:
       - docker#v5.12.0:
-          image: "gradle:8-jdk21"
+          image: "<image-with-jdk21-gradle9-and-gh>"
           environment:
             - PUBLISH_TOKEN
             - CERTIFICATE_CHAIN
             - PRIVATE_KEY
             - PRIVATE_KEY_PASSWORD
+            - GITHUB_TOKEN

Verify the final image includes gh, or install it before the first gh command.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.buildkite/pipeline.release.yml around lines 6 - 20, The pipeline is not
forwarding GITHUB_TOKEN into the Docker container, is using escaped env
placeholders ($${...}) that may become literal, and uses a base image
(gradle:8-jdk21) that mismatches the project's Gradle version and may lack the
GitHub CLI; update the Docker plugin block to pass unescaped required env vars
(PUBLISH_TOKEN, CERTIFICATE_CHAIN, PRIVATE_KEY, PRIVATE_KEY_PASSWORD,
GITHUB_TOKEN) so they are injected at runtime, ensure the container either
matches the project's Gradle version or (preferably) use the project Gradle
wrapper (invoke ./gradlew instead of gradle) to align tooling, and
verify/install the gh CLI in the image before any gh commands run (or switch to
an image that already includes gh).
.buildkite/pipeline.ui-tests.yml (1)

18-28: ⚠️ Potential issue | 🟠 Major

Fail the UI step when the IDE never becomes ready.

All three readiness loops still fall through after 15 failed attempts and then run tests. Add an explicit timeout failure before invoking the test command.

Proposed fix
         # Wait for IDE to be ready (equivalent to url-health-check-action)
+        READY=0
         for i in $$(seq 1 15); do
           if curl -sf http://127.0.0.1:8082 > /dev/null 2>&1; then
             echo "IDE is ready"
+            READY=1
             break
           fi
           echo "Attempt $$i/15 — waiting 30s..."
           sleep 30
         done
+        if [ "$$READY" -ne 1 ]; then
+          echo "IDE did not become ready after 15 attempts"
+          exit 1
+        fi

Apply the same guard to macOS. For Windows:

         for /L %%i in (1,1,15) do (
           curl -sf http://127.0.0.1:8082 >nul 2>&1 && (echo IDE is ready & goto :ready)
           echo Attempt %%i/15 - waiting 30s...
           timeout /t 30 /nobreak >nul
         )
+        echo IDE did not become ready after 15 attempts
+        exit /b 1
         :ready

Also applies to: 42-51, 65-72

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.buildkite/pipeline.ui-tests.yml around lines 18 - 28, The readiness loop
that checks the IDE (the for loop that curls http://127.0.0.1:8082 and then
proceeds to run ./gradlew test) currently falls through after 15 failed
attempts; modify the loop logic in the pipeline UI test steps so that if the
loop never succeeds you exit with a non-zero status (e.g., set a failure flag or
test for success after the loop and call exit 1) before invoking ./gradlew test;
apply the same change to the equivalent macOS and Windows readiness blocks
referenced in the diff so the job fails fast when the IDE never becomes ready.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.buildkite/pipeline.release.yml:
- Around line 30-36: The pipeline invokes the container's Gradle binary which
can mismatch the repo wrapper; update the two Gradle invocations to use the
checked-in wrapper by replacing the command strings that call "gradle
patchChangelog --release-note=..." and "gradle publishPlugin" with "./gradlew
patchChangelog --release-note=..." and "./gradlew publishPlugin" respectively so
the release job runs with the pinned Gradle wrapper version.

In @.buildkite/pipeline.yml:
- Around line 41-47: The pipeline uses the system gradle binary but runs on the
default agent without Gradle; update the shell commands that call gradle (the
ones that populate PROPERTIES, VERSION, and CHANGELOG) to invoke the repository
Gradle wrapper instead by replacing calls to "gradle" with "./gradlew" so the
commands use ./gradlew properties and ./gradlew getChangelog.

In `@build.gradle.kts`:
- Around line 118-120: Remove the JVM option from pluginVerification.freeArgs
(it is passed to the Plugin Verifier CLI, not the JVM); delete "-Xmx1g" from
pluginVerification.freeArgs and instead configure JVM heap for the verifier
either by setting jvmArgs on the verifyPlugin task (e.g., configure the
verifyPlugin task's jvmArgs = listOf("-Xmx1g")) or rely on org.gradle.jvmargs in
gradle.properties (currently set to -Xmx2048m); update or add the verifyPlugin
task configuration accordingly and ensure pluginVerification.freeArgs only
contains CLI arguments, not JVM flags.

---

Duplicate comments:
In @.buildkite/pipeline.qodana.yml:
- Around line 10-12: The env assignment for QODANA_TOKEN currently uses an extra
escape ($${QODANA_TOKEN?}) which can pass the literal string into Docker; change
the value to use Buildkite interpolation ${QODANA_TOKEN?} (no extra $) so the
secret is injected at upload time, or remove the QODANA_TOKEN env line entirely
and inject the secret via Buildkite agent secrets; update the env key named
QODANA_TOKEN accordingly in the pipeline configuration.
- Around line 16-18: The current CHANGED calculation only diffs the last commit
(git diff --name-only HEAD~1 HEAD) which misses earlier PR commits, and NON_DOC
can fail if grep returns no matches; update CHANGED to prefer the full PR range
(e.g., CHANGED="$(git diff --name-only origin/main...HEAD 2>/dev/null || git
diff --name-only HEAD~1 HEAD 2>/dev/null)") and make NON_DOC resilient by
capturing the filtered output with a fallback so grep exit status doesn't break
the script (e.g., NON_DOC="$(echo "$CHANGED" | grep -vE
'^(CHANGELOG|CONTRIBUTING|CODE_OF_CONDUCT|README)\.md$' | grep -v '^img/' ||
true)"), then keep the same check if [ -z "$NON_DOC" ] to decide skipping
Qodana.

In @.buildkite/pipeline.release.yml:
- Around line 21-25: The pipeline uses TAG (set via TAG="$$BUILDKITE_TAG") which
can be empty for non-tag builds, causing subsequent gh release view/upload calls
to run with an invalid identifier; add an early validation after TAG is set to
check if TAG is empty and if so print an error and exit non-zero, and apply the
same guard before any gh release view or gh release upload usage (refer to the
TAG and RELEASE_BODY variables and the gh release view/upload commands) so the
job fails fast when not running for a tag.
- Around line 6-20: The pipeline is not forwarding GITHUB_TOKEN into the Docker
container, is using escaped env placeholders ($${...}) that may become literal,
and uses a base image (gradle:8-jdk21) that mismatches the project's Gradle
version and may lack the GitHub CLI; update the Docker plugin block to pass
unescaped required env vars (PUBLISH_TOKEN, CERTIFICATE_CHAIN, PRIVATE_KEY,
PRIVATE_KEY_PASSWORD, GITHUB_TOKEN) so they are injected at runtime, ensure the
container either matches the project's Gradle version or (preferably) use the
project Gradle wrapper (invoke ./gradlew instead of gradle) to align tooling,
and verify/install the gh CLI in the image before any gh commands run (or switch
to an image that already includes gh).

In @.buildkite/pipeline.ui-tests.yml:
- Around line 18-28: The readiness loop that checks the IDE (the for loop that
curls http://127.0.0.1:8082 and then proceeds to run ./gradlew test) currently
falls through after 15 failed attempts; modify the loop logic in the pipeline UI
test steps so that if the loop never succeeds you exit with a non-zero status
(e.g., set a failure flag or test for success after the loop and call exit 1)
before invoking ./gradlew test; apply the same change to the equivalent macOS
and Windows readiness blocks referenced in the diff so the job fails fast when
the IDE never becomes ready.

In @.buildkite/pipeline.yml:
- Around line 49-51: The current pipeline command deletes all draft releases;
change the jq filter used against gh api repos/{owner}/{repo}/releases to select
only items where .draft == true AND .tag_name == "v$$VERSION" (i.e., use a
combined predicate like .[] | select(.draft == true and .tag_name ==
"v$$VERSION") | .id) so that the xargs deletion that calls gh api -X DELETE
repos/{owner}/{repo}/releases/{} only removes the draft release matching the tag
being regenerated.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: fda73180-9117-4cac-8118-b8b9ecbb9ae2

📥 Commits

Reviewing files that changed from the base of the PR and between 22ae847 and 0f11d0b.

📒 Files selected for processing (6)
  • .buildkite/pipeline.qodana.yml
  • .buildkite/pipeline.release.yml
  • .buildkite/pipeline.ui-tests.yml
  • .buildkite/pipeline.yml
  • build.gradle.kts
  • gradle.properties

Comment on lines +30 to +36
if [ -n "$$CHANGELOG" ]; then
gradle patchChangelog --release-note="$$CHANGELOG"
fi

gradle publishPlugin

gh release upload "$$TAG" ./build/distributions/*
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify release pipeline Gradle invocations against the wrapper version.
set -euo pipefail

echo "Wrapper Gradle distribution:"
fd -a 'gradle-wrapper.properties' . | xargs -r sed -n '1,20p'

echo
echo "Buildkite Gradle invocations:"
rg -n -C2 '\bgradle\b|\.\/gradlew|gradlew\.bat' --glob '.buildkite/*.yml'

Repository: z8dn/advanced-android-project-view

Length of output: 521


🏁 Script executed:

#!/bin/bash
# Fix: Use proper escaping for rg regex pattern
set -euo pipefail

echo "Checking .buildkite/pipeline.release.yml around lines 30-36:"
head -40 .buildkite/pipeline.release.yml | tail -15

echo
echo "Searching for gradle invocations in .buildkite/ directory:"
rg 'gradle|gradlew' '.buildkite/' -n

Repository: z8dn/advanced-android-project-view

Length of output: 1860


Use ./gradlew so release uses the checked-in wrapper.

The release pipeline currently runs gradle from the container image (gradle:8-jdk21), while the repository wrapper is pinned to Gradle 9.4.1. This version mismatch can cause release-only Gradle behavior to diverge from the main build.

Lines 31 and 34 in .buildkite/pipeline.release.yml need to be updated to use ./gradlew:

  • Line 31: gradle patchChangelog./gradlew patchChangelog
  • Line 34: gradle publishPlugin./gradlew publishPlugin
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.buildkite/pipeline.release.yml around lines 30 - 36, The pipeline invokes
the container's Gradle binary which can mismatch the repo wrapper; update the
two Gradle invocations to use the checked-in wrapper by replacing the command
strings that call "gradle patchChangelog --release-note=..." and "gradle
publishPlugin" with "./gradlew patchChangelog --release-note=..." and "./gradlew
publishPlugin" respectively so the release job runs with the pinned Gradle
wrapper version.

Comment thread .buildkite/pipeline.yml
Comment on lines +41 to +47
env:
GITHUB_TOKEN: $${GITHUB_TOKEN?}
commands:
- |
PROPERTIES="$$(gradle properties --console=plain -q)"
VERSION="$$(echo "$$PROPERTIES" | grep "^version:" | cut -f2- -d ' ')"
CHANGELOG="$$(gradle getChangelog --unreleased --no-header --console=plain -q)"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .buildkite/pipeline.yml

Repository: z8dn/advanced-android-project-view

Length of output: 2177


🏁 Script executed:

fd -type f gradle-wrapper

Repository: z8dn/advanced-android-project-view

Length of output: 248


🌐 Web query:

Buildkite YAML env block $$ escaping interpolation environment variables

💡 Result:

In Buildkite pipeline YAML, particularly within env blocks, use $$ to escape the $ character for runtime environment variable interpolation. This prevents premature substitution during pipeline upload and allows the variable to be evaluated when the agent runs the step. For example: - command: "deploy.sh $$SERVER" env: SERVER: "server-a" Here, $$SERVER becomes $SERVER at runtime, so the shell expands SERVER. Both $$ and $ work for escaping. This applies to commands, triggers, and env values needing runtime evaluation. Official docs confirm: escape $ with $$ or $ for runtime vars (sources 3,5,8,9). Pipeline upload interpolates ${VAR} immediately unless escaped (source 5). For secrets, $$ also prevents exposure during upload (source 10).

Citations:


🏁 Script executed:

find . -name "gradlew*" -o -name "gradle-wrapper*" 2>/dev/null

Repository: z8dn/advanced-android-project-view

Length of output: 180


🏁 Script executed:

git ls-files | grep -i gradle

Repository: z8dn/advanced-android-project-view

Length of output: 363


Use ./gradlew instead of gradle on the default agent.

This step runs on the default agent (line 40: queue: default), not the Gradle Docker image. The gradle commands on lines 45 and 47 will fail if the agent does not have Gradle installed. The repository includes a Gradle wrapper (./gradlew), which should be used instead.

The GITHUB_TOKEN escaping at line 42 is already correct: $${GITHUB_TOKEN?} uses double-$ to prevent substitution during pipeline upload and allow runtime shell evaluation. Do not change this.

Proposed fix
     env:
       GITHUB_TOKEN: $${GITHUB_TOKEN?}
     commands:
       - |
-        PROPERTIES="$$(gradle properties --console=plain -q)"
+        PROPERTIES="$$(./gradlew properties --console=plain -q)"
          VERSION="$$(echo "$$PROPERTIES" | grep "^version:" | cut -f2- -d ' ')"
-        CHANGELOG="$$(gradle getChangelog --unreleased --no-header --console=plain -q)"
+        CHANGELOG="$$(./gradlew getChangelog --unreleased --no-header --console=plain -q)"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
env:
GITHUB_TOKEN: $${GITHUB_TOKEN?}
commands:
- |
PROPERTIES="$$(gradle properties --console=plain -q)"
VERSION="$$(echo "$$PROPERTIES" | grep "^version:" | cut -f2- -d ' ')"
CHANGELOG="$$(gradle getChangelog --unreleased --no-header --console=plain -q)"
env:
GITHUB_TOKEN: $${GITHUB_TOKEN?}
commands:
- |
PROPERTIES="$$(./gradlew properties --console=plain -q)"
VERSION="$$(echo "$$PROPERTIES" | grep "^version:" | cut -f2- -d ' ')"
CHANGELOG="$$(./gradlew getChangelog --unreleased --no-header --console=plain -q)"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.buildkite/pipeline.yml around lines 41 - 47, The pipeline uses the system
gradle binary but runs on the default agent without Gradle; update the shell
commands that call gradle (the ones that populate PROPERTIES, VERSION, and
CHANGELOG) to invoke the repository Gradle wrapper instead by replacing calls to
"gradle" with "./gradlew" so the commands use ./gradlew properties and ./gradlew
getChangelog.

Comment thread build.gradle.kts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant