Skip to content

Commit c20ef4c

Browse files
authored
ci: adjustments to the ecosystem compat tests (#31076)
Allows to build matrix report split by OS and program being run.
1 parent eaebf88 commit c20ef4c

File tree

3 files changed

+241
-66
lines changed

3 files changed

+241
-66
lines changed

.github/workflows/ecosystem_compat_test.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,52 @@ jobs:
2626
uses: denoland/setup-deno@v2
2727
with:
2828
deno-version: canary
29+
- name: Install Python
30+
uses: actions/setup-python@v5
31+
with:
32+
python-version: 3.11
33+
- name: Authenticate with Google Cloud
34+
uses: google-github-actions/auth@v2
35+
with:
36+
project_id: denoland
37+
credentials_json: '${{ secrets.GCP_SA_KEY }}'
38+
export_environment_variables: true
39+
create_credentials_file: true
2940
- name: Setup gcloud
3041
uses: google-github-actions/setup-gcloud@v2
3142
with:
3243
project_id: denoland
3344
- name: Run tests
3445
run: deno -A tools/ecosystem_compat_tests.ts
46+
- name: Upload the report to dl.deno.land
47+
run: |-
48+
gsutil -h "Cache-Control: public, max-age=3600" cp tools/ecosystem_report.json gs://dl.deno.land/ecosystem-compat-test/$(date +%F)/report-${{matrix.os}}.json
49+
summary:
50+
runs-on: ubuntu-latest
51+
needs: test
52+
if: ${{ always() }}
53+
steps:
54+
- name: Checkout
55+
uses: actions/checkout@v4
56+
with:
57+
submodules: true
58+
- name: Setup Deno
59+
uses: denoland/setup-deno@v2
60+
- name: Install Python
61+
uses: actions/setup-python@v5
62+
with:
63+
python-version: 3.11
64+
- name: Authenticate with Google Cloud
65+
uses: google-github-actions/auth@v2
66+
with:
67+
project_id: denoland
68+
credentials_json: '${{ secrets.GCP_SA_KEY }}'
69+
export_environment_variables: true
70+
create_credentials_file: true
71+
- name: Setup gcloud
72+
uses: google-github-actions/setup-gcloud@v2
73+
with:
74+
project_id: denoland
3575
- name: Post message to slack channel
3676
run: deno -A tools/ecosystem_compat_slack.ts
3777
env:

tools/ecosystem_compat_slack.ts

Lines changed: 152 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,44 +29,173 @@ const client = new WebClient(token, {
2929
});
3030

3131
function formatDuration(duration: number) {
32-
return (duration / 1000).toFixed(2) + "s";
32+
return (duration / 1000).toFixed(0) + "s";
3333
}
3434

35-
function createMessage(ecosystemReport: EcosystemReport) {
36-
let mrkdwn = "Package manager report\n";
35+
function createMessage(ecosystemReports: Record<string, EcosystemReport>) {
36+
const elements = [];
3737

38-
mrkdwn += `*npm*: exit code: ${ecosystemReport.npm.exitCode}, duration: ${
39-
formatDuration(ecosystemReport.npm.duration)
40-
}\n`;
41-
mrkdwn += `*yarn*: exit code: ${ecosystemReport.yarn.exitCode}, duration: ${
42-
formatDuration(ecosystemReport.yarn.duration)
43-
}\n`;
44-
mrkdwn += `*pnpm*: exit code: ${ecosystemReport.pnpm.exitCode}, duration: ${
45-
formatDuration(ecosystemReport.pnpm.duration)
46-
}\n`;
38+
elements.push({
39+
type: "section",
40+
text: {
41+
type: "mrkdwn",
42+
text: "*Package manager report*\n\n",
43+
},
44+
});
4745

48-
return [
46+
const tableHeader = [
4947
{
50-
type: "section",
51-
text: {
52-
type: "mrkdwn",
53-
text: mrkdwn,
54-
},
48+
type: "rich_text",
49+
elements: [
50+
{
51+
type: "rich_text_section",
52+
elements: [
53+
{
54+
type: "text",
55+
text: "Program",
56+
style: {
57+
bold: true,
58+
},
59+
},
60+
],
61+
},
62+
],
63+
},
64+
{
65+
type: "rich_text",
66+
elements: [
67+
{
68+
type: "rich_text_section",
69+
elements: [
70+
{
71+
type: "text",
72+
text: "Linux",
73+
style: {
74+
bold: true,
75+
},
76+
},
77+
],
78+
},
79+
],
80+
},
81+
{
82+
type: "rich_text",
83+
elements: [
84+
{
85+
type: "rich_text_section",
86+
elements: [
87+
{
88+
type: "text",
89+
text: "macOS",
90+
style: {
91+
bold: true,
92+
},
93+
},
94+
],
95+
},
96+
],
97+
},
98+
{
99+
type: "rich_text",
100+
elements: [
101+
{
102+
type: "rich_text_section",
103+
elements: [
104+
{
105+
type: "text",
106+
text: "Windows",
107+
style: {
108+
bold: true,
109+
},
110+
},
111+
],
112+
},
113+
],
55114
},
56115
];
116+
117+
const rows = [];
118+
119+
const programs = Object.keys(ecosystemReports["darwin"]);
120+
for (const program of programs) {
121+
const row = [
122+
{
123+
type: "rich_text",
124+
elements: [
125+
{
126+
type: "rich_text_section",
127+
elements: [
128+
{
129+
type: "text",
130+
text: program,
131+
},
132+
],
133+
},
134+
],
135+
},
136+
];
137+
138+
for (const os of ["darwin", "linux", "windows"]) {
139+
const report = ecosystemReports[os][program] satisfies PmResult;
140+
141+
const text = `${
142+
report.exitCode === 0 ? "✅" : "❌"
143+
} code: ${report.exitCode}, (${formatDuration(report.duration)})`;
144+
row.push({
145+
type: "rich_text",
146+
elements: [
147+
{
148+
type: "rich_text_section",
149+
elements: [
150+
{
151+
type: "text",
152+
text: text,
153+
style: {
154+
code: true,
155+
},
156+
},
157+
],
158+
},
159+
],
160+
});
161+
}
162+
163+
rows.push(row);
164+
}
165+
166+
elements.push({
167+
type: "table",
168+
rows: [tableHeader, ...rows],
169+
});
170+
return elements;
171+
}
172+
173+
async function downloadOsReports() {
174+
const oses = ["windows", "linux", "darwin"];
175+
const reports: Record<string, string> = {};
176+
for (const os of oses) {
177+
const res = await fetch(
178+
`https://dl.deno.land/ecosystem-compat-test/${
179+
new Date()
180+
.toISOString()
181+
.substring(0, 10)
182+
}/report-${os}.json`,
183+
);
184+
if (res.status === 200) {
185+
reports[os] = await res.json() satisfies EcosystemReport;
186+
}
187+
}
188+
return reports;
57189
}
58190

59191
async function main() {
60-
const ecosystemReport = await Deno.readTextFile(
61-
import.meta.resolve("./ecosystem_report.json"),
62-
)
63-
.then(JSON.parse) as EcosystemReport;
192+
const ecosystemReports = await downloadOsReports();
64193

65194
try {
66195
const result = await client.chat.postMessage({
67196
token,
68197
channel,
69-
blocks: createMessage(ecosystemReport),
198+
blocks: createMessage(ecosystemReports),
70199
unfurl_links: false,
71200
unfurl_media: false,
72201
});

tools/ecosystem_compat_tests.ts

Lines changed: 49 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/env -S deno run --allow-all --config=tests/config/deno.json
22
// Copyright 2018-2025 the Deno authors. MIT license.
33
import $ from "jsr:@david/dax@^0.42.0";
4+
import { join } from "./util.js";
45

56
async function setupTestRepo() {
67
await teardownTestRepo();
@@ -11,7 +12,7 @@ async function teardownTestRepo() {
1112
await $`rm -rf nextjs-demo`;
1213
}
1314

14-
async function runPackageManager(pm, cmd) {
15+
async function runPackageManager(pm: string, cmd: string) {
1516
const state = Date.now();
1617
const result =
1718
await $`cd nextjs-demo ; rm -rf node_modules ; ${Deno.execPath()} run -A --no-config npm:${pm} ${cmd}`
@@ -27,61 +28,66 @@ async function runPackageManager(pm, cmd) {
2728
};
2829
}
2930

30-
function testNpm() {
31-
return runPackageManager("npm", "install");
31+
async function testNpm() {
32+
$.logStep("Testing npm...");
33+
const report = await runPackageManager("npm", "install");
34+
if (report.exitCode === 0) {
35+
$.logStep("npm install succeeded");
36+
} else {
37+
$.logWarn(`npm install failed: ${report.stderr}`);
38+
}
39+
return report;
3240
}
3341

34-
function testYarn() {
35-
return runPackageManager("yarn", "install");
42+
async function testYarn() {
43+
$.logStep("Testing yarn...");
44+
const report = await runPackageManager("yarn", "install");
45+
if (report.exitCode === 0) {
46+
$.logStep("yarn install succeeded");
47+
} else {
48+
$.logWarn(`yarn install failed: ${report.stderr}`);
49+
}
50+
return report;
3651
}
3752

38-
function testPnpm() {
39-
return runPackageManager("pnpm", "install");
53+
async function testPnpm() {
54+
$.logStep("Testing pnpm...");
55+
const report = await runPackageManager("pnpm", "install");
56+
if (report.exitCode === 0) {
57+
$.logStep("pnpm install succeeded");
58+
} else {
59+
$.logWarn(`pnpm install failed: ${report.stderr}`);
60+
}
61+
return report;
4062
}
4163

4264
async function main() {
43-
let passed = true;
4465
$.logStep("Setting up test repo...");
4566
await setupTestRepo();
46-
$.logStep("Testing npm...");
67+
4768
const npmResult = await testNpm();
48-
if (npmResult.exitCode !== 0) {
49-
passed = false;
50-
$.logWarn(`npm install failed: ${npmResult.stderr}`);
51-
}
52-
$.logStep("Testing yarn...");
5369
const yarnResult = await testYarn();
54-
if (yarnResult.exitCode !== 0) {
55-
passed = false;
56-
$.logWarn(`yarn install failed: ${yarnResult.stderr}`);
57-
}
58-
$.logStep("Testing pnpm...");
5970
const pnpmResult = await testPnpm();
60-
if (pnpmResult.exitCode !== 0) {
61-
passed = false;
62-
$.logWarn(`pnpm install failed: ${pnpmResult.stderr}`);
63-
}
64-
if (passed) {
65-
$.logStep("All tests passed!");
66-
} else {
67-
$.logError("Some tests failed");
68-
}
71+
const reports = {
72+
npm: {
73+
exitCode: npmResult.exitCode,
74+
duration: npmResult.duration,
75+
},
76+
yarn: {
77+
exitCode: yarnResult.exitCode,
78+
duration: yarnResult.duration,
79+
},
80+
pnpm: {
81+
exitCode: pnpmResult.exitCode,
82+
duration: pnpmResult.duration,
83+
},
84+
};
85+
86+
$.logStep("Final report:");
87+
$.log(reports);
6988
await Deno.writeTextFile(
70-
import.meta.resolve("./ecosystem_report.json"),
71-
JSON.stringify({
72-
npm: {
73-
exitCode: npmResult.exitCode,
74-
duration: npmResult.duration,
75-
},
76-
yarn: {
77-
exitCode: yarnResult.exitCode,
78-
duration: yarnResult.duration,
79-
},
80-
pnpm: {
81-
exitCode: pnpmResult.exitCode,
82-
duration: pnpmResult.duration,
83-
},
84-
}),
89+
join(import.meta.dirname!, "ecosystem_report.json"),
90+
JSON.stringify(reports),
8591
);
8692
}
8793

0 commit comments

Comments
 (0)