|
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 | +# ──────────────────────────────────────────────────────────────── |
26 | 16 | 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 |
32 | 35 |
|
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 | +# ──────────────────────────────────────────────────────────────── |
34 | 44 | jobs: |
35 | | - e2e: |
36 | | - name: "E2E – ${{ matrix.project }}" # Shows up as “E2E – alpha” |
| 45 | + resolve-setups: |
37 | 46 | 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' }} |
41 | 132 |
|
42 | | - # Matrix drives one job per project. |
43 | 133 | 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 |
47 | 143 |
|
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 }} |
51 | 152 |
|
52 | | - # ── 3️⃣ STEPS ─────────────────────────────────────────────── |
53 | 153 | 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 |
54 | 208 |
|
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