1212
1313concurrency :
1414 group : ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
15- cancel-in-progress : false
15+ cancel-in-progress : true
1616
1717jobs :
1818 linting :
@@ -52,17 +52,14 @@ jobs:
5252 - name : Run mypy type checking
5353 run : uv run --frozen mypy langfuse --no-error-summary
5454
55- ci :
55+ unit-tests :
5656 runs-on : blacksmith-4vcpu-ubuntu-2404
5757 timeout-minutes : 30
5858 env :
5959 LANGFUSE_BASE_URL : " http://localhost:3000"
60- LANGFUSE_PUBLIC_KEY : " pk-lf-1234567890"
61- LANGFUSE_SECRET_KEY : " sk-lf-1234567890"
62- OPENAI_API_KEY : ${{ secrets.OPENAI_API_KEY }}
63- # SERPAPI_API_KEY: ${{ secrets.SERPAPI_API_KEY }}
64- HUGGINGFACEHUB_API_TOKEN : ${{ secrets.HUGGINGFACEHUB_API_TOKEN }}
65- ANTHROPIC_API_KEY : ${{ secrets.ANTHROPIC_API_KEY }}
60+ LANGFUSE_PUBLIC_KEY : " pk-lf-test"
61+ LANGFUSE_SECRET_KEY : " sk-lf-test"
62+ OPENAI_API_KEY : " test-openai-key"
6663 strategy :
6764 fail-fast : false
6865 matrix :
@@ -73,56 +70,95 @@ jobs:
7370 - " 3.13"
7471 - " 3.14"
7572
76- name : Test on Python version ${{ matrix.python-version }}
73+ name : Unit tests on Python ${{ matrix.python-version }}
7774 steps :
7875 - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
79- - uses : pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5
76+ - name : Install uv and set Python version
77+ uses : astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8
8078 with :
81- version : 10.33.0
79+ version : " 0.11.2"
80+ python-version : ${{ matrix.python-version }}
81+ enable-cache : true
82+
83+ - name : Check Python version
84+ run : python --version
8285
83- - name : Clone langfuse server
86+ - name : Install the project dependencies
87+ run : uv sync --locked
88+
89+ - name : Run the automated tests
8490 run : |
85- git clone https://github.com/langfuse/langfuse.git ./langfuse-server && echo $(cd ./langfuse-server && git rev-parse HEAD)
91+ python --version
92+ uv run --frozen pytest -n auto --dist worksteal -s -v --log-cli-level=INFO tests/unit
8693
87- - name : Setup node (for langfuse server)
88- uses : actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
89- with :
90- node-version : 24
94+ e2e-tests :
95+ runs-on : ubuntu-latest
96+ timeout-minutes : 30
97+ strategy :
98+ fail-fast : false
99+ matrix :
100+ include :
101+ - suite : e2e
102+ job_name : E2E shard 1 tests on Python 3.13
103+ shard_name : shard-1
104+ shard_index : 0
105+ shard_count : 2
106+ - suite : e2e
107+ job_name : E2E shard 2 tests on Python 3.13
108+ shard_name : shard-2
109+ shard_index : 1
110+ shard_count : 2
111+ - suite : live_provider
112+ job_name : E2E live-provider tests on Python 3.13
113+ shard_name : live-provider
114+ env :
115+ LANGFUSE_BASE_URL : " http://localhost:3000"
116+ LANGFUSE_PUBLIC_KEY : " pk-lf-1234567890"
117+ LANGFUSE_SECRET_KEY : " sk-lf-1234567890"
118+ LANGFUSE_INIT_ORG_ID : " 0c6c96f4-0ca0-4f16-92a8-6dd7d7c6a501"
119+ LANGFUSE_INIT_ORG_NAME : " SDK Test Org"
120+ LANGFUSE_INIT_PROJECT_ID : " 7a88fb47-b4e2-43b8-a06c-a5ce950dc53a"
121+ LANGFUSE_INIT_PROJECT_NAME : " SDK Test Project"
122+ LANGFUSE_INIT_PROJECT_PUBLIC_KEY : " pk-lf-1234567890"
123+ LANGFUSE_INIT_PROJECT_SECRET_KEY : " sk-lf-1234567890"
124+ LANGFUSE_INIT_USER_EMAIL : " sdk-tests@langfuse.local"
125+ LANGFUSE_INIT_USER_NAME : " SDK Tests"
126+ LANGFUSE_INIT_USER_PASSWORD : " langfuse-ci-password"
127+ LANGFUSE_E2E_READ_TIMEOUT_SECONDS : " 60"
128+ LANGFUSE_E2E_READ_INTERVAL_SECONDS : " 0.5"
129+ OPENAI_API_KEY : ${{ secrets.OPENAI_API_KEY }}
130+ # SERPAPI_API_KEY: ${{ secrets.SERPAPI_API_KEY }}
131+ HUGGINGFACEHUB_API_TOKEN : ${{ secrets.HUGGINGFACEHUB_API_TOKEN }}
132+ ANTHROPIC_API_KEY : ${{ secrets.ANTHROPIC_API_KEY }}
91133
92- - name : Cache langfuse server dependencies
93- uses : actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5
134+ name : ${{ matrix.job_name }}
135+ steps :
136+ - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
137+ - name : Install uv and set Python version
138+ uses : astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8
94139 with :
95- path : ./langfuse-server/node_modules
96- key : langfuse-serve-${{ hashFiles('langfuse-server/pnpm-lock.yaml') }}
97- restore-keys : |
98- langfuse-serve-
140+ version : " 0.11.2"
141+ python-version : " 3.13"
142+ enable-cache : true
143+ - name : Install the project dependencies
144+ run : uv sync --locked
145+ - name : Check uv Python version
146+ run : uv run --frozen python --version
147+ - name : Prepare langfuse server compose
148+ run : |
149+ mkdir -p ./langfuse-server
150+ LANGFUSE_SERVER_SHA="$(git ls-remote https://github.com/langfuse/langfuse.git HEAD | cut -f1)"
151+ curl -fsSL "https://raw.githubusercontent.com/langfuse/langfuse/${LANGFUSE_SERVER_SHA}/docker-compose.yml" \
152+ -o ./langfuse-server/docker-compose.yml
153+ echo "${LANGFUSE_SERVER_SHA}"
99154
100155 - name : Run langfuse server
101156 run : |
102157 cd ./langfuse-server
103158
104- echo "::group::Run langfuse server"
105- TELEMETRY_ENABLED=false docker compose up -d postgres
106- echo "::endgroup::"
107-
108- echo "::group::Logs from langfuse server"
109- TELEMETRY_ENABLED=false docker compose logs
110- echo "::endgroup::"
111-
112- echo "::group::Install dependencies (necessary to run seeder)"
113- pnpm i
114- echo "::endgroup::"
115-
116- echo "::group::Seed db"
117- cp .env.dev.example .env
118- pnpm run db:migrate
119- pnpm run db:seed
120- echo "::endgroup::"
121- rm -rf .env
122-
123- echo "::group::Run server"
124-
159+ echo "::group::Start langfuse server"
125160 TELEMETRY_ENABLED=false \
161+ NEXT_PUBLIC_LANGFUSE_RUN_NEXT_INIT=true \
126162 LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT=http://localhost:9090 \
127163 LANGFUSE_INGESTION_QUEUE_DELAY_MS=10 \
128164 LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL_MS=10 \
@@ -131,51 +167,81 @@ jobs:
131167 LANGFUSE_ENABLE_EVENTS_TABLE_V2_APIS=true \
132168 LANGFUSE_ENABLE_EVENTS_TABLE_OBSERVATIONS=true \
133169 docker compose up -d
134-
135170 echo "::endgroup::"
136171
137- # Add this step to check the health of the container
138172 - name : Health check for langfuse server
139173 run : |
140174 echo "Checking if the langfuse server is up..."
141175 retry_count=0
142- max_retries=10
143- until curl --output /dev/null --silent --head --fail http://localhost:3000/api/public/health
176+ max_retries=20
177+ until curl --output /dev/null --silent --head --fail http://localhost:3000/api/public/health && \
178+ uv run --frozen python -c "from langfuse import Langfuse; client = Langfuse(); project_id = client._get_project_id(); assert project_id == '7a88fb47-b4e2-43b8-a06c-a5ce950dc53a', project_id; print(project_id)"
144179 do
145180 retry_count=`expr $retry_count + 1`
146181 echo "Attempt $retry_count of $max_retries..."
147182 if [ $retry_count -ge $max_retries ]; then
148183 echo "Langfuse server did not respond in time. Printing logs..."
149- docker logs langfuse-server-langfuse-web-1
184+ (cd ./langfuse-server && docker compose ps)
185+ (cd ./langfuse-server && docker compose logs langfuse-web langfuse-worker)
150186 echo "Failing the step..."
151187 exit 1
152188 fi
153189 sleep 5
154190 done
155191 echo "Langfuse server is up and running!"
156192
157- - name : Install uv and set Python version
158- uses : astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8
159- with :
160- version : " 0.11.2"
161- python-version : ${{ matrix.python-version }}
162- enable-cache : true
163-
164- - name : Check Python version
165- run : python --version
166-
167- - name : Install the project dependencies
168- run : uv sync --locked
169-
170- - name : Run the automated tests
193+ - name : Select e2e shard files
194+ if : ${{ matrix.suite == 'e2e' }}
171195 run : |
172- python --version
173- uv run --frozen pytest -n auto --dist loadfile -s -v --log-cli-level=INFO
196+ uv run --frozen python scripts/select_e2e_shard.py \
197+ --shard-index ${{ matrix.shard_index }} \
198+ --shard-count ${{ matrix.shard_count }} \
199+ --json
200+ uv run --frozen python scripts/select_e2e_shard.py \
201+ --shard-index ${{ matrix.shard_index }} \
202+ --shard-count ${{ matrix.shard_count }} \
203+ > "$RUNNER_TEMP/e2e-shard-files.txt"
204+ cat "$RUNNER_TEMP/e2e-shard-files.txt"
205+
206+ - name : Run the parallel end-to-end tests
207+ if : ${{ matrix.suite == 'e2e' }}
208+ run : |
209+ uv run --frozen python --version
210+ mapfile -t e2e_files < "$RUNNER_TEMP/e2e-shard-files.txt"
211+ set +e
212+ uv run --frozen pytest -n 4 --dist worksteal -s -v --log-cli-level=INFO "${e2e_files[@]}" -m "not serial_e2e"
213+ status=$?
214+ set -e
215+ if [ "$status" -eq 5 ]; then
216+ echo "No parallel e2e tests selected for this shard."
217+ elif [ "$status" -ne 0 ]; then
218+ exit "$status"
219+ fi
220+
221+ - name : Run serial end-to-end tests
222+ if : ${{ matrix.suite == 'e2e' }}
223+ run : |
224+ mapfile -t e2e_files < "$RUNNER_TEMP/e2e-shard-files.txt"
225+ set +e
226+ uv run --frozen pytest -s -v --log-cli-level=INFO "${e2e_files[@]}" -m "serial_e2e"
227+ status=$?
228+ set -e
229+ if [ "$status" -eq 5 ]; then
230+ echo "No serial e2e tests selected for this shard."
231+ elif [ "$status" -ne 0 ]; then
232+ exit "$status"
233+ fi
234+
235+ - name : Run live-provider tests
236+ if : ${{ matrix.suite == 'live_provider' }}
237+ run : |
238+ uv run --frozen python --version
239+ uv run --frozen pytest -n 4 --dist worksteal -s -v --log-cli-level=INFO tests/live_provider -m "live_provider"
174240
175241 all-tests-passed :
176242 # This allows us to have a branch protection rule for tests and deploys with matrix
177243 runs-on : blacksmith-2vcpu-ubuntu-2404
178- needs : [ci , linting, type-checking]
244+ needs : [unit-tests, e2e-tests , linting, type-checking]
179245 if : always()
180246 steps :
181247 - name : Successful deploy
0 commit comments