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
38 changes: 36 additions & 2 deletions .github/workflows/maint-80-langsmith-metrics-dashboard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ jobs:
set -uo pipefail
REGISTRY=config/langsmith_fleet_registry.json
mkdir -p .metrics-tmp/fleet
trusted_workflow_paths="$(jq -c '.trusted_artifact_workflow_paths // []' "$REGISTRY")"
# Always start from an empty combined file so repos with no artifact
# surface as "missing" (the registry-driven rollup never skips them).
: > .metrics-tmp/fleet/combined-fleet.ndjson
Expand All @@ -178,16 +179,49 @@ jobs:
# treated as "missing", never as a job failure.
while IFS=$'\t' read -r repo artifact_name; do
[ -z "$repo" ] && continue
echo "🔎 Resolving $artifact_name in $repo ..."
echo "🔎 Resolving $artifact_name or prefixed variant in $repo ..."
artifacts_json=$(gh api --paginate --slurp --method GET \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/$repo/actions/artifacts?per_page=100" \
2>> .metrics-tmp/fleet/fleet_errors.log || echo "")
artifact_id=$(printf '%s' "$artifacts_json" | jq -r \
--arg artifact_name "$artifact_name" \
'[.[].artifacts[]? | select(.name == $artifact_name and .expired == false)] | sort_by(.created_at) | last | .id // empty' \
'[.[].artifacts[]?
| select(.expired == false)
| select(.name == $artifact_name)]
| sort_by(.created_at)
| last
| .id // empty' \
Comment thread
coderabbitai[bot] marked this conversation as resolved.
2>> .metrics-tmp/fleet/fleet_errors.log || echo "")
if [ -z "$artifact_id" ] || [ "$artifact_id" = "null" ]; then
prefixed_candidates=$(printf '%s' "$artifacts_json" | jq -r \
--arg artifact_name "$artifact_name" \
'[.[].artifacts[]?
| select(.expired == false)
| select(.name != $artifact_name and (.name | endswith($artifact_name)))]
| sort_by(.created_at)
| reverse[]
| [.id, (.workflow_run.id // "")]
| @tsv' \
2>> .metrics-tmp/fleet/fleet_errors.log || echo "")
while IFS=$'\t' read -r candidate_id candidate_run_id; do
[ -z "$candidate_id" ] && continue
[ -z "$candidate_run_id" ] && continue
candidate_run_path=$(gh api --method GET \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/$repo/actions/runs/$candidate_run_id" \
--jq '.path // ""' \
2>> .metrics-tmp/fleet/fleet_errors.log || echo "")
if printf '%s' "$trusted_workflow_paths" | jq -e \
--arg path "$candidate_run_path" \
'index($path) != null' >/dev/null; then
artifact_id="$candidate_id"
break
fi
done <<< "$prefixed_candidates"
fi
if [ -z "$artifact_id" ] || [ "$artifact_id" = "null" ]; then
echo " ↪ no current artifact for $repo (missing)"
continue
Expand Down
37 changes: 35 additions & 2 deletions .github/workflows/maint-81-langsmith-fleet-conformance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ jobs:
const registry = JSON.parse(
fs.readFileSync('config/langsmith_fleet_registry.json', 'utf8')
);
const trustedWorkflowPaths = new Set(
registry.trusted_artifact_workflow_paths || []
);
fs.mkdirSync('.metrics-tmp/fleet', { recursive: true });

for (const entry of registry.repos) {
Expand All @@ -62,11 +65,41 @@ jobs:
github.rest.actions.listArtifactsForRepo({
owner,
repo: repoName,
name: entry.artifact_name,
per_page: 100,
})
);
const artifact = artifacts.data.artifacts.find((item) => !item.expired);
const candidates = artifacts.data.artifacts.filter((item) =>
!item.expired &&
(item.name === entry.artifact_name || item.name.endsWith(entry.artifact_name))
);
const exactCandidates = candidates.filter(
(item) => item.name === entry.artifact_name
);
let artifact = exactCandidates.sort(
(left, right) => new Date(right.created_at) - new Date(left.created_at)
)[0];
Comment thread
coderabbitai[bot] marked this conversation as resolved.
if (!artifact) {
const suffixCandidates = candidates
.filter((item) => item.name !== entry.artifact_name)
.sort((left, right) => new Date(right.created_at) - new Date(left.created_at));
for (const candidate of suffixCandidates) {
const runId = candidate.workflow_run && candidate.workflow_run.id;
if (!runId) {
continue;
}
const run = await withRetry(() =>
github.rest.actions.getWorkflowRun({
owner,
repo: repoName,
run_id: runId,
})
);
if (trustedWorkflowPaths.has(run.data.path)) {
artifact = candidate;
break;
}
}
}
if (!artifact) {
core.warning(`No ${entry.artifact_name} artifact found for ${entry.repo}`);
continue;
Expand Down
61 changes: 60 additions & 1 deletion .github/workflows/reusable-10-ci-python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1532,8 +1532,11 @@ jobs:
ref: ${{ inputs.workflows_ref || 'main' }}
path: .workflows-lib
token: ${{ steps.app_token.outputs.token || github.token }}
persist-credentials: false
sparse-checkout: |
.github/actions/artifact-cache
config/langsmith_fleet_registry.json
scripts/ensure_langsmith_fleet_artifact.py
sparse-checkout-cone-mode: false

- name: Install uv
Expand Down Expand Up @@ -2451,6 +2454,62 @@ jobs:
retention-days: 7
overwrite: true

- name: Checkout Workflows LangSmith fleet helper
if: >-
${{
always()
&& !inputs.cache
&& matrix.python-version == env.PRIMARY_PYTHON_VERSION
}}
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: stranske/Workflows
# @main-only policy (issue #2346): `@main` is the single supported pin,
# so checking out the helper layer at `main` is intentional and correct
# - callers ride `@main`, hence main IS the pinned ref. The
# `workflows_ref` input is a vestige that defaults to 'main'; do not
# rely on it to pin helpers at a non-main ref (the helper layer is only
# validated as a unit on `main`).
ref: ${{ inputs.workflows_ref || 'main' }}
path: .workflows-lib
token: ${{ steps.app_token.outputs.token || github.token }}
persist-credentials: false
Comment thread
coderabbitai[bot] marked this conversation as resolved.
sparse-checkout: |
config/langsmith_fleet_registry.json
scripts/ensure_langsmith_fleet_artifact.py
sparse-checkout-cone-mode: false
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed

- name: Ensure LangSmith fleet telemetry artifact
Comment thread
stranske marked this conversation as resolved.
if: >-
${{
always()
&& matrix.python-version == env.PRIMARY_PYTHON_VERSION
}}
env:
PYTHON_VERSION: ${{ matrix.python-version }}
run: |
helper="${GITHUB_WORKSPACE}/.workflows-lib/scripts/ensure_langsmith_fleet_artifact.py"
registry="${GITHUB_WORKSPACE}/.workflows-lib/config/langsmith_fleet_registry.json"
if [ ! -f "$helper" ]; then
helper="${GITHUB_WORKSPACE}/scripts/ensure_langsmith_fleet_artifact.py"
registry="${GITHUB_WORKSPACE}/config/langsmith_fleet_registry.json"
fi
if [ ! -f "$helper" ]; then
echo "::warning::LangSmith fleet fallback helper is unavailable; skipping fallback artifact ensure."
exit 0
fi
python "$helper" \
--registry "$registry" \
--project-root "${PROJECT_ROOT}" \
--repository "${GITHUB_REPOSITORY}" \
--run-id "${GITHUB_RUN_ID}" \
--run-attempt "${GITHUB_RUN_ATTEMPT}" \
--workflow "${GITHUB_WORKFLOW}" \
--job "${GITHUB_JOB}" \
--python-version "${PYTHON_VERSION}" \
--sha "${GITHUB_SHA}" \
--event-name "${GITHUB_EVENT_NAME}"

- name: Check LangSmith fleet telemetry artifact
id: langsmith_fleet_artifact
if: >-
Expand Down Expand Up @@ -2478,7 +2537,7 @@ jobs:
continue-on-error: true
uses: actions/upload-artifact@v7
with:
name: ${{ inputs['artifact-prefix'] }}langsmith-fleet
name: ${{ inputs['artifact-prefix'] }}langsmith-fleet.ndjson
path: ${{ env.PROJECT_ROOT }}/artifacts/langsmith/langsmith-fleet.ndjson
if-no-files-found: warn
retention-days: 90
Expand Down
5 changes: 5 additions & 0 deletions config/langsmith_fleet_registry.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
{
"schema_version": "langsmith-fleet-registry/v1",
"stale_after_hours": 168,
"trusted_artifact_workflow_paths": [
".github/workflows/pr-00-gate.yml",
".github/workflows/selftest-reusable-ci.yml",
".github/workflows/maint-62-integration-consumer.yml"
],
"repos": [
{
"repo": "stranske/Workflows",
Expand Down
Loading
Loading