One common issue that arises after a migration to Jira Cloud is the presence of “migrated” tags in various parts of your instance.
In this blog post, we’ll explore how to automate the cleanup of these “migrated” tags in Jira Cloud using Python. After migrating from a Jira On-premises, you may find tags like “(Migrated)” appended to field descriptions, custom field names, field configurations and many other places. These tags can make your Jira environment less organized and user-friendly.
Purpose of the Script
The purpose of the Python script provided in this blog post is to streamline the cleanup of “migrated” tags in Jira Cloud after a migration. It addresses the following tasks:
- Deleting Tags from Field Configurations: Removes “(Migrated)” tags from field configurations, ensuring that your project’s field settings are clean and clear.
- Deleting Tags from Custom Fields Descriptions: Cleans up custom field descriptions by removing “(Migrated)” tags, making it easier to understand the purpose of each custom field.
- Deleting Tags from Custom Fields Names: Improves the readability of your custom field names by removing “(Migrated)” tags, helping your team members quickly identify the fields they need.
Prerequisites
Before we begin, ensure you have the following:
- Python installed on your machine.
- Necessary Python packages (requests, json) installed using pip.
import json
import requests
from requests.auth import HTTPBasicAuth
# Cloud parameters
cloud_base_URL = "https://<your_domain>.atlassian.net"
cloud_email = "<your_email>"
cloud_token = "<your_token>" #https://id.atlassian.com/manage-profile/security/api-tokens
def get_choice():
print('\nPlease select what you want to clean:')
print('[1] Delete tags from Field Configurations')
print('[2] Delete tags from Custom Fields DESCRIPTIONS')
print('[3] Delete tags from Custom Fields NAMES')
choice = input('->')
print('You chose option [' + choice + "]")
return choice
def send_put_request(url, payload, headers, auth):
try:
response = requests.put(url, data=payload, headers=headers, auth=auth)
print(f"PUT request to {url} with payload: {payload}")
return response
except requests.RequestException as e:
print(f"Request failed: {e}")
return None
def clean_field_configuration_schemes():
print("Starting to clean field configuration schemes.")
auth = HTTPBasicAuth(cloud_email, cloud_token)
headers = {
"Accept": "application/json",
"Content-Type": "application/json"
}
fieldConfigurations_url = f'{cloud_base_URL}/rest/api/3/fieldconfiguration'
fieldConfigurations = requests.get(fieldConfigurations_url, auth=auth).json()
for i, fieldConfiguration in enumerate(fieldConfigurations["values"], start=1):
fieldConfiguration_id = fieldConfiguration["id"]
print(f"\nField Configuration {i}/{len(fieldConfigurations['values'])} >>> ID: {fieldConfiguration_id}")
startAt = 0
while True:
fieldconfigurationItems_url = f'{cloud_base_URL}/rest/api/3/fieldconfiguration/{fieldConfiguration_id}/fields?startAt={startAt}'
fieldconfigurationItems = requests.get(fieldconfigurationItems_url, auth=auth).json()
payload_list = []
for item in fieldconfigurationItems["values"]:
if "description" in item and "(Migrated" in item['description'] and "customfield_13218" not in item["id"] and "customfield_13433" not in item["id"]:
original_description = item['description']
updated_description = item['description'].split("(Migrated", 1)[0].strip()
print(f"Updating field {item['id']}: Description changed from '{original_description}' to '{updated_description}'")
payload = {
"id": item['id'],
"description": updated_description,
}
payload_list.append(payload)
if len(payload_list) > 0:
payload = json.dumps({"fieldConfigurationItems": payload_list})
url = f'{cloud_base_URL}/rest/api/3/fieldconfiguration/{fieldConfiguration_id}/fields'
response = send_put_request(url, payload, headers, auth)
if response and response.status_code != 204:
print("Response text (only if error):")
print(response.text)
if fieldconfigurationItems["isLast"]:
break
else:
startAt += 50
print("Completed cleaning of field configuration schemes.")
def clean_fields_descriptions():
print("Starting to clean field descriptions.")
auth = HTTPBasicAuth(cloud_email, cloud_token)
headers = {
"Accept": "application/json",
"Content-Type": "application/json"
}
startAt = 0
while True:
fields_url = f'{cloud_base_URL}/rest/api/3/field/search?query=(Migrated&startAt={startAt}'
fields = requests.get(fields_url, auth=auth).json()
for i, field in enumerate(fields["values"], start=1):
print(f"\nField {i}/{len(fields['values'])} >>> ID: {field['id']}")
if "description" in field and "(Migrated" in field['description']:
original_description = field['description']
updated_description = field['description'].split("(Migrated", 1)[0].strip()
print(f"Updating field {field['id']}: Description changed from '{original_description}' to '{updated_description}'")
payload = json.dumps({
"description": updated_description,
})
url = f'{cloud_base_URL}/rest/api/3/field/{field["id"]}'
response = send_put_request(url, payload, headers, auth)
if response and response.status_code != 204:
print("Response text (only if error):")
print(response.text)
if fields["isLast"]:
break
else:
startAt += 50
print("Completed cleaning of field descriptions.")
def clean_fields_names():
print("Starting to clean field names.")
auth = HTTPBasicAuth(cloud_email, cloud_token)
headers = {
"Accept": "application/json",
"Content-Type": "application/json"
}
startAt = 0
while True:
fields_url = f'{cloud_base_URL}/rest/api/3/field/search?query=(migrated)&startAt={startAt}'
fields = requests.get(fields_url, auth=auth).json()
for i, field in enumerate(fields["values"], start=1):
print(f"\nField {i}/{len(fields['values'])} >>> ID: {field['id']}")
if "name" in field and "(migrated)" in field['name']:
original_name = field['name']
updated_name = field['name'].split("(migrated)", 1)[0].strip()
print(f"Updating field {field['id']}: Name changed from '{original_name}' to '{updated_name}'")
payload = json.dumps({
"name": updated_name,
})
url = f'{cloud_base_URL}/rest/api/3/field/{field["id"]}'
response = send_put_request(url, payload, headers, auth)
if response and response.status_code != 204:
print("Response text (only if error):")
print(response.text)
if fields["isLast"]:
break
else:
startAt += 50
print("Completed cleaning of field names.")
if __name__ == "__main__":
choice = get_choice()
if choice == '1':
clean_field_configuration_schemes()
elif choice == '2':
clean_fields_descriptions()
elif choice == '3':
clean_fields_names()
else:
print('Not a valid option.')
How the Script Works
Let’s break down how the script works and what each part does:
- Initialization: The script starts by initializing the cloud parameters, including the Jira Cloud base URL, email, and token.
- User Input: It prompts the user to choose the data cleanup task they want to perform (Field Configurations, Custom Fields Descriptions, or Custom Fields Names).
- Authentication: The script handles authentication to the Jira Cloud API using HTTP Basic Authentication.
- Data Cleanup Functions: There are three functions in the script, each responsible for cleaning up a specific type of data:
edit_field_configuration_schemes(): Cleans Field Configurations.edit_fields(): Cleans Custom Fields Descriptions.edit_fields_names(): Cleans Custom Fields Names.
- Sending PUT Requests: The script sends PUT requests to the Jira Cloud API to update the data based on the cleanup rules specified.
- Printing Status: It prints informative messages to keep the user informed about the progress and any issues that may arise during the cleanup.
How to Use the Script
- Configure Parameters: Open the script and configure the cloud parameters at the beginning of the file, including the Jira Cloud base URL, email, and token.
- Install Dependencies: Make sure you have the required Python packages (requests, json) installed using pip.
- Run the Script: Execute the script using Python by running
python script.pyin your terminal. - Choose Cleanup Task: Select the cleanup task you want to perform by entering the corresponding number.
- Monitor Progress: The script will provide real-time feedback on its progress, including HTTP response codes and any errors encountered.
- Verify Cleanup: After the script completes, verify that the data in your Jira instance has been cleaned up according to your specifications.
Conclusion
Automating data cleanup in Jira Cloud can save you time and ensure that your intance remains organized and relevant, especially after a migration. By using the Python script provided in this blog post, you can efficiently remove the “migrated” tags from field configurations, custom field descriptions, and custom field names. This automation simplifies the cleanup process a user-friendly Jira environment.
Feel free to customize the script further to suit your specific cleanup requirements.