mirror of
https://github.com/langchain-ai/docs.git
synced 2026-08-27 02:41:59 -04:00
0e7fba2d52
## Summary - Pin `ctriolo/action-create-linear-issue` to the immutable commit SHA for `v0.7` so the `LINEAR_API_KEY` is no longer exposed to a mutable third-party action tag. - Pass GitHub PR base refs/SHAs and workflow output values through environment variables before shell use. - Apply the same base-ref hardening to adjacent docs diff-check workflows to avoid the same pattern recurring. ## Corridor findings - Fixes https://app.corridor.dev/projects/86f45f70-3153-46d0-b0f6-5ec9dba1ace1/findings/eb002ea1-903e-4a2b-94a5-5ebc4b60bab2 - Fixes https://app.corridor.dev/projects/86f45f70-3153-46d0-b0f6-5ec9dba1ace1/findings/1bbe3c85-75f4-4ece-8c96-cd857c5be291 ## Validation - `ruby -e 'require \"yaml\"; Dir[\"/tmp/docs/.github/workflows/*.yml\"].each { |p| YAML.load_file(p) }; puts \"parsed workflows\"'` - `git diff --check` Co-authored-by: langsmith-fleet[bot] <langsmith-fleet[bot]@users.noreply.github.com>
158 lines
5.1 KiB
YAML
158 lines
5.1 KiB
YAML
---
|
|
name: Test Code Samples
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
on:
|
|
pull_request:
|
|
paths:
|
|
- "src/code-samples/**"
|
|
- ".github/workflows/test-code-samples.yml"
|
|
workflow_dispatch:
|
|
schedule:
|
|
# Run every Sunday at 00:00 UTC
|
|
- cron: "0 0 * * 0"
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
test-code-samples:
|
|
# GitHub does not expose repository secrets to workflows triggered from fork PRs.
|
|
# These tests require provider API keys for some samples, so skip on forks.
|
|
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false)
|
|
runs-on: ubuntu-latest
|
|
# Scheduled and manual runs test all samples; PR runs may touch many files in large refactors.
|
|
timeout-minutes: ${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && 90 || 60 }}
|
|
services:
|
|
postgres:
|
|
image: pgvector/pgvector:pg17
|
|
env:
|
|
POSTGRES_PASSWORD: postgres
|
|
POSTGRES_DB: postgres
|
|
ports:
|
|
- 5432:5432
|
|
options: >-
|
|
--health-cmd pg_isready
|
|
--health-interval 10s
|
|
--health-timeout 5s
|
|
--health-retries 5
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v6
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Get modified code sample paths
|
|
id: files
|
|
env:
|
|
EVENT_NAME: ${{ github.event_name }}
|
|
PR_BASE_REF: ${{ github.event.pull_request.base.ref }}
|
|
BEFORE_SHA: ${{ github.event.before }}
|
|
run: |
|
|
if [[ "$EVENT_NAME" == "schedule" || "$EVENT_NAME" == "workflow_dispatch" ]]; then
|
|
echo "run_all=true" >> "$GITHUB_OUTPUT"
|
|
echo "Full run: testing all code samples"
|
|
else
|
|
echo "run_all=false" >> "$GITHUB_OUTPUT"
|
|
|
|
if [[ "$EVENT_NAME" == "pull_request" ]]; then
|
|
git fetch origin "$PR_BASE_REF"
|
|
BASE=$(git merge-base HEAD "origin/$PR_BASE_REF")
|
|
else
|
|
BASE="$BEFORE_SHA"
|
|
fi
|
|
|
|
FILES=$(git diff --name-only "$BASE" HEAD -- src/code-samples/ \
|
|
| grep -E '\.(py|ts|java|kt|go|sh)$' \
|
|
| tr '\n' ' ' || true)
|
|
|
|
{ echo "files<<FILESEND"; echo "$FILES"; echo "FILESEND"; } >> "$GITHUB_OUTPUT"
|
|
if [[ -n "$FILES" ]]; then
|
|
echo "Modified code samples: $FILES"
|
|
else
|
|
echo "No modified .py, .ts, .java, .kt, .go, or .sh files in src/code-samples/"
|
|
fi
|
|
fi
|
|
|
|
- name: Set up Python and uv
|
|
uses: ./.github/actions/uv_setup
|
|
with:
|
|
python-version: "3.13"
|
|
|
|
- name: Install project dependencies
|
|
run: uv sync
|
|
|
|
- name: Install Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: "20"
|
|
|
|
- name: Set up Java (for JBang)
|
|
uses: actions/setup-java@v4
|
|
with:
|
|
distribution: "temurin"
|
|
java-version: "21"
|
|
|
|
- name: Install JBang
|
|
uses: jbangdev/setup-jbang@v0.1.1
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@v5
|
|
with:
|
|
go-version-file: src/code-samples/go.mod
|
|
|
|
- name: Wait for PostgreSQL
|
|
run: |
|
|
for i in $(seq 1 30); do
|
|
if python3 -c "
|
|
import socket
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
s.settimeout(2)
|
|
try:
|
|
s.connect(('127.0.0.1', 5432))
|
|
s.close()
|
|
except OSError:
|
|
exit(1)
|
|
"; then
|
|
echo "PostgreSQL is ready"
|
|
exit 0
|
|
fi
|
|
echo "Waiting for PostgreSQL... ($i/30)"
|
|
sleep 2
|
|
done
|
|
echo "PostgreSQL did not become ready"
|
|
exit 1
|
|
|
|
- name: Test code samples
|
|
id: test
|
|
env:
|
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
ANTHROPIC_BASE_URL: ${{ secrets.ANTHROPIC_BASE_URL }}
|
|
ANTHROPIC_CUSTOM_HEADERS: ${{ secrets.ANTHROPIC_CUSTOM_HEADERS }}
|
|
LS_GATEWAY_KEY: ${{ secrets.LS_GATEWAY_KEY }}
|
|
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
POSTGRES_URI: postgresql://postgres:postgres@127.0.0.1:5432/postgres?sslmode=disable
|
|
TAVILY_API_KEY: ${{ secrets.TAVILY_API_KEY }}
|
|
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
|
DAYTONA_API_KEY: ${{ secrets.DAYTONA_API_KEY }}
|
|
DAYTONA_API_URL: ${{ secrets.DAYTONA_API_URL }}
|
|
RUN_ALL: ${{ steps.files.outputs.run_all }}
|
|
MODIFIED_FILES: ${{ steps.files.outputs.files }}
|
|
run: |
|
|
if [[ "$RUN_ALL" == "true" ]]; then
|
|
echo "Running all code samples..."
|
|
make test-code-samples
|
|
else
|
|
FILES="$MODIFIED_FILES"
|
|
FILES=$(echo "$FILES" | tr -d '\n' | xargs)
|
|
if [[ -z "$FILES" ]]; then
|
|
echo "No code samples to test"
|
|
exit 0
|
|
fi
|
|
make test-code-samples FILES="$FILES"
|
|
fi
|