@allurereport/plugin-jira 3.0.0-beta.21
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/README.md +212 -0
- package/dist/helpers.d.ts +8 -0
- package/dist/helpers.js +81 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/plugin.d.ts +17 -0
- package/dist/plugin.js +167 -0
- package/dist/types.d.ts +49 -0
- package/dist/types.js +1 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# Jira Plugin
|
|
2
|
+
|
|
3
|
+
[<img src="https://allurereport.org/public/img/allure-report.svg" height="85px" alt="Allure Report logo" align="right" />](https://allurereport.org "Allure Report")
|
|
4
|
+
|
|
5
|
+
- Learn more about Allure Report at [allurereport.org](https://allurereport.org)
|
|
6
|
+
- 📚 [Documentation](https://allurereport.org/docs/) – Discover the official documentation for Allure Report
|
|
7
|
+
- ❓ [Questions and Support](https://github.com/orgs/allure-framework/discussions/categories/questions-support) – Get help from the team and community
|
|
8
|
+
- 📢 [Official Announcements](https://github.com/orgs/allure-framework/discussions/categories/announcements) – Stay up to date with the latest updates
|
|
9
|
+
- 💬 [General Discussion](https://github.com/orgs/allure-framework/discussions/categories/general-discussion) – Engage in casual conversations, share insights, and ideas with the community
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
|
|
15
|
+
This plugin allows you to send Allure reports to Jira.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
Use your preferred package manager to install the package:
|
|
20
|
+
|
|
21
|
+
```shell
|
|
22
|
+
npm add @allurereport/plugin-jira
|
|
23
|
+
yarn add @allurereport/plugin-jira
|
|
24
|
+
pnpm add @allurereport/plugin-jira
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Then, add the plugin to the Allure configuration file:
|
|
28
|
+
|
|
29
|
+
```diff
|
|
30
|
+
import { defineConfig } from "allure";
|
|
31
|
+
|
|
32
|
+
export default defineConfig({
|
|
33
|
+
name: "Allure Report",
|
|
34
|
+
output: "./allure-report",
|
|
35
|
+
historyPath: "./history.jsonl",
|
|
36
|
+
plugins: {
|
|
37
|
+
+ jira: {
|
|
38
|
+
+ options: {
|
|
39
|
+
+ webhook: "https://95f453e...",
|
|
40
|
+
+ token: "dmR2dWto...",
|
|
41
|
+
+ issue: "JIRA-123",
|
|
42
|
+
+ uploadReport: true,
|
|
43
|
+
+ uploadResults: true
|
|
44
|
+
+ },
|
|
45
|
+
+ },
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Options
|
|
51
|
+
|
|
52
|
+
The plugin accepts the following options:
|
|
53
|
+
|
|
54
|
+
| Option | Description | Type | Environment Variable |
|
|
55
|
+
| --------------- | ---------------------------------------------------- | --------- | ---------------------------- |
|
|
56
|
+
| `webhook` | Allure Jira Integration Webhook URL | `string` | `ALLURE_JIRA_WEBHOOK` |
|
|
57
|
+
| `token` | Generated Atlassian API token | `string` | `ALLURE_JIRA_TOKEN` |
|
|
58
|
+
| `issue` | Jira issue to link report to | `string` | `ALLURE_JIRA_ISSUE` |
|
|
59
|
+
| `uploadReport` | Whether to upload the report to specified jira issue | `boolean` | `ALLURE_JIRA_UPLOAD_REPORT` |
|
|
60
|
+
| `uploadResults` | Whether to upload the test results to linked issues | `boolean` | `ALLURE_JIRA_UPLOAD_RESULTS` |
|
|
61
|
+
|
|
62
|
+
**Note:** Any values set in your `allurerc.mjs` configuration file will take precedence over values defined in environment variables.
|
|
63
|
+
|
|
64
|
+
### Webhook URL
|
|
65
|
+
|
|
66
|
+
1. Navigate to your app's "Get Started" page.
|
|
67
|
+
2. Copy the webhook URL provided on that page.
|
|
68
|
+
|
|
69
|
+
### Token
|
|
70
|
+
|
|
71
|
+
1. Navigate to [Atlassian Account > Security > API Tokens](https://id.atlassian.com/manage/api-tokens).
|
|
72
|
+
2. Click the "Create API token with scopes" button.
|
|
73
|
+
3. Enter a name for your token and set an expiration date.
|
|
74
|
+
4. Select "Jira" as the API token application.
|
|
75
|
+
5. Search for and enable the `read:jira-user` scope.
|
|
76
|
+
6. Save the token and copy it to your clipboard.
|
|
77
|
+
7. Create a string in the format `useremail:api_token`, where `useremail` is your Jira account email and `api_token` is the token you just created. Then, encode this string using BASE64.
|
|
78
|
+
|
|
79
|
+
- Linux/Unix/MacOS:
|
|
80
|
+
|
|
81
|
+
```shell
|
|
82
|
+
echo -n "user@example.com:api_token_string" | base64
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
- Windows 7 and later, using Microsoft Powershell:
|
|
86
|
+
```powershell
|
|
87
|
+
$Text = "user@example.com:api_token_string"
|
|
88
|
+
$Bytes = [System.Text.Encoding]::UTF8.GetBytes($Text)
|
|
89
|
+
$EncodedText = [Convert]::ToBase64String($Bytes)
|
|
90
|
+
$EncodedText
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
_Access token is required to verify your permissions and to ensure you have edit access for the specified Jira issue(s). It is used only for this verification step and nothing else._
|
|
94
|
+
|
|
95
|
+
## Usage
|
|
96
|
+
|
|
97
|
+
### Uploading Test Results and/or Reports to Jira
|
|
98
|
+
|
|
99
|
+
When you set either the `uploadReport` or `uploadResults` flag to `true`, the plugin will automatically upload the Allure report or test results to Jira during the report generation process.
|
|
100
|
+
|
|
101
|
+
- Use `uploadReport: true` to attach the full report to a specific Jira issue.
|
|
102
|
+
- Use `uploadResults: true` to upload individual test results linked to Jira issues.
|
|
103
|
+
|
|
104
|
+
Once report generation is finished, the specified data is seamlessly sent to your Jira instance—no extra commands required.
|
|
105
|
+
|
|
106
|
+
**Note:**
|
|
107
|
+
|
|
108
|
+
- The user associated with the provided token must have edit permissions for any Jira issues specified in the `issue` option, as well as for any issues linked in your tests.
|
|
109
|
+
- Only issues belonging to the Jira instance specified by provided `webhook` URL will be processed or updated by the plugin.
|
|
110
|
+
|
|
111
|
+
### Clearing Uploaded Data
|
|
112
|
+
|
|
113
|
+
You can remove previously uploaded test data from Jira using the `allure jira clear` command. This allows you to clear reports, results, or both from one or multiple Jira issues.
|
|
114
|
+
|
|
115
|
+
#### Clear Uploaded Reports
|
|
116
|
+
|
|
117
|
+
Use the `--reports` flag to delete uploaded reports for the specified issue(s):
|
|
118
|
+
|
|
119
|
+
```shell
|
|
120
|
+
# Using npm
|
|
121
|
+
npx allure jira clear --token <token> --webhook <webhook-url> --issue <issue-key> --reports
|
|
122
|
+
|
|
123
|
+
# Using yarn
|
|
124
|
+
yarn allure jira clear --token <token> --webhook <webhook-url> --issue <issue-key> --reports
|
|
125
|
+
|
|
126
|
+
# Using pnpm
|
|
127
|
+
pnpm allure jira clear --token <token> --webhook <webhook-url> --issue <issue-key> --reports
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
You may specify multiple issues by repeating the `--issue` flag:
|
|
131
|
+
|
|
132
|
+
```shell
|
|
133
|
+
# Using npm
|
|
134
|
+
npx allure jira clear --token dmR2dWto... --webhook https://95f453e... --issue JIRA-1 --reports
|
|
135
|
+
npx allure jira clear --token dmR2dWto... --webhook https://95f453e... --issue JIRA-1 --issue JIRA-2 --reports
|
|
136
|
+
|
|
137
|
+
# Using yarn
|
|
138
|
+
yarn allure jira clear --token dmR2dWto... --webhook https://95f453e... --issue JIRA-1 --reports
|
|
139
|
+
yarn allure jira clear --token dmR2dWto... --webhook https://95f453e... --issue JIRA-1 --issue JIRA-2 --reports
|
|
140
|
+
|
|
141
|
+
# Using pnpm
|
|
142
|
+
pnpm allure jira clear --token dmR2dWto... --webhook https://95f453e... --issue JIRA-1 --reports
|
|
143
|
+
pnpm allure jira clear --token dmR2dWto... --webhook https://95f453e... --issue JIRA-1 --issue JIRA-2 --reports
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
#### Clear Uploaded Test Results
|
|
147
|
+
|
|
148
|
+
Use the `--results` flag to delete test results uploaded to one or more issues:
|
|
149
|
+
|
|
150
|
+
```shell
|
|
151
|
+
# Using npm
|
|
152
|
+
npx allure jira clear --token <token> --webhook <webhook-url> --issue <issue-key> --results
|
|
153
|
+
|
|
154
|
+
# Using yarn
|
|
155
|
+
yarn allure jira clear --token <token> --webhook <webhook-url> --issue <issue-key> --results
|
|
156
|
+
|
|
157
|
+
# Using pnpm
|
|
158
|
+
pnpm allure jira clear --token <token> --webhook <webhook-url> --issue <issue-key> --results
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Examples:
|
|
162
|
+
|
|
163
|
+
```shell
|
|
164
|
+
# Using npm
|
|
165
|
+
npx allure jira clear --token dmR2dWto... --webhook https://95f453e... --issue JIRA-1 --results
|
|
166
|
+
npx allure jira clear --token dmR2dWto... --webhook https://95f453e... --issue JIRA-1 --issue JIRA-2 --results
|
|
167
|
+
|
|
168
|
+
# Using yarn
|
|
169
|
+
yarn allure jira clear --token dmR2dWto... --webhook https://95f453e... --issue JIRA-1 --results
|
|
170
|
+
yarn allure jira clear --token dmR2dWto... --webhook https://95f453e... --issue JIRA-1 --issue JIRA-2 --results
|
|
171
|
+
|
|
172
|
+
# Using pnpm
|
|
173
|
+
pnpm allure jira clear --token dmR2dWto... --webhook https://95f453e... --issue JIRA-1 --results
|
|
174
|
+
pnpm allure jira clear --token dmR2dWto... --webhook https://95f453e... --issue JIRA-1 --issue JIRA-2 --results
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
#### Clear Both Reports and Results
|
|
178
|
+
|
|
179
|
+
To remove both uploaded reports and test results from the specified issues, use both flags together:
|
|
180
|
+
|
|
181
|
+
```shell
|
|
182
|
+
# Using npm
|
|
183
|
+
npx allure jira clear --token <token> --webhook <webhook-url> --issue <issue-key> --results --reports
|
|
184
|
+
|
|
185
|
+
# Using yarn
|
|
186
|
+
yarn allure jira clear --token <token> --webhook <webhook-url> --issue <issue-key> --results --reports
|
|
187
|
+
|
|
188
|
+
# Using pnpm
|
|
189
|
+
pnpm allure jira clear --token <token> --webhook <webhook-url> --issue <issue-key> --results --reports
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Examples:
|
|
193
|
+
|
|
194
|
+
```shell
|
|
195
|
+
# Using npm
|
|
196
|
+
npx allure jira clear --token dmR2dWto... --webhook https://95f453e... --issue JIRA-1 --results --reports
|
|
197
|
+
npx allure jira clear --token dmR2dWto... --webhook https://95f453e... --issue JIRA-1 --issue JIRA-2 --results --reports
|
|
198
|
+
|
|
199
|
+
# Using yarn
|
|
200
|
+
yarn allure jira clear --token dmR2dWto... --webhook https://95f453e... --issue JIRA-1 --results --reports
|
|
201
|
+
yarn allure jira clear --token dmR2dWto... --webhook https://95f453e... --issue JIRA-1 --issue JIRA-2 --results --reports
|
|
202
|
+
|
|
203
|
+
# Using pnpm
|
|
204
|
+
pnpm allure jira clear --token dmR2dWto... --webhook https://95f453e... --issue JIRA-1 --results --reports
|
|
205
|
+
pnpm allure jira clear --token dmR2dWto... --webhook https://95f453e... --issue JIRA-1 --issue JIRA-2 --results --reports
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**Tip:**
|
|
209
|
+
|
|
210
|
+
- You can use the `--issue` flag multiple times in a single command to target several Jira issues at once.
|
|
211
|
+
- Always provide a valid `--token` for authentication and correct `--webhook` from the app in your Jira instance.
|
|
212
|
+
- Use the flags `--reports`, `--results`, or both based on what you want to clear.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type TestResult } from "@allurereport/core-api";
|
|
2
|
+
import { type ForgePluginTestResult } from "./types.js";
|
|
3
|
+
export declare const isJiraIssueKey: (issue: string) => boolean;
|
|
4
|
+
export declare const findJiraLink: (tr: TestResult) => import("@allurereport/core-api").TestLink | undefined;
|
|
5
|
+
export declare const prepareTestResults: (trs: TestResult[]) => ForgePluginTestResult[];
|
|
6
|
+
export declare const trimName: (name: string) => string;
|
|
7
|
+
export declare const trimParameters: (p: string) => string;
|
|
8
|
+
export declare const trimCiInfoLabel: (label: string) => string;
|
package/dist/helpers.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { DEFAULT_ENVIRONMENT } from "@allurereport/core-api";
|
|
2
|
+
const isJiraUrl = (url) => {
|
|
3
|
+
const jiraPattern = /^https:\/\/[a-zA-Z0-9-]+\.atlassian\.net\/browse\/[A-Z]+-\d+$/;
|
|
4
|
+
return jiraPattern.test(url);
|
|
5
|
+
};
|
|
6
|
+
export const isJiraIssueKey = (issue) => {
|
|
7
|
+
const jiraPattern = /^[A-Z]+-\d+$/;
|
|
8
|
+
return jiraPattern.test(issue);
|
|
9
|
+
};
|
|
10
|
+
export const findJiraLink = (tr) => {
|
|
11
|
+
return tr.links.find((link) => isJiraUrl(link.url));
|
|
12
|
+
};
|
|
13
|
+
const filterKeyParams = (params, runsCount) => {
|
|
14
|
+
const result = [];
|
|
15
|
+
const intermediate = new Map();
|
|
16
|
+
for (const p of params) {
|
|
17
|
+
if (p.excluded || p.hidden) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (!intermediate.has(p.name)) {
|
|
21
|
+
intermediate.set(p.name, { value: p.value, count: 1 });
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (intermediate.get(p.name).value !== p.value) {
|
|
25
|
+
intermediate.delete(p.name);
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
intermediate.get(p.name).count++;
|
|
29
|
+
}
|
|
30
|
+
for (const [name, value] of intermediate) {
|
|
31
|
+
if (value.count === runsCount) {
|
|
32
|
+
result.push({ name, value: value.value });
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
const filterOutDefaultEnvironment = (env) => {
|
|
39
|
+
if (env === DEFAULT_ENVIRONMENT) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
return env;
|
|
43
|
+
};
|
|
44
|
+
export const prepareTestResults = (trs) => {
|
|
45
|
+
const trMap = new Map();
|
|
46
|
+
for (const tr of trs) {
|
|
47
|
+
const jiraLink = findJiraLink(tr);
|
|
48
|
+
if (!jiraLink) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const trId = tr.historyId ?? tr.id;
|
|
52
|
+
if (!trMap.has(trId)) {
|
|
53
|
+
trMap.set(trId, {
|
|
54
|
+
id: trId,
|
|
55
|
+
entries: [],
|
|
56
|
+
issue: jiraLink,
|
|
57
|
+
name: trimName(tr.name),
|
|
58
|
+
keyParams: [],
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
const storedTr = trMap.get(trId);
|
|
62
|
+
storedTr.entries.push({ status: tr.status, env: filterOutDefaultEnvironment(tr.environment), date: tr.stop });
|
|
63
|
+
storedTr.keyParams.push(...tr.parameters);
|
|
64
|
+
}
|
|
65
|
+
return Array.from(trMap.values()).map((tr) => {
|
|
66
|
+
return {
|
|
67
|
+
...tr,
|
|
68
|
+
keyParams: filterKeyParams(tr.keyParams, tr.entries.length),
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
const trimStrMax = (str, maxLength = 255) => {
|
|
73
|
+
if (str.length <= maxLength) {
|
|
74
|
+
return str;
|
|
75
|
+
}
|
|
76
|
+
const trimmed = str.slice(0, maxLength);
|
|
77
|
+
return `${trimmed.replace(/\.+$/, "")}...`;
|
|
78
|
+
};
|
|
79
|
+
export const trimName = (name) => trimStrMax(name, 255);
|
|
80
|
+
export const trimParameters = (p) => trimStrMax(p, 120);
|
|
81
|
+
export const trimCiInfoLabel = (label) => trimStrMax(label, 120);
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { JiraPlugin as default, type JiraPluginOptions } from "./plugin.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { JiraPlugin as default } from "./plugin.js";
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AllureStore, Plugin, PluginContext } from "@allurereport/plugin-api";
|
|
2
|
+
export interface JiraPluginOptions {
|
|
3
|
+
webhook?: string;
|
|
4
|
+
token?: string;
|
|
5
|
+
issue?: string;
|
|
6
|
+
uploadReport?: boolean;
|
|
7
|
+
uploadResults?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare class JiraPlugin implements Plugin {
|
|
10
|
+
#private;
|
|
11
|
+
readonly options: JiraPluginOptions;
|
|
12
|
+
constructor(options?: JiraPluginOptions);
|
|
13
|
+
clearReports(issues: string[]): Promise<void>;
|
|
14
|
+
clearResults(issues: string[]): Promise<void>;
|
|
15
|
+
clearAll(issues: string[]): Promise<void>;
|
|
16
|
+
done(context: PluginContext, store: AllureStore): Promise<void>;
|
|
17
|
+
}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
2
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
3
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
4
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
|
+
};
|
|
6
|
+
var _JiraPlugin_instances, _JiraPlugin_pluginName, _JiraPlugin_pluginOptions_get, _JiraPlugin_verifyOptions, _JiraPlugin_requestForgeApp, _JiraPlugin_uploadResults, _JiraPlugin_getReportStatus, _JiraPlugin_getStatisticByEnv, _JiraPlugin_getCiInfo, _JiraPlugin_getReportDate, _JiraPlugin_uploadReport, _JiraPlugin_uploadAll;
|
|
7
|
+
import { DEFAULT_ENVIRONMENT, getWorstStatus, statusesList } from "@allurereport/core-api";
|
|
8
|
+
import axios, { isAxiosError } from "axios";
|
|
9
|
+
import { isJiraIssueKey, prepareTestResults, trimCiInfoLabel, trimName } from "./helpers.js";
|
|
10
|
+
const TRUE_VALUES = ["true", "1"];
|
|
11
|
+
export class JiraPlugin {
|
|
12
|
+
constructor(options = {}) {
|
|
13
|
+
_JiraPlugin_instances.add(this);
|
|
14
|
+
this.options = options;
|
|
15
|
+
_JiraPlugin_pluginName.set(this, "Allure Jira Plugin");
|
|
16
|
+
}
|
|
17
|
+
async clearReports(issues) {
|
|
18
|
+
const payload = { issues, reports: true };
|
|
19
|
+
return await __classPrivateFieldGet(this, _JiraPlugin_instances, "m", _JiraPlugin_requestForgeApp).call(this, { operation: "clear", payload });
|
|
20
|
+
}
|
|
21
|
+
async clearResults(issues) {
|
|
22
|
+
return await __classPrivateFieldGet(this, _JiraPlugin_instances, "m", _JiraPlugin_requestForgeApp).call(this, { operation: "clear", payload: { issues, results: true } });
|
|
23
|
+
}
|
|
24
|
+
async clearAll(issues) {
|
|
25
|
+
const payload = { issues, reports: true, results: true };
|
|
26
|
+
return await __classPrivateFieldGet(this, _JiraPlugin_instances, "m", _JiraPlugin_requestForgeApp).call(this, { operation: "clear", payload });
|
|
27
|
+
}
|
|
28
|
+
async done(context, store) {
|
|
29
|
+
__classPrivateFieldGet(this, _JiraPlugin_instances, "m", _JiraPlugin_verifyOptions).call(this);
|
|
30
|
+
const { uploadReport, uploadResults } = __classPrivateFieldGet(this, _JiraPlugin_instances, "a", _JiraPlugin_pluginOptions_get);
|
|
31
|
+
if (!uploadReport && !uploadResults) {
|
|
32
|
+
throw new Error(`[${__classPrivateFieldGet(this, _JiraPlugin_pluginName, "f")}] Set at least one of the options: uploadReport or uploadResults`);
|
|
33
|
+
}
|
|
34
|
+
if (uploadReport && uploadResults) {
|
|
35
|
+
await __classPrivateFieldGet(this, _JiraPlugin_instances, "m", _JiraPlugin_uploadAll).call(this, context, store);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (uploadReport) {
|
|
39
|
+
await __classPrivateFieldGet(this, _JiraPlugin_instances, "m", _JiraPlugin_uploadReport).call(this, context, store);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (uploadResults) {
|
|
43
|
+
await __classPrivateFieldGet(this, _JiraPlugin_instances, "m", _JiraPlugin_uploadResults).call(this, context, store);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
_JiraPlugin_pluginName = new WeakMap(), _JiraPlugin_instances = new WeakSet(), _JiraPlugin_pluginOptions_get = function _JiraPlugin_pluginOptions_get() {
|
|
49
|
+
return {
|
|
50
|
+
token: this.options.token || process.env.ALLURE_JIRA_TOKEN,
|
|
51
|
+
webhook: this.options.webhook || process.env.ALLURE_JIRA_WEBHOOK,
|
|
52
|
+
reportIssue: this.options.issue ?? process.env.ALLURE_JIRA_ISSUE,
|
|
53
|
+
uploadReport: this.options.uploadReport ?? TRUE_VALUES.includes(process.env.ALLURE_JIRA_UPLOAD_REPORT ?? ""),
|
|
54
|
+
uploadResults: this.options.uploadResults ?? TRUE_VALUES.includes(process.env.ALLURE_JIRA_UPLOAD_RESULTS ?? ""),
|
|
55
|
+
};
|
|
56
|
+
}, _JiraPlugin_verifyOptions = function _JiraPlugin_verifyOptions() {
|
|
57
|
+
const { token, webhook } = __classPrivateFieldGet(this, _JiraPlugin_instances, "a", _JiraPlugin_pluginOptions_get);
|
|
58
|
+
if (!token) {
|
|
59
|
+
throw new Error(`[${__classPrivateFieldGet(this, _JiraPlugin_pluginName, "f")}] token is not set`);
|
|
60
|
+
}
|
|
61
|
+
if (!webhook) {
|
|
62
|
+
throw new Error(`[${__classPrivateFieldGet(this, _JiraPlugin_pluginName, "f")}] webhook is not set`);
|
|
63
|
+
}
|
|
64
|
+
}, _JiraPlugin_requestForgeApp = async function _JiraPlugin_requestForgeApp(props) {
|
|
65
|
+
const { operation, payload, version = "v1" } = props;
|
|
66
|
+
const { token, webhook } = __classPrivateFieldGet(this, _JiraPlugin_instances, "a", _JiraPlugin_pluginOptions_get);
|
|
67
|
+
const requestData = {
|
|
68
|
+
operation,
|
|
69
|
+
version,
|
|
70
|
+
payload,
|
|
71
|
+
token: token,
|
|
72
|
+
};
|
|
73
|
+
try {
|
|
74
|
+
await axios.post(webhook, requestData);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
if (isAxiosError(error)) {
|
|
78
|
+
const errorMessage = error.response?.data?.message || error.message;
|
|
79
|
+
throw new Error(`[${__classPrivateFieldGet(this, _JiraPlugin_pluginName, "f")}] Allure Jira Integration app error: ${errorMessage}`);
|
|
80
|
+
}
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
}, _JiraPlugin_uploadResults = async function _JiraPlugin_uploadResults(context, store) {
|
|
84
|
+
const allTestResults = await store.allTestResults();
|
|
85
|
+
if (allTestResults.length === 0) {
|
|
86
|
+
throw new Error(`[${__classPrivateFieldGet(this, _JiraPlugin_pluginName, "f")}] no test results found`);
|
|
87
|
+
}
|
|
88
|
+
const testResults = prepareTestResults(allTestResults);
|
|
89
|
+
const payload = {
|
|
90
|
+
results: testResults,
|
|
91
|
+
reportUrl: context.reportUrl,
|
|
92
|
+
};
|
|
93
|
+
await __classPrivateFieldGet(this, _JiraPlugin_instances, "m", _JiraPlugin_requestForgeApp).call(this, { operation: "upload-results", payload });
|
|
94
|
+
}, _JiraPlugin_getReportStatus = async function _JiraPlugin_getReportStatus(store, statistic) {
|
|
95
|
+
const globalErrors = await store.allGlobalErrors();
|
|
96
|
+
const globalExitCode = await store.globalExitCode();
|
|
97
|
+
const code = globalExitCode?.actual ?? globalExitCode?.original;
|
|
98
|
+
const hasGlobalErrors = globalErrors.length > 0;
|
|
99
|
+
if (hasGlobalErrors) {
|
|
100
|
+
return "failed";
|
|
101
|
+
}
|
|
102
|
+
if (code === 0) {
|
|
103
|
+
return "passed";
|
|
104
|
+
}
|
|
105
|
+
const worstStatus = getWorstStatus(statusesList
|
|
106
|
+
.map((status) => {
|
|
107
|
+
const value = statistic[status] ?? 0;
|
|
108
|
+
return value > 0 ? status : undefined;
|
|
109
|
+
})
|
|
110
|
+
.filter((status) => status !== undefined)) ?? "passed";
|
|
111
|
+
if (worstStatus === "passed") {
|
|
112
|
+
return "passed";
|
|
113
|
+
}
|
|
114
|
+
return "failed";
|
|
115
|
+
}, _JiraPlugin_getStatisticByEnv = async function _JiraPlugin_getStatisticByEnv(store) {
|
|
116
|
+
const statisticByEnv = {};
|
|
117
|
+
const envs = await store.allEnvironments();
|
|
118
|
+
for (const env of envs) {
|
|
119
|
+
if (env === DEFAULT_ENVIRONMENT) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
statisticByEnv[env] = await store.testsStatistic((tr) => tr.environment === env);
|
|
123
|
+
}
|
|
124
|
+
return statisticByEnv;
|
|
125
|
+
}, _JiraPlugin_getCiInfo = async function _JiraPlugin_getCiInfo(context) {
|
|
126
|
+
const jobUrl = context.ci?.pullRequestUrl ?? context.ci?.jobUrl ?? context.ci?.jobRunUrl;
|
|
127
|
+
const jobLabel = context.ci?.pullRequestName ?? context.ci?.jobName ?? context.ci?.jobRunName;
|
|
128
|
+
return { url: jobUrl, label: jobLabel ? trimCiInfoLabel(jobLabel) : undefined };
|
|
129
|
+
}, _JiraPlugin_getReportDate = async function _JiraPlugin_getReportDate(store) {
|
|
130
|
+
const trs = await store.allTestResults();
|
|
131
|
+
return trs.reduce((acc, { stop }) => Math.max(acc, stop || 0), 0);
|
|
132
|
+
}, _JiraPlugin_uploadReport = async function _JiraPlugin_uploadReport(context, store) {
|
|
133
|
+
const { reportIssue } = __classPrivateFieldGet(this, _JiraPlugin_instances, "a", _JiraPlugin_pluginOptions_get);
|
|
134
|
+
if (!reportIssue) {
|
|
135
|
+
throw new Error(`[${__classPrivateFieldGet(this, _JiraPlugin_pluginName, "f")}] reportIssue is not set`);
|
|
136
|
+
}
|
|
137
|
+
if (!isJiraIssueKey(reportIssue)) {
|
|
138
|
+
throw new Error(`[${__classPrivateFieldGet(this, _JiraPlugin_pluginName, "f")}] reportIssue is not a valid Jira issue key`);
|
|
139
|
+
}
|
|
140
|
+
const statistic = await store.testsStatistic();
|
|
141
|
+
if (statistic.total === 0) {
|
|
142
|
+
throw new Error(`[${__classPrivateFieldGet(this, _JiraPlugin_pluginName, "f")}] no test results found`);
|
|
143
|
+
}
|
|
144
|
+
const history = await store.allHistoryDataPoints();
|
|
145
|
+
const reportStatus = await __classPrivateFieldGet(this, _JiraPlugin_instances, "m", _JiraPlugin_getReportStatus).call(this, store, statistic);
|
|
146
|
+
const statisticByEnv = await __classPrivateFieldGet(this, _JiraPlugin_instances, "m", _JiraPlugin_getStatisticByEnv).call(this, store);
|
|
147
|
+
const date = await __classPrivateFieldGet(this, _JiraPlugin_instances, "m", _JiraPlugin_getReportDate).call(this, store);
|
|
148
|
+
const ciInfo = await __classPrivateFieldGet(this, _JiraPlugin_instances, "m", _JiraPlugin_getCiInfo).call(this, context);
|
|
149
|
+
const payload = {
|
|
150
|
+
issue: reportIssue,
|
|
151
|
+
report: {
|
|
152
|
+
id: context.reportUuid,
|
|
153
|
+
history: history.map(({ uuid }) => uuid),
|
|
154
|
+
status: reportStatus,
|
|
155
|
+
name: trimName(context.reportName),
|
|
156
|
+
url: context.reportUrl,
|
|
157
|
+
date,
|
|
158
|
+
ciInfo: ciInfo.url ? { url: ciInfo.url, label: ciInfo.label } : undefined,
|
|
159
|
+
statistic,
|
|
160
|
+
statisticByEnv,
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
await __classPrivateFieldGet(this, _JiraPlugin_instances, "m", _JiraPlugin_requestForgeApp).call(this, { operation: "upload-report", payload });
|
|
164
|
+
}, _JiraPlugin_uploadAll = async function _JiraPlugin_uploadAll(context, store) {
|
|
165
|
+
await __classPrivateFieldGet(this, _JiraPlugin_instances, "m", _JiraPlugin_uploadReport).call(this, context, store);
|
|
166
|
+
await __classPrivateFieldGet(this, _JiraPlugin_instances, "m", _JiraPlugin_uploadResults).call(this, context, store);
|
|
167
|
+
};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Statistic, TestLink, TestParameter, TestStatus } from "@allurereport/core-api";
|
|
2
|
+
type JiraIssue = string;
|
|
3
|
+
export type ForgePluginTestResult = {
|
|
4
|
+
id: string;
|
|
5
|
+
entries: {
|
|
6
|
+
status: TestStatus;
|
|
7
|
+
env?: string;
|
|
8
|
+
date: number;
|
|
9
|
+
}[];
|
|
10
|
+
keyParams: Pick<TestParameter, "name" | "value">[];
|
|
11
|
+
issue: TestLink;
|
|
12
|
+
name: string;
|
|
13
|
+
};
|
|
14
|
+
export type ForgePluginReport = {
|
|
15
|
+
id: string;
|
|
16
|
+
history: string[];
|
|
17
|
+
status: TestStatus;
|
|
18
|
+
ciInfo?: {
|
|
19
|
+
url: string;
|
|
20
|
+
label?: string;
|
|
21
|
+
};
|
|
22
|
+
statistic: Statistic;
|
|
23
|
+
statisticByEnv: Record<string, Statistic>;
|
|
24
|
+
name: string;
|
|
25
|
+
url?: string;
|
|
26
|
+
date: number;
|
|
27
|
+
};
|
|
28
|
+
export type ForgeAppOperations = "upload-report" | "upload-results" | "clear";
|
|
29
|
+
export type ForgeAppVersions = "v1";
|
|
30
|
+
export type ClearPayload = {
|
|
31
|
+
issues: string[];
|
|
32
|
+
reports?: boolean;
|
|
33
|
+
results?: boolean;
|
|
34
|
+
};
|
|
35
|
+
export type ForgeAppRequest = {
|
|
36
|
+
operation: ForgeAppOperations;
|
|
37
|
+
version: ForgeAppVersions;
|
|
38
|
+
payload: Record<string, unknown>;
|
|
39
|
+
token: string;
|
|
40
|
+
};
|
|
41
|
+
export type UploadReportPayload = {
|
|
42
|
+
issue: JiraIssue;
|
|
43
|
+
report: ForgePluginReport;
|
|
44
|
+
};
|
|
45
|
+
export type UploadResultsPayload = {
|
|
46
|
+
results: ForgePluginTestResult[];
|
|
47
|
+
reportUrl: string;
|
|
48
|
+
};
|
|
49
|
+
export {};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@allurereport/plugin-jira",
|
|
3
|
+
"version": "3.0.0-beta.21",
|
|
4
|
+
"description": "Allure Plugin to Report results to Jira",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"allure",
|
|
7
|
+
"testing",
|
|
8
|
+
"report",
|
|
9
|
+
"plugin",
|
|
10
|
+
"jira"
|
|
11
|
+
],
|
|
12
|
+
"repository": "https://github.com/allure-framework/allure3",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"author": "Qameta Software",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"main": "./dist/index.js",
|
|
20
|
+
"module": "./dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"files": [
|
|
23
|
+
"./dist"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "run clean && tsc --project ./tsconfig.json",
|
|
27
|
+
"clean": "rimraf ./dist",
|
|
28
|
+
"eslint": "eslint ./src/**/*.{js,jsx,ts,tsx}",
|
|
29
|
+
"eslint:format": "eslint --fix ./src/**/*.{js,jsx,ts,tsx}",
|
|
30
|
+
"test": "rimraf ./out && vitest run"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@allurereport/core-api": "3.0.0-beta.21",
|
|
34
|
+
"@allurereport/plugin-api": "3.0.0-beta.21",
|
|
35
|
+
"axios": "^1.9.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@faker-js/faker": "^9.8.0",
|
|
39
|
+
"@stylistic/eslint-plugin": "^2.6.1",
|
|
40
|
+
"@types/eslint": "^8.56.11",
|
|
41
|
+
"@types/node": "^20.17.9",
|
|
42
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
43
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
44
|
+
"@vitest/runner": "^2.1.9",
|
|
45
|
+
"allure-vitest": "^3.3.3",
|
|
46
|
+
"eslint": "^8.57.0",
|
|
47
|
+
"eslint-config-prettier": "^9.1.0",
|
|
48
|
+
"eslint-plugin-import": "^2.29.1",
|
|
49
|
+
"eslint-plugin-jsdoc": "^50.0.0",
|
|
50
|
+
"eslint-plugin-n": "^17.10.1",
|
|
51
|
+
"eslint-plugin-no-null": "^1.0.2",
|
|
52
|
+
"eslint-plugin-prefer-arrow": "^1.2.3",
|
|
53
|
+
"rimraf": "^6.0.1",
|
|
54
|
+
"typescript": "^5.6.3",
|
|
55
|
+
"vitest": "^2.1.9"
|
|
56
|
+
}
|
|
57
|
+
}
|