allure-report-publisher 5.0.0-alpha.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.
Files changed (40) hide show
  1. package/LICENSE.txt +21 -0
  2. package/README.md +253 -0
  3. package/bin/dev.cmd +3 -0
  4. package/bin/dev.js +5 -0
  5. package/bin/run.cmd +3 -0
  6. package/bin/run.js +5 -0
  7. package/dist/commands/upload/index.d.ts +31 -0
  8. package/dist/commands/upload/index.js +198 -0
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.js +1 -0
  11. package/dist/lib/allure/config.d.ts +8 -0
  12. package/dist/lib/allure/config.js +125 -0
  13. package/dist/lib/allure/report-generator.d.ts +11 -0
  14. package/dist/lib/allure/report-generator.js +43 -0
  15. package/dist/lib/ci/info/base.d.ts +6 -0
  16. package/dist/lib/ci/info/base.js +4 -0
  17. package/dist/lib/ci/info/github.d.ts +9 -0
  18. package/dist/lib/ci/info/github.js +21 -0
  19. package/dist/lib/ci/info/gitlab.d.ts +17 -0
  20. package/dist/lib/ci/info/gitlab.js +47 -0
  21. package/dist/lib/uploader/base.d.ts +40 -0
  22. package/dist/lib/uploader/base.js +101 -0
  23. package/dist/lib/uploader/s3.d.ts +17 -0
  24. package/dist/lib/uploader/s3.js +113 -0
  25. package/dist/types/index.d.ts +8 -0
  26. package/dist/types/index.js +1 -0
  27. package/dist/utils/ci.d.ts +5 -0
  28. package/dist/utils/ci.js +13 -0
  29. package/dist/utils/config.d.ts +17 -0
  30. package/dist/utils/config.js +43 -0
  31. package/dist/utils/glob.d.ts +4 -0
  32. package/dist/utils/glob.js +35 -0
  33. package/dist/utils/logger.d.ts +14 -0
  34. package/dist/utils/logger.js +51 -0
  35. package/dist/utils/spinner.d.ts +4 -0
  36. package/dist/utils/spinner.js +28 -0
  37. package/dist/utils/uploader.d.ts +11 -0
  38. package/dist/utils/uploader.js +19 -0
  39. package/oclif.manifest.json +237 -0
  40. package/package.json +82 -0
package/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Andrejs Cunskis
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
13
+ all 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
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,253 @@
1
+ # allure-report-publisher
2
+
3
+ [![Docker Image Version (latest semver)](https://img.shields.io/docker/v/andrcuns/allure-report-publisher?color=blue&label=docker&sort=semver)](https://hub.docker.com/r/andrcuns/allure-report-publisher)
4
+ [![Docker Pulls](https://img.shields.io/docker/pulls/andrcuns/allure-report-publisher)](https://hub.docker.com/r/andrcuns/allure-report-publisher)
5
+ ![Workflow status](https://github.com/andrcuns/allure-report-publisher/workflows/Test/badge.svg)
6
+
7
+ Upload your report to a file storage of your choice.
8
+
9
+ ![Demo](demo.gif)
10
+
11
+ # Usage
12
+
13
+ <!-- usage -->
14
+ ```sh-session
15
+ $ npm install -g allure-report-publisher
16
+ $ allure-report-publisher COMMAND
17
+ running command...
18
+ $ allure-report-publisher (--version)
19
+ allure-report-publisher/5.0.0-alpha.0 linux-x64 node-v25.2.1
20
+ $ allure-report-publisher --help [COMMAND]
21
+ USAGE
22
+ $ allure-report-publisher COMMAND
23
+ ...
24
+ ```
25
+ <!-- usagestop -->
26
+ <!-- commands -->
27
+ * [`allure-report-publisher upload TYPE`](#allure-report-publisher-upload-type)
28
+
29
+ ## `allure-report-publisher upload TYPE`
30
+
31
+ Generate and upload allure report to cloud storage
32
+
33
+ ```
34
+ USAGE
35
+ $ allure-report-publisher upload TYPE [--baseUrl <value>] [-r <value>] [-b <value>] [-p <value>] [-c
36
+ <value>] [--reportName <value>] [--ciReportTitle <value>] [--summary behaviors|suites|packages|total]
37
+ [--summaryTableType ascii|markdown] [--updatePr comment|description|actions] [--collapseSummary] [--color]
38
+ [--copyLatest] [--debug] [--flakyWarningStatus] [--ignoreMissingResults] [-o <value>] [--parallel <value>]
39
+
40
+ ARGUMENTS
41
+ TYPE (s3|gcs|gitlab-artifacts) Cloud storage provider type
42
+
43
+ FLAGS
44
+ -b, --bucket=<value> [env: ALLURE_BUCKET] Cloud storage bucket name (required for s3/gcs)
45
+ -c, --config=<value> [env: ALLURE_CONFIG_PATH] The path to allure config file (only .json or .yaml are
46
+ supported)
47
+ -o, --output=<value> [env: ALLURE_OUTPUT] Output directory for generated report (default: temp dir for
48
+ cloud, "allure-report" for gitlab-artifacts)
49
+ -p, --prefix=<value> [env: ALLURE_PREFIX] Prefix for report path in cloud storage (ignored for
50
+ gitlab-artifacts)
51
+ -r, --resultsGlob=<value> [default: ./**/allure-results, env: ALLURE_RESULTS_GLOB] Glob pattern for allure
52
+ results directories
53
+ --baseUrl=<value> [env: ALLURE_BASE_URL] Custom base URL for report links
54
+ --ciReportTitle=<value> [default: Allure Report, env: ALLURE_CI_REPORT_TITLE] Title for PR
55
+ comment/description section
56
+ --collapseSummary [env: ALLURE_COLLAPSE_SUMMARY] Create collapsible summary section in PR
57
+ --[no-]color [env: ALLURE_COLOR] Force color output
58
+ --copyLatest [env: ALLURE_COPY_LATEST] Keep copy of latest run report at base prefix (ignored for
59
+ gitlab-artifacts)
60
+ --debug [env: ALLURE_DEBUG] Print debug log output
61
+ --flakyWarningStatus [env: ALLURE_FLAKY_WARNING_STATUS] Mark run with ! status if flaky tests found
62
+ --ignoreMissingResults [env: ALLURE_IGNORE_MISSING_RESULTS] Ignore missing allure results
63
+ --parallel=<value> [default: 8, env: ALLURE_PARALLEL] Number of parallel threads for upload
64
+ --reportName=<value> [env: ALLURE_REPORT_NAME] Custom report name in Allure report (ignored with
65
+ config-path)
66
+ --summary=<option> [default: total, env: ALLURE_SUMMARY] Add test summary table to PR
67
+ <options: behaviors|suites|packages|total>
68
+ --summaryTableType=<option> [default: ascii, env: ALLURE_SUMMARY_TABLE_TYPE] Summary table format
69
+ <options: ascii|markdown>
70
+ --updatePr=<option> [env: ALLURE_UPDATE_PR] Update PR with report URL (comment/description/actions)
71
+ <options: comment|description|actions>
72
+
73
+ DESCRIPTION
74
+ Generate and upload allure report to cloud storage
75
+
76
+ EXAMPLES
77
+ $ allure-report-publisher upload s3 --results-glob="path/to/allure-results" --bucket=my-bucket
78
+
79
+ $ allure-report-publisher upload gcs --results-glob="paths/to/**/allure-results" --bucket=my-bucket --prefix=my-project/prs
80
+
81
+ $ allure-report-publisher upload gitlab-artifacts --results-glob="paths/to/**/allure-results"
82
+
83
+ $ allure-report-publisher upload s3 --results-glob="path/to/allure-results" --bucket=my-bucket --update-pr=comment --summary=behaviors
84
+ ```
85
+
86
+ _See code: [src/commands/upload/index.ts](https://github.com/andrcuns/allure-report-publisher/blob/v5.0.0-alpha.0/src/commands/upload/index.ts)_
87
+ <!-- commandsstop -->
88
+
89
+ ## Docker
90
+
91
+ To use cli via docker, run following command:
92
+
93
+ ```sh-session
94
+ docker pull andrcuns/allure-report-publisher:latest
95
+ ```
96
+
97
+ # Storage providers
98
+
99
+ Multiple cloud storage providers are supported
100
+
101
+ ## AWS S3
102
+
103
+ Requires environment variables `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` or credentials file `~/.aws/credentials`
104
+
105
+ Additional configuration:
106
+
107
+ - `AWS_REGION`: configure s3 region, default: `us-east-1`
108
+ - `AWS_FORCE_PATH_STYLE`: when set to true, the bucket name is always left in the request URI and never moved to the host as a sub-domain, default: `false`
109
+ - `AWS_ENDPOINT`: custom s3 endpoint when used with other s3 compatible storage
110
+
111
+ ## Google Cloud Storage
112
+
113
+ Requires on of the following environment variables.
114
+
115
+ credentials.json file location:
116
+
117
+ - `STORAGE_CREDENTIALS`
118
+ - `STORAGE_KEYFILE`
119
+ - `GOOGLE_CLOUD_CREDENTIALS`
120
+ - `GOOGLE_CLOUD_KEYFILE`
121
+ - `GCLOUD_KEYFILE`
122
+
123
+ credentials.json contents:
124
+
125
+ - `GOOGLE_CLOUD_CREDENTIALS_JSON`
126
+ - `STORAGE_CREDENTIALS_JSON`
127
+ - `STORAGE_KEYFILE_JSON`
128
+ - `GOOGLE_CLOUD_CREDENTIALS_JSON`
129
+ - `GOOGLE_CLOUD_KEYFILE_JSON`
130
+ - `GCLOUD_KEYFILE_JSON`
131
+
132
+ ## Gitlab Artifacts
133
+
134
+ This storage provider is only supported for GitLab CI. Because GitLab does not expose public api for uploading artifacts, a job must be configured to upload the report as an artifact. Example:
135
+
136
+ ```yaml
137
+ # .gitlab-ci.yml
138
+ artifacts:
139
+ paths:
140
+ - allure-report
141
+ ```
142
+
143
+ where `allure-report` is the directory containing the generated Allure report and can be overridden via `--output` option.
144
+
145
+ Requires environment variable `GITLAB_AUTH_TOKEN` where token is a GitLab personal access token with `api` scope capable of downloading artifacts and retrieving job and pipeline information.
146
+
147
+ This provider is meant to be used with [GitLab CI](#gitlab-ci).
148
+
149
+ # CI
150
+
151
+ `allure-report-publisher` will automatically detect if used in CI environment and add relevant executor info and history.
152
+
153
+ Following CI providers are supported:
154
+
155
+ - Github Actions
156
+ - Gitlab CI
157
+
158
+ ## Pull requests
159
+
160
+ It is possible to update pull requests with urls to published reports and execution summary.
161
+
162
+ - `--update-pr=(comment|description|actions)`: post report urls in pr description, as a comment or step summary for github actions
163
+ - `--summary=(behaviors|suites|packages|total)`: add execution summary table
164
+ - `--summary-table-type=(ascii|markdown)`: use markdown or ascii table formatting
165
+ - `--[no-]collapse-summary`: add summary in collapsable section
166
+
167
+ Example:
168
+
169
+ ---
170
+
171
+ `# Allure report`
172
+
173
+ `allure-report-publisher` generated test report!
174
+
175
+ **rspec**: ✅ [test report](https://storage.googleapis.com/allure-test-reports/allure-report-publisher/refs/heads/main/index.html) for [1b756f48](https://github.com/andrcuns/allure-report-publisher/commit/HEAD)
176
+
177
+ ```markdown
178
+ +--------------------------------------------------------+
179
+ | total summary |
180
+ +-----------+--------+--------+---------+-------+--------+
181
+ | | passed | failed | skipped | flaky | result |
182
+ +-----------+--------+--------+---------+-------+--------+
183
+ | Total | 100 | 0 | 2 | 0 | ✅ |
184
+ +-----------+--------+--------+---------+-------+--------+
185
+ ```
186
+
187
+ ---
188
+
189
+ ## Github Actions
190
+
191
+ Additional configuration is done via environment variables
192
+
193
+ Authentication for PR updates:
194
+
195
+ - `GITHUB_AUTH_TOKEN`: github auth token with api access
196
+
197
+ Following environment variables can override default CI values:
198
+
199
+ - `ALLURE_JOB_NAME`: overrides default `GITHUB_JOB` value which is used as name for report url section
200
+ - `ALLURE_RUN_ID`: overrides default `GITHUB_RUN_ID` value which is used as name for the run number
201
+
202
+ ### allure-publish-action
203
+
204
+ [allure-publish-action](https://github.com/marketplace/actions/allure-publish-action) can be used to easily run report publishing from any github actions job.
205
+
206
+ ## Gitlab CI
207
+
208
+ Additional configuration is done via environment variables
209
+
210
+ ### Authentication
211
+
212
+ Authentication for MR updates:
213
+
214
+ - `GITLAB_AUTH_TOKEN`: gitlab access token with api access
215
+
216
+ ### CI values
217
+
218
+ Following environment variables can override default CI values:
219
+
220
+ - `ALLURE_JOB_NAME`: overrides default `CI_JOB_NAME` value which is used as name for report url section
221
+ - `ALLURE_RUN_ID`: overrides default `CI_PIPELINE_ID` value which is used as name for the run number
222
+
223
+ In case merge request triggers a downstream pipeline yet you want to update original merge request, overriding following environment variables might be useful:
224
+
225
+ - `ALLURE_PROJECT_PATH`: overrides default `CI_PROJECT_PATH` value
226
+ - `ALLURE_MERGE_REQUEST_IID`: overrides default `CI_MERGE_REQUEST_IID` value
227
+ - `ALLURE_COMMIT_SHA`: overrides default `CI_MERGE_REQUEST_SOURCE_BRANCH_SHA` or `CI_COMMIT_SHA` values
228
+
229
+ ### Summary comment behavior
230
+
231
+ If reporter is executed with options `--update-pr=comment` and `--unresolved-discussion-on-failure`, it's possible to additionally configure the unresolved discussion note:
232
+
233
+ - `ALLURE_FAILURE_ALERT_COMMENT`: comment added to create unresolved discussion note, default: `There are some test failures that need attention`
234
+
235
+ ### CI/CD catalog resource
236
+
237
+ [allure-report-publisher CI/CD catalog resource](https://gitlab.com/andrcuns/allure-report-publisher) can be used to easily integrate report publishing in to Gitlab CI pipelines.
238
+
239
+ # Development
240
+
241
+ Local development tool are handled by [mise](https://mise.jdx.dev/). After checking out the repo, run `mise install` to install necessary dev tools. Run `pnpm install` to install all node dependencies. To run tests, use `pnpm run test`. `bin/dev.js` allows to execute the cli directly from the source code without building it first.
242
+
243
+ # Contributing
244
+
245
+ Bug reports and pull requests are welcome on GitHub at <https://github.com/andrcuns/allure-report-publisher>. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/andrcuns/allure-report-publisher/blob/main/CODE_OF_CONDUCT.md).
246
+
247
+ # License
248
+
249
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
250
+
251
+ # Code of Conduct
252
+
253
+ Everyone interacting in the allure-report-publisher project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/andrcuns/allure-report-publisher/blob/main/CODE_OF_CONDUCT.md).
package/bin/dev.cmd ADDED
@@ -0,0 +1,3 @@
1
+ @echo off
2
+
3
+ node --import tsx --no-warnings=ExperimentalWarning "%~dp0\dev" %*
package/bin/dev.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env -S node --import tsx --disable-warning=ExperimentalWarning
2
+
3
+ import {execute} from '@oclif/core'
4
+
5
+ await execute({development: true, dir: import.meta.url})
package/bin/run.cmd ADDED
@@ -0,0 +1,3 @@
1
+ @echo off
2
+
3
+ node "%~dp0\run" %*
package/bin/run.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import {execute} from '@oclif/core'
4
+
5
+ await execute({dir: import.meta.url})
@@ -0,0 +1,31 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Upload extends Command {
3
+ static args: {
4
+ type: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ static flags: {
9
+ baseUrl: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ resultsGlob: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
11
+ bucket: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ prefix: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
+ reportName: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
+ ciReportTitle: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
16
+ summary: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
17
+ summaryTableType: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
18
+ updatePr: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
19
+ collapseSummary: import("@oclif/core/interfaces").BooleanFlag<boolean>;
20
+ color: import("@oclif/core/interfaces").BooleanFlag<boolean>;
21
+ copyLatest: import("@oclif/core/interfaces").BooleanFlag<boolean>;
22
+ debug: import("@oclif/core/interfaces").BooleanFlag<boolean>;
23
+ flakyWarningStatus: import("@oclif/core/interfaces").BooleanFlag<boolean>;
24
+ ignoreMissingResults: import("@oclif/core/interfaces").BooleanFlag<boolean>;
25
+ output: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
26
+ parallel: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
27
+ };
28
+ run(): Promise<void>;
29
+ private validateInputs;
30
+ private getAllureResults;
31
+ }
@@ -0,0 +1,198 @@
1
+ import { Args, Command, Flags } from '@oclif/core';
2
+ import { existsSync } from 'node:fs';
3
+ import path from 'node:path';
4
+ import { getAllureConfig } from '../../lib/allure/config.js';
5
+ import { ReportGenerator } from '../../lib/allure/report-generator.js';
6
+ import { config } from '../../utils/config.js';
7
+ import { getAllureResultsPaths } from '../../utils/glob.js';
8
+ import { logger } from '../../utils/logger.js';
9
+ import { spin } from '../../utils/spinner.js';
10
+ import { getUploader } from '../../utils/uploader.js';
11
+ export default class Upload extends Command {
12
+ static args = {
13
+ type: Args.string({
14
+ description: 'Cloud storage provider type',
15
+ options: ['s3', 'gcs', 'gitlab-artifacts'],
16
+ required: true,
17
+ }),
18
+ };
19
+ static description = 'Generate and upload allure report to cloud storage';
20
+ static examples = [
21
+ '<%= config.bin %> <%= command.id %> s3 --results-glob="path/to/allure-results" --bucket=my-bucket',
22
+ '<%= config.bin %> <%= command.id %> gcs --results-glob="paths/to/**/allure-results" --bucket=my-bucket --prefix=my-project/prs',
23
+ '<%= config.bin %> <%= command.id %> gitlab-artifacts --results-glob="paths/to/**/allure-results"',
24
+ '<%= config.bin %> <%= command.id %> s3 --results-glob="path/to/allure-results" --bucket=my-bucket --update-pr=comment --summary=behaviors',
25
+ ];
26
+ static flags = {
27
+ baseUrl: Flags.string({
28
+ aliases: ['base-url'],
29
+ description: 'Custom base URL for report links',
30
+ env: 'ALLURE_BASE_URL',
31
+ }),
32
+ resultsGlob: Flags.string({
33
+ aliases: ['results-glob'],
34
+ char: 'r',
35
+ default: './**/allure-results',
36
+ description: 'Glob pattern for allure results directories',
37
+ env: 'ALLURE_RESULTS_GLOB',
38
+ }),
39
+ bucket: Flags.string({
40
+ char: 'b',
41
+ description: 'Cloud storage bucket name (required for s3/gcs)',
42
+ env: 'ALLURE_BUCKET',
43
+ }),
44
+ prefix: Flags.string({
45
+ char: 'p',
46
+ description: 'Prefix for report path in cloud storage (ignored for gitlab-artifacts)',
47
+ env: 'ALLURE_PREFIX',
48
+ }),
49
+ config: Flags.string({
50
+ char: 'c',
51
+ description: 'The path to allure config file (only .json or .yaml are supported)',
52
+ env: 'ALLURE_CONFIG_PATH',
53
+ }),
54
+ reportName: Flags.string({
55
+ aliases: ['report-name'],
56
+ description: 'Custom report name in Allure report (ignored with config-path)',
57
+ env: 'ALLURE_REPORT_NAME',
58
+ }),
59
+ ciReportTitle: Flags.string({
60
+ aliases: ['ci-report-title'],
61
+ default: 'Allure Report',
62
+ description: 'Title for PR comment/description section',
63
+ env: 'ALLURE_CI_REPORT_TITLE',
64
+ }),
65
+ summary: Flags.string({
66
+ default: 'total',
67
+ description: 'Add test summary table to PR',
68
+ env: 'ALLURE_SUMMARY',
69
+ options: ['behaviors', 'suites', 'packages', 'total'],
70
+ }),
71
+ summaryTableType: Flags.string({
72
+ aliases: ['summary-table-type'],
73
+ default: 'ascii',
74
+ description: 'Summary table format',
75
+ env: 'ALLURE_SUMMARY_TABLE_TYPE',
76
+ options: ['ascii', 'markdown'],
77
+ }),
78
+ updatePr: Flags.string({
79
+ aliases: ['update-pr'],
80
+ description: 'Update PR with report URL (comment/description/actions)',
81
+ env: 'ALLURE_UPDATE_PR',
82
+ options: ['comment', 'description', 'actions'],
83
+ }),
84
+ // Boolean flags
85
+ collapseSummary: Flags.boolean({
86
+ aliases: ['collapse-summary'],
87
+ default: false,
88
+ description: 'Create collapsible summary section in PR',
89
+ env: 'ALLURE_COLLAPSE_SUMMARY',
90
+ }),
91
+ color: Flags.boolean({
92
+ allowNo: true,
93
+ description: 'Force color output',
94
+ env: 'ALLURE_COLOR',
95
+ }),
96
+ copyLatest: Flags.boolean({
97
+ aliases: ['copy-latest'],
98
+ default: false,
99
+ description: 'Keep copy of latest run report at base prefix (ignored for gitlab-artifacts)',
100
+ env: 'ALLURE_COPY_LATEST',
101
+ }),
102
+ debug: Flags.boolean({
103
+ default: false,
104
+ description: 'Print debug log output',
105
+ env: 'ALLURE_DEBUG',
106
+ }),
107
+ flakyWarningStatus: Flags.boolean({
108
+ aliases: ['flaky-warning-status'],
109
+ default: false,
110
+ description: 'Mark run with ! status if flaky tests found',
111
+ env: 'ALLURE_FLAKY_WARNING_STATUS',
112
+ }),
113
+ ignoreMissingResults: Flags.boolean({
114
+ aliases: ['ignore-missing-results'],
115
+ default: false,
116
+ description: 'Ignore missing allure results',
117
+ env: 'ALLURE_IGNORE_MISSING_RESULTS',
118
+ }),
119
+ output: Flags.string({
120
+ char: 'o',
121
+ description: 'Output directory for generated report (default: temp dir for cloud, "allure-report" for gitlab-artifacts)',
122
+ env: 'ALLURE_OUTPUT',
123
+ }),
124
+ parallel: Flags.integer({
125
+ default: 8,
126
+ description: 'Number of parallel threads for upload',
127
+ env: 'ALLURE_PARALLEL',
128
+ }),
129
+ };
130
+ async run() {
131
+ const { args, flags } = await this.parse(Upload);
132
+ const colorEnabled = flags.color ?? process.stdout.isTTY;
133
+ config.initialize({ color: colorEnabled, debug: flags.debug, parallel: flags.parallel });
134
+ try {
135
+ const storageType = args.type;
136
+ await this.validateInputs(storageType, flags);
137
+ logger.section('Generating allure report');
138
+ const resultPaths = await this.getAllureResults(flags.resultsGlob, flags.ignoreMissingResults);
139
+ if (resultPaths === undefined)
140
+ return;
141
+ const allureConfig = getAllureConfig(flags.config, flags.reportName);
142
+ const uploader = getUploader(storageType, {
143
+ baseUrl: flags.baseUrl,
144
+ bucket: flags.bucket,
145
+ copyLatest: flags.copyLatest,
146
+ parallel: flags.parallel,
147
+ prefix: flags.prefix,
148
+ output: await allureConfig.outputPath(),
149
+ historyPath: await allureConfig.historyPath(),
150
+ plugins: await allureConfig.plugins(),
151
+ });
152
+ const reportGenerator = new ReportGenerator(flags.resultsGlob, allureConfig, () => uploader.downloadHistory());
153
+ await reportGenerator.execute();
154
+ logger.section(`Uploading report to ${storageType}`);
155
+ await uploader.upload();
156
+ // TODO: Update PR if requested
157
+ if (flags.updatePr) {
158
+ logger.section('Updating PR/MR');
159
+ logger.info('PR update not yet implemented');
160
+ }
161
+ }
162
+ catch (error) {
163
+ logger.error(error.message);
164
+ this.exit(1);
165
+ }
166
+ }
167
+ async validateInputs(type, flags) {
168
+ if (type !== 'gitlab-artifacts' && !flags.bucket) {
169
+ throw new Error(`--bucket is required for storage type "${type}"\nOnly gitlab-artifacts does not require a bucket.`);
170
+ }
171
+ if (flags.baseUrl) {
172
+ try {
173
+ // eslint-disable-next-line no-new
174
+ new URL(flags.baseUrl);
175
+ }
176
+ catch {
177
+ throw new Error(`Invalid base URL: ${flags.baseUrl}\nBase URL must be a valid URL starting with http:// or https://`);
178
+ }
179
+ }
180
+ if (flags.parallel < 1) {
181
+ throw new Error(`Invalid parallel threads: ${flags.parallel}\nParallel threads must be >= 1`);
182
+ }
183
+ if (flags.config) {
184
+ const ext = path.extname(flags.config).toLowerCase();
185
+ const supportedExts = ['.json', '.yaml'];
186
+ if (!supportedExts.includes(ext)) {
187
+ throw new Error(`Unsupported config file format: ${ext}\nSupported formats are: ${supportedExts.join(', ')}`);
188
+ }
189
+ if (existsSync(flags.config) === false) {
190
+ throw new Error(`Config file not found at path: ${flags.config}`);
191
+ }
192
+ }
193
+ }
194
+ async getAllureResults(resultsGlob, ignoreMissingResults) {
195
+ const resultPaths = await spin(getAllureResultsPaths(resultsGlob, ignoreMissingResults), `scanning allure results directories`, { ignoreError: ignoreMissingResults });
196
+ return resultPaths;
197
+ }
198
+ }
@@ -0,0 +1 @@
1
+ export { run } from '@oclif/core';
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { run } from '@oclif/core';
@@ -0,0 +1,8 @@
1
+ import { PluginName } from '../../types/index.js';
2
+ export interface AllureConfig {
3
+ configPath(): string;
4
+ historyPath(): Promise<string>;
5
+ outputPath(): Promise<string>;
6
+ plugins(): Promise<PluginName[]>;
7
+ }
8
+ export declare function getAllureConfig(configPath?: string, reportName?: string): AllureConfig;
@@ -0,0 +1,125 @@
1
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
5
+ import yaml from 'yaml';
6
+ import { logger } from '../../utils/logger.js';
7
+ import { spin } from '../../utils/spinner.js';
8
+ const defaultReportBasePath = path.join(os.tmpdir(), 'allure-report-publisher');
9
+ const defaultConfig = {
10
+ output: path.join(defaultReportBasePath, 'allure-report'),
11
+ historyPath: path.join(defaultReportBasePath, 'history.jsonl'),
12
+ appendHistory: true,
13
+ plugins: {
14
+ awesome: {
15
+ options: {
16
+ enabled: true,
17
+ singleFile: true,
18
+ reportName: 'Test Report',
19
+ },
20
+ },
21
+ },
22
+ };
23
+ class CustomConfig {
24
+ _configPath;
25
+ _parsedConfig = defaultConfig;
26
+ constructor(configPath) {
27
+ this._configPath = configPath;
28
+ }
29
+ configPath() {
30
+ return this._configPath;
31
+ }
32
+ async historyPath() {
33
+ const config = await this.customConfig();
34
+ const path = config.historyPath;
35
+ if (!path)
36
+ throw new Error('History path is not defined in the allure config');
37
+ return path;
38
+ }
39
+ async outputPath() {
40
+ const config = await this.customConfig();
41
+ return config.output || defaultConfig.output;
42
+ }
43
+ async plugins() {
44
+ const config = await this.customConfig();
45
+ const plugins = new Set(['allure2', 'awesome', 'classic', 'csv', 'dashboard']);
46
+ const configPlugins = config?.plugins || defaultConfig.plugins;
47
+ return Object.entries(configPlugins)
48
+ .filter(([pluginName, config]) => plugins.has(pluginName) && (config.enabled ?? true))
49
+ .map(([pluginName]) => pluginName);
50
+ }
51
+ async customConfig() {
52
+ if (this._parsedConfig === defaultConfig) {
53
+ this._parsedConfig = await spin(this.loadConfig(), 'loading custom allure config');
54
+ }
55
+ return this._parsedConfig;
56
+ }
57
+ async loadConfig() {
58
+ const ext = path.extname(this._configPath).toLowerCase();
59
+ switch (ext) {
60
+ case '.cjs':
61
+ case '.js':
62
+ case '.mjs': {
63
+ const fileUrl = pathToFileURL(this._configPath).href;
64
+ const module = await import(fileUrl);
65
+ // module.default will contain the object returned by defineConfig()
66
+ // allure loads parser with default config setup which will create error in the output
67
+ // plain object should be exported to avoid that
68
+ const defaultConfig = module.default;
69
+ if (defaultConfig === undefined) {
70
+ throw new Error(`No default export found in the config file: ${this._configPath}`);
71
+ }
72
+ logger.debug(`Loaded JS config: ${JSON.stringify(defaultConfig, null, 2)}`);
73
+ return defaultConfig;
74
+ }
75
+ case '.json': {
76
+ const content = JSON.parse(readFileSync(this._configPath, 'utf8'));
77
+ logger.debug(`Loaded JSON config: ${JSON.stringify(content, null, 2)}`);
78
+ return content;
79
+ }
80
+ case '.yaml': {
81
+ const content = yaml.parse(readFileSync(this._configPath, 'utf8'));
82
+ logger.debug(`Loaded YAML config: ${JSON.stringify(content, null, 2)}`);
83
+ return content;
84
+ }
85
+ default: {
86
+ throw new Error(`Unsupported config file format: ${ext}`);
87
+ }
88
+ }
89
+ }
90
+ }
91
+ class DefaultConfig {
92
+ _configCreated;
93
+ _configPath;
94
+ reportName;
95
+ constructor(reportName) {
96
+ this._configCreated = false;
97
+ this._configPath = path.join(defaultReportBasePath, 'allurerc.json');
98
+ this.reportName = reportName;
99
+ }
100
+ configPath() {
101
+ if (this._configCreated)
102
+ return this._configPath;
103
+ mkdirSync(defaultReportBasePath, { recursive: true });
104
+ const config = { ...defaultConfig };
105
+ if (this.reportName)
106
+ config.plugins.awesome.options.reportName = this.reportName;
107
+ writeFileSync(this._configPath, JSON.stringify(config, null, 2));
108
+ this._configCreated = true;
109
+ return this._configPath;
110
+ }
111
+ async plugins() {
112
+ return ['awesome'];
113
+ }
114
+ async historyPath() {
115
+ return defaultConfig.historyPath;
116
+ }
117
+ async outputPath() {
118
+ return defaultConfig.output;
119
+ }
120
+ }
121
+ export function getAllureConfig(configPath, reportName) {
122
+ if (configPath)
123
+ return new CustomConfig(configPath);
124
+ return new DefaultConfig(reportName);
125
+ }