In Atlassian's Bamboo you can re-order the environments in a deployment project by clicking Edit, Actions and then Move Up or Move Down.
When you've got a lot of environments, trying to re-order them takes a long time and it's very monotonous.
From past attempts to automate other aspects of Bamboo I've found the Bamboo APIs to be limited in comparison to what you can do through the UI.
For this problem I put together a fairly simple Python script using Selenium webdriver to automate the process of re-ordering environments.
Prerequisites
- You need to be using Python 3+
- Install the
selenium
python package using pip - Download ChromeDriver and place this on your
PATH
The Script
This script will use Selenium to launch an instance of Chrome via the ChromeDriver. Using the driver the script will interact with the page performing the re-ordering task that you'd otherwise have to do manually.
I tested this script using Bamboo 6.3.2
import os
import re
import urllib
from argparse import ArgumentParser
from time import sleep
from selenium import webdriver
from selenium.webdriver import ActionChains
class DeploymentProject:
def __init__(self, driver, base_url, url):
self.driver = driver
self.base_url = base_url
self.url = url
self.driver.get(self.url)
self.__load()
def sort_environments(self):
while not self.__sort_environments():
print('Sorting')
def __sort_environments(self):
for deploy_env in self.environments:
diff = deploy_env.sorted_position - deploy_env.current_position
if diff == 0:
print("%s - has the correct order" % deploy_env.name)
elif diff > 0:
deploy_env.move_down()
self.__load()
return False
else:
deploy_env.move_up()
self.__load()
return False
return True
def __load(self):
self.environments = []
current_position = 1
for project_block in self.driver.find_elements_by_css_selector("li.configure-project-environment"):
env_name = re.sub(r"^Environment: ", "", project_block.find_element_by_tag_name('h3').text)
env_id = int(re.sub(r"configure-project-environment-", "", project_block.get_attribute("id")))
self.__add_environment(DeployEnvironment(self.driver, env_name, env_id, current_position))
current_position += 1
self.environments = sorted(self.environments, key=lambda env: env.name)
sorted_pos = 1
for environment in self.environments:
environment.sorted_position = sorted_pos
sorted_pos += 1
def __add_environment(self, deploy_environment):
self.environments.append(deploy_environment)
class DeployEnvironment:
def __init__(self, driver, name, environment_id, current_position):
self.name = name
self.driver = driver
self.environment_id = environment_id
self.current_position = current_position
self.sorted_position = -1
self.env_block = self.driver.find_element_by_id("configure-project-environment-%d" % self.environment_id)
def move_down(self):
print("Moving down - %s (%d)" % (self.name, self.environment_id))
self.__edit_actions_menu()
self.driver.find_element_by_partial_link_text('Move down').click()
def move_up(self):
print("Moving up - %s (%d)" % (self.name, self.environment_id))
self.__edit_actions_menu()
self.driver.find_element_by_partial_link_text('Move up').click()
def __edit_actions_menu(self):
actions = ActionChains(self.driver)
actions.move_to_element(self.env_block).perform()
self.env_block.find_element_by_css_selector('button.aui-button.aui-button-subtle.toggle').click()
actions.move_to_element(self.env_block).perform()
sleep(1)
self.env_block.find_element_by_css_selector('a.aui-button.aui-dropdown2-trigger.aui-button-subtle').click()
sleep(1)
class Bamboo:
def __init__(self, base_url):
self.base_url = base_url
self.driver = webdriver.Chrome()
self.driver.implicitly_wait(5)
self.driver.maximize_window()
def login(self, username, password):
self.driver.get(self.__url("/userlogin!doDefault.action"))
username_textbox = self.driver.find_element_by_id("loginForm_os_username")
password_textbox = self.driver.find_element_by_id("loginForm_os_password")
username_textbox.send_keys(username)
password_textbox.send_keys(password)
password_textbox.submit()
def logout(self):
self.driver.get(self.__url("/userLogout.action"))
def configure_deployment_project(self, deployment_id):
return DeploymentProject(self.driver, self.base_url,
self.__url("/deploy/config/configureDeploymentProject.action?id=%s" % deployment_id))
def __url(self, suffix):
return urllib.parse.urljoin(self.base_url, suffix)
def close(self):
self.driver.close()
def main():
parser = ArgumentParser()
parser.add_argument('deploy_id', type=str, help='Deployment Project ID')
parser.add_argument('--server', type=str,
default=os.getenv('BAMBOO_URL'), help='Bamboo server url (e.g. https://bamboo.example.com')
parser.add_argument('--username', type=str,
default=os.getenv('BAMBOO_USERNAME'), help='Bamboo username')
parser.add_argument('--password', type=str,
default=os.getenv('BAMBOO_PASSWORD'), help='Bamboo password')
args = parser.parse_args()
bamboo = Bamboo(args.server)
bamboo.login(args.username, args.password)
deployment_project = bamboo.configure_deployment_project(args.deploy_id)
deployment_project.sort_environments()
bamboo.logout()
bamboo.close()
if __name__ == '__main__':
main()
Running the script
Run the script providing the address of your bamboo server, credentials and the deploy ID.
The deploy ID is take from the ID parameter of the deployment pages:
/deploy/viewDeploymentProjectEnvironments.action?id=16973826
With the above example the deploy ID is 16973826
.
Re-ordering a long list of environments can now be done automatically by running the script:
python bamboo_deployment_ordering.py --server https://bamboo.example.com --username james --password ******** 16973826
Updated 23 Feb 2018 22:20: Updated to support XSRF protection.