Skip to content

Commit 19a7563

Browse files
authored
Merge pull request #14 from azure-ai-foundry/python-tools-estraight
e2e tests with different triggers
2 parents 3c86a06 + b10c489 commit 19a7563

File tree

1 file changed

+205
-98
lines changed

1 file changed

+205
-98
lines changed

.github/workflows/run-samples.yml

Lines changed: 205 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,215 @@
1-
# ---------------------------------------------------------------
2-
# .github/workflows/project-e2e-tests.yml
3-
#
4-
# PURPOSE
5-
# ▸ Run the same end-to-end test-suite against **many already-
6-
# provisioned projects**. Each project has its own value for
7-
# PROJECT_CLIENT, while MODEL_DEPLOYMENT_NAME is global.
8-
#
9-
# HOW TO USE
10-
# 1. Under **Settings ▸ Environments** create one environment
11-
# per project (project-alpha, project-beta, …).
12-
# 2. In every environment add the secret PROJECT_CLIENT
13-
# with that project’s value.
14-
# 3. In **Settings ▸ Secrets → Actions** (repo-level) add a
15-
# secret called MODEL_DEPLOYMENT_NAME that is identical
16-
# for all projects.
17-
# 4. List your projects in the matrix below.
18-
# 5. Push a PR that touches tests/ → this workflow fans out
19-
# and runs once per project, each run getting the correct
20-
# secrets automatically.
21-
# ---------------------------------------------------------------
22-
23-
name: Project E2E Tests
24-
25-
# ── 1️⃣ WHEN TO RUN ─────────────────────────────────────────────
1+
# .github/workflows/run-samples.yml
2+
# -----------------------------------------------------------------
3+
# Run the same end-to-end test-suite against multiple "setups".
4+
# A setup represents one already-provisioned environment
5+
# (e.g., SAI_UAI or UAI) that supplies its own PROJECT_CLIENT
6+
# secret. MODEL_DEPLOYMENT_NAME is shared across all setups.
7+
# The workflow can be started three ways:
8+
# 1. Automatically on any PR that modifies docs-samples/agents/**
9+
# 2. Manually from the Actions tab / GitHub CLI (workflow_dispatch)
10+
# 3. Via a slash-command comment in a PR ("/e2e <setup list>")
11+
# -----------------------------------------------------------------
12+
13+
# ────────────────────────────────────────────────────────────────
14+
# 0️⃣ TRIGGERS
15+
# ────────────────────────────────────────────────────────────────
2616
on:
27-
pull_request_target: # Use target so the workflow
28-
# file comes from the protected
29-
branches: [ main ] # main branch (safer than PR),
30-
paths: # and we still have access to
31-
- "tests/**" # secrets for cloud creds.
17+
# Automatic validation on pull requests
18+
pull_request_target:
19+
# Only PRs whose base branch is main
20+
branches:
21+
- main
22+
# Only when sample code changes
23+
paths:
24+
- docs-samples/agents/**
25+
26+
# Run-button or gh CLI trigger
27+
workflow_dispatch:
28+
inputs:
29+
setups:
30+
description: "Setups to test (SAI_UAI,UAI) or 'all'"
31+
required: false
32+
ref:
33+
description: "Git ref to test (defaults to branch head)"
34+
required: false
3235

33-
# ── 2️⃣ JOB DEFINITION (matrix fan-out) ─────────────────────────
36+
# Slash-command trigger inside pull-request comments
37+
issue_comment:
38+
types:
39+
- created
40+
41+
# ────────────────────────────────────────────────────────────────
42+
# 1️⃣ HELPER JOB – figure out which setups to test
43+
# ────────────────────────────────────────────────────────────────
3444
jobs:
35-
e2e:
36-
name: "E2E – ${{ matrix.project }}" # Shows up as “E2E – alpha”
45+
resolve-setups:
3746
runs-on: ubuntu-latest
38-
permissions:
39-
contents: read # read the repo
40-
id-token: write # (only if you OIDC into Azure, AWS, …)
47+
outputs:
48+
matrix: ${{ steps.build.outputs.matrix }}
49+
50+
steps:
51+
# Build the matrix JSON that downstream job will consume
52+
- id: build
53+
uses: actions/github-script@v7
54+
with:
55+
result-encoding: string
56+
script: |
57+
// Define all possible setups that this workflow supports.
58+
const ALL_SETUPS = ['SAI_UAI', 'UAI'];
59+
60+
// Helper function to parse user input (comma-separated or 'all') into a list of setups.
61+
function parse(input) {
62+
// If input is empty, null, or 'all', return the full list.
63+
if (
64+
!input ||
65+
input.trim() === '' ||
66+
input.trim().toLowerCase() === 'all'
67+
) {
68+
return ALL_SETUPS;
69+
}
70+
// Otherwise, split the comma-separated string, trim whitespace, and remove empty entries.
71+
return input
72+
.split(',')
73+
.map((s) => s.trim())
74+
.filter(Boolean);
75+
}
76+
77+
// Array to hold the setups requested for this specific workflow run.
78+
let requested = [];
79+
80+
// Determine the requested setups based on how the workflow was triggered.
81+
switch (context.eventName) {
82+
case 'workflow_dispatch': {
83+
// Triggered manually via UI or API.
84+
// Get the 'setups' input provided by the user.
85+
const inp = core.getInput('setups');
86+
// Parse the user input.
87+
requested = parse(inp);
88+
break;
89+
}
90+
case 'issue_comment': {
91+
// Triggered by a comment on a pull request.
92+
const body = context.payload.comment.body;
93+
// Check if the comment starts with the slash command '/e2e'.
94+
const match = body.match(/^\/e2e\s+(.+)$/i);
95+
if (match) {
96+
// If it matches, parse the arguments provided after '/e2e'.
97+
requested = parse(match[1]);
98+
} else {
99+
// If the comment doesn't match the command format, do nothing.
100+
core.notice('Comment does not contain /e2e command');
101+
}
102+
break;
103+
}
104+
case 'pull_request_target':
105+
// Triggered automatically by a PR change matching the path filter.
106+
// Default to running all defined setups.
107+
requested = ALL_SETUPS;
108+
break;
109+
}
110+
111+
// Validate that at least one setup was selected or determined.
112+
if (!requested.length) {
113+
// If no setups are found (e.g., invalid comment), fail the workflow early.
114+
core.setFailed('No setups selected – stopping workflow.');
115+
}
116+
117+
// Construct the matrix object in the format required by the downstream job's strategy.
118+
const matrix = {
119+
// The 'include' key pairs with the 'setup' variable name used in the e2e job.
120+
include: requested.map((s) => ({ setup: s }))
121+
};
122+
123+
// Convert the JavaScript matrix object into a JSON string to be used as the step's output.
124+
return JSON.stringify(matrix);
125+
126+
# ────────────────────────────────────────────────────────────────
127+
# 2️⃣ MAIN TEST JOB – one copy per setup
128+
# ────────────────────────────────────────────────────────────────
129+
e2e:
130+
needs: resolve-setups
131+
if: ${{ needs.resolve-setups.result == 'success' }}
41132

42-
# Matrix drives one job per project.
43133
strategy:
44-
fail-fast: false # Don’t cancel others if one fails
45-
matrix:
46-
project: [ SAI_UAI, UAI] # <── ADD / REMOVE PROJECT_CLIENTS here
134+
# Use the matrix built by the helper job
135+
matrix: ${{ fromJSON(needs.resolve-setups.outputs.matrix) }}
136+
# Do not cancel other setups if one fails
137+
fail-fast: false
138+
139+
# Human-readable name in the Actions UI
140+
name: "E2E – ${{ matrix.setup }}"
141+
# Virtual-machine image
142+
runs-on: ubuntu-latest
47143

48-
# Map the matrix entry → matching Environment
49-
# e.g. alpha → project-alpha
50-
environment: project-${{ matrix.project }}
144+
permissions:
145+
# Needed to read repo contents
146+
contents: read
147+
# Needed if you acquire a cloud token via OIDC
148+
id-token: write
149+
150+
# Map to per-setup environment (for PROJECT_CLIENT secret)
151+
environment: setup-${{ matrix.setup }}
51152

52-
# ── 3️⃣ STEPS ───────────────────────────────────────────────
53153
steps:
154+
# ── Check out the code at the desired ref
155+
- name: Checkout code
156+
uses: actions/checkout@v4
157+
with:
158+
ref: ${{ github.event.inputs.ref ||
159+
github.event.pull_request.head.sha ||
160+
github.ref }}
161+
162+
# ── Set up Node.js for JavaScript tests
163+
- name: Set up Node.js
164+
uses: actions/setup-node@v4
165+
with:
166+
node-version: '20'
167+
cache: npm
168+
169+
# ── Install JavaScript dependencies
170+
- name: Install npm packages
171+
run: npm ci
172+
173+
# ── Run Vitest
174+
- name: Run Vitest
175+
env:
176+
PROJECT_CLIENT: ${{ secrets.PROJECT_CLIENT }}
177+
MODEL_DEPLOYMENT_NAME: ${{ secrets.MODEL_DEPLOYMENT_NAME }}
178+
run: npx vitest run --coverage
179+
180+
# ── Set up .NET SDK
181+
- name: Set up .NET SDK
182+
uses: actions/setup-dotnet@v4
183+
with:
184+
dotnet-version: '8.0.x'
185+
186+
# ── Restore .NET dependencies
187+
- name: dotnet restore
188+
run: dotnet restore
189+
190+
# ── Run .NET tests
191+
- name: dotnet test
192+
env:
193+
PROJECT_CLIENT: ${{ secrets.PROJECT_CLIENT }}
194+
MODEL_DEPLOYMENT_NAME: ${{ secrets.MODEL_DEPLOYMENT_NAME }}
195+
run: dotnet test -c Release --verbosity normal
196+
197+
# ── Set up Python
198+
- name: Set up Python
199+
uses: actions/setup-python@v5
200+
with:
201+
python-version: '3.11'
202+
cache: pip
203+
204+
# ── Install Python requirements
205+
- name: Install Python dependencies
206+
run: |
207+
pip install -r docs-samples/agents/python/requirements.txt
54208
55-
# -- 3.1 Check out PR code ----------------------------------
56-
- name: Checkout code
57-
uses: actions/checkout@v4
58-
59-
# -- 3.2 JavaScript / TypeScript (Vitest) -------------------
60-
- name: Set up Node.js (for Vitest)
61-
uses: actions/setup-node@v4
62-
with:
63-
node-version: "20" # use LTS; bump as needed
64-
cache: npm # built-in cache keyed by package-lock.json
65-
66-
- name: Install JS dependencies
67-
run: npm ci
68-
69-
- name: Run Vitest integration suite
70-
# Inject the secrets as environment variables that your app/tests read.
71-
env:
72-
PROJECT_CLIENT: ${{ secrets.PROJECT_CLIENT }}
73-
MODEL_DEPLOYMENT_NAME: ${{ secrets.MODEL_DEPLOYMENT_NAME }}
74-
run: |
75-
# Add any flags you like: coverage, reporters, etc.
76-
npx vitest run
77-
78-
# -- 3.3 .NET (dotnet test) ---------------------------------
79-
- name: Set up .NET SDK
80-
uses: actions/setup-dotnet@v4
81-
with:
82-
dotnet-version: "8.0.x" # or 6.x / 7.x
83-
84-
- name: Restore & build .NET projects
85-
run: dotnet restore
86-
87-
- name: Run .NET tests
88-
env:
89-
PROJECT_CLIENT: ${{ secrets.PROJECT_CLIENT }}
90-
MODEL_DEPLOYMENT_NAME: ${{ secrets.MODEL_DEPLOYMENT_NAME }}
91-
run: |
92-
dotnet test --configuration Release --verbosity normal
93-
94-
# -- 3.4 Python / Pytest -------------------------
95-
- name: Set up Python
96-
uses: actions/setup-python@v5
97-
with:
98-
python-version: "3.9"
99-
cache: pip
100-
101-
- name: Install Python deps
102-
run: pip install -r requirements.txt
103-
104-
- name: Run pytest
105-
env:
106-
PROJECT_CLIENT: ${{ secrets.PROJECT_CLIENT }}
107-
MODEL_DEPLOYMENT_NAME: ${{ secrets.MODEL_DEPLOYMENT_NAME }}
108-
run: pytest -q
209+
# ── Run PyTest
210+
- name: Run PyTest
211+
env:
212+
PROJECT_CLIENT: ${{ secrets.PROJECT_CLIENT }}
213+
MODEL_DEPLOYMENT_NAME: ${{ secrets.MODEL_DEPLOYMENT_NAME }}
214+
run: |
215+
pytest docs-samples/agents/python --maxfail=1 --disable-warnings

0 commit comments

Comments
 (0)