playwright-slack-report-burak 3.5.1 → 3.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/ResultsParser.js +25 -131
- package/dist/src/SlackReporter.js +1 -1
- package/package.json +1 -1
|
@@ -9,7 +9,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
9
9
|
const fs = require('fs');
|
|
10
10
|
const os = require('os');
|
|
11
11
|
const path = require('path');
|
|
12
|
-
const axios = require('axios');
|
|
13
12
|
const { exec, execFileSync } = require('child_process');
|
|
14
13
|
let AdmZip;
|
|
15
14
|
try {
|
|
@@ -31,26 +30,19 @@ const PLAYWRIGHT_REPORT_DIR = path.join('./', 'playwright-report');
|
|
|
31
30
|
const GITHUB_RUN_ID = process.env.GITHUB_RUN_ID || 'local';
|
|
32
31
|
const GITHUB_RUN_ATTEMPT = process.env.GITHUB_RUN_ATTEMPT || '1';
|
|
33
32
|
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const GCS_REPORTS_FOLDER_PREFIX = process.env.GCS_REPORTS_FOLDER_PREFIX;
|
|
38
|
-
const GCS_UPLOAD_API_BASE_URL = process.env.GCS_UPLOAD_API_BASE_URL;
|
|
39
|
-
|
|
40
|
-
// MinIO artifact storage configuration (artifacts uploaded by shards 2+ as
|
|
41
|
-
// <bucket>/shard-artifacts/<run_id>-<run_attempt>/shard-<shard>.tar.zst, a zstd-compressed tar of playwright-report)
|
|
33
|
+
// MinIO storage configuration. Artifacts uploaded by shards 2+ as
|
|
34
|
+
// <bucket>/shard-artifacts/<run_id>-<run_attempt>/shard-<shard>.tar.zst (a zstd-compressed tar of playwright-report),
|
|
35
|
+
// merged HTML reports uploaded by shard 1 under <bucket>/playwright-reports/<run_id>-<run_attempt>/
|
|
42
36
|
const MINIO_ENDPOINT = process.env.MINIO_ENDPOINT;
|
|
43
37
|
const MINIO_ACCESS_KEY = process.env.MINIO_ACCESS_KEY;
|
|
44
38
|
const MINIO_SECRET_KEY = process.env.MINIO_SECRET_KEY;
|
|
45
39
|
const MINIO_BUCKET = process.env.MINIO_BUCKET;
|
|
46
40
|
const MINIO_ALIAS = 'minio';
|
|
47
41
|
const MINIO_ARTIFACTS_DIR = 'shard-artifacts';
|
|
42
|
+
const MINIO_REPORTS_DIR = 'playwright-reports';
|
|
48
43
|
|
|
49
44
|
const getMinioObjectPath = (shard) => `${MINIO_ALIAS}/${MINIO_BUCKET}/${MINIO_ARTIFACTS_DIR}/${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}/shard-${shard}.tar.zst`;
|
|
50
|
-
|
|
51
|
-
// Helper functions for report paths
|
|
52
|
-
const getRunFolder = () => `${GCS_REPORTS_FOLDER_PREFIX}/${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}`;
|
|
53
|
-
const getGcsObjectPath = (relativePath) => `${getRunFolder()}/${relativePath}`;
|
|
45
|
+
const getMinioReportsPath = () => `${MINIO_ALIAS}/${MINIO_BUCKET}/${MINIO_REPORTS_DIR}/${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}`;
|
|
54
46
|
|
|
55
47
|
// ============================================================================
|
|
56
48
|
|
|
@@ -185,7 +177,7 @@ class ResultsParser {
|
|
|
185
177
|
}
|
|
186
178
|
|
|
187
179
|
await this.mergeReports();
|
|
188
|
-
await this.
|
|
180
|
+
await this.pushReportsToMinio();
|
|
189
181
|
} else if (singleShardNoBlob) {
|
|
190
182
|
// Single shard without blob (e.g. different reporter config): use node summary for Slack report
|
|
191
183
|
const nodeSummaryFile = path.join(SUMMARIES_DIR, 'node_summary_1.json');
|
|
@@ -573,130 +565,32 @@ class ResultsParser {
|
|
|
573
565
|
}
|
|
574
566
|
}
|
|
575
567
|
|
|
576
|
-
async
|
|
577
|
-
if (!
|
|
578
|
-
|
|
568
|
+
async pushReportsToMinio() {
|
|
569
|
+
if (!process.env.CI) {
|
|
570
|
+
console.log('Skipping MinIO push: not in CI');
|
|
571
|
+
return;
|
|
579
572
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
try {
|
|
583
|
-
serviceAccount = JSON.parse(GCS_SERVICE_ACCOUNT_KEY);
|
|
584
|
-
} catch (e) {
|
|
585
|
-
// Try reading from file path
|
|
586
|
-
if (fs.existsSync(GCS_SERVICE_ACCOUNT_KEY)) {
|
|
587
|
-
serviceAccount = JSON.parse(fs.readFileSync(GCS_SERVICE_ACCOUNT_KEY, 'utf-8'));
|
|
588
|
-
} else {
|
|
589
|
-
throw new Error('Invalid GCS_SERVICE_ACCOUNT_KEY: must be JSON string or file path');
|
|
590
|
-
}
|
|
573
|
+
if (!MINIO_ENDPOINT || !MINIO_ACCESS_KEY || !MINIO_SECRET_KEY || !MINIO_BUCKET) {
|
|
574
|
+
throw new Error('MinIO configuration is required: set MINIO_ENDPOINT, MINIO_ACCESS_KEY, MINIO_SECRET_KEY and MINIO_BUCKET');
|
|
591
575
|
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
const jwt = require('jsonwebtoken');
|
|
595
|
-
const now = Math.floor(Date.now() / 1000);
|
|
596
|
-
const token = jwt.sign(
|
|
597
|
-
{
|
|
598
|
-
iss: serviceAccount.client_email,
|
|
599
|
-
scope: 'https://www.googleapis.com/auth/devstorage.full_control',
|
|
600
|
-
aud: 'https://oauth2.googleapis.com/token',
|
|
601
|
-
exp: now + 3600,
|
|
602
|
-
iat: now
|
|
603
|
-
},
|
|
604
|
-
serviceAccount.private_key,
|
|
605
|
-
{ algorithm: 'RS256' }
|
|
606
|
-
);
|
|
607
|
-
|
|
608
|
-
const tokenResponse = await axios.post('https://oauth2.googleapis.com/token', {
|
|
609
|
-
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
|
610
|
-
assertion: token
|
|
611
|
-
});
|
|
612
|
-
|
|
613
|
-
return tokenResponse.data.access_token;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
async pushReportsToGCS() {
|
|
617
|
-
// Only push in CI environment with required configuration
|
|
618
|
-
if (!process.env.CI || !GCS_SERVICE_ACCOUNT_KEY) {
|
|
619
|
-
console.log('Skipping GCS push: not in CI or missing GCS_SERVICE_ACCOUNT_KEY');
|
|
576
|
+
if (!fs.existsSync(PLAYWRIGHT_REPORT_DIR)) {
|
|
577
|
+
console.warn('Warning: playwright-report directory not found, nothing to upload to MinIO');
|
|
620
578
|
return;
|
|
621
579
|
}
|
|
622
|
-
|
|
580
|
+
const destination = getMinioReportsPath();
|
|
581
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mc-reports-'));
|
|
582
|
+
const mcConfigDir = path.join(tmpDir, '.mc');
|
|
623
583
|
try {
|
|
624
|
-
console.log(`Uploading playwright-report
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
// Collect all files from playwright-report directory
|
|
630
|
-
const files = this.getAllFilesRecursive(PLAYWRIGHT_REPORT_DIR);
|
|
631
|
-
|
|
632
|
-
// Normalize the base directory path for path replacement
|
|
633
|
-
const baseDirPath = path.resolve(PLAYWRIGHT_REPORT_DIR);
|
|
634
|
-
|
|
635
|
-
// Upload all files to GCS
|
|
636
|
-
for (const file of files) {
|
|
637
|
-
// Get relative path from playwright-report directory
|
|
638
|
-
const relativePath = path.relative(baseDirPath, file).replace(/\\/g, '/');
|
|
639
|
-
const objectPath = getGcsObjectPath(relativePath);
|
|
640
|
-
const content = fs.readFileSync(file);
|
|
641
|
-
|
|
642
|
-
// Upload file to GCS
|
|
643
|
-
const uploadUrl = `${GCS_UPLOAD_API_BASE_URL}/b/${GCS_BUCKET_NAME}/o?uploadType=media&name=${encodeURIComponent(objectPath)}`;
|
|
644
|
-
|
|
645
|
-
await axios.post(uploadUrl, content, {
|
|
646
|
-
headers: {
|
|
647
|
-
'Authorization': `Bearer ${accessToken}`,
|
|
648
|
-
'Content-Type': this.getContentType(file)
|
|
649
|
-
}
|
|
650
|
-
});
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
console.log(`Successfully uploaded ${files.length} files to GCS bucket: ${GCS_BUCKET_NAME} in folder: ${getRunFolder()}`);
|
|
584
|
+
console.log(`Uploading playwright-report to MinIO: ${destination}`);
|
|
585
|
+
// Pass credentials as separate args (not embedded in a URL) to avoid encoding issues.
|
|
586
|
+
execFileSync('mc', ['--config-dir', mcConfigDir, 'alias', 'set', MINIO_ALIAS, MINIO_ENDPOINT, MINIO_ACCESS_KEY, MINIO_SECRET_KEY], { stdio: 'ignore' });
|
|
587
|
+
execFileSync('mc', ['--config-dir', mcConfigDir, 'cp', '--recursive', `${PLAYWRIGHT_REPORT_DIR}/`, `${destination}/`], { stdio: 'inherit' });
|
|
588
|
+
console.log(`Successfully uploaded playwright-report to MinIO: ${destination}`);
|
|
654
589
|
} catch (error) {
|
|
655
|
-
console.warn('Warning: Failed to push reports to
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
getContentType(filePath) {
|
|
663
|
-
const ext = path.extname(filePath).toLowerCase();
|
|
664
|
-
const contentTypes = {
|
|
665
|
-
'.html': 'text/html',
|
|
666
|
-
'.css': 'text/css',
|
|
667
|
-
'.js': 'application/javascript',
|
|
668
|
-
'.json': 'application/json',
|
|
669
|
-
'.png': 'image/png',
|
|
670
|
-
'.jpg': 'image/jpeg',
|
|
671
|
-
'.jpeg': 'image/jpeg',
|
|
672
|
-
'.gif': 'image/gif',
|
|
673
|
-
'.svg': 'image/svg+xml',
|
|
674
|
-
'.zip': 'application/zip',
|
|
675
|
-
'.txt': 'text/plain',
|
|
676
|
-
'.xml': 'application/xml'
|
|
677
|
-
};
|
|
678
|
-
return contentTypes[ext] || 'application/octet-stream';
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
getAllFilesRecursive(dir, fileList = []) {
|
|
682
|
-
if (!fs.existsSync(dir)) {
|
|
683
|
-
return fileList;
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
const files = fs.readdirSync(dir);
|
|
687
|
-
|
|
688
|
-
for (const file of files) {
|
|
689
|
-
const filePath = path.join(dir, file);
|
|
690
|
-
const stat = fs.statSync(filePath);
|
|
691
|
-
|
|
692
|
-
if (stat.isDirectory()) {
|
|
693
|
-
this.getAllFilesRecursive(filePath, fileList);
|
|
694
|
-
} else {
|
|
695
|
-
fileList.push(filePath);
|
|
696
|
-
}
|
|
590
|
+
console.warn('Warning: Failed to push reports to MinIO. This may not affect the overall process.', error.message);
|
|
591
|
+
} finally {
|
|
592
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
697
593
|
}
|
|
698
|
-
|
|
699
|
-
return fileList;
|
|
700
594
|
}
|
|
701
595
|
}
|
|
702
596
|
exports.default = ResultsParser;
|
|
@@ -86,7 +86,7 @@ class SlackReporter {
|
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
88
88
|
if (this.sendResults === 'branch') {
|
|
89
|
-
this.log('🛑 Branch mode: skipping Slack post (
|
|
89
|
+
this.log('🛑 Branch mode: skipping Slack post (MinIO upload completed)');
|
|
90
90
|
return;
|
|
91
91
|
}
|
|
92
92
|
const agent = this.proxy ? new https_proxy_agent_1.HttpsProxyAgent(this.proxy) : undefined;
|
package/package.json
CHANGED