Skip to content
Merged
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
119 changes: 82 additions & 37 deletions docker/server-pipeline.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ set -uo pipefail

REQUIRED_VARS=(
CODACY_API_TOKEN
ANTHROPIC_API_KEY
GIT_TOKEN
CODACY_PROVIDER
CODACY_ORG_NAME
Expand All @@ -27,6 +26,11 @@ if [[ ${#missing[@]} -gt 0 ]]; then
exit 1
fi

if [[ -z "${ANTHROPIC_API_KEY:-}" && -z "${GEMINI_API_KEY:-}" ]]; then
echo "ERROR: missing required env vars: ANTHROPIC_API_KEY or GEMINI_API_KEY (at least one must be set)" >&2
exit 1
fi

# Provider-specific HTTPS clone URL construction.
# Token value comes from GIT_TOKEN; the username portion differs per provider.
case "${CODACY_PROVIDER}" in
Expand Down Expand Up @@ -62,42 +66,83 @@ fi
cd "${WORKSPACE}"
mkdir -p "$(dirname "${SUMMARY_PATH}")"

CLAUDE_STREAM_FILE=$(mktemp)
RUN_STARTED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)

echo "==> Running configure-codacy-cloud"
claude -p "/configure-codacy-cloud" \
--model "${CLAUDE_MODEL:-claude-sonnet-4-6}" \
--output-format stream-json \
--verbose \
--include-partial-messages \
| tee "${CLAUDE_STREAM_FILE}" \
| jq --unbuffered -rj 'select(.type == "stream_event" and .event.delta.type? == "text_delta") | .event.delta.text'
SKILL_EXIT=${PIPESTATUS[0]}
RUN_FINISHED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)
echo

# Extract run metadata from the captured stream.
# model lives on assistant message events (.message.model), not on the result event.
RUN_META=$(jq -rsc \
--arg startedAt "${RUN_STARTED_AT}" \
--arg finishedAt "${RUN_FINISHED_AT}" '
. as $events |
($events | map(select(.type == "assistant")) | first | .message.model // "unknown") as $model |
($events | map(select(.type == "result")) | last) as $result |
$result | {
llm: "anthropic",
model: $model,
startedAt: $startedAt,
finishedAt: $finishedAt,
tokensIn: (.usage.input_tokens // 0),
tokensOut: (.usage.output_tokens // 0),
durationMs: (.duration_ms // 0),
costUsd: (.total_cost_usd // 0),
sessionId: (.session_id // "")
}
' "${CLAUDE_STREAM_FILE}")
rm -f "${CLAUDE_STREAM_FILE}"
if [[ -n "${ANTHROPIC_API_KEY:-}" ]]; then
CLAUDE_STREAM_FILE=$(mktemp)
RUN_STARTED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)

echo "==> Running configure-codacy-cloud with Claude..."
claude -p "/configure-codacy-cloud" \
--model "${CLAUDE_MODEL:-claude-sonnet-4-6}" \
--output-format stream-json \
--verbose \
--include-partial-messages \
| tee "${CLAUDE_STREAM_FILE}" \
| jq --unbuffered -rj 'select(.type == "stream_event" and .event.delta.type? == "text_delta") | .event.delta.text'
SKILL_EXIT=${PIPESTATUS[0]}
RUN_FINISHED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)
echo

# Extract run metadata from the captured stream.
# model lives on assistant message events (.message.model), not on the result event.
RUN_META=$(jq -rsc \
--arg startedAt "${RUN_STARTED_AT}" \
--arg finishedAt "${RUN_FINISHED_AT}" '
. as $events |
($events | map(select(.type == "assistant")) | first | .message.model // "unknown") as $model |
($events | map(select(.type == "result")) | last) as $result |
$result | {
llm: "anthropic",
model: $model,
startedAt: $startedAt,
finishedAt: $finishedAt,
tokensIn: (.usage.input_tokens // 0),
tokensOut: (.usage.output_tokens // 0),
durationMs: (.duration_ms // 0),
costUsd: (.total_cost_usd // 0),
sessionId: (.session_id // "")
}
' "${CLAUDE_STREAM_FILE}")
rm -f "${CLAUDE_STREAM_FILE}"

elif [[ -n "${GEMINI_API_KEY:-}" ]]; then
echo "==> Running configure-codacy-cloud with Gemini..."
SKILL_MD="/opt/codacy-skills/skills/configure-codacy-cloud/SKILL.md"
if [[ ! -f "${SKILL_MD}" ]]; then
echo "ERROR: ${SKILL_MD} not found in the container" >&2
exit 1
fi
GEMINI_STREAM_FILE=$(mktemp)
RUN_STARTED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)

gemini -y --skip-trust -m "${GEMINI_MODEL:-gemini-3-flash-preview}" -o stream-json \
-p "Execute the skill instructions provided above." < "${SKILL_MD}" \
| tee "${GEMINI_STREAM_FILE}" \
| jq --unbuffered -rj 'select(.type == "message" and .role == "assistant") | .content'
SKILL_EXIT=${PIPESTATUS[0]}
RUN_FINISHED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)
echo

RUN_META=$(jq -rsc \
--arg startedAt "${RUN_STARTED_AT}" \
--arg finishedAt "${RUN_FINISHED_AT}" '
. as $events |
($events | map(select(.type == "init")) | first | .session_id // "") as $sessionId |
($events | map(select(.type == "init")) | first | .model // "unknown") as $model |
($events | map(select(.type == "result")) | last) as $result |
{
llm: "gemini",
model: $model,
startedAt: $startedAt,
finishedAt: $finishedAt,
tokensIn: ($result.stats.input_tokens // 0),
tokensOut: ($result.stats.output_tokens // 0),
durationMs: ($result.stats.duration_ms // 0),
costUsd: ((($result.stats.input_tokens // 0) * 0.50 + ($result.stats.output_tokens // 0) * 3.00) / 1000000),
sessionId: $sessionId
}
' "${GEMINI_STREAM_FILE}")
rm -f "${GEMINI_STREAM_FILE}"
fi

if [[ ! -f "${SUMMARY_PATH}" ]]; then
echo "==> Skill did not produce ${SUMMARY_PATH}, writing fallback summary"
Expand Down