Migrate CI from GitHub Actions to Buildkite#48
Conversation
|
Warning Rate limit exceeded
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 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 configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds 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
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Qodana for JVMIt seems all right 👌 No new problems were found according to the checks applied ☁️ View the detailed Qodana report Contact Qodana teamContact us at qodana-support@jetbrains.com
|
There was a problem hiding this comment.
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
📒 Files selected for processing (5)
.buildkite/pipeline.qodana.yml.buildkite/pipeline.release.yml.buildkite/pipeline.ui-tests.yml.buildkite/pipeline.ymlgradle.properties
| env: | ||
| QODANA_TOKEN: $${QODANA_TOKEN?} | ||
| QODANA_ENDPOINT: "https://qodana.cloud" |
There was a problem hiding this comment.
🧩 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
Citations:
- 1: https://buildkite.com/docs/pipelines/configure/environment-variables
- 2: https://buildkite.com/docs/pipelines/environment-variables
- 3: https://buildkite.com/docs/guides/environment-variables
- 4: https://buildkite.com/docs/agent/cli/reference/pipeline
- 5: https://www.buildkite.com/docs/pipelines/security/secrets/risk-considerations
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.
| 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 |
There was a problem hiding this comment.
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.
| 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: |
There was a problem hiding this comment.
🧩 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.ymlRepository: 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 yamlRepository: z8dn/advanced-android-project-view
Length of output: 60
🏁 Script executed:
# Check if there are other buildkite pipeline files or docs
fd 'pipeline' --type fRepository: 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 -20Repository: 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/ -iRepository: 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.
| - | | ||
| TAG="$$BUILDKITE_TAG" | ||
|
|
||
| if [ -z "$$RELEASE_BODY" ]; then | ||
| RELEASE_BODY="$$(gh release view "$$TAG" --json body -q '.body')" |
There was a problem hiding this comment.
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.
| - | | |
| 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.
| - | | ||
| # 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 |
There was a problem hiding this comment.
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
+ fiApply 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
:readyAlso 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.
| gh api repos/{owner}/{repo}/releases \ | ||
| --jq '.[] | select(.draft == true) | .id' \ | ||
| | xargs -I '{}' gh api -X DELETE repos/{owner}/{repo}/releases/{} |
There was a problem hiding this comment.
🧩 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.
| 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).
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>
22ae847 to
3b86d09
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (6)
.buildkite/pipeline.yml (1)
49-51:⚠️ Potential issue | 🔴 CriticalLimit draft deletion to the release tag being regenerated.
This still deletes every draft release in the repository before creating
v$$VERSION. Filter by bothdraft == trueandtag_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 | 🟠 MajorDo not escape
QODANA_TOKENin theenv: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/pipelineProposed 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 | 🟠 MajorDiff the full PR range before deciding to skip Qodana.
HEAD~1 HEADonly 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 | 🟠 MajorFail fast when the release pipeline is not running for a tag.
TAGcan be empty outside tag builds, causinggh release view/uploadto 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 | 🔴 CriticalFix secret interpolation, pass
GITHUB_TOKEN, and use the project Gradle version.The Docker step calls
gh, butGITHUB_TOKENis not forwarded into the container and thegradle:8-jdk21image may not include GitHub CLI. It also bypasses the project wrapper (gradle-wrapper.propertiesuses Gradle 9.4.1) and the escapedenv:assignments can become literal placeholder values. Use runtime secret injection or unescaped required variables, forwardGITHUB_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_TOKENVerify the final image includes
gh, or install it before the firstghcommand.🤖 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 | 🟠 MajorFail 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 + fiApply 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 :readyAlso 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
📒 Files selected for processing (6)
.buildkite/pipeline.qodana.yml.buildkite/pipeline.release.yml.buildkite/pipeline.ui-tests.yml.buildkite/pipeline.ymlbuild.gradle.ktsgradle.properties
| if [ -n "$$CHANGELOG" ]; then | ||
| gradle patchChangelog --release-note="$$CHANGELOG" | ||
| fi | ||
|
|
||
| gradle publishPlugin | ||
|
|
||
| gh release upload "$$TAG" ./build/distributions/* |
There was a problem hiding this comment.
🧩 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/' -nRepository: 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.
| 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)" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .buildkite/pipeline.ymlRepository: z8dn/advanced-android-project-view
Length of output: 2177
🏁 Script executed:
fd -type f gradle-wrapperRepository: 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
Citations:
- 1: https://buildkite.com/docs/pipelines/configure/environment-variables
- 2: https://buildkite.com/docs/agent/cli/reference/pipeline
- 3: https://buildkite.com/docs/pipelines/environment-variables
- 4: https://buildkite.com/docs/guides/environment-variables
- 5: https://buildkite.com/docs/pipelines/security/secrets/risk-considerations
🏁 Script executed:
find . -name "gradlew*" -o -name "gradle-wrapper*" 2>/dev/nullRepository: z8dn/advanced-android-project-view
Length of output: 180
🏁 Script executed:
git ls-files | grep -i gradleRepository: 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.
| 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.
Summary
.buildkite/pipeline.yml— main CI pipeline (build → test + verify in parallel → release draft onmain).buildkite/pipeline.release.yml— publishes plugin to JetBrains Marketplace on tag push, opens changelog PR.buildkite/pipeline.ui-tests.yml— manual UI test matrix across Linux, macOS, and Windows agents.buildkite/pipeline.qodana.yml— Qodana code quality scan, skips doc-only changesThe 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
actions/upload-artifactartifact_paths:${{ steps.x.outputs.y }}buildkite-agent meta-data set/getneeds:depends_on:branches: [main]branches: "main"on stepsecrets.*Required secrets to configure in Buildkite:
GITHUB_TOKEN— release draft + changelog PRPUBLISH_TOKEN,CERTIFICATE_CHAIN,PRIVATE_KEY,PRIVATE_KEY_PASSWORD— JetBrains Marketplace publishQODANA_TOKEN— Qodana scanAgent requirements: Java 21 (Zulu) pre-installed; adjust
JAVA_HOMEpaths in each pipeline to match your agent OS images. Windows UI test step usesgradlew.batandcmdsyntax.Test plan
pipeline.ymlon a test branch push and verify build/test/verify steps all passmainpipeline.ui-tests.ymland verify IDE health check passes on at least Linuxpipeline.qodana.ymlskips correctly when only doc files are changedpipeline.release.ymlon a test tag and confirm Marketplace publish + changelog PR creation🤖 Generated with Claude Code
Summary by CodeRabbit