-
Notifications
You must be signed in to change notification settings - Fork 0
202 lines (180 loc) · 7.59 KB
/
Copy pathtest.yaml
File metadata and controls
202 lines (180 loc) · 7.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
name: "Test Dev Container Features"
on:
push:
branches: [main]
paths:
- "src/**"
- "test/**"
pull_request:
branches: [main]
paths:
- "src/**"
- "test/**"
workflow_dispatch:
inputs:
tier:
description: "Which tier to run"
type: choice
default: full
options:
- full
- daily
schedule:
# Daily 06:00 UTC — high-risk tier (most fragile floating installers only)
- cron: "0 6 * * *"
# Monday 07:00 UTC — full tier (every feature)
- cron: "0 7 * * 1"
jobs:
# Single source of truth for "what runs". The daily cron (and a manual
# `tier: daily` dispatch) run only the most fragile features; everything else
# (weekly cron, full dispatch, push, PR) runs the complete matrix.
setup:
runs-on: ubuntu-latest
outputs:
tier: ${{ steps.plan.outputs.tier }}
autogen-matrix: ${{ steps.plan.outputs.autogen-matrix }}
scenario-features: ${{ steps.plan.outputs.scenario-features }}
steps:
- id: plan
env:
EVENT_SCHEDULE: ${{ github.event.schedule }}
DISPATCH_TIER: ${{ github.event.inputs.tier }}
run: |
if [ "$EVENT_SCHEDULE" = "0 6 * * *" ] || [ "$DISPATCH_TIER" = "daily" ]; then
tier=daily
else
tier=full
fi
echo "tier=$tier" >> "$GITHUB_OUTPUT"
full_autogen='{"include":[{"feature":"ai-clis","baseImage":"mcr.microsoft.com/devcontainers/javascript-node:22"},{"feature":"modern-cli-tools","baseImage":"mcr.microsoft.com/devcontainers/base:ubuntu-24.04"},{"feature":"node-dev-tools","baseImage":"mcr.microsoft.com/devcontainers/javascript-node:22"},{"feature":"rust-dev-tools","baseImage":"mcr.microsoft.com/devcontainers/rust:latest"},{"feature":"github-actions-tools","baseImage":"mcr.microsoft.com/devcontainers/base:ubuntu-24.04"},{"feature":"python-tools","baseImage":"mcr.microsoft.com/devcontainers/python:latest"}]}'
daily_autogen='{"include":[{"feature":"ai-clis","baseImage":"mcr.microsoft.com/devcontainers/javascript-node:22"},{"feature":"modern-cli-tools","baseImage":"mcr.microsoft.com/devcontainers/base:ubuntu-24.04"}]}'
full_scenarios='["ai-clis","modern-cli-tools","node-dev-tools","rust-dev-tools","github-actions-tools","python-tools"]'
daily_scenarios='["ai-clis","modern-cli-tools"]'
if [ "$tier" = "daily" ]; then
echo "autogen-matrix=$daily_autogen" >> "$GITHUB_OUTPUT"
echo "scenario-features=$daily_scenarios" >> "$GITHUB_OUTPUT"
else
echo "autogen-matrix=$full_autogen" >> "$GITHUB_OUTPUT"
echo "scenario-features=$full_scenarios" >> "$GITHUB_OUTPUT"
fi
- name: Show plan
run: |
echo "tier=${{ steps.plan.outputs.tier }}"
echo "autogen-matrix=${{ steps.plan.outputs.autogen-matrix }}"
echo "scenario-features=${{ steps.plan.outputs.scenario-features }}"
test-autogenerated:
needs: setup
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.setup.outputs.autogen-matrix) }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
- name: Install DevContainer CLI
run: npm install -g @devcontainers/cli
- name: Run auto-generated tests
run: devcontainer features test --features ${{ matrix.feature }} --base-image ${{ matrix.baseImage }} .
test-scenarios:
needs: setup
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
feature: ${{ fromJSON(needs.setup.outputs.scenario-features) }}
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
- name: Install DevContainer CLI
run: npm install -g @devcontainers/cli
- name: Run scenario tests
run: devcontainer features test --features ${{ matrix.feature }} --skip-autogenerated .
test-global:
needs: setup
# The all-features composition test is broad; skip it on the daily
# high-risk tier and keep it on full runs (weekly / push / PR / dispatch).
# It is a blocking job like the others: a failure marks the run red (so PR
# authors catch composition breakage) and surfaces to notify-on-failure on
# scheduled/dispatched runs. (It cannot be continue-on-error, or its result
# would report as success to the notify gate and never alert.)
if: needs.setup.outputs.tier != 'daily'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
- name: Install DevContainer CLI
run: npm install -g @devcontainers/cli
- name: Run global scenario tests
run: devcontainer features test --global-scenarios-only .
# On scheduled (or manually dispatched) runs, surface failures as a single
# deduplicated GitHub issue. Upstream third-party installers can break without
# any change to this repo, so a red check on an otherwise-idle repo would
# otherwise go unnoticed. Not gated to PRs — those already show a red check.
notify-on-failure:
needs: [setup, test-autogenerated, test-scenarios, test-global]
if: always() && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- uses: actions/github-script@v7
env:
NEEDS: ${{ toJSON(needs) }}
TIER: ${{ needs.setup.outputs.tier }}
with:
script: |
const needs = JSON.parse(process.env.NEEDS);
const failed = Object.entries(needs)
.filter(([, v]) => v.result === 'failure')
.map(([name]) => name);
if (failed.length === 0) {
core.info('No failed jobs — nothing to report.');
return;
}
const tier = process.env.TIER || 'unknown';
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const label = 'installer-breakage';
const title = 'Scheduled feature validation failed';
const body = [
`Scheduled feature validation (**${tier}** tier) failed.`,
'',
`**Failed jobs:** ${failed.join(', ')}`,
`**Run:** ${runUrl}`,
'',
'This usually means an upstream third-party installer changed or broke.',
'Open the run above to see which feature failed.',
].join('\n');
const existing = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: label,
});
if (existing.data.length > 0) {
const number = existing.data[0].number;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: number,
body,
});
core.info(`Commented on existing issue #${number}.`);
} else {
const created = await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title,
body,
labels: [label],
});
core.info(`Opened issue #${created.data.number}.`);
}