Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .buildkite/claude-analysis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/buildkite/pipeline-schema/main/schema.json
---

# This pipeline is dynamically uploaded at the end of the build after a wait step

agents:
queue: default

steps:
- label: ":claude: Claude Build Analysis"
key: claude-analysis
if: build.state == "failing"
soft_fail: true
command: "exit 1"
artifact_paths:
- "/tmp/claude_debug_${BUILDKITE_BUILD_ID}.txt"
- "/tmp/claude_response_${BUILDKITE_BUILD_ID}.json"
- "/tmp/buildkite_logs_${BUILDKITE_BUILD_ID}.txt"
plugins:
- $CLAUDE_PLUGIN:
api_key: "$ANTHROPIC_API_KEY"
buildkite_api_token: "$BUILDKITE_TOKEN_FOR_CLAUDE"
analysis_level: "build"
build_log_mode: "failed"
trigger: "on-failure"
max_log_lines: 1500
custom_prompt: "Do not mention successful points, focus on failures and recovery to keep the analysis succinct. Only add the `Best Practices` section if the changes in this PR are directly relevant to it. Only add a `Root Cause` section when you're sure about the issues' causes."
model: "claude-sonnet-4-5"

- label: ":claude: 💬 Comment Claude Analysis"
command: .buildkite/commands/comment-claude-analysis.sh
depends_on: claude-analysis
allow_dependency_failure: true
if: build.pull_request.id != null
plugins:
- $CI_TOOLKIT_PLUGIN

15 changes: 15 additions & 0 deletions .buildkite/commands/comment-claude-analysis.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash -eu

# The claude-analysis step only runs when there are build failures,
# so if it ran (and soft_failed), it means there were failures that Claude analyzed.
CLAUDE_OUTCOME=$(buildkite-agent step get outcome --step claude-analysis 2>/dev/null || echo "not_run")

if [[ "${CLAUDE_OUTCOME}" == "soft_failed" ]]; then
comment_on_pr --id claude-build-analysis "## 🤖 Build Failure Analysis

This build has failures. Claude has analyzed them - <a href=\"${BUILDKITE_BUILD_URL}/annotations\" target=\"_blank\">check the build annotations</a> for details."
else
# Remove the comment if the build is now passing (claude-analysis did not run)
comment_on_pr --id claude-build-analysis --if-exist delete
fi

45 changes: 32 additions & 13 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ steps:
depends_on: ~

- label: ":eyeglasses: Reader one-off TestFlight Upload"
key: testflight_upload_reader
depends_on: [build_asc_reader, testflight_triggered_reader]
command: |
if .buildkite/commands/should-skip-job.sh --job-type build; then
Expand All @@ -53,6 +54,7 @@ steps:
# Create Prototype Builds for WP and JP
#################
- group: "🛠 Prototype Builds"
key: prototype_builds_group
steps:
- label: "🛠 WordPress Prototype Build"
command: ".buildkite/commands/prototype-build-wordpress.sh"
Expand Down Expand Up @@ -95,6 +97,7 @@ steps:
# Run Unit Tests
#################
- group: "🔬 Unit Tests"
key: unit_tests_group
steps:
- label: "🔬 :wordpress: Unit Tests"
command: ".buildkite/commands/run-unit-tests.sh"
Expand All @@ -113,19 +116,15 @@ steps:
notify:
- github_commit_status:
context: "Reader Unit Tests"
- label: "🔬 Keystone Unit Tests"
command: .buildkite/commands/run-unit-tests-for-scheme.sh Keystone
# Disabled till https://github.com/wordpress-mobile/WordPress-iOS/pull/24537 is completed
#
# The boolean value has to be a string explicitly.
# See validation error against schema.
if: "false"
plugins: [$CI_TOOLKIT_PLUGIN]
artifact_paths:
- "build/results/*"
notify:
- github_commit_status:
context: "Unit Tests Keystone"
# Disabled till https://github.com/wordpress-mobile/WordPress-iOS/pull/24537 is completed
# - label: "🔬 Keystone Unit Tests"
# command: .buildkite/commands/run-unit-tests-for-scheme.sh Keystone
# plugins: [$CI_TOOLKIT_PLUGIN]
# artifact_paths:
# - "build/results/*"
# notify:
# - github_commit_status:
# context: "Unit Tests Keystone"
Comment on lines -116 to +127
Copy link
Contributor

Choose a reason for hiding this comment

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

Why commenting the whole step?

I mean, it makes sense so the parser doesn't have to bother with something that is hardcoded if: "false" and the result is the same, but was it to help with this PR or something that stood out?

Perhaps given the commit it the change is in, e349939, it was to reduce the logs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, this was a minor issue -- in the state summary of all jobs that I implemented in the fork, I noticed the status for this job was something weird (Keystone Unit Tests: exit_status=pending, state=broken) that Claude was picking up as an error and polluting a little bit the analysis with a red herring.

- label: "🔬 WordPressData Unit Tests"
command: .buildkite/commands/run-unit-tests-for-scheme.sh WordPressData
plugins: [$CI_TOOLKIT_PLUGIN]
Expand All @@ -139,6 +138,7 @@ steps:
# UI Tests
#################
- group: "🔬 UI Tests"
key: ui_tests_group
steps:
- label: "🔬 :jetpack: UI Tests (iPhone)"
command: .buildkite/commands/run-ui-tests.sh 'iPhone 17'
Expand Down Expand Up @@ -168,6 +168,7 @@ steps:
# Linters
#################
- group: "Linters"
key: linters_group
steps:
- label: "☢️ Danger - PR Check"
command: danger
Expand Down Expand Up @@ -201,3 +202,21 @@ steps:
- label: ":sleuth_or_spy: Lint Localized Strings Format"
command: .buildkite/commands/lint-localized-strings-format.sh
plugins: [$CI_TOOLKIT_PLUGIN]

#################
# Claude Build Analysis - dynamically uploaded so Build result conditions evaluate at runtime after the wait
#################
- label: ":claude: 🕵️ Check for Build Failures and Run Claude Analysis"
command: |
source .buildkite/shared-pipeline-vars
buildkite-agent pipeline upload .buildkite/claude-analysis.yml
# Add specific group dependencies. Using a `wait` step wouldn't work as it would never start given the prompt block
depends_on:
- build_asc_reader
- linters_group
- prototype_builds_group
- unit_tests_group
- ui_tests_group
allow_dependency_failure: true
agents:
queue: upload
1 change: 1 addition & 0 deletions .buildkite/shared-pipeline-vars
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ CI_TOOLKIT_PLUGIN_VERSION="5.3.1"

export IMAGE_ID="xcode-$XCODE_VERSION"
export CI_TOOLKIT_PLUGIN="automattic/a8c-ci-toolkit#$CI_TOOLKIT_PLUGIN_VERSION"
export CLAUDE_PLUGIN="iangmaia/claude-summarize#iangmaia/add-build-log-mode"
Copy link
Contributor Author

@iangmaia iangmaia Jan 8, 2026

Choose a reason for hiding this comment

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

I've created a Pull Request to the claude-summarize-buildkite-plugin project introducing the build_log_mode attribute, allowing us to send to for analysis Claude only failed jobs, saving a lot on tokens usage.
Hopefully it won't take long to merge it and we can revert to the main repo again.

Copy link
Contributor

Choose a reason for hiding this comment

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

Otherwise, we can always keep using or fork, whic I think you mentioned this elsewhere, too.