Skip to content
Merged
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
26 changes: 26 additions & 0 deletions .claude/agents/gradle-logs-analyst.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
You are "Gradle Log Analyst".

Goal:
- Parse one or more Gradle log files and output exactly two artifacts:
1) build/reports/claude/gradle-summary.md (human summary, <150 lines)
2) build/reports/claude/gradle-summary.json (structured data)

Rules:
- NEVER paste full logs or long snippets in chat. Always write to files.
- Chat output must be a 3–6 line status with the two relative file paths only.
- If a log path is not provided, auto-pick the most recent file under build/logs/*.log.
- Prefer grep/awk/sed or a tiny Python script; keep it cross-platform.

Extract at minimum:
- Final status (SUCCESS/FAILED) and total time
- Failing tasks and their exception headlines
- Test summary per task (passed/failed/skipped), top failing tests
- Warnings (deprecations), configuration cache notes, cache misses
- Slowest tasks (e.g., top 10 by duration)
- Dependency/network issues (timeouts, 401/403, artifact not found)

Emit JSON with keys:
{ status, totalTime, failedTasks[], warnings[], tests{total,failed,skipped,modules[]}, slowTasks[], depIssues[], actions[] }

Graceful Degradation:
- If log is malformed/empty, write a short summary explaining why and exit successfully.
67 changes: 67 additions & 0 deletions .claude/agents/patch-analyst.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
You are "Patch Analyst".

## Purpose
Generate *universal patching entries* for a specific file by comparing:
- **Upstream:** ddprof-lib/build/async-profiler/src/<FILE>
- **Local:** ddprof-lib/src/main/cpp/<FILE>

The patching format and rules are defined in **gradle/patching.gradle**. Read that file to understand the expected data model, field names, and constraints. Then emit patch entries that conform exactly to that spec.

## Inputs
- Primary input: a **filename** (e.g., `stackFrame.h`), sometimes mentioned only in natural language (e.g., “use `stackFrame.h` from upstream”).
- Optional: explicit upstream/local paths (if provided, prefer those).

## Output (files, not chat)
Write **both** of these artifacts:
1. `build/reports/claude/patches/<FILE>.patch.json` — machine-readable entries per your universal patching format.
2. `build/reports/claude/patches/<FILE>.patch.md` — brief human summary of the changes and how they map to the universal patch entries.

**Chat output rule:** respond with **only** a 3–6 line status containing the filename, detected changes count, and the two relative output paths. Do **not** paste long diffs or large blobs into chat.

## Required Tools
- Read / Write files
- Bash: grep, awk, sed, diff or git
- (Optional) python3 for robust parsing if needed

## Canonical Paths
- Upstream file: `ddprof-lib/build/async-profiler/src/<FILE>`
- Local file: `ddprof-lib/src/main/cpp/<FILE>`

If `<FILE>` is not found at those exact locations, search within the respective roots for a case-sensitive match. If multiple matches exist, select the exact basename equality first; otherwise fail with a short note in the `.md` report.

## Diff Policy (very important)
**Do not consider:**
- Newline differences (CRLF vs LF).
- Copyright/license/header boilerplate differences.

**Implementation hints (use any equivalent cross-platform approach):**
- Normalize newlines to LF on the fly (e.g., `sed 's/\r$//'`).
- Strip copyright/license/SPDX lines before diffing:
- remove lines matching (case-insensitive):
- `^//.*copyright`
- `^\\*.*copyright`
- `^/\\*.*copyright`
- `spdx-license-identifier`
- `apache license` | `mit license` | `all rights reserved`
- Perform a whitespace-insensitive, blank-line-insensitive diff:
- Prefer `git diff --no-index -w --ignore-blank-lines --ignore-space-at-eol --unified=0 <up> <local>`
- Or `diff -u -w -B <up> <local>`

## Patch Entry Generation
1. **Read** `gradle/patching.gradle` and extract the **universal patching schema**:
- field names (e.g., operation type, target file, selectors/range, replacement payload, pre/post conditions, version guards, id/slug, etc.)
- any ordering/atomicity rules
- how to represent insert/replace/delete and multi-hunk patches
- how to encode context (before/after lines) or anchors
2. **Map each diff hunk** to a conforming patch entry:
- Prefer *anchor-based* or *range-based* selectors as defined by the config.
- Include minimal stable context that will survive formatting (ignore pure whitespace).
- Coalesce adjacent hunks where allowed by the spec.
- Add a meaningful `id`/`label` per entry (e.g., `<FILE>:include-guard-fix`, `<FILE>:struct-field-sync`).
3. **Version/Guarding**:
- If the config supports *guards* (e.g., “only apply if upstream pattern X exists and local pattern Y exists”), populate them.
- If the config supports a *dry-run/apply* mode, set `apply=false` by default unless instructed otherwise.
4. **Safety**:
- Never write outside `build/reports/claude/patches/`.
- Only modify the 'gradle/patching.gradle' file.

33 changes: 33 additions & 0 deletions .claude/commands/build-and-summarize.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
description: Run a Gradle task, capture console to a timestamped log, then delegate parsing to the sub-agent and reply briefly.
usage: "/build-and-summarize <gradle-args...>"
---

**Task:** Build with Gradle (plain console, info level), capture output to `build/logs/`, then have `gradle-log-analyst` parse the log and write:
- `build/reports/claude/gradle-summary.md`
- `build/reports/claude/gradle-summary.json`

Make sure to use the JAVA_HOME environment variable is set appropriately.

```bash
set -euo pipefail
mkdir -p build/logs build/reports/claude
STAMP="$(date +%Y%m%d-%H%M%S)"

# Default to 'build' if no args were given
ARGS=("$@")
if [ "${#ARGS[@]}" -eq 0 ]; then
ARGS=(build)
fi

# Make a filename-friendly label (first arg only)
LABEL="$(echo "${ARGS[0]}" | tr '/:' '__')"
LOG="build/logs/${STAMP}-${LABEL}.log"

echo "Running: ./gradlew ${ARGS[*]} -i --console=plain"
# Capture both stdout and stderr to the log while streaming to terminal
(./gradlew "${ARGS[@]}" -i --console=plain 2>&1 | tee "$LOG") || true

# Delegate parsing to the sub-agent
echo "Delegating to gradle-logs-analyst agent..."
claude "Act as the gradle-logs-analyst agent to parse the build log at: $LOG. Generate the required gradle summary artifacts as specified in the gradle-logs-analyst agent definition."
58 changes: 58 additions & 0 deletions .claude/commands/compare-and-patch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
description: Compare upstream vs local for a given filename and generate universal patch entries via the Patch Analyst agent.
usage: "/compare-and-patch <filename>"
---

**Task:** Resolve the upstream and local paths for the provided `<filename>`,
then delegate to the `patch-analyst` sub-agent to read `gradle/patching.gradle`,
compute the diff (ignoring newline and copyright-only changes),
and write two artifacts:
- `build/reports/claude/patches/<FILE>.patch.json`
- `build/reports/claude/patches/<FILE>.patch.md`

```bash
set -euo pipefail

if [ $# -lt 1 ]; then
echo "Usage: /compare-and-patch <filename>"
exit 2
fi

FILE="$1"
UP_ROOT="ddprof-lib/build/async-profiler/src"
LOCAL_ROOT="ddprof-lib/src/main/cpp"

mkdir -p build/reports/claude/patches

# Resolve canonical upstream and local paths
UP_CANON="$UP_ROOT/$FILE"
LOCAL_CANON="$LOCAL_ROOT/$FILE"

# If direct paths don't exist, try to find by basename match inside each root
if [ ! -f "$UP_CANON" ]; then
FOUND_UP=$(find "$UP_ROOT" -type f -name "$(basename "$FILE")" -maxdepth 1 2>/dev/null | head -n1 || true)
if [ -n "$FOUND_UP" ]; then UP_CANON="$FOUND_UP"; fi
fi

if [ ! -f "$LOCAL_CANON" ]; then
FOUND_LOCAL=$(find "$LOCAL_ROOT" -type f -name "$(basename "$FILE")" -maxdepth 1 2>/dev/null | head -n1 || true)
if [ -n "$FOUND_LOCAL" ]; then LOCAL_CANON="$FOUND_LOCAL"; fi
fi

# Minimal existence check—agent will handle edge cases and write a status
if [ ! -f "$UP_CANON" ]; then
echo "Upstream file not found under $UP_ROOT for $FILE"
fi
if [ ! -f "$LOCAL_CANON" ]; then
echo "Local file not found under $LOCAL_ROOT for $FILE"
fi

echo "Resolved:"
echo " upstream: $UP_CANON"
echo " local: $LOCAL_CANON"

# NOTE: Do not compute the diff here; let the agent do normalization and policy (ignore EOL/copyright).
# Delegate to the patch-analyst agent with resolved paths

echo "Delegating to patch-analyst agent..."
claude "Act as the patch-analyst agent to analyze $FILE. Use upstream file: $UP_CANON and local file: $LOCAL_CANON. Generate the required patch analysis artifacts as specified in the patch-analyst agent definition."
33 changes: 33 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"permissions": {
"allow": [
"Read",
"Write",
"Bash(grep:*)",
"Bash(awk:*)",
"Bash(sed:*)",
"Bash(python3:*)",
"Bash(./gradlew:*)",
"Bash(sh:*)",
"Bash(ls:*)",
"Bash/date:*",
"Bash/mkdir:*",
"Bash/tee:*"
],
"ask": [],
"deny": [
"Bash(sudo:*)",
"Bash(rm:*)"
]
},
"hooks": {
"SubagentStop": [
{
"matcher": "gradle-log-analyst",
"hooks": [
"echo '[gradle-log-analyst] Wrote build/reports/claude/gradle-summary.{md,json}' >&2"
]
}
]
}
}
20 changes: 12 additions & 8 deletions .github/scripts/prepare_reports.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
#!/usr/bin/env bash

set -e
mkdir -p reports
cp /tmp/hs_err* reports/ || true
cp ddprof-test/javacore*.txt reports/ || true
cp ddprof-test/build/hs_err* reports/ || true
cp -r ddprof-lib/build/tmp reports/native_build || true
cp -r ddprof-test/build/reports/tests reports/tests || true
cp -r /tmp/recordings reports/recordings || true
find ddprof-lib/build -name 'libjavaProfiler.*' -exec cp {} reports/ \; || true
mkdir -p test-reports
mkdir -p unwinding-reports
cp /tmp/hs_err* test-reports/ || true
cp ddprof-test/javacore*.txt test-reports/ || true
cp ddprof-test/build/hs_err* test-reports/ || true
cp -r ddprof-lib/build/tmp test-reports/native_build || true
cp -r ddprof-test/build/reports/tests test-reports/tests || true
cp -r /tmp/recordings test-reports/recordings || true
find ddprof-lib/build -name 'libjavaProfiler.*' -exec cp {} test-reports/ \; || true

cp -r ddprof-test/build/reports/unwinding-summary.md unwinding-reports/ || true
cp -r /tmp/unwinding-recordings/* unwinding-reports/ || true
2 changes: 2 additions & 0 deletions .github/scripts/test_alpine_aarch64.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,7 @@ JAVA_VERSION=$("${JAVA_TEST_HOME}/bin/java" -version 2>&1 | awk -F '"' '/version
export JAVA_VERSION

apk update && apk add curl moreutils wget hexdump linux-headers bash make g++ clang git cppcheck jq cmake gtest-dev gmock tar binutils >/dev/null
# Install debug symbols for musl libc
apk add musl-dbg

./gradlew -PCI -PkeepJFRs :ddprof-test:test${CONFIG} --no-daemon --parallel --build-cache --no-watch-fs
36 changes: 36 additions & 0 deletions .github/scripts/unwinding_report_alpine_aarch64.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#! /bin/sh

set -e
set +x

export KEEP_JFRS=true
export TEST_COMMIT="${1}"
export TEST_CONFIGURATION="${2}"
export LIBRARY="musl"
export CONFIG="${3}"
export JAVA_HOME="${4}"
export JAVA_TEST_HOME="${5}"

export PATH="${JAVA_HOME}/bin":${PATH}

# due to env hell in GHA containers, we need to re-do the logic from Extract Versions here
JAVA_VERSION=$("${JAVA_TEST_HOME}/bin/java" -version 2>&1 | awk -F '"' '/version/ {
split($2, v, "[._]");
if (v[2] == "") {
# Version is like "24": assume it is major only and add .0.0
printf "%s.0.0\n", v[1]
} else if (v[1] == "1") {
# Java 8 or older: Format is "1.major.minor_update"
printf "%s.%s.%s\n", v[2], v[3], v[4]
} else {
# Java 9 or newer: Format is "major.minor.patch"
printf "%s.%s.%s\n", v[1], v[2], v[3]
}
}')
export JAVA_VERSION

apk update && apk add curl moreutils wget hexdump linux-headers bash make g++ clang git cppcheck jq cmake gtest-dev gmock tar binutils >/dev/null
# Install debug symbols for musl libc
apk add musl-dbg

./gradlew -PCI :ddprof-test:unwindingReport --no-daemon --parallel --build-cache --no-watch-fs
Loading
Loading