Skip to content

Commit 6692895

Browse files
authored
ci: add workflow to run package managers under deno (#31070)
This commit adds a workflow that runs on a schedule (once per day) that runs a quick integration test for other package manager running in Deno.
1 parent d9b87e1 commit 6692895

File tree

3 files changed

+211
-0
lines changed

3 files changed

+211
-0
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: ecosystem_compat_test
2+
3+
on:
4+
schedule:
5+
- cron: '0 10 * * *'
6+
workflow_dispatch:
7+
8+
jobs:
9+
test:
10+
runs-on: '${{ matrix.runner }}'
11+
strategy:
12+
matrix:
13+
include:
14+
- os: linux
15+
runner: ubuntu-latest
16+
- os: windows
17+
runner: windows-latest
18+
- os: darwin
19+
runner: macos-latest
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v4
23+
with:
24+
submodules: true
25+
- name: Setup Deno
26+
uses: denoland/setup-deno@v2
27+
with:
28+
deno-version: canary
29+
- name: Setup gcloud
30+
uses: google-github-actions/setup-gcloud@v2
31+
with:
32+
project_id: denoland
33+
- name: Run tests
34+
run: deno -A tools/ecosystem_compat_tests.ts
35+
- name: Post message to slack channel
36+
run: deno -A tools/ecosystem_compat_slack.ts
37+
env:
38+
SLACK_TOKEN: ${{ secrets.NODE_COMPAT_SLACK_TOKEN }} # NodeCompat bot
39+
SLACK_CHANNEL: ${{ secrets.NODE_COMPAT_SLACK_CHANNEL }}

tools/ecosystem_compat_slack.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright 2018-2025 the Deno authors. MIT license.
2+
// deno-lint-ignore-file no-console
3+
4+
import { LogLevel, WebClient } from "npm:@slack/[email protected]";
5+
6+
const token = Deno.env.get("SLACK_TOKEN");
7+
const channel = Deno.env.get("SLACK_CHANNEL");
8+
9+
if (!token) {
10+
console.error("SLACK_TOKEN is required");
11+
}
12+
if (!channel) {
13+
console.error("SLACK_CHANNEL is required");
14+
}
15+
16+
interface PmResult {
17+
exitCode: number;
18+
duration: number;
19+
}
20+
21+
interface EcosystemReport {
22+
npm: PmResult;
23+
yarn: PmResult;
24+
pnpm: PmResult;
25+
}
26+
27+
const client = new WebClient(token, {
28+
logLevel: LogLevel.DEBUG,
29+
});
30+
31+
function formatDuration(duration: number) {
32+
return (duration / 1000).toFixed(2) + "s";
33+
}
34+
35+
function createMessage(ecosystemReport: EcosystemReport) {
36+
let mrkdwn = "Package manager report\n";
37+
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`;
47+
48+
return [
49+
{
50+
type: "section",
51+
text: {
52+
type: "mrkdwn",
53+
text: mrkdwn,
54+
},
55+
},
56+
];
57+
}
58+
59+
async function main() {
60+
const ecosystemReport = await Deno.readTextFile(
61+
import.meta.resolve("./ecosystem_report.json"),
62+
)
63+
.then(JSON.parse) as EcosystemReport;
64+
65+
try {
66+
const result = await client.chat.postMessage({
67+
token,
68+
channel,
69+
blocks: createMessage(ecosystemReport),
70+
unfurl_links: false,
71+
unfurl_media: false,
72+
});
73+
74+
console.log(result);
75+
} catch (error) {
76+
console.error(error);
77+
}
78+
}
79+
80+
await main();

tools/ecosystem_compat_tests.ts

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#!/usr/bin/env -S deno run --allow-all --config=tests/config/deno.json
2+
// Copyright 2018-2025 the Deno authors. MIT license.
3+
import $ from "jsr:@david/dax@^0.42.0";
4+
5+
async function setupTestRepo() {
6+
await teardownTestRepo();
7+
await $`git clone https://github.com/lucacasonato/nextjs-demo`;
8+
}
9+
10+
async function teardownTestRepo() {
11+
await $`rm -rf nextjs-demo`;
12+
}
13+
14+
async function runPackageManager(pm, cmd) {
15+
const state = Date.now();
16+
const result =
17+
await $`cd nextjs-demo ; rm -rf node_modules ; ${Deno.execPath()} run -A --no-config npm:${pm} ${cmd}`
18+
.stdout("inheritPiped").stderr("inheritPiped").noThrow().timeout(
19+
"60s",
20+
);
21+
const duration = Date.now() - state;
22+
return {
23+
exitCode: result.code,
24+
stdout: result.stdout,
25+
stderr: result.stderr,
26+
duration,
27+
};
28+
}
29+
30+
function testNpm() {
31+
return runPackageManager("npm", "install");
32+
}
33+
34+
function testYarn() {
35+
return runPackageManager("yarn", "install");
36+
}
37+
38+
function testPnpm() {
39+
return runPackageManager("pnpm", "install");
40+
}
41+
42+
async function main() {
43+
let passed = true;
44+
$.logStep("Setting up test repo...");
45+
await setupTestRepo();
46+
$.logStep("Testing npm...");
47+
const npmResult = await testNpm();
48+
if (npmResult.exitCode !== 0) {
49+
passed = false;
50+
$.logWarn(`npm install failed: ${npmResult.stderr}`);
51+
}
52+
$.logStep("Testing yarn...");
53+
const yarnResult = await testYarn();
54+
if (yarnResult.exitCode !== 0) {
55+
passed = false;
56+
$.logWarn(`yarn install failed: ${yarnResult.stderr}`);
57+
}
58+
$.logStep("Testing pnpm...");
59+
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+
}
69+
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+
}),
85+
);
86+
}
87+
88+
try {
89+
await main();
90+
} finally {
91+
await teardownTestRepo();
92+
}

0 commit comments

Comments
 (0)