Jenkins API & Confluence Integration for Test Reporting: A step-by-step guide

Introduction

Test reporting is one of the most important tools used by software development teams to keep track of testing progress, troubleshoot issues, and make better decisions.

In this blog, we’ll look at how you can integrate Jenkins API with Confluence to build dynamic pie charts that show test pass and test fail results.

This integration allows you to centralize your test reporting, automate your documentation updates, and enhance collaboration among your team members.

Advantages of Integration: There are various advantages for test reporting when integrating the Jenkins API with Confluence.

Automated Test Reporting: Teams may automate the process of retrieving test results and adding dynamic information, such as pie charts that show test pass and fail percentages, to Confluence pages by utilizing the Jenkins API.

Real-time Visibility: Stakeholders may monitor the status of testing and make data-driven choices thanks to the integration’s real-time visibility into test findings. The constantly updated pie charts guarantee that documentation is always current by reflecting the most recent test results.

Enhanced Cooperation: Teams can work together in real time on documentation using Confluence, which acts as a centralized platform for test reporting. Teams may share insights with stakeholders and effectively depict test findings by integrating dynamic pie charts into Confluence pages.

Confluence Integration with Jenkins API Implementation:
This is a detailed how-to for setting up Confluence integration and Jenkins API for test reporting:

Set up Jenkins API Access: To authenticate API queries, get API tokens or credentials from Jenkins.

Confluence Page Structure Definition: Make templates or Confluence pages for test reporting that include areas for test pass and fail outcomes.

Create a Jenkins Pipeline Script: To create a scripted pipeline that starts tests and returns results, use the Jenkins Pipeline DSL.

Create Test Pass/Fail Data: To obtain the test pass and fail counts from the test execution report, utilize the Jenkins API.

Create Pie Chart Data: Determine the percentage of test pass and fail outcomes, then prepare the information for graphical representation in a pie chart.

Confluence Page Updates: Update using the Confluence REST API.

In the below mentioned section added the python code to generate and add the pie chart in the target confluence page.

Code to collect response for a particular given job from Jenkins using Jenkins APIs:-

def get_build_data(job_name):
    url = f'https://jenkinsURL/{job_name}/api/json'
    response = requests.get(url)
    build_data = response.json()
    return build_data

Code to collect the current build related data and status from Jenkins:-

def extract_build_status(build_data):
    builds = build_data['jobs']
    print(builds)
    dict = {}
    for build in builds:
        dict[build['name']] = build['color']

    return dict

Potting the pie chart:-

# # Step 3: Prepare data for visualization
# based on the colored icon will conclude passed or failed
def prepare_data(build_statuses):
    success_count = build_statuses.count('blue')
    failure_count = build_statuses.count('yellow') + build_statuses.count('red')
    return success_count, failure_count

def prepare_data_with_job_name(build_statuses):
    success_count = sum(1 for build in build_statuses if build['color'] == 'blue')
    failure_count = sum(1 for build in build_statuses if build['color'] in ['yellow', 'red', 'aborted'])
    return success_count, failure_count


# # Step 4: Generate pie chart
#
def generate_pie_chart(success_count, failure_count,output_file):
    labels = ['Success', 'Failure']
    counts = [success_count, failure_count]
    plt.pie(counts, labels=labels, autopct='%1.1f%%')
    plt.title('Build Status')
    plt.axis('equal')  # Equal aspect ratio ensures that pie is drawn as a circle.
    # plt.show()
    plt.savefig(output_file)  # Save the pie chart as an image file
    plt.close()  # Close the plot to release resources

# Plot pie chart with job name
def plot_pie_chart(data, output_file):

    
    pass_jobs = [job_name for job_name, status in data.items() if status == 'blue']
    fail_jobs = [job_name for job_name, status in data.items() if status != 'blue']

    # Create labels and counts for the pie chart
    labels = ['Failed', 'Passed']  # Reversed order to match the colors assignment
    counts = [len(fail_jobs), len(pass_jobs)]  # Reversed order to match the colors assignment

    # Map colors to labels
    colors = {'Passed': 'green', 'Failed': 'red'}

    # Increase figure size
    plt.figure(figsize=(16, 8))

    # Create the pie chart subplot
    plt.subplot(1, 2, 1)
    patches, texts, autotexts = plt.pie(counts, labels=labels, colors=[colors[label] for label in labels],
                                        autopct='%1.1f%%', startangle=140)
    # plt.title('Job Status', fontsize=16)

    # Remove axis and background
    plt.axis('off')
    plt.gca().set_facecolor('none')

    # # Annotate each slice with "Pass" or "Fail"
    # for text in autotexts:
    #     text.set_text("Pass" if text.get_text() == str(len(pass_jobs)) else "Fail")
    #     text.set_fontsize(12)  # Increase font size

    # Create the table subplot
    plt.subplot(1, 2, 2)
    table_data = [(job_name, 'Pass') for job_name in pass_jobs] + [(job_name, 'Fail') for job_name in fail_jobs]
    column_labels = ['Job Name', 'Status']

    # Remove axis and background
    plt.axis('off')
    plt.gca().set_facecolor('none')

    table = plt.table(cellText=table_data, colLabels=column_labels, loc='center', fontsize=12)  # Increase font size
    table.auto_set_column_width([0, 1])  # Adjust column width automatically

    plt.tight_layout()  # Adjust layout to minimize white space
    plt.subplots_adjust(wspace=0)  # Remove horizontal space between subplots
    # plt.show()
    plt.savefig(output_file, dpi=200)  # Save the pie chart as an image file with higher resolution
    plt.close()  # Close the plot to release resources

Attach the image in the confluence page using confluence API token:

# To attach image will rewrite this. The image will be added below the para.
def attach_image_after_paragraph(sectionTextFromBodyOfHTML,image_file):
    # Set up Confluence connection
    username = 'userName'
    api_token = 'api token generate from confluence my profile'
    jira_url = ('https://confluence page link /wiki')
    page_id='put page ID of the page'

    confluence = Confluence(
        url=jira_url,
        username=username,
        password=api_token
    )
    # Define the path to the image file
    image_path = f'put the path of image file '

    filename = f'/put the path of image file '
    confluence.attach_file(f'/put the path of image file ', page_id='page id ')
    image = f'<ac:image> <ri:attachment ri:filename="{image_file}" /> </ac:image>'
    existing_content = confluence.get_page_by_id('page id ', expand='body.storage')['body']['storage']['value']
    # //Now find the paragraph, and below that add the new plot
    # Specify the text of the existing paragraph
    # existing_paragraph_text = 'target text after which the image added'
    existing_paragraph_text=paragraphText
    # Find the index of the existing paragraph text
    existing_paragraph_index = existing_content.find(existing_paragraph_text)


    # If the existing paragraph text is found, insert the image after it
    if existing_paragraph_index != -1:
        # Find the index of the end of the paragraph (after the closing </p> tag)
        paragraph_end_index = existing_content.find('</p>', existing_paragraph_index) + len('</p>')
        # Construct the updated content with the image tag inserted after the paragraph
        updated_content = (existing_content[:paragraph_end_index] +
                           image +
                           existing_content[paragraph_end_index:])
        print(updated_content)
        # Update the page with the modified content
        # confluence.update_page(
        #     page_id=page_id,
        #     title="title updated One",
        #     body={
        #         'storage': {
        #             'value': updated_content,
        #             'representation': 'storage'
        #         }
        #     }
        # )
        confluence.update_page(
            page_id=page_id,
            title="page title",
            body=updated_content)
        print("Image inserted after the paragraph successfully.")
    else:
        print("Existing paragraph not found.")

Call this script from any Jenkins job and make it scheduled to update after a particular event.