Jenkinsapi check and update multibranch xml

Hello,

I have been looking into the jenkinsapi for python and found that there is the option to configure a multibranch pipeline by providing an xml. However, I have not found any method to check if the multibranch pipeline is created in the server, a method to modify the configuration by providing another xml or a method to delete the multibranch pipeline. Are there any methods for such purposes in the jenkinsapi?

Hello @apalomer :wave:

Are you referring to this wrapper: Using Python-Jenkins — Python Jenkins 1.1.1.dev1 documentation ?

Hello. I am revisiting this topic as I still cannot find such a feature. I am not refering to the python library that @poddingue points, I am refering to jenkinsapi

A multibranch pipeline is just a special type of job. From the code the only difference from creating other job types is that for multibranch it triggers an initial scan.
If the job creation was successful the create_multibranch_pipeline should return an array with the job name. If it failed I would assume the method throws an exception.

Updating or deleting a job is not different for multibranch jobs than for any other job type so there are no dedicated methods required. The job.py has a method to update the config, just use it.
Same for deleting just delete via the api like you would delete any other kind of job.

1 Like

Whenever I create a multibranch pipeline, it returns an array of jobs similar to:

multibranch_1/tag1
multibranch_1/tag2
multibranch_1/master
multibranch_1/develop
....
multibranch_1/feature%2Fmy-cool-feature

Moreover, if I list all jobs:

jenkins = Jenkins('https://my-jenkins.com', username='my-user', password='my-password')
jobs = jekins.get_jobs()
for j in jobs:
  print(j)

I get something like:

('none-multibranch-job1', <jenkinsapi.job.Job none-multibranch-job1>)
('none-multibranch-job2', <jenkinsapi.job.Job none-multibranch-job2>)
('multibranch_1/tag1', <jenkinsapi.job.Job tag1>)
('multibranch_1/tag2', <jenkinsapi.job.Job tag2>)
('multibranch_1/master', <jenkinsapi.job.Job master>)
('multibranch_1/develop', <jenkinsapi.job.Job develop>)
....
('multibranch_1/feature%2Fmy-cool-feature', <jenkinsapi.job.Job feature%2Fmy-cool-feature>)
('none-multibranch-job3', <jenkinsapi.job.Job none-multibranch-job3>)
('none-multibranch-job4', <jenkinsapi.job.Job none-multibranch-job4>)
('multibranch_2/master', <jenkinsapi.job.Job master>)
('multibranch_2/develop', <jenkinsapi.job.Job develop>)
...
('multibranch_2/feature%2Fanother-cool-feature', <jenkinsapi.job.Job feature%2Fanother-cool-feature>)
...

Obviously, if I try to get a multibranch pipeline as a job I get an error:

job = jenkins.get_job('multibranch_2')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/ubuntu/ros2_ws/.venv/lib/python3.12/site-packages/jenkinsapi/jenkins.py", line 171, in get_job
    return self.jobs[jobname]
           ~~~~~~~~~^^^^^^^^^
  File "/home/ubuntu/ros2_ws/.venv/lib/python3.12/site-packages/jenkinsapi/jobs.py", line 95, in __getitem__
    raise UnknownJob(job_name)
jenkinsapi.custom_exceptions.UnknownJob: 'multibranch_2'

Therefore I cannot use the jenkinsapi.job.Job.update_config because I cannot get such Job object from the multibranch_2 pipeline.

However, I’ve been able to update it using other methods (inspried in the soruce code of jenkinsapi.jobs.Jobs.create_multibranch_pipeline method):

def update_multibranch_pipeline(jenkins: Jenkins, job_name: str, job_config: str) -> List[Job]:
    url = f"{jenkins.baseurl:s}/job/{job_name:s}/config.xml"
    response = jenkins.requester.post_url(url, params={}, data=job_config.encode("utf-8"))
    if response.status_code != 200:
        print(f"Failed to update job '{job_name:s}' with config:\n{job_config:s}")
        print(
            f"Response: {response.status_code:d} {response.reason:s}\n{response.content.decode('utf-8')}"
        )
        return []

    # Launch scan/indexing to discover the branches...
    jenkins.requester.post_and_confirm_status(
        "{}/job/{}/build".format(jenkins.baseurl, job_name),
        data="",
        valid=[200, 302],  # expect 302 without redirects
        allow_redirects=False,
    )
    start_time = time.time()
    # redirect-url does not work with indexing;
    # so the only workaround found is to parse the console output
    # until scan has finished.
    scan_finished = False
    while not scan_finished and time.time() < start_time + 60:
        indexing_console_text = jenkins.requester.get_url(
            "{}/job/{}/indexing/consoleText".format(jenkins.baseurl, job_name)
        )
        if indexing_console_text.text.strip().split("\n")[-1].startswith("Finished:"):
            scan_finished = True
        time.sleep(1)

    # now search for all jobs created; those who start with job_name + '/'
    jobs = []
    for name in jenkins.get_jobs_list():
        if name.startswith(job_name + "/"):
            jobs.append(jenkins.get_job(name))
            
    return jobs

technically a multibranch pipeline job is actually a generated folder. But for Jenkins it makes no difference from api point of view.

1 Like