Skip to content

Commit 2a8ff22

Browse files
Jira Upload Utility (#70)
<!-- markdownlint-disable-next-line first-line-heading --> ## Description <!-- Describe your changes in detail. --> This adds a utility for uploading test results to Jira. ## Context <!-- Why is this change required? What problem does it solve? --> Allows for the easy transfer of test evidence to associated Jira tickets using a manual or automated method. ## Type of changes <!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply. --> - [ ] Refactoring (non-breaking change) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would change existing functionality) - [ ] Bug fix (non-breaking change which fixes an issue) ## Checklist <!-- Go over all the following points, and put an `x` in all the boxes that apply. --> - [x] I am familiar with the [contributing guidelines](https://github.com/nhs-england-tools/playwright-python-blueprint/blob/main/CONTRIBUTING.md) - [x] I have followed the code style of the project - [ ] I have added tests to cover my changes (where appropriate) - [x] I have updated the documentation accordingly - [ ] This PR is a result of pair or mob programming --- ## Sensitive Information Declaration To ensure the utmost confidentiality and protect your and others privacy, we kindly ask you to NOT including [PII (Personal Identifiable Information) / PID (Personal Identifiable Data)](https://digital.nhs.uk/data-and-information/keeping-data-safe-and-benefitting-the-public) or any other sensitive data in this PR (Pull Request) and the codebase changes. We will remove any PR that do contain any sensitive information. We really appreciate your cooperation in this matter. - [x] I confirm that neither PII/PID nor sensitive data are included in this PR and the codebase changes.
1 parent 3c868fa commit 2a8ff22

File tree

15 files changed

+945
-13
lines changed

15 files changed

+945
-13
lines changed

Makefile

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,22 @@ include scripts/init.mk
55

66
# ==============================================================================
77

8-
# NOTE: This project currently only uses this Makefile as part of CI/CD checks.
8+
# This allows the setup of Playwright by using a single command ready to use, and checks
9+
# if the user is in a virtual environment before running the setup.
10+
11+
.PHONY: check-venv
12+
check-venv: # Checks if in a Python venv / VIRTUALENV before installing a bunch of dependencies
13+
@python -c "import sys, os; \
14+
venv = (hasattr(sys, 'real_prefix') or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix) or 'VIRTUAL_ENV' in os.environ); \
15+
import sys; sys.exit(0 if venv else 1)"
16+
17+
setup-playwright: # Install Playwright and associated packages, and create local.env
18+
@echo "Checking for virtual environment..."
19+
$(MAKE) check-venv || (echo "ERROR: Not in a virtual environment, please create before running this command!"; exit 1)
20+
21+
@echo "Install Playwright"
22+
pip install -r requirements.txt
23+
playwright install
24+
25+
@echo "Setup local.env file"
26+
python setup_env_file.py

README.md

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Playwright Python Blueprint
22

3-
[![CI/CD Pull Request](https://github.com/nhs-england-tools/repository-template/actions/workflows/cicd-1-pull-request.yaml/badge.svg)](https://github.com/nhs-england-tools/playwright-python-blueprint/actions/workflows/cicd-1-pull-request.yaml)
3+
[![CI/CD Pull Request](https://github.com/nhs-england-tools/playwright-python-blueprint/actions/workflows/cicd-1-pull-request.yaml/badge.svg)](https://github.com/nhs-england-tools/playwright-python-blueprint/actions/workflows/cicd-1-pull-request.yaml)
44

55
This project is designed to provide a blueprint to allow for development teams to start quickly developing UI tests using [Playwright Python](https://playwright.dev/python/), providing the base framework and utilities to allow for initial focus on writing tests, rather than configuration of the framework itself. Playwright is the current mainstream UI testing tool for NHS England, as outlined on the [NHS England Tech Radar](https://radar.engineering.england.nhs.uk/).
66

@@ -16,6 +16,7 @@ This project is designed to provide a blueprint to allow for development teams t
1616
- [Getting Started](#getting-started)
1717
- [Utilities](#utilities)
1818
- [Using Environment Variables For Secrets](#using-environment-variables-for-secrets)
19+
- [Using the Jira Upload Script](#using-the-jira-upload-script)
1920
- [Contributing](#contributing)
2021
- [Contacts](#contacts)
2122
- [Licence](#licence)
@@ -111,6 +112,56 @@ The local.env file is set in the [.gitignore file](./.gitignore), so by default
111112

112113
> NOTE: You should never commit this file or any secrets in the codebase directly.
113114
115+
## Using the Jira Upload Script
116+
117+
Included with this code is a Jira Upload utility that will allow for the uploading of artifacts from test runs to
118+
a Jira ticket directly. The script itself ([`jira_upload.py`](jira_upload.py)) can be invoked using the following
119+
command:
120+
121+
```shell
122+
python jira_upload.py
123+
```
124+
125+
For this to work, you need to set the follow environment variables (which you can do via local.env):
126+
127+
| Key | Required | Description |
128+
| --------------------- | -------- | ------------------------------------------------------------------------------------------------------ |
129+
| `JIRA_URL` | Yes | The Jira instance url to connect to |
130+
| `JIRA_PROJECT_KEY` | Yes | The project key for the Jira project to upload to |
131+
| `JIRA_API_KEY` | Yes | The Jira API key for your user, which can be generated in Jira via Profile > Personal Access Tokens |
132+
| `JIRA_TICKET_REFERENCE` | No | The Jira ticket you want to default to, if required. Can be left blank to use branch-based referencing |
133+
134+
This command will do the following actions:
135+
136+
1. Work out the Jira ticket to upload to and confirm it is a valid reference, by using the following logic:
137+
1. If a `--jira-ref` value has been provided, use that value.
138+
2. If a `JIRA_TICKET_REFERENCE` environment variable exists, use that value.
139+
3. If none of the above, check if you are in a feature branch and if so, compiles the Jira ticket reference by combining the project key and the end of the feature branch (when in the format `feature/<shortcode>-<jira_ticket_number>`).
140+
2. Check the `test-results/` directory (or custom directory if specified) for appropriate files under 10MB (Jira's file limit), specifically:
141+
1. HTML files (e.g. `report.html` generated by `pytest`).
142+
2. Trace Files (e.g. `test_name/trace.zip` generated by Playwright).
143+
3. Screenshots (e.g. `test_screenshot.png` generated by Playwright).
144+
4. CSV Files (e.g. `results.csv` generated during test execution from the UI).
145+
3. Prompt the user to confirm that they are updating the correct ticket and the correct files are being uploaded. If files already exist on the ticket with a matching name, a unique name will be provided unless `--overwrite-files` is provided.
146+
4. If `y` is selected, upload the files and add a comment (unless `--no-comment` is provided) to Jira outlining the files uploaded and if possible, the environment information from the test run (unless `--no-env-data` is provided).
147+
148+
You can also pass in the following arguments which will have the noted effects:
149+
150+
| Argument | Description |
151+
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
152+
| `--jira-ref <Jira Reference>` | The Jira ticket to upload to. Will take precedence over auto-deriving from branch name and the set environment variable. |
153+
| `--results-dir <Directory>` | The directory to point to. If not set, points to `test-results/` (the default directory for test results in this repository). |
154+
| `--no-html` | Don't include HTML files in the upload. |
155+
| `--no-trace` | Don't include Trace files (.zip) in the upload. |
156+
| `--no-csv` | Don't include CSV files in the upload. |
157+
| `--no-screenshots` | Don't include screenshots (.png) in the upload. |
158+
| `--no-comment` | Don't add a Jira comment highlighting the results. |
159+
| `--no-env-data` | Don't include environment data in the Jira comment (if getting environment data has been configured). |
160+
| `--overwrite-files` | If a filename exists on the ticket that matches those in the results directory, overwrite them. |
161+
| `--auto-confirm` | Will not ask if you want to proceed if provided, and will assume that yes has been pressed. |
162+
163+
Further information on the available actions for this logic can be found in the [Jira Confluence Utility utility guide](./docs/utility-guides/JiraConfluenceUtil.md).
164+
114165
## Contributing
115166

116167
Further guidance on contributing to this project can be found in our [contribution](./CONTRIBUTING.md) page.
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
# Utility Guide: JiraConfluenceUtil
2+
3+
The `JiraConfluenceUtil` utility provides methods for interacting with Jira and Confluence, specifically for uploading Playwright test results and metadata to Jira tickets.
4+
5+
> NOTE: For most use cases, you should use the [jira_upload.py](../../jira_upload.py) script as outlined in the [README](../../README.md).
6+
> This guide is for developers who want to use the utility directly in custom workflows or scripts.
7+
8+
## Table of Contents
9+
10+
- [Utility Guide: JiraConfluenceUtil](#utility-guide-jiraconfluenceutil)
11+
- [Table of Contents](#table-of-contents)
12+
- [Using the JiraConfluenceUtil class](#using-the-jiraconfluenceutil-class)
13+
- [Required Environment Variables](#required-environment-variables)
14+
- [Initialise the class](#initialise-the-class)
15+
- [Public Methods](#public-methods)
16+
- [`get_issue_data`](#get_issue_data)
17+
- [`get_issue_summary_in_issue_data`](#get_issue_summary_in_issue_data)
18+
- [`check_attachment_exists_in_issue_data`](#check_attachment_exists_in_issue_data)
19+
- [`is_valid_jira_reference`](#is_valid_jira_reference)
20+
- [`determine_jira_reference_local`](#determine_jira_reference_local)
21+
- [`get_environment_metadata_if_available`](#get_environment_metadata_if_available)
22+
- [`is_file_is_less_than_jira_file_limit`](#is_file_is_less_than_jira_file_limit)
23+
- [`upload_test_results_dir_to_jira`](#upload_test_results_dir_to_jira)
24+
- [Example Usage](#example-usage)
25+
26+
## Using the JiraConfluenceUtil class
27+
28+
### Required Environment Variables
29+
30+
The following environment variables need to be set (in local.env if running locally) for any Jira-based actions:
31+
32+
- **JIRA_URL**: The Jira instance to upload to.
33+
- **JIRA_PROJECT_KEY**: The Jira project key that should be uploaded to.
34+
- **JIRA_API_KEY**: The API key to use to complete actions. Locally you should generate your own key, and use a bot in a pipeline/workflow.
35+
36+
The following environment variables are optional:
37+
38+
- **JIRA_TICKET_REFERENCE**: The Jira ticket to push to if set. If not, will attempt to derive the value from the git branch.
39+
40+
The following environment variables need to be set for any Confluence-based actions:
41+
42+
- **CONFLUENCE_URL**: The Confluence instance to upload to.
43+
- **CONFLUENCE_API_KEY**: The API key to use to complete actions. Locally you should generate your own key, and use a bot in a pipeline/workflow.
44+
45+
### Initialise the class
46+
47+
You can initialise the class by importing and creating an instance:
48+
49+
```python
50+
from utils.jira_confluence_util import JiraConfluenceUtil
51+
52+
util = JiraConfluenceUtil()
53+
```
54+
55+
You can also specify a custom results directory:
56+
57+
```python
58+
util = JiraConfluenceUtil(results_dir="path/to/results")
59+
```
60+
61+
## Public Methods
62+
63+
### `get_issue_data`
64+
65+
```python
66+
get_issue_data(ticket_id: str) -> dict | None
67+
```
68+
69+
Checks if a Jira issue exists and returns its data as a dictionary, or `None` if not found.
70+
71+
---
72+
73+
### `get_issue_summary_in_issue_data`
74+
75+
```python
76+
get_issue_summary_in_issue_data(issue_data: dict) -> str | None
77+
```
78+
79+
Returns a summary string for the given Jira issue data in the format "[Ticket]: [Summary Line]", or `None` if not available.
80+
81+
---
82+
83+
### `check_attachment_exists_in_issue_data`
84+
85+
```python
86+
check_attachment_exists_in_issue_data(issue_data: dict, filename: str) -> bool
87+
```
88+
89+
Checks if a Jira issue already has an attachment with the specified filename.
90+
91+
---
92+
93+
### `is_valid_jira_reference`
94+
95+
```python
96+
is_valid_jira_reference(ticket_id: str) -> bool
97+
```
98+
99+
Validates that the Jira ticket reference is in the expected format (e.g., `SCM-1234` or `BSS2-5678`).
100+
101+
---
102+
103+
### `determine_jira_reference_local`
104+
105+
```python
106+
determine_jira_reference_local() -> str
107+
```
108+
109+
Determines the Jira ticket reference from the current git branch or if `JIRA_TICKET_REFERENCE` has been set.
110+
111+
This is currently configured to search for the format `feature/[Jira Reference]`, so for example:
112+
113+
- `feature/TEST-1234` would return `TEST-1234`.
114+
- `feature/TEST-2345-feature-name` would return `TEST-2345`.
115+
116+
> NOTE: Depending on your projects branch naming strategy, you may want to modify this method to suit your needs
117+
> accordingly.
118+
119+
---
120+
121+
### `get_environment_metadata_if_available`
122+
123+
```python
124+
get_environment_metadata_if_available() -> str
125+
```
126+
127+
This is method designed to return metadata for the environment under test. In this project, it is a stub method
128+
designed to be overwritten.
129+
130+
> NOTE: You will need to populate this method with the code required to get the metadata for your environment.
131+
> It is heavily recommended that you populate `results.json` with the data required, and then read the file
132+
> using this method to extract the data required.
133+
134+
---
135+
136+
### `is_file_is_less_than_jira_file_limit`
137+
138+
```python
139+
is_file_is_less_than_jira_file_limit(file_path: Path) -> bool
140+
```
141+
142+
Checks if the file size is below the Jira upload limit (10MB).
143+
144+
---
145+
146+
### `upload_test_results_dir_to_jira`
147+
148+
```python
149+
upload_test_results_dir_to_jira(
150+
ticket_id: str,
151+
overwrite_files: bool = True,
152+
include_html: bool = True,
153+
include_trace_files: bool = True,
154+
include_screenshots: bool = True,
155+
include_csv: bool = True,
156+
include_env_metadata: bool = True,
157+
add_comment: bool = True,
158+
automatically_accept: bool = False,
159+
) -> None
160+
```
161+
162+
Uploads files from the results directory to the specified Jira ticket.
163+
Options allow you to control which file types are included, whether to overwrite existing files, add a comment, and auto-confirm the upload.
164+
165+
For any files over 10MB, they will **not** be uploaded using this method as they will exceed the default file size limit
166+
set for Jira.
167+
168+
Each of the following arguments relate to the following actions:
169+
170+
- `overwrite_files` = If the file already exists on Jira, it will overwrite the file and use the same name if True. If false, it'll generate a unique filename based on the date/time of the upload.
171+
- `include_html` = Will check for any `.html` files in the root of the `results_dir` provided and include them if under 10MB if True.
172+
- `include_trace_files` = Will check for any `.zip` files in subdirectories of the `results_dir` provided and include them if under 10MB if True, renaming the file to include the subdirectory name.
173+
- `include_screenshots` = Will check for any `.png` files in the rood directory `results_dir` provided and the `screenshot/` subdirectory and include them if under 10MB if True.
174+
- `include_csv` = Will check for any `.csv` files in the root of the `results_dir` provided and include them if under 10MB if True.
175+
- `include_env_metadata` = Will check for any environment metadata generated by `get_environment_metadata_if_available` and include it in the comment if True.
176+
- `add_comment` = Will add a comment to Jira summarizing all the attachments and environment metadata if True.
177+
- `automatically_accept` = Will bypass generating a terminal message that needs to be accepted and assume the answer was `y` if True.
178+
179+
---
180+
181+
## Example Usage
182+
183+
```python
184+
from utils.jira_confluence_util import JiraConfluenceUtil
185+
186+
util = JiraConfluenceUtil()
187+
ticket_id = util.determine_jira_reference_local()
188+
if util.is_valid_jira_reference(ticket_id):
189+
util.upload_test_results_dir_to_jira(
190+
ticket_id=ticket_id,
191+
overwrite_files=True,
192+
include_html=True,
193+
include_trace_files=True,
194+
include_screenshots=True,
195+
include_csv=True,
196+
include_env_metadata=True,
197+
add_comment=True,
198+
automatically_accept=False
199+
)
200+
```

0 commit comments

Comments
 (0)