playwright-slack-report-burak 3.5.0 → 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 +28 -133
- 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,25 +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
|
-
// <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
|
-
const MINIO_ALIAS = '
|
|
47
|
-
|
|
48
|
-
const
|
|
40
|
+
const MINIO_ALIAS = 'minio';
|
|
41
|
+
const MINIO_ARTIFACTS_DIR = 'shard-artifacts';
|
|
42
|
+
const MINIO_REPORTS_DIR = 'playwright-reports';
|
|
49
43
|
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
const getGcsObjectPath = (relativePath) => `${getRunFolder()}/${relativePath}`;
|
|
44
|
+
const getMinioObjectPath = (shard) => `${MINIO_ALIAS}/${MINIO_BUCKET}/${MINIO_ARTIFACTS_DIR}/${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}/shard-${shard}.tar.zst`;
|
|
45
|
+
const getMinioReportsPath = () => `${MINIO_ALIAS}/${MINIO_BUCKET}/${MINIO_REPORTS_DIR}/${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}`;
|
|
53
46
|
|
|
54
47
|
// ============================================================================
|
|
55
48
|
|
|
@@ -184,7 +177,7 @@ class ResultsParser {
|
|
|
184
177
|
}
|
|
185
178
|
|
|
186
179
|
await this.mergeReports();
|
|
187
|
-
await this.
|
|
180
|
+
await this.pushReportsToMinio();
|
|
188
181
|
} else if (singleShardNoBlob) {
|
|
189
182
|
// Single shard without blob (e.g. different reporter config): use node summary for Slack report
|
|
190
183
|
const nodeSummaryFile = path.join(SUMMARIES_DIR, 'node_summary_1.json');
|
|
@@ -572,130 +565,32 @@ class ResultsParser {
|
|
|
572
565
|
}
|
|
573
566
|
}
|
|
574
567
|
|
|
575
|
-
async
|
|
576
|
-
if (!
|
|
577
|
-
|
|
568
|
+
async pushReportsToMinio() {
|
|
569
|
+
if (!process.env.CI) {
|
|
570
|
+
console.log('Skipping MinIO push: not in CI');
|
|
571
|
+
return;
|
|
578
572
|
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
try {
|
|
582
|
-
serviceAccount = JSON.parse(GCS_SERVICE_ACCOUNT_KEY);
|
|
583
|
-
} catch (e) {
|
|
584
|
-
// Try reading from file path
|
|
585
|
-
if (fs.existsSync(GCS_SERVICE_ACCOUNT_KEY)) {
|
|
586
|
-
serviceAccount = JSON.parse(fs.readFileSync(GCS_SERVICE_ACCOUNT_KEY, 'utf-8'));
|
|
587
|
-
} else {
|
|
588
|
-
throw new Error('Invalid GCS_SERVICE_ACCOUNT_KEY: must be JSON string or file path');
|
|
589
|
-
}
|
|
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');
|
|
590
575
|
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
const jwt = require('jsonwebtoken');
|
|
594
|
-
const now = Math.floor(Date.now() / 1000);
|
|
595
|
-
const token = jwt.sign(
|
|
596
|
-
{
|
|
597
|
-
iss: serviceAccount.client_email,
|
|
598
|
-
scope: 'https://www.googleapis.com/auth/devstorage.full_control',
|
|
599
|
-
aud: 'https://oauth2.googleapis.com/token',
|
|
600
|
-
exp: now + 3600,
|
|
601
|
-
iat: now
|
|
602
|
-
},
|
|
603
|
-
serviceAccount.private_key,
|
|
604
|
-
{ algorithm: 'RS256' }
|
|
605
|
-
);
|
|
606
|
-
|
|
607
|
-
const tokenResponse = await axios.post('https://oauth2.googleapis.com/token', {
|
|
608
|
-
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
|
609
|
-
assertion: token
|
|
610
|
-
});
|
|
611
|
-
|
|
612
|
-
return tokenResponse.data.access_token;
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
async pushReportsToGCS() {
|
|
616
|
-
// Only push in CI environment with required configuration
|
|
617
|
-
if (!process.env.CI || !GCS_SERVICE_ACCOUNT_KEY) {
|
|
618
|
-
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');
|
|
619
578
|
return;
|
|
620
579
|
}
|
|
621
|
-
|
|
580
|
+
const destination = getMinioReportsPath();
|
|
581
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mc-reports-'));
|
|
582
|
+
const mcConfigDir = path.join(tmpDir, '.mc');
|
|
622
583
|
try {
|
|
623
|
-
console.log(`Uploading playwright-report
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
// Collect all files from playwright-report directory
|
|
629
|
-
const files = this.getAllFilesRecursive(PLAYWRIGHT_REPORT_DIR);
|
|
630
|
-
|
|
631
|
-
// Normalize the base directory path for path replacement
|
|
632
|
-
const baseDirPath = path.resolve(PLAYWRIGHT_REPORT_DIR);
|
|
633
|
-
|
|
634
|
-
// Upload all files to GCS
|
|
635
|
-
for (const file of files) {
|
|
636
|
-
// Get relative path from playwright-report directory
|
|
637
|
-
const relativePath = path.relative(baseDirPath, file).replace(/\\/g, '/');
|
|
638
|
-
const objectPath = getGcsObjectPath(relativePath);
|
|
639
|
-
const content = fs.readFileSync(file);
|
|
640
|
-
|
|
641
|
-
// Upload file to GCS
|
|
642
|
-
const uploadUrl = `${GCS_UPLOAD_API_BASE_URL}/b/${GCS_BUCKET_NAME}/o?uploadType=media&name=${encodeURIComponent(objectPath)}`;
|
|
643
|
-
|
|
644
|
-
await axios.post(uploadUrl, content, {
|
|
645
|
-
headers: {
|
|
646
|
-
'Authorization': `Bearer ${accessToken}`,
|
|
647
|
-
'Content-Type': this.getContentType(file)
|
|
648
|
-
}
|
|
649
|
-
});
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
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}`);
|
|
653
589
|
} catch (error) {
|
|
654
|
-
console.warn('Warning: Failed to push reports to
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
getContentType(filePath) {
|
|
662
|
-
const ext = path.extname(filePath).toLowerCase();
|
|
663
|
-
const contentTypes = {
|
|
664
|
-
'.html': 'text/html',
|
|
665
|
-
'.css': 'text/css',
|
|
666
|
-
'.js': 'application/javascript',
|
|
667
|
-
'.json': 'application/json',
|
|
668
|
-
'.png': 'image/png',
|
|
669
|
-
'.jpg': 'image/jpeg',
|
|
670
|
-
'.jpeg': 'image/jpeg',
|
|
671
|
-
'.gif': 'image/gif',
|
|
672
|
-
'.svg': 'image/svg+xml',
|
|
673
|
-
'.zip': 'application/zip',
|
|
674
|
-
'.txt': 'text/plain',
|
|
675
|
-
'.xml': 'application/xml'
|
|
676
|
-
};
|
|
677
|
-
return contentTypes[ext] || 'application/octet-stream';
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
getAllFilesRecursive(dir, fileList = []) {
|
|
681
|
-
if (!fs.existsSync(dir)) {
|
|
682
|
-
return fileList;
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
const files = fs.readdirSync(dir);
|
|
686
|
-
|
|
687
|
-
for (const file of files) {
|
|
688
|
-
const filePath = path.join(dir, file);
|
|
689
|
-
const stat = fs.statSync(filePath);
|
|
690
|
-
|
|
691
|
-
if (stat.isDirectory()) {
|
|
692
|
-
this.getAllFilesRecursive(filePath, fileList);
|
|
693
|
-
} else {
|
|
694
|
-
fileList.push(filePath);
|
|
695
|
-
}
|
|
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 });
|
|
696
593
|
}
|
|
697
|
-
|
|
698
|
-
return fileList;
|
|
699
594
|
}
|
|
700
595
|
}
|
|
701
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