gha-workflow-testing 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 global-data-analytics
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,214 @@
1
+ # @global-data-analytics/gha-test
2
+
3
+ TypeScript library for testing GitHub Actions workflows with detailed reporting and assertions.
4
+
5
+ ## Features
6
+
7
+ - ๐Ÿ” **GitHub API Integration** - Fetch workflow runs, jobs, steps, and artifacts
8
+ - โœ… **Rich Assertions** - Test jobs, steps, artifacts, and JFrog deployments
9
+ - ๐Ÿ“Š **Detailed Reporting** - Generate markdown reports for GitHub Actions summaries
10
+ - ๐ŸŽฏ **Type-Safe** - Full TypeScript support with type definitions
11
+ - ๐Ÿงช **Jest Integration** - Works seamlessly with Jest testing framework
12
+
13
+ ## Installation
14
+
15
+ ### Option 1: Via Git (Immediate - No setup required)
16
+
17
+ ```bash
18
+ npm install git+https://github.com/global-data-analytics/dops-gha-tests.git
19
+ ```
20
+
21
+ ### Option 2: Via GitHub Packages (Coming soon)
22
+
23
+ ```bash
24
+ # Configure .npmrc
25
+ echo "@global-data-analytics:registry=https://npm.pkg.github.com" >> .npmrc
26
+
27
+ # Install
28
+ npm install @global-data-analytics/gha-test
29
+ ```
30
+
31
+ ## Quick Start
32
+
33
+ ### 1. Set Environment Variables
34
+
35
+ ```bash
36
+ export GITHUB_TOKEN="your-github-token"
37
+ export GITHUB_REPOSITORY="owner/repo"
38
+ ```
39
+
40
+ ### 2. Write Tests
41
+
42
+ ```typescript
43
+ import { GitHubAPI, assertJobSuccess, getReporter } from '@global-data-analytics/gha-test';
44
+
45
+ const WORKFLOW_NAME = 'CI Workflow';
46
+
47
+ describe('CI Workflow Tests', () => {
48
+ let api: GitHubAPI;
49
+ let runId: number;
50
+
51
+ beforeAll(async () => {
52
+ api = new GitHubAPI();
53
+ const reporter = getReporter(WORKFLOW_NAME);
54
+
55
+ runId = await api.getLatestRun(WORKFLOW_NAME);
56
+ reporter.setRunId(runId);
57
+
58
+ // Load all jobs and steps for comprehensive reporting
59
+ await reporter.loadAllJobsAndSteps(api);
60
+ });
61
+
62
+ afterAll(() => {
63
+ const reporter = getReporter();
64
+ reporter.writeToGithubSummary();
65
+ reporter.printReport();
66
+ });
67
+
68
+ it('should complete build job', async () => {
69
+ const reporter = getReporter();
70
+ const jobs = await api.getJobs(runId);
71
+
72
+ assertJobSuccess(jobs, 'build', reporter, 'success');
73
+ });
74
+ });
75
+ ```
76
+
77
+ ### 3. Run Tests
78
+
79
+ ```bash
80
+ npm test
81
+ ```
82
+
83
+ ## API Reference
84
+
85
+ ### GitHubAPI
86
+
87
+ Class for interacting with the GitHub API.
88
+
89
+ ```typescript
90
+ const api = new GitHubAPI();
91
+
92
+ // Get latest workflow run
93
+ const runId = await api.getLatestRun('My Workflow');
94
+
95
+ // Get jobs in a run
96
+ const jobs = await api.getJobs(runId);
97
+
98
+ // Wait for jobs to complete (optional - usually not needed with workflow_run trigger)
99
+ await api.waitForJobsCompletion(runId, timeout, pollInterval);
100
+
101
+ // Get steps in a job
102
+ const steps = await api.getSteps(runId, 'job-name');
103
+
104
+ // Get artifacts
105
+ const artifacts = await api.getArtifacts(runId);
106
+ ```
107
+
108
+ ### Assertions
109
+
110
+ Functions for testing workflow components.
111
+
112
+ ```typescript
113
+ // Assert job completed with expected conclusion
114
+ assertJobSuccess(jobs, 'job-name', reporter, 'success');
115
+
116
+ // Assert step completed successfully
117
+ assertStepSuccess(steps, 'step-name', 'job-name', reporter, 'success');
118
+
119
+ // Assert artifact exists
120
+ assertArtifactExists(artifacts, 'artifact-name', reporter);
121
+
122
+ // Assert JFrog artifact exists
123
+ await assertJFrogArtifactExists({
124
+ jfrogUrl: 'https://mcd.jfrog.io',
125
+ repository: 'gdap-docker-dev',
126
+ artifactPath: 'dops/your-app',
127
+ artifactName: 'dev',
128
+ jfrogToken: process.env.JFROG_TOKEN,
129
+ reporter,
130
+ });
131
+ ```
132
+
133
+ ### Reporter
134
+
135
+ Class for generating test reports.
136
+
137
+ ```typescript
138
+ const reporter = getReporter('Workflow Name');
139
+
140
+ // Set run ID
141
+ reporter.setRunId(runId);
142
+
143
+ // Load all jobs and steps for complete visibility
144
+ await reporter.loadAllJobsAndSteps(api);
145
+
146
+ // Record test results (done automatically by assertions)
147
+ reporter.recordJobTest('job-name', true, 'success', 'success');
148
+ reporter.recordStepTest('job-name', 'step-name', true, 'success', 'success');
149
+ reporter.recordArtifactTest('artifact-name', 'exists', true, 'expected');
150
+
151
+ // Generate and write report
152
+ reporter.writeToGithubSummary(); // Write to GitHub Actions summary
153
+ reporter.printReport(); // Print to console
154
+ ```
155
+
156
+ ## Project Structure
157
+
158
+ ```
159
+ dops-gha-tests/
160
+ โ”œโ”€โ”€ src/
161
+ โ”‚ โ”œโ”€โ”€ github-api.ts # GitHub API client
162
+ โ”‚ โ”œโ”€โ”€ assertions.ts # Test assertions
163
+ โ”‚ โ”œโ”€โ”€ reporter.ts # Test reporter
164
+ โ”‚ โ””โ”€โ”€ index.ts # Main exports
165
+ โ”œโ”€โ”€ package.json
166
+ โ”œโ”€โ”€ tsconfig.json
167
+ โ””โ”€โ”€ README.md
168
+ ```
169
+
170
+ ## Building
171
+
172
+ ```bash
173
+ npm run build
174
+ ```
175
+
176
+ This will compile TypeScript to JavaScript in the `dist/` directory.
177
+
178
+ ## Development
179
+
180
+ ```bash
181
+ # Install dependencies
182
+ npm install
183
+
184
+ # Lint code
185
+ npm run lint
186
+
187
+ # Format code
188
+ npm run format
189
+
190
+ # Build
191
+ npm run build
192
+ ```
193
+
194
+ ## Environment Variables
195
+
196
+ | Variable | Required | Description |
197
+ |----------|----------|-------------|
198
+ | `GITHUB_TOKEN` | Yes | GitHub API token with workflow read access |
199
+ | `GITHUB_REPOSITORY` | Yes | Repository in `owner/repo` format |
200
+ | `GITHUB_STEP_SUMMARY` | No | Path to GitHub Actions summary file (auto-set in CI) |
201
+ | `JFROG_TOKEN` | No | JFrog access token for artifact verification |
202
+ | `GDAP_ARTIFACTORY_ACCESS_TOKEN` | No | Alternative JFrog token |
203
+
204
+ ## Example Usage
205
+
206
+ See [dops-testing](https://github.com/global-data-analytics/dops-testing) repository for complete examples of how to use this library.
207
+
208
+ ## License
209
+
210
+ MIT
211
+
212
+ ## Maintainers
213
+
214
+ DOPS Team - Data Operations & Platform Services
@@ -0,0 +1,23 @@
1
+ import { Jobs, Steps, Artifacts } from './github-api';
2
+ import { WorkflowTestReporter } from './reporter';
3
+ export declare function assertJobSuccess(jobs: Jobs, jobName: string, reporter?: WorkflowTestReporter, expectedConclusion?: string): void;
4
+ export declare function assertStepSuccess(steps: Steps, stepName: string, jobName?: string, reporter?: WorkflowTestReporter, expectedConclusion?: string): void;
5
+ export declare function assertArtifactExists(artifacts: Artifacts, artifactName: string, reporter?: WorkflowTestReporter): void;
6
+ export declare function assertFileInArtifact(artifactFiles: {
7
+ [filename: string]: Buffer;
8
+ }, filename: string, artifactName?: string, reporter?: WorkflowTestReporter): void;
9
+ export declare function assertFileContains(artifactFiles: {
10
+ [filename: string]: Buffer;
11
+ }, filename: string, expectedContent: string | Buffer, artifactName?: string, reporter?: WorkflowTestReporter): void;
12
+ export interface JFrogArtifactOptions {
13
+ jfrogUrl: string;
14
+ repository: string;
15
+ artifactPath: string;
16
+ artifactName: string;
17
+ jfrogApiKey?: string;
18
+ jfrogToken?: string;
19
+ reporter?: WorkflowTestReporter;
20
+ jobName?: string;
21
+ }
22
+ export declare function assertJFrogArtifactExists(options: JFrogArtifactOptions): Promise<void>;
23
+ //# sourceMappingURL=assertions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assertions.d.ts","sourceRoot":"","sources":["../src/assertions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAElD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,oBAAoB,EAC/B,kBAAkB,GAAE,MAAkB,GACrC,IAAI,CA2CN;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,oBAAoB,EAC/B,kBAAkB,GAAE,MAAkB,GACrC,IAAI,CAkCN;AAED,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,SAAS,EACpB,YAAY,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,IAAI,CAmCN;AAED,wBAAgB,oBAAoB,CAClC,aAAa,EAAE;IAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,EAC7C,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,MAAM,EACrB,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,IAAI,CAmCN;AAED,wBAAgB,kBAAkB,CAChC,aAAa,EAAE;IAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,EAC7C,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,GAAG,MAAM,EAChC,YAAY,CAAC,EAAE,MAAM,EACrB,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,IAAI,CAsDN;AAMD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAgIf"}
@@ -0,0 +1,260 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.assertJobSuccess = assertJobSuccess;
7
+ exports.assertStepSuccess = assertStepSuccess;
8
+ exports.assertArtifactExists = assertArtifactExists;
9
+ exports.assertFileInArtifact = assertFileInArtifact;
10
+ exports.assertFileContains = assertFileContains;
11
+ exports.assertJFrogArtifactExists = assertJFrogArtifactExists;
12
+ const axios_1 = __importDefault(require("axios"));
13
+ function assertJobSuccess(jobs, jobName, reporter, expectedConclusion = 'success') {
14
+ try {
15
+ if (!jobs[jobName]) {
16
+ const availableJobs = Object.keys(jobs).join('\n - ');
17
+ throw new Error(`${jobName} not found. Available jobs:\n - ${availableJobs}`);
18
+ }
19
+ const jobInfo = jobs[jobName];
20
+ const { status, conclusion } = jobInfo;
21
+ if (conclusion !== expectedConclusion) {
22
+ if (conclusion === null) {
23
+ throw new Error(`${jobName} did not complete with expected conclusion '${expectedConclusion}'.\n` +
24
+ ` Status: ${status}\n` +
25
+ ` Conclusion: ${conclusion} (job was skipped, cancelled, or still running)`);
26
+ }
27
+ else {
28
+ throw new Error(`${jobName} did not have expected conclusion.\n` +
29
+ ` Expected: ${expectedConclusion}\n` +
30
+ ` Actual: ${conclusion}\n` +
31
+ ` Status: ${status}`);
32
+ }
33
+ }
34
+ console.log(`โœ… ${jobName} completed with conclusion '${expectedConclusion}'`);
35
+ // Record success in reporter
36
+ if (reporter) {
37
+ reporter.recordJobTest(jobName, true, expectedConclusion, conclusion);
38
+ }
39
+ }
40
+ catch (error) {
41
+ // Record failure in reporter
42
+ if (reporter) {
43
+ const conclusion = jobs[jobName]?.conclusion || 'unknown';
44
+ reporter.recordJobTest(jobName, false, expectedConclusion, conclusion);
45
+ }
46
+ throw error;
47
+ }
48
+ }
49
+ function assertStepSuccess(steps, stepName, jobName, reporter, expectedConclusion = 'success') {
50
+ try {
51
+ if (!steps[stepName]) {
52
+ const availableSteps = Object.keys(steps).join('\n - ');
53
+ throw new Error(`Step '${stepName}' not found. Available steps:\n - ${availableSteps}`);
54
+ }
55
+ const stepInfo = steps[stepName];
56
+ const { conclusion } = stepInfo;
57
+ if (conclusion !== expectedConclusion) {
58
+ throw new Error(`Step '${stepName}' did not have expected conclusion.\n` +
59
+ ` Expected: ${expectedConclusion}\n` +
60
+ ` Actual: ${conclusion}`);
61
+ }
62
+ console.log(`โœ… Step '${stepName}' completed with conclusion '${expectedConclusion}'`);
63
+ // Record success in reporter
64
+ if (reporter && jobName) {
65
+ reporter.recordStepTest(jobName, stepName, true, expectedConclusion, conclusion || undefined);
66
+ }
67
+ }
68
+ catch (error) {
69
+ // Record failure in reporter
70
+ if (reporter && jobName) {
71
+ const conclusion = steps[stepName]?.conclusion || 'unknown';
72
+ reporter.recordStepTest(jobName, stepName, false, expectedConclusion, conclusion || undefined);
73
+ }
74
+ throw error;
75
+ }
76
+ }
77
+ function assertArtifactExists(artifacts, artifactName, reporter) {
78
+ try {
79
+ if (!artifacts[artifactName]) {
80
+ const availableArtifacts = Object.keys(artifacts).length > 0
81
+ ? Object.keys(artifacts).join('\n - ')
82
+ : '(no artifacts)';
83
+ throw new Error(`Artifact '${artifactName}' not found. Available artifacts:\n - ${availableArtifacts}`);
84
+ }
85
+ const artifactInfo = artifacts[artifactName];
86
+ if (artifactInfo.expired) {
87
+ throw new Error(`Artifact '${artifactName}' has expired`);
88
+ }
89
+ console.log(`โœ… Artifact '${artifactName}' exists (size: ${artifactInfo.size} bytes)`);
90
+ // Record success in reporter
91
+ if (reporter) {
92
+ reporter.recordArtifactTest(artifactName, 'exists', true, 'exists');
93
+ }
94
+ }
95
+ catch (error) {
96
+ // Record failure in reporter
97
+ if (reporter) {
98
+ reporter.recordArtifactTest(artifactName, 'exists', false, 'exists', 'not found or expired');
99
+ }
100
+ throw error;
101
+ }
102
+ }
103
+ function assertFileInArtifact(artifactFiles, filename, artifactName, reporter) {
104
+ try {
105
+ if (!artifactFiles[filename]) {
106
+ const availableFiles = Object.keys(artifactFiles).length > 0
107
+ ? Object.keys(artifactFiles).join('\n - ')
108
+ : '(no files)';
109
+ throw new Error(`File '${filename}' not found in artifact. Available files:\n - ${availableFiles}`);
110
+ }
111
+ console.log(`โœ… File '${filename}' found in artifact`);
112
+ // Record success in reporter
113
+ if (reporter && artifactName) {
114
+ reporter.recordArtifactTest(artifactName, `file '${filename}' exists`, true, filename);
115
+ }
116
+ }
117
+ catch (error) {
118
+ // Record failure in reporter
119
+ if (reporter && artifactName) {
120
+ reporter.recordArtifactTest(artifactName, `file '${filename}' exists`, false, filename, 'not found');
121
+ }
122
+ throw error;
123
+ }
124
+ }
125
+ function assertFileContains(artifactFiles, filename, expectedContent, artifactName, reporter) {
126
+ try {
127
+ assertFileInArtifact(artifactFiles, filename, artifactName, reporter);
128
+ const fileContent = artifactFiles[filename];
129
+ const expectedBuffer = typeof expectedContent === 'string'
130
+ ? Buffer.from(expectedContent)
131
+ : expectedContent;
132
+ if (!fileContent.includes(expectedBuffer)) {
133
+ const contentStr = typeof expectedContent === 'string'
134
+ ? expectedContent
135
+ : expectedContent.toString();
136
+ throw new Error(`File '${filename}' does not contain expected content: ${contentStr}`);
137
+ }
138
+ console.log(`โœ… File '${filename}' contains expected content`);
139
+ // Record success in reporter
140
+ if (reporter && artifactName) {
141
+ const contentPreview = (typeof expectedContent === 'string'
142
+ ? expectedContent
143
+ : expectedContent.toString()).substring(0, 50);
144
+ reporter.recordArtifactTest(artifactName, `file '${filename}' contains content`, true, contentPreview);
145
+ }
146
+ }
147
+ catch (error) {
148
+ // Record failure in reporter
149
+ if (reporter && artifactName) {
150
+ const contentPreview = (typeof expectedContent === 'string'
151
+ ? expectedContent
152
+ : expectedContent.toString()).substring(0, 50);
153
+ reporter.recordArtifactTest(artifactName, `file '${filename}' contains content`, false, contentPreview, 'not found');
154
+ }
155
+ throw error;
156
+ }
157
+ }
158
+ async function assertJFrogArtifactExists(options) {
159
+ const { jfrogUrl, repository, artifactPath, artifactName, jfrogApiKey, jfrogToken, reporter, } = options;
160
+ // Create artifact display name for reporter
161
+ const jfrogArtifactDisplayName = `JFrog: ${repository}/${artifactPath}/${artifactName}`;
162
+ try {
163
+ // Get credentials from parameters or environment
164
+ const apiKey = jfrogApiKey || process.env.MCD_ACTIONS_DD_API_KEY;
165
+ const token = jfrogToken || process.env.GDAP_ARTIFACTORY_ACCESS_TOKEN;
166
+ if (!apiKey && !token) {
167
+ throw new Error('JFrog credentials not provided. Set one of:\n' +
168
+ ' - JFROG_API_KEY or GDAP_ARTIFACTORY_ACCESS_TOKEN environment variable\n' +
169
+ ' - JFROG_TOKEN environment variable\n' +
170
+ ' - Pass jfrogApiKey or jfrogToken parameter');
171
+ }
172
+ // Build artifact URL
173
+ const cleanJfrogUrl = jfrogUrl.replace(/\/$/, '');
174
+ const cleanArtifactPath = artifactPath.replace(/^\/|\/$/g, '');
175
+ const artifactUrl = `${cleanJfrogUrl}/artifactory/${repository}/${cleanArtifactPath}/${artifactName}`;
176
+ // Set up authentication headers
177
+ const headers = {};
178
+ let authMethod;
179
+ if (apiKey) {
180
+ headers['X-JFrog-Art-Api'] = apiKey;
181
+ authMethod = 'API Key';
182
+ }
183
+ else {
184
+ headers['Authorization'] = `Bearer ${token}`;
185
+ authMethod = 'Bearer Token';
186
+ }
187
+ console.log('๐Ÿ” Checking JFrog artifact existence...');
188
+ console.log(` URL: ${artifactUrl}`);
189
+ console.log(` Auth: ${authMethod}`);
190
+ // Make HEAD request to check if artifact exists
191
+ const response = await axios_1.default.head(artifactUrl, {
192
+ headers,
193
+ timeout: 30000,
194
+ maxRedirects: 5,
195
+ });
196
+ if (response.status === 200) {
197
+ // Artifact exists! Get metadata from response headers
198
+ const fileSize = response.headers['content-length'] || 'unknown';
199
+ const checksumSha1 = response.headers['x-checksum-sha1'] || 'N/A';
200
+ const lastModified = response.headers['last-modified'] || 'N/A';
201
+ console.log(`โœ… Artifact '${artifactName}' exists in JFrog Artifactory`);
202
+ console.log(` Repository: ${repository}`);
203
+ console.log(` Path: ${artifactPath}`);
204
+ console.log(` Size: ${fileSize} bytes`);
205
+ console.log(` SHA1: ${checksumSha1}`);
206
+ console.log(` Last Modified: ${lastModified}`);
207
+ // Record success in reporter as artifact
208
+ if (reporter) {
209
+ reporter.recordArtifactTest(jfrogArtifactDisplayName, 'exists in JFrog', true, `Size: ${fileSize} bytes, SHA1: ${checksumSha1.substring(0, 8)}...`);
210
+ }
211
+ }
212
+ }
213
+ catch (error) {
214
+ let errorMsg;
215
+ if (axios_1.default.isAxiosError(error)) {
216
+ if (error.response?.status === 404) {
217
+ errorMsg =
218
+ `โŒ Artifact '${artifactName}' not found in JFrog Artifactory.\n` +
219
+ ` Repository: ${repository}\n` +
220
+ ` Path: ${artifactPath}\n` +
221
+ ` Status: 404 Not Found`;
222
+ }
223
+ else if (error.response?.status === 401) {
224
+ errorMsg =
225
+ `โŒ Authentication failed when checking JFrog artifact.\n` +
226
+ ` Status: 401 Unauthorized`;
227
+ }
228
+ else if (error.response?.status === 403) {
229
+ errorMsg =
230
+ `โŒ Permission denied when checking JFrog artifact.\n` +
231
+ ` Status: 403 Forbidden`;
232
+ }
233
+ else if (error.code === 'ECONNREFUSED' || error.code === 'ENOTFOUND') {
234
+ errorMsg =
235
+ `โŒ Failed to connect to JFrog Artifactory.\n` +
236
+ ` Error: Connection error`;
237
+ }
238
+ else if (error.code === 'ETIMEDOUT' || error.code === 'ECONNABORTED') {
239
+ errorMsg =
240
+ `โŒ Request to JFrog Artifactory timed out.\n` +
241
+ ` Timeout: 30 seconds`;
242
+ }
243
+ else {
244
+ errorMsg =
245
+ `โŒ Unexpected response when checking JFrog artifact.\n` +
246
+ ` Status: ${error.response?.status}\n` +
247
+ ` Error: ${error.message}`;
248
+ }
249
+ }
250
+ else {
251
+ errorMsg = `โŒ Error checking JFrog artifact: ${error.message}`;
252
+ }
253
+ // Record failure in reporter
254
+ if (reporter) {
255
+ reporter.recordArtifactTest(jfrogArtifactDisplayName, 'exists in JFrog', false, 'artifact exists', 'not found or error');
256
+ }
257
+ throw new Error(errorMsg);
258
+ }
259
+ }
260
+ //# sourceMappingURL=assertions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assertions.js","sourceRoot":"","sources":["../src/assertions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ export interface JobInfo {
2
+ status: string;
3
+ conclusion: string | null;
4
+ }
5
+ export interface Jobs {
6
+ [jobName: string]: JobInfo;
7
+ }
8
+ export interface StepInfo {
9
+ conclusion: string | null;
10
+ number: number;
11
+ }
12
+ export interface Steps {
13
+ [stepName: string]: StepInfo;
14
+ }
15
+ export interface ArtifactInfo {
16
+ id: number;
17
+ size: number;
18
+ expired: boolean;
19
+ url: string;
20
+ }
21
+ export interface Artifacts {
22
+ [artifactName: string]: ArtifactInfo;
23
+ }
24
+ export declare class GitHubAPI {
25
+ private repo;
26
+ private client;
27
+ constructor();
28
+ getLatestRun(workflowName: string): Promise<number>;
29
+ getJobs(runId: number): Promise<Jobs>;
30
+ waitForJobsCompletion(runId: number, timeout?: number, pollInterval?: number): Promise<Jobs>;
31
+ getSteps(runId: number, jobName: string): Promise<Steps>;
32
+ getArtifacts(runId: number): Promise<Artifacts>;
33
+ downloadArtifact(artifactId: number): Promise<{
34
+ [filename: string]: Buffer;
35
+ }>;
36
+ private sleep;
37
+ }
38
+ //# sourceMappingURL=github-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-api.d.ts","sourceRoot":"","sources":["../src/github-api.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,IAAI;IACnB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,KAAK;IACpB,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,SAAS;IACxB,CAAC,YAAY,EAAE,MAAM,GAAG,YAAY,CAAC;CACtC;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,MAAM,CAAgB;;IAqBxB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAmBnD,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBrC,qBAAqB,CACzB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,MAAY,EACrB,YAAY,GAAE,MAAW,GACxB,OAAO,CAAC,IAAI,CAAC;IAyBV,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAwBxD,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAqB/C,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IAcnF,OAAO,CAAC,KAAK;CAGd"}