Skip to content

Commit cb5ca60

Browse files
gingerbenwCopilot
andcommitted
update attw check
Co-authored-by: Copilot <copilot@github.com>
1 parent b558134 commit cb5ca60

7 files changed

Lines changed: 174 additions & 120 deletions

File tree

.github/workflows/attw-check.yml

Lines changed: 0 additions & 84 deletions
This file was deleted.

.github/workflows/pr-diff.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ jobs:
4848
cat packages/browser/dist/bugsnag.min.js | gzip | wc -c > .diff/size-after-gzipped
4949
cp coverage/coverage-summary.json .diff/coverage-after.json
5050
51+
- name: Run ATTW check
52+
continue-on-error: true
53+
env:
54+
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
55+
ELECTRON_DISABLE_SANDBOX: 1
56+
run: |
57+
npm run test:attw || true
58+
5159
- name: Run danger
5260
uses: danger/danger-js@67ed2c1f42fd2fc198cc3c14b43c8f83351f4fe9 # 13.0.5
5361
env:

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,5 @@ Gemfile.lock
2424
*.iml
2525
zscaler-root-ca.crt*
2626
.ts38-validation
27+
# Arethetypeswrong working files
28+
attw-results.json

dangerfile.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* global markdown */
22

3-
const { readFileSync } = require('fs')
3+
const { readFileSync, existsSync } = require('fs')
4+
const { execSync } = require('child_process')
45
const coverageDiff = require('coverage-diff')
56

67
const before = {
@@ -25,6 +26,22 @@ const showDiff = n => {
2526
return '_No change_'
2627
}
2728

29+
let attwReport = ''
30+
if (existsSync(`${__dirname}/attw-results.json`)) {
31+
try {
32+
const attwOutput = execSync('node scripts/parse-attw-results.js --format=markdown', {
33+
encoding: 'utf8',
34+
stdio: ['pipe', 'pipe', 'pipe']
35+
})
36+
attwReport = `\n\n${attwOutput}`
37+
} catch (error) {
38+
// Script exits with code 1 if there are problems, but we still want the output
39+
if (error.stdout) {
40+
attwReport = `\n\n${error.stdout}`
41+
}
42+
}
43+
}
44+
2845
markdown(`
2946
### \`@bugsnag/browser\` bundle size diff
3047
@@ -36,5 +53,5 @@ markdown(`
3653
3754
### code coverage diff
3855
39-
${coverageDiff.diff(before.coverage, after.coverage).results}
56+
${coverageDiff.diff(before.coverage, after.coverage).results}${attwReport}
4057
`)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
"build": "lerna run build",
8787
"clean": "lerna run clean",
8888
"build:electron": "lerna run build --scope '@bugsnag/plugin-electron-ipc' --scope '@bugsnag/plugin-electron-app' --scope '@bugsnag/plugin-electron-client-state-persistence'",
89-
"test:attw": "lerna exec --concurrency 1 -- attw --pack . -f json > attw-results.json",
89+
"test:attw": "node scripts/run-attw.js",
9090
"test:lint": "eslint --report-unused-disable-directives .",
9191
"test:lint-native": "bash scripts/cppcheck.sh",
9292
"test:unit:electron-runner": "xvfb-maybe --auto-servernum -- jest -c config/electron-jest.config.js --rootDir .",

scripts/parse-attw-results.js

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,50 +10,63 @@ const path = require('path');
1010

1111
function parseResults(filePath) {
1212
const content = fs.readFileSync(filePath, 'utf8');
13-
const lines = content.split('\n');
14-
const results = [];
1513

16-
let currentJson = '';
17-
let braceCount = 0;
18-
let inJson = false;
19-
20-
for (const line of lines) {
21-
// Skip empty lines and lines that don't start a JSON object if we're not already in one
22-
if (!inJson && !line.trim().startsWith('{')) {
23-
continue;
14+
try {
15+
// Try parsing as a JSON array first (new format)
16+
const parsed = JSON.parse(content);
17+
if (Array.isArray(parsed)) {
18+
return parsed;
2419
}
20+
// If it's a single object, wrap it in an array
21+
return [parsed];
22+
} catch (error) {
23+
// Fall back to parsing multiple JSON objects separated by newlines (legacy format)
24+
console.warn('⚠️ Using legacy multi-object JSON parsing. Consider running with the new script.');
25+
const lines = content.split('\n');
26+
const results = [];
2527

26-
// Start tracking a new JSON object
27-
if (line.trim().startsWith('{') && braceCount === 0) {
28-
inJson = true;
29-
currentJson = '';
30-
braceCount = 0;
31-
}
28+
let currentJson = '';
29+
let braceCount = 0;
30+
let inJson = false;
3231

33-
if (inJson) {
34-
currentJson += line + '\n';
32+
for (const line of lines) {
33+
// Skip empty lines and lines that don't start a JSON object if we're not already in one
34+
if (!inJson && !line.trim().startsWith('{')) {
35+
continue;
36+
}
3537

36-
// Count braces to know when we've completed a JSON object
37-
for (const char of line) {
38-
if (char === '{') braceCount++;
39-
if (char === '}') braceCount--;
38+
// Start tracking a new JSON object
39+
if (line.trim().startsWith('{') && braceCount === 0) {
40+
inJson = true;
41+
currentJson = '';
42+
braceCount = 0;
4043
}
4144

42-
// When braceCount returns to 0, we have a complete JSON object
43-
if (braceCount === 0) {
44-
try {
45-
const parsed = JSON.parse(currentJson);
46-
results.push(parsed);
47-
} catch (err) {
48-
console.error('Error parsing JSON object:', err.message);
45+
if (inJson) {
46+
currentJson += line + '\n';
47+
48+
// Count braces to know when we've completed a JSON object
49+
for (const char of line) {
50+
if (char === '{') braceCount++;
51+
if (char === '}') braceCount--;
52+
}
53+
54+
// When braceCount returns to 0, we have a complete JSON object
55+
if (braceCount === 0) {
56+
try {
57+
const parsed = JSON.parse(currentJson);
58+
results.push(parsed);
59+
} catch (err) {
60+
console.error('Error parsing JSON object:', err.message);
61+
}
62+
inJson = false;
63+
currentJson = '';
4964
}
50-
inJson = false;
51-
currentJson = '';
5265
}
5366
}
67+
68+
return results;
5469
}
55-
56-
return results;
5770
}
5871

5972
function analyzeResults(results) {

scripts/run-attw.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#!/usr/bin/env node
2+
3+
const { execSync } = require('child_process');
4+
const fs = require('fs');
5+
const path = require('path');
6+
7+
/**
8+
* Run ATTW checks on all packages and output a properly formatted JSON file
9+
*/
10+
11+
function getPackages() {
12+
try {
13+
const output = execSync('npx lerna list --all --json', {
14+
encoding: 'utf8',
15+
stdio: ['pipe', 'pipe', 'pipe']
16+
});
17+
return JSON.parse(output);
18+
} catch (error) {
19+
console.error('Failed to get package list from lerna:', error.message);
20+
process.exit(1);
21+
}
22+
}
23+
24+
function runAttwForPackage(packagePath) {
25+
try {
26+
const output = execSync('npx attw --pack . -f json', {
27+
cwd: packagePath,
28+
encoding: 'utf8',
29+
stdio: ['pipe', 'pipe', 'pipe']
30+
});
31+
32+
// Parse the JSON output (handle pretty-printed multi-line JSON)
33+
return JSON.parse(output);
34+
} catch (error) {
35+
// attw may exit with non-zero code if problems are found
36+
// but the output should still be valid JSON
37+
if (error.stdout) {
38+
try {
39+
return JSON.parse(error.stdout);
40+
} catch {
41+
console.error(`Failed to parse ATTW output for ${packagePath}:`, error.message);
42+
return null;
43+
}
44+
}
45+
console.error(`Failed to run ATTW for ${packagePath}:`, error.message);
46+
return null;
47+
}
48+
}
49+
50+
function main() {
51+
console.log('Getting package list...');
52+
const packages = getPackages();
53+
console.log(`Found ${packages.length} packages`);
54+
55+
const results = [];
56+
let checked = 0;
57+
let skipped = 0;
58+
59+
for (const pkg of packages) {
60+
// Skip private packages
61+
if (pkg.private) {
62+
console.log(`Skipping private package: ${pkg.name}`);
63+
skipped++;
64+
continue;
65+
}
66+
67+
console.log(`Checking ${pkg.name}...`);
68+
const result = runAttwForPackage(pkg.location);
69+
70+
if (result) {
71+
results.push(result);
72+
checked++;
73+
} else {
74+
skipped++;
75+
}
76+
}
77+
78+
// Write the results as a proper JSON array
79+
const outputPath = path.join(process.cwd(), 'attw-results.json');
80+
fs.writeFileSync(outputPath, JSON.stringify(results, null, 2), 'utf8');
81+
82+
console.log(`\n✅ ATTW check complete!`);
83+
console.log(` Packages checked: ${checked}`);
84+
console.log(` Packages skipped: ${skipped}`);
85+
console.log(` Results written to: ${outputPath}`);
86+
87+
// Exit with error code if any package has problems
88+
const packagesWithProblems = results.filter(r =>
89+
r.problems && Object.keys(r.problems).length > 0
90+
).length;
91+
92+
if (packagesWithProblems > 0) {
93+
console.log(`\n⚠️ ${packagesWithProblems} package(s) have type issues`);
94+
process.exit(1);
95+
}
96+
}
97+
98+
main();

0 commit comments

Comments
 (0)