项目作者: xebialabs-community

项目描述 :
XLR code snippets using python and jython API
高级语言: Python
项目地址: git://github.com/xebialabs-community/xlr-jython-code-snippets.git


xlr-jython-code-snippets

XLR code snippets using python and jython API.

Dynamically Create Release Flow based on data map ( Jenkins example )

  1. import json
  2. server = 'Jenkins'
  3. serverCI = configurationApi.searchByTypeAndTitle("jenkins.Server", str(server))[0]
  4. print(serverCI)
  5. datamap = '''[
  6. {
  7. "name": "Jenkins tasks",
  8. "entries": [
  9. {
  10. "name": "Jenkins1",
  11. "taskType": "jenkins.Build",
  12. "precondition": "None",
  13. "propertyMap": {"username":"test","password":"1234","jobName":"TEST/job/test1"}
  14. },
  15. {
  16. "name": "Jenkins2",
  17. "taskType": "jenkins.Build",
  18. "precondition": "None",
  19. "propertyMap": {"username":"test","password":"1234","jobName":"TEST/job/test2"}
  20. },
  21. {
  22. "name": "Jenkins3",
  23. "taskType": "jenkins.Build",
  24. "precondition": "None",
  25. "propertyMap": {"username":"test","password":"1234","jobName":"TEST/job/test3"}
  26. }
  27. ],
  28. "execution": "parallel"
  29. }
  30. ]
  31. '''
  32. dataobj = json.loads(datamap)
  33. for item in dataobj:
  34. phase = phaseApi.newPhase(item['name'])
  35. phase = phaseApi.addPhase(release.id, phase)
  36. if str(item['execution']) == "parallel":
  37. pgrouptask = taskApi.newTask("xlrelease.ParallelGroup")
  38. pgrouptask.title = "Jenkins parrallel tasks"
  39. phase = taskApi.addTask(phase.id, pgrouptask)
  40. for entry in item['entries']:
  41. task = taskApi.newTask(entry['taskType'])
  42. task.setTitle(entry['name'])
  43. task.setPrecondition(entry['precondition'])
  44. task.pythonScript.setProperty("jenkinsServer", serverCI)
  45. properties = entry['propertyMap']
  46. for property in properties:
  47. task.pythonScript.setProperty(property,properties[property])
  48. taskApi.addTask(phase.id, task)

Configure reference to Certificates for access by Python Libraries in plugins

There are third party python libraries that often refer to a certificate using certifi for connecting to secured URLs. If the cert is self-signed, you might need to make it available to the python lib.

  1. put the cert in a cert.pem file or append it to a cacerts.pem file
  2. Store the file in a referenable location from XL Server
  3. Create an environment variable inside run.sh/run.cmd referring to cert path.
    eg. export REQUESTS_CA_BUNDLE=$XLD_HOME/certs/cert.pem.
  4. Restart the server.

Lookup all task types in XLR

  1. from com.xebialabs.deployit.plugin.api.reflect import Type
  2. from com.xebialabs.deployit.plugin.api.reflect.DescriptorRegistry import getDescriptorRegistry
  3. taskDesc = Type.valueOf("xlrelease.Task")
  4. registry = getDescriptorRegistry(taskDesc.getTypeSource())
  5. print("%s\n"%registry)
  6. descriptors = registry.getDescriptors()
  7. tasks = [d.getType() for d in descriptors if d.isVirtual() == False and (d.isAssignableTo(Type.valueOf("xlrelease.Task")) or d.isAssignableTo(Type.valueOf("xlrelease.PythonScript")))]
  8. print("tasks: %s\n" % tasks)

Refer to passwords in xl-release-server.conf in jython

Setup

In release-server.conf, provide this

  1. my.password=somepassword

On restart of the server, this is encrypted (and will be something like

  1. my.password={aes\:v0}vEWwVYoSXqKXW+1Zro5u4KwFiMfsQJ0TJBeTsmtXgv8\=

Refer to password in plugin/custom jython script (tested in XLR 9.5.2 )

  1. from com.xebialabs.xlrelease.config import XlrConfig
  2. #To retrieve the decrypted password:
  3. myTemp = XlrConfig.getInstance().getRootConfig()
  4. print myTemp.getString("my.password")

Use custom python modules in XL Release

Sample Using git module.

  1. Download the library code https://files.pythonhosted.org/packages/d2/e8/0bd80cc9e1422f5449d663479459c3c032ff7acaf6609a63324d23bde9ac/GitPython-3.0.5.tar.gz

  2. untar/unzip and take out the actual module folder from it. In the above case, its the git folder.

  3. Now go under XLR_HOME/lib folder
  4. Create a new folder called Lib ( case sensitive )
  5. Copy the git module folder under Lib. Will look like this XLR_HOME/lib/Lib/git
  6. Find the jython standalone jar name by doing a file search ls jython*.
  7. Now run this command to update the jython jar with the contents of the Lib folder
    jar -uvf jython-standalone-2.7.1.patch2618.jar Lib

if would give an output like this while it adds the git python module

adding: Lib/(in = 0) (out= 0)(stored 0%) adding: Lib/git/(in = 0) (out= 0)(stored 0%) adding: Lib/git/db.py(in = 1963) (out= 802)(deflated 59%) adding: Lib/git/cmd.py(in = 42869) (out= 12482)(deflated 70%) adding: Lib/git/config.py(in = 28415) (out= 8096)(deflated 71%) adding: Lib/git/compat.py(in = 9436) (out= 3080)(deflated 67%) adding: Lib/git/test/(in = 0) (out= 0)(stored 0%) adding: Lib/git/test/test_stats.py(in = 971) (out= 412)(deflated 57%)

  1. Restart XLR and you should be able to use git module in jython script task.

The same can be done with XLD and then using it in plugins.

Important: If you want to use a python library under a custom plugin script inside XLRelease, instead of copying to lib/Lib and bundling up, you can bundle up the module inside the plugin jar at the root level. If you are working under ext folder, then you may keep the module under there while using it in the custom scripts backing the custom tasks.
Disclaimer : Another important thing to keep in mind is that on upgrades, you will have to manually update the jython library in that version with these modules.

Create a new Stage and add it to a new Environment

  1. from com.xebialabs.xlrelease.domain.environments import EnvironmentStage, Environment
  2. from com.xebialabs.xlrelease.api.v1.filter import EnvironmentStageFilters
  3. # Create a new stage and create it
  4. stage = EnvironmentStage()
  5. stage.setTitle("MyStage")
  6. environmentStageApi.create(stage)
  7. # Create a new filter to find the stage we just created with its real ID
  8. filter = EnvironmentStageFilters("MyStage")
  9. stageList = environmentStageApi.search(filter)
  10. if stageList:
  11. # Set the stage in the enviroment and create it
  12. envir = Environment()
  13. envir.setTitle("MyEnvironment")
  14. envir.setStage(stageList[0]._delegate)
  15. environmentApi.create(envir)

Dynamically choose a target server for all tasks of that type in a release

  1. # The variable servicenow_instance can be presented to the user as a listbox choice type during the start of release
  2. # Then using a bootstrap jython task in the start of the release, User's selection can be dynamically applied to all service
  3. # now tasks so they all point to the chosen server endpoing
  4. servicenow_servers = configurationApi.searchByTypeAndTitle("servicenow.Server", releaseVariables['servicenow_instance'])
  5. for p in release.phases:
  6. for t in p.tasks:
  7. if str(t.getTaskType()).split('.')[0] == 'servicenow':
  8. temp_task = taskApi.getTask(t.id)
  9. temp_task.pythonScript.setProperty("servicenowServer",servicenow_servers[0])
  10. taskApi.updateTask(temp_task.id, temp_task)

Search for a release in Release Group

  1. from com.xebialabs.xlrelease.domain.group import ReleaseGroup
  2. from com.xebialabs.xlrelease.api.v1.forms import ReleaseGroupFilters
  3. from com.xebialabs.xlrelease.api.v1.forms import ReleaseGroupOrderMode
  4. from com.xebialabs.xlrelease.domain.group import ReleaseGroupStatus
  5. rgfilter = ReleaseGroupFilters()
  6. rgfilter.withTitle(groupName)
  7. rgfilter.statuses = [ ReleaseGroupStatus.FAILED, ReleaseGroupStatus.IN_PROGRESS, ReleaseGroupStatus.PAUSED,ReleaseGroupStatus.FAILING ]
  8. rg = releaseGroupApi.resource.searchGroups(rgfilter, 0, 10, ReleaseGroupOrderMode.RISK)

Create a Release Group Dynamically and add the current release

  1. from com.xebialabs.xlrelease.domain.group import ReleaseGroup
  2. from com.xebialabs.xlrelease.api.v1.forms import ReleaseGroupFilters
  3. from com.xebialabs.xlrelease.api.v1.forms import ReleaseGroupOrderMode
  4. from com.xebialabs.xlrelease.domain.group import ReleaseGroupStatus
  5. from java.util import Calendar, Date
  6. cal = Calendar.getInstance()
  7. cal.setTime(Date())
  8. r = ReleaseGroup()
  9. r.title = "myReleaseGroup"
  10. r.folderId = "Applications/FolderSamplesAndTutorials"
  11. r.startDate = cal.getTime()
  12. cal.add(Calendar.DAY_OF_WEEK, 7)
  13. r.endDate = cal.getTime()
  14. releaseGroupApi.resource.createGroup(r)
  15. releaseGroupApi.resource.addMembersToGroup(r.id,[release.id])

Messing about with attributes (or Facets as they are really known)

  1. import com.xebialabs.xlrelease.api.v1.filter.ApplicationFilters as ApplicationFilters
  2. def get_app_id_from_name(applicationName):
  3. """
  4. Given a string representing the name of an XL Release Application return the
  5. corresponding applicationId
  6. :param str applicationName - Name of the XLRelease application
  7. In all unhappy cases it will return an empty string -
  8. TODO: something better
  9. """
  10. if applicationName:
  11. appList = applicationApi.search(ApplicationFilters(applicationName, None))
  12. if appList:
  13. return appList[-1].id
  14. else:
  15. return ""
  16. else:
  17. return ""
  18. # For the task in question (myTask in this example)
  19. if myTask.facets:
  20. #TODO: Loop through facets to find Deployment one!
  21. appId = get_app_id_from_name(component)
  22. if appId:
  23. myTask.facets[0].applicationId = appId
  24. myTask.facets[0].version = version

Creating a task with Facets

#f03c15 Warning - uses currently undocumented and non-public Api (FacetsApi)

  1. import com.xebialabs.xlrelease.api.v1.filter.ApplicationFilters as ApplicationFilters
  2. import com.xebialabs.xlrelease.api.v1.filter.EnvironmentFilters as EnvironmentFilters
  3. def get_app_id_from_name(applicationName):
  4. if applicationName:
  5. appList = applicationApi.search(ApplicationFilters(applicationName, None))
  6. if appList:
  7. return appList[-1].id
  8. else:
  9. return ""
  10. else:
  11. return ""
  12. def get_env_id_from_name(envName, stage):
  13. if envName:
  14. envList = environmentApi.search(EnvironmentFilters(envName, stage, None))
  15. if envList:
  16. return envList[-1].id
  17. else:
  18. return ""
  19. else:
  20. return ""
  21. containerId = getCurrentTask().container.id
  22. taskToAdd = taskApi.newTask("xlrelease.ScriptTask")
  23. taskToAdd.title = "ScriptCreated"
  24. taskToAdd.script = "import time \ntime.sleep(5)"
  25. appId = get_app_id_from_name("Wish List")
  26. if appId:
  27. deployFacet = facetApi.newFacet("udm.DeploymentTaskFacet")
  28. deployFacet.applicationId = appId
  29. deployFacet.version = "1.0.0"
  30. deployFacet.environmentId = get_env_id_from_name("DEV", "Development")
  31. deployFacet.targetId = taskToAdd.id
  32. print deployFacet.toString()
  33. taskfacets = list()
  34. taskfacets.append(deployFacet)
  35. taskToAdd.setFacets(taskfacets)
  36. createdTask=taskApi.addTask(containerId, taskToAdd)

Skip the current task (Uses OnFailureHandler (8.1+))

  1. from com.xebialabs.xlrelease.domain.recover import TaskRecoverOp
  2. task.setTaskFailureHandlerEnabled(True)
  3. task.setTaskRecoverOp(TaskRecoverOp.SKIP_TASK)
  4. taskApi.updateTask(task)
  5. raise Exception("Jenkins job was not built.")

Set the release title using release variables

  1. #use the 'component' and 'version' release varible as title
  2. title = "{component}/{version}".format(**releaseVariables)
  3. print(title)
  4. release.title = title
  5. releaseApi.updateRelease(release)

Get previous task

  1. def previousTask(task):
  2. index = 0
  3. for item in phase.tasks:
  4. if item.id == task.id:
  5. break
  6. index = index + 1
  7. return task.getPhase().tasks[index-1]
  8. print task.title
  9. print "previous task is: " + str(previousTask(task).title)

Get Gated tasks before a task

  1. def gatesBeforeTask(task):
  2. gatesList = []
  3. for item in phase.tasks:
  4. if str(item.getTaskType()) == "xlrelease.GateTask":
  5. gatesList.append(item)
  6. if item.id == task.id:
  7. break
  8. return gatesList
  9. print "start gates " + str(phase.getStartGates())
  10. for item in gatesBeforeTask(task):
  11. print item.title

Add a Gate task with a dependency

  1. current_phase = getCurrentPhase()
  2. task = taskApi.newTask("xlrelease.GateTask")
  3. task.title = "My Gate Task"
  4. taskApi.addTask(current_phase.id, task)
  5. blocking_release = "<Name of your Release>"
  6. blocking_phase = "<Name of your Phase>"
  7. blocking_task_name = "<Name of your task>"
  8. dependent_release = releaseApi.searchReleasesByTitle(blocking_release)[0]
  9. blocking_task = taskApi.searchTasksByTitle(blocking_task_name, blocking_phase, dependent_release.id)[0]
  10. taskApi.addDependency(task.id, blocking_task.id)

Find a task by title

  1. def findTaskByTitle(title):
  2. list = []
  3. for item in phase.tasks:
  4. if item.title == title:
  5. list.append(item)
  6. return list

Check/uncheck a gate condition via REST API

# Sample call: python gateupdate.py Release546450 UAT ‘Gate 2’ ‘Gate 2 condition 1’ ‘true’

  1. import requests
  2. import sys
  3. releaseId = sys.argv[1]
  4. phaseTitle = sys.argv[2]
  5. gateTitle = sys.argv[3]
  6. conditionTitle = sys.argv[4]
  7. conditionChecked = sys.argv[5]
  8. release = requests.get('http://admin:xlradmin@localhost:5516/releases/' + releaseId)
  9. for phase in release.json()['phases']:
  10. if phase['title'] == phaseTitle:
  11. for task in phase['tasks']:
  12. if task['title'] == gateTitle:
  13. for condition in task['conditions']:
  14. if condition['title'] == conditionTitle:
  15. condition['checked'] = conditionChecked
  16. r = requests.put('http://admin:xlradmin@localhost:5516/gates/conditions/' + condition['id'], json=condition)
  17. print r.status_code

Fetch variables from another release

  1. rvar = releaseApi.getVariables(releaseidvar)
  2. for r in rvar:
  3. print "key:%s , value:%s \n" % (r._delegate.key,r._delegate.value)

or

  1. myRelease = getCurrentRelease()
  2. for r in myRelease.variables:
  3. print "key:%s , value:%s \n" % (r.key, r.value)

Update automated task server entry

  1. t = taskApi.searchTasksByTitle("buildjar","Build",release.id)[0]
  2. jenkinslist = configurationApi.searchByTypeAndTitle("jenkins.Server",releaseVariables['jenkinsserver'])
  3. t.pythonScript.jenkinsServer = jenkinslist[0]
  4. taskApi.updateTask(t)

Fetch URL for selected server in a automated task

  1. t = taskApi.searchTasksByTitle("buildjar","Build",release.id)
  2. jenkinsUrl = t[0].pythonScript.jenkinsServer.url
  3. releaseVariables['jarurl'] = "%s/job/buildjar/%s/artifact/abc.jar" % (jenkinsUrl, releaseVariables['buildjarbn'])

Create table/fancy markdown in a task description

  1. a = [1,2,3,4,5,6]
  2. out=  "|Heading \n |---\n"
  3. for item in a:
  4.     out= "{0}|{1}\n".format(out,item)
  5. task.description = out
  6. taskApi.updateTask(task)

Image

images/tableintaskdescription.png

Xlrelease add dynamic tags

  1. release.tags.add('abc')
  2. releaseApi.updateRelease(release)

Print classpath

  1. from java.lang import ClassLoader
  2. cl = ClassLoader.getSystemClassLoader()
  3. paths = map(lambda url: url.getFile(), cl.getURLs())
  4. print paths

Add a folder

  1. from com.xebialabs.xlrelease.domain.folder import Folder
  2. newFolder = Folder()
  3. newFolder.title="MyFolder"
  4. folderApi.addFolder("Applications",newFolder)

Copy a template

  1. templates = folderApi.getTemplates("Applications")
  2. # Pick the first template
  3. template = templates[0]
  4. # Give it a new title
  5. template.title = "new template"
  6. templateApi.createTemplate(template)

Generate a release pipeline dynamically with parallel group and tasks from a provided dataset

  1. import json
  2. teamProjectName = "MyProject"
  3. buildDefinitionName = "mybuildDef"
  4. datamap = '''[
  5. {
  6. "name": "libs",
  7. "entries": [
  8. {
  9. "name": "a-library",
  10. "skip": "false"
  11. },
  12. {
  13. "name": "b-library",
  14. "skip": "false"
  15. },
  16. {
  17. "name": "c-library",
  18. "skip": "true"
  19. }
  20. ],
  21. "execution": "sequence"
  22. },
  23. {
  24. "name": "messages",
  25. "entries": [
  26. {
  27. "name": "a-messages",
  28. "skip": "false"
  29. },
  30. {
  31. "name": "b-messages",
  32. "skip": "true"
  33. },
  34. {
  35. "name": "c-messages",
  36. "skip": "false"
  37. }
  38. ],
  39. "execution": "parallel"
  40. },
  41. {
  42. "name": "services",
  43. "entries": [
  44. {
  45. "name": "a-service",
  46. "skip": "false"
  47. },
  48. {
  49. "name": "b-service",
  50. "skip": "false"
  51. }
  52. ],
  53. "execution": "parallel"
  54. }
  55. ]
  56. '''
  57. dataobj = json.loads(datamap)
  58. for item in dataobj:
  59. phase = phaseApi.newPhase(item['name'])
  60. phase = phaseApi.addPhase(release.id, phase)
  61. if str(item['execution']) == "parallel":
  62. pgrouptask = taskApi.newTask("xlrelease.ParallelGroup")
  63. pgrouptask.title = "Parallel Run"
  64. phase = taskApi.addTask(phase.id, pgrouptask)
  65. for entry in item['entries']:
  66. task = taskApi.newTask("vsts.QueueBuild")
  67. task.title = entry['name']
  68. task.pythonScript.setProperty("teamProjectName", teamProjectName)
  69. task.pythonScript.setProperty("buildDefinitionName", buildDefinitionName)
  70. if entry['skip'] == "true":
  71. task.precondition = "True == False"
  72. taskApi.addTask(phase.id, task)

Use a template deployment task of any type to generate multiple copies based on a map of component:versions

  • Create a template with this script task
  • Add a sequential/Parallel Group
  • In group add your template deployment task with same name as templateTask varable below - (currently ScriptTask or any CustomScriptTask (e.g. jenkins) types
  • Add precondition to your template task so it is always skipped (e.g. result = False)
  • Add attributes if you want - component and version will be added to the Application (must exsist) and Version fields
  • Remember to set run as user properties
  1. import com.xebialabs.xlrelease.api.v1.filter.ApplicationFilters as ApplicationFilters
  2. componentVersions={'Wish List':'2.0.1','Address Book':'2.1.3','Shopping Cart':'2.0.0'}
  3. templateTask = "Deploy Me Lots"
  4. # Get the template task - limitation here is if phases are named the same
  5. taskToCopy = taskApi.searchTasksByTitle(templateTask, getCurrentPhase().title, getCurrentRelease().id)[-1]
  6. #print taskToCopy.getType()
  7. def get_app_id_from_name(applicationName):
  8. """
  9. Given a string representing the name of an XL Release Application return the
  10. corresponding applicationId
  11. :param str applicationName - Name of the XLRelease application
  12. In all unhappy cases it will return an empty string -
  13. TODO: something better
  14. """
  15. if applicationName:
  16. appList = applicationApi.search(ApplicationFilters(applicationName, None))
  17. if appList:
  18. return appList[-1].id
  19. else:
  20. return ""
  21. else:
  22. return ""
  23. def multi_replace(string, replacements, ignore_case=False):
  24. """
  25. Given a string and a dict, replaces occurrences of the dict keys found in the
  26. string, with their corresponding values. The replacements will occur in "one pass",
  27. i.e. there should be no clashes.
  28. :param str string: string to perform replacements on
  29. :param dict replacements: replacement dictionary {str_to_find: str_to_replace_with}
  30. :param bool ignore_case: whether to ignore case when looking for matches
  31. :rtype: str the replaced string
  32. """
  33. if ignore_case:
  34. replacements = dict((pair[0].lower(), pair[1]) for pair in sorted(replacements.iteritems()))
  35. rep_sorted = sorted(replacements, key=lambda s: (len(s), s), reverse=True)
  36. rep_escaped = [re.escape(replacement) for replacement in rep_sorted]
  37. pattern = re.compile("|".join(rep_escaped), re.I if ignore_case else 0)
  38. return pattern.sub(lambda match: replacements[match.group(0).lower() if ignore_case else match.group(0)], string)
  39. # For all the entries in the component version map
  40. for component,version in componentVersions.iteritems():
  41. # Define replacements for this iteration
  42. replacements = {'{{component}}':component,'{{version}}':version}
  43. if "xlrelease.ScriptTask" in str(taskToCopy.getType()):
  44. taskToCopy.script = multi_replace(taskToCopy.script,replacements)
  45. elif "xlrelease.CustomScriptTask" in str(taskToCopy.getType()):
  46. for property in taskToCopy.pythonScript.getInputProperties():
  47. propertyName = str(property).split('.')[-1]
  48. propertyValue = taskToCopy.pythonScript.getProperty(propertyName)
  49. if type(propertyValue) is unicode:
  50. print "Replacing property`%s` it was [`%s`] \n" % (propertyName,propertyValue)
  51. taskToCopy.pythonScript.setProperty(propertyName,multi_replace(propertyValue, replacements))
  52. else:
  53. #TODO: Investigate other task types
  54. print "Unsupported task to copy"
  55. exit(1)
  56. taskToCopy.title = "Deploying %s at version %s" % (component, version)
  57. taskToCopy.precondition = ""
  58. if taskToCopy.facets:
  59. #TODO: Loop through facets to find Deployment one!
  60. appId = get_app_id_from_name(component)
  61. if appId:
  62. taskToCopy.facets[0].applicationId = appId
  63. taskToCopy.facets[0].version = version
  64. else:
  65. taskToCopy.precondition="print 'No valid AppName for attributes'\nexit(1)"
  66. createdTask = taskApi.addTask(taskToCopy.container.id, taskToCopy)

Add a Custom task (MyCustomTask.TestMapOutPut) in curent running Release and set a Key-Value (dicoPackageMap) in output property (MapOut)

  1. curRelease = getCurrentRelease()
  2. curPhase = getCurrentPhase().title
  3. task = taskApi.newTask("MyCustomTask.TestMapOutPut")
  4. task.title = "ScriptCreated"
  5. task.variableMapping = {"pythonScript.MapOut" : "$""{dicoPackageMap}"}
  6. createdTask=taskApi.addTask(getCurrentPhase().id, task)
  7. taskApi.assignTask(createdTask.id,"Admin")

Adding Date, working with Date

  1. from java.util import Calendar, Date
  2. cal = Calendar.getInstance()
  3. cal.setTime(Date())
  4. cal.add(Calendar.DAY_OF_WEEK, 7)
  5. print cal.getTime()

Add a Task as the last Task in phase by copying a previous Task

  1. t = getTasksByTitle("t1", "New Phase")[0]
  2. newtask = taskApi.copyTask(t.id, phase.id, len(phase.getTasks()))

Scheduling a task dynamically

  1. from java.util import Calendar, Date
  2. cal = Calendar.getInstance()
  3. cal.setTime(getCurrentTask().startDate)
  4. cal.add(Calendar.DAY_OF_WEEK, 2)
  5. # getting a task that is ahead of current task in the flow
  6. t = getTasksByTitle("t1", "New Phase")[0]
  7. t.setScheduledStartDate(cal.getTime())
  8. taskApi.updateTask(t)

Create a Self Scheduling Task Block - Style 1 ( Try style 2 below as its improved )

This example makes use of a Sequential Group. You can have any number of tasks within the sequential group but the last task should be a Jython Script/Custom Task with the following Script. The script will replicate its parent Sequential Group and then reschedule the newly cloned group for a certain datetime

  1. parenttask = getCurrentTask().container
  2. # find the sequential group child
  3. sequentialGroupId = None
  4. activetask = None
  5. # Iterating on the children to find SequentialGroup ID and the last active manual task ID
  6. for child in parenttask.getChildren():
  7. if str(child.type).lower() == "xlrelease.SequentialGroup".lower():
  8. sequentialGroupId = child.id
  9. if str(child.type).lower() == "xlrelease.Task".lower() and str(child.status).lower() == "IN_PROGRESS".lower():
  10. activetask = child.id
  11. # Setting up a notification task
  12. notfication = taskApi.newTask("xlrelease.NotificationTask")
  13. notfication.subject = "Sending Notification at %s" % datetime.today()
  14. notfication.addresses = Set(["a@gmail.com", "b@gmail.com"])
  15. notfication.body = "hi Hello"
  16. taskApi.addTask(sequentialGroupId, notfication)
  17. # Setting up a manual task
  18. manualtask = taskApi.newTask("xlrelease.Task")
  19. manualtask.title = "Waiting for Activity on %s" % ( datetime.today() + timedelta(days=1) )
  20. taskApi.addTask(sequentialGroupId, manualtask)
  21. # assigning it to the admin user to mark it complete in the next step
  22. taskApi.assignTask(activetask,"admin")
  23. taskApi.completeTask(activetask,Comment())

Create a Self Scheduling Task Block - Style 2 ( Better )

This example makes use of a Sequential Group. You can have any number of tasks within the sequential group but the last task should be a Jython Script/Custom Task with the following Script. The script will replicate its parent Sequential Group and then reschedule the newly cloned group for a certain datetime

The script task sets a variable repeatTask as boolean with default True. This will keep on rescheduling the sequential group as long as the value is True. To stop repeating, either programatically or manually set the repeatTask variable to false.

  1. from java.util import Calendar, Date
  2. import time
  3. # Get the parent block for current script task
  4. parenttask = getCurrentTask().container
  5. # Use calendar to increment the time
  6. cal = Calendar.getInstance()
  7. cal.setTime(parenttask.startDate)
  8. cal.add(Calendar.DAY_OF_WEEK, 2)
  9. # Create a new task from that parenttask as the next task
  10. newtask = taskApi.copyTask(parenttask.id, phase.id, len(phase.getTasks()))
  11. # Set the newtask to the new time and title
  12. newtask.setScheduledStartDate(cal.getTime())
  13. newtask.title = parenttask.title
  14. newtask.precondition = "releaseVariables[\"repeatTask\"] == True"
  15. # Update the new task
  16. taskApi.updateTask(newtask)
  17. releaseVariables["repeatTask"] = True

Create/Populate a List Variable using Jython

There are different interpreted types for different type of variables within the api. Usual way of knowing the right name is eg.
If variable type is StringVariable, then xlr type is xlrelease.StringVariable

Some variable types are

  • StringVariable
  • ListStringVariable
  • MapStringStringVariable
  • PasswordStringVariable
  • SetStringVariable
  1. from com.xebialabs.xlrelease.api.v1.forms import Variable
  2. mylist = [1,2,3,4]
  3. listvar = Variable()
  4. listvar.value = mylist
  5. listvar.key = "mylistvar"
  6. listvar.type = "xlrelease.ListStringVariable"
  7. releaseApi.createVariable(release.id,listvar )

And Listboxes?

These are slightly different, the variable itself can be a StringVariable type but the options are provided using a provider. This is not really documented but the following code snippet works for this use-case

  1. from com.xebialabs.xlrelease.api.v1.forms import Variable
  2. from com.xebialabs.xlrelease.domain.variables import ListOfStringValueProviderConfiguration
  3. mylist = ["1","2","3","4"]
  4. listvar = Variable()
  5. listvar.value = "1"
  6. listvar.key = "mylistvar"
  7. listvar.type = "xlrelease.StringVariable"
  8. provider1 = ListOfStringValueProviderConfiguration()
  9. provider1.id = "myvariableProvider"
  10. provider1.values = mylist
  11. listvar.valueProvider = provider1
  12. releaseApi.createVariable(release.id,listvar )

Update Owner of a new Release

  1. c = CreateRelease()
  2. c.setReleaseTitle('Test Release')
  3. # Create a new release using template ID
  4. r = templateApi.create('Releaseedf803f0dfc145189d8d38714679e075', c)
  5. # Providing new owner
  6. r.owner = 'tester1'
  7. releaseApi.updateRelease(r)

Update a variable in another release

  1. releasetitle = "test1"
  2. varkey = "local_ip"
  3. releases = releaseApi.searchReleasesByTitle(releasetitle)
  4. releaseidvar = releases[0].id
  5. rvar = releaseApi.getVariables(releaseidvar)
  6. vartoupdate = [ item for item in rvar if item.key == varkey ] [0]
  7. vartoupdate.value = "newvalue"
  8. releaseApi.updateVariable(vartoupdate)

Generate a markdown table with phase/task/task status into a variable for using in email

  1. out = "|Phase|Task|Status|\n|---|---|---|\n"
  2. for ph in release.phases:
  3. if str(ph.status) != "PLANNED":
  4. for tsk in phase.tasks:
  5. out= "{0}|{1}|{2}|{3}\n".format(out,ph.title,tsk.title,tsk.status)
  6. releaseVariables["emailcontent"] = out

Capture a map/dict with key values and print it as a markdown table

  1. out="|Ticket ID|Description|\n|---|---|\n"
  2. for key, value in releaseVariables["issueList"].iteritems():
  3. out= "{0}|{1}|{2}\n".format(out,key,value)
  4. releaseVariables["printedTable"] = out

Custom task to Add a manual task just after the current running one

ie, how to find task position and add a new one just after it

  1. -- synthetic.xml
  2. <type type="dev.addManualAfter" extends="xlrelease.PythonScript">
  3. <property name="scriptLocation" default="dev/addManualAfter.py" hidden="true" ></property>
  4. <property name="taskColor" hidden="true" default="#009CDB"></property>
  5. </type>
  6. -- dev/addManualAfter.py
  7. def addManual(createTaskName):
  8. a = getMyPositionAndContainer(getCurrentTask(),getCurrentPhase())
  9. mytaskPos = a[0]
  10. mycontainer = a[1]
  11. taskFound = a[2]
  12. if taskFound:
  13. task = taskApi.newTask("xlrelease.Task")
  14. task.title = str(createTaskName)
  15. phaseApi.addTask(mycontainer.id,task,mytaskPos+1)
  16. else:
  17. raise Exception("**Exception: Task [{0}] not found in [{1}]**".format(getCurrentTask().title,getCurrentPhase().title))
  18. def getMyPositionAndContainer(mytask,mycontainer):
  19. isfound = False
  20. i = 0
  21. for item in mycontainer.tasks:
  22. #print "[%s/%s]" %(str(item.type),item.title)
  23. if str(item.type) == "xlrelease.SequentialGroup":
  24. res = getMyPositionAndContainer(mytask,item)
  25. i = res[0]
  26. mycontainer = res[1]
  27. isfound = res[2]
  28. else:
  29. if item.id == mytask.id:
  30. isfound = True
  31. break
  32. if isfound == True:
  33. break
  34. i = i + 1
  35. return [i,mycontainer,isfound]
  36. addManual("AutoCreated")

Dynamically Generate Deployment Task based on json Data

  1. import json
  2. teamProjectName = "MyProject"
  3. buildDefinitionName = "mybuildDef"
  4. datamap = '''[
  5. {
  6. "name": "libs",
  7. "entries": [
  8. {
  9. "name": "a-library",
  10. "skip": "false"
  11. },
  12. {
  13. "name": "b-library",
  14. "skip": "false"
  15. },
  16. {
  17. "name": "c-library",
  18. "skip": "true"
  19. }
  20. ],
  21. "execution": "sequence"
  22. },
  23. {
  24. "name": "messages",
  25. "entries": [
  26. {
  27. "name": "a-messages",
  28. "skip": "false"
  29. },
  30. {
  31. "name": "b-messages",
  32. "skip": "true"
  33. },
  34. {
  35. "name": "c-messages",
  36. "skip": "false"
  37. }
  38. ],
  39. "execution": "parallel"
  40. },
  41. {
  42. "name": "services",
  43. "entries": [
  44. {
  45. "name": "a-service",
  46. "skip": "false"
  47. },
  48. {
  49. "name": "b-service",
  50. "skip": "false"
  51. }
  52. ],
  53. "execution": "parallel"
  54. }
  55. ]
  56. '''
  57. dataobj = json.loads(datamap)
  58. for item in dataobj:
  59. phase = phaseApi.newPhase(item['name'])
  60. phase = phaseApi.addPhase(release.id, phase)
  61. if str(item['execution']) == "parallel":
  62. pgrouptask = taskApi.newTask("xlrelease.ParallelGroup")
  63. pgrouptask.title = "Parallel Run"
  64. phase = taskApi.addTask(phase.id, pgrouptask)
  65. for entry in item['entries']:
  66. task = taskApi.newTask("xldeploy.Deploy")
  67. task.title = entry['name']
  68. task.pythonScript.setProperty("deploymentEnvironment", entry['name'])
  69. task.pythonScript.setProperty("deploymentPackage", "app-%s" % entry['name'])
  70. if entry['skip'] == "true":
  71. task.precondition = "True == False"
  72. taskApi.addTask(phase.id, task)

Dynamically update the Variable Value for a Create Release Task in a release

  1. for t in phase.tasks:
  2. if str(t.getTaskType()).split('.')[1] == 'CreateReleaseTask':
  3. for template_var in t.templateVariables:
  4. if template_var.key == 'dpackage':
  5. template_var.value = 'oclc'
  6. taskApi.updateTask(t.id, t)
  1. from com.xebialabs.xlrelease.domain.variables import StringVariable
  2. subreleasesTaskGroup = taskApi.searchTasksByTitle("Subreleases", getCurrentPhase().title, getCurrentRelease().id)[0]
  3. for subrelease in releaseVariables["jiraIssues"]:
  4. taskToAdd = taskApi.newTask("xlrelease.CreateReleaseTask")
  5. taskToAdd.newReleaseTitle = "Subrelease {}".format(subrelease)
  6. taskToAdd.templateId = templateApi.getTemplates('Billing Portal Core')[0].id
  7. taskToAdd.folderId = folderApi.find('Billing Portal App/Sandbox', 2).id
  8. jiraissue = StringVariable()
  9. jiraissue.setKey("jiraIssue")
  10. jiraissue.setValue("SAN-0001")
  11. taskToAdd.templateVariables = [jiraissue]
  12. taskApi.addTask(subreleasesTaskGroup.id, taskToAdd)

(code valid for un custom task with a “TaskType” string property)

  1. from com.xebialabs.deployit.plugin.api.reflect import Type
  2. from com.xebialabs.deployit.plugin.api.reflect.DescriptorRegistry import getDescriptorRegistry
  3. taskDesc = Type.valueOf("xlrelease.Task")
  4. registry = getDescriptorRegistry(taskDesc.getTypeSource())
  5. descriptors = registry.getDescriptors()
  6. tasks = [d.getType() for d in descriptors if d.isVirtual() == False and (d.isAssignableTo(Type.valueOf("xlrelease.Task")) or d.isAssignableTo(Type.valueOf("xlrelease.PythonScript")))]
  7. print("tasks: %s\n" % tasks)
  8. TaskType="XlrTasks.TaskType"
  9. #Returns the list of planned or active releases that are visible to the current user
  10. print "**Running or planned visible releases - Task type [%s]**"%(TaskType)
  11. page=0
  12. allRunningReleases=releaseApi.getReleases(page,100,1)
  13. while len(allRunningReleases) > 0:
  14. for r in allRunningReleases:
  15. cnt=0
  16. for p in r.phases:
  17. for t in p.tasks:
  18. if str(t.getTaskType()) == TaskType:
  19. cnt=cnt+1
  20. if cnt>0:
  21. print ("%s : %s")%(r.url,cnt)
  22. page=page+1
  23. allRunningReleases=releaseApi.getReleases(page,100,1)
  24. #Returns the list of templates that are visible to the current user.
  25. print ""
  26. print "**Visible templates - Task type [%s]**"%(TaskType)
  27. page=0
  28. allTemplates=templateApi.getTemplates("",[],page,100,1)
  29. while len(allTemplates) > 0:
  30. for r in allTemplates:
  31. cnt=0
  32. for p in r.phases:
  33. for t in p.tasks:
  34. if str(t.getTaskType()) == TaskType:
  35. cnt=cnt+1
  36. if cnt>0:
  37. print ("%s : %s")%(r.url,cnt)
  38. page=page+1
  39. allTemplates=templateApi.getTemplates("",[],page,100,1)

Get folder path from Folder id

  1. def getFolderPathById(folderid):
  2. target=folderid
  3. foldername=folderApi.getFolder(target).title
  4. folderPath=""
  5. res = [i for i in range(len(target)) if target.startswith("/", i)]
  6. for p in res:
  7. if target[0:p] != "Applications":
  8. folderPath = "%s%s/"%(folderPath,folderApi.getFolder(target[0:p]).title)
  9. return folderPath + foldername