Featured image of post OpenAPI-Use Jenkins to Detect OpenAPI Changes + Email Docs Team

OpenAPI-Use Jenkins to Detect OpenAPI Changes + Email Docs Team

So, you’re maintaining manual API documentation, but how do you know when to update it?

If your API changes, but nobody tells the documentation team… you’ve got a problem.

What if Jenkins could:
Detect when swagger.json changes
Log the differences in a file
Trigger a documentation update notification
Fail the build if documentation updates are ignored


🔥 The Plan

We’re setting up two Jenkins jobs to monitor OpenAPI changes:

1️⃣ API Repo Jenkins Job – Detects changes in swagger.json and logs them in a apichangessensedbyjenkins.txt file.
2️⃣ Docs Repo Jenkins Job – Watches for changes in this file and emails the doc team with the API diff.

If the diff logging fails, the API build fails.
If documentation updates are ignored, a reminder email is sent.


🛠 Step 1: Set Up Jenkins to Detect OpenAPI Changes

✅ 1.1: Install Required Tools on Jenkins Server

Make sure Jenkins has:

  • Git (apt install git or choco install git)
  • jq (JSON diff tool, apt install jq or choco install jq)
  • diff (should be pre-installed)

✅ 1.2: Create Jenkins Job to Detect API Changes

  1. Open Jenkins DashboardNew ItemFreestyle Project
  2. Name it Detect-OpenAPI-Changes
  3. Under Source Code Management, choose Git, and add your API repo URL.
  4. Under Build Triggers, enable Poll SCM (e.g., every 5 minutes: H/5 * * * *).
  5. Add the following Bash Script under Build Steps → Execute Shell:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/bin/bash

# Define paths
API_REPO="/var/lib/jenkins/workspace/Detect-OpenAPI-Changes"
DOCS_REPO="/var/lib/jenkins/workspace/API-Docs-Changes"
SWAGGER_FILE="$API_REPO/swagger.json"
OLD_SWAGGER_FILE="$API_REPO/old_swagger.json"
CHANGE_LOG="$DOCS_REPO/apichangessensedbyjenkins.txt"

# Clone docs repo
if [ ! -d "$DOCS_REPO" ]; then
    git clone git@github.com:your-org/api-docs.git "$DOCS_REPO"
fi

# Pull latest changes
cd "$DOCS_REPO"
git pull origin main

# Check if old swagger file exists
if [ -f "$OLD_SWAGGER_FILE" ]; then
    # Compute JSON diff
    DIFF=$(diff <(jq -S . "$OLD_SWAGGER_FILE") <(jq -S . "$SWAGGER_FILE"))

    if [ "$DIFF" != "" ]; then
        echo "Swagger JSON has changed!"
        
        # Append diff to log file
        echo "----------------------------" >> "$CHANGE_LOG"
        echo "Date: $(date)" >> "$CHANGE_LOG"
        echo "Commit: $(git -C "$API_REPO" rev-parse HEAD)" >> "$CHANGE_LOG"
        echo "Changes:" >> "$CHANGE_LOG"
        echo "$DIFF" >> "$CHANGE_LOG"
        
        # Push changes to docs repo
        git add "$CHANGE_LOG"
        git commit -m "API changes detected by Jenkins on $(date)"
        git push origin main
    else
        echo "No changes detected in Swagger JSON."
    fi
else
    echo "First run, saving initial Swagger file."
fi

# Save new Swagger file for future comparison
cp "$SWAGGER_FILE" "$OLD_SWAGGER_FILE"
  1. Save and Build Now.
  2. Check if apichangessensedbyjenkins.txt is created/updated in your API-Docs repo.

📩 Step 2: Set Up Jenkins to Notify the Documentation Team

✅ 2.1: Create a Second Jenkins Job

  1. Open Jenkins DashboardNew ItemFreestyle Project
  2. Name it Notify-Docs-Team
  3. Under Source Code Management, choose Git, and add the API-Docs repo URL.
  4. Under Build Triggers, enable Poll SCM (H/5 * * * *).
  5. Under Build Steps → Execute Shell, add:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/bash

DOCS_REPO="/var/lib/jenkins/workspace/API-Docs-Changes"
CHANGE_LOG="$DOCS_REPO/apichangessensedbyjenkins.txt"

# Pull latest changes
cd "$DOCS_REPO"
git pull origin main

# Check if file has been updated
if git diff --name-only HEAD~1 HEAD | grep -q "apichangessensedbyjenkins.txt"; then
    echo "Swagger changes detected! Sending email notification..."
    
    # Extract last changes
    DIFF_CONTENT=$(tail -n 20 "$CHANGE_LOG")

    # Send email
    echo -e "Subject: API Documentation Update Required\n\nThe following API changes were detected:\n\n$DIFF_CONTENT" | sendmail -v docs-team@example.com
else
    echo "No new API changes detected."
fi
  1. Save and Build Now.
  2. Check email inbox for API change notifications.

🚨 Step 3: Fail Build if API Docs Aren’t Updated

If the documentation team doesn’t update the API docs (by updating the swagger.json) after changes, we can fail the build.

  1. In Notify-Docs-Team, go to Post-Build Actions → Add Post-Build Script
  2. Add the following check:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#!/bin/bash

DOCS_REPO="/var/lib/jenkins/workspace/API-Docs-Changes"
CHANGE_LOG="$DOCS_REPO/apichangessensedbyjenkins.txt"

# Get last commit message
LAST_COMMIT_MSG=$(git -C "$DOCS_REPO" log -1 --pretty=%B)

# If the last commit was by Jenkins, the docs haven't been updated yet
if [[ "$LAST_COMMIT_MSG" == *"API changes detected by Jenkins"* ]]; then
    echo "Documentation has not been updated. Failing build."
    exit 1
else
    echo "Documentation updated. Build successful."
fi

Now, if the docs team doesn’t update API documentation, the build will fail, forcing them to take action.


So, Jenkins is now detecting API changes, logging diffs, and failing the build if documentation isn’t updated. Great!

But now the docs team has a new problem:
➡️ How do they actually update the Swagger JSON and prevent build failures?

The answer? A simple Python script.
(Which is the answer to most things in life hahaha.. )

How The Docs Team can push a button after the docs are fix- and make the build work again

🚀 The Plan

The docs team will:
✅ Run a Python script to pull the latest swagger.json
✅ Manually review and update the documentation
✅ Commit and push the updated swagger.json
✅ Fix the Jenkins failure, keeping API docs up to date

Let’s build it. 🚀


🔧 Step 1: Install Dependencies

The script uses GitPython to manage Git operations and jsondiff to detect changes in swagger.json.

Install them with:

1
pip install gitpython jsondiff

📝 Step 2: Create the Python Script

Save the following script as update_swagger.py in the manual documentation repository.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
import os
import json
import git
import subprocess
from jsondiff import diff

# Set repository paths
DOCS_REPO_PATH = os.path.abspath(".")  # Run this script inside the docs repo
API_REPO_URL = "git@github.com:your-org/api-repo.git"  # API repository
TEMP_CLONE_PATH = "/tmp/api-repo"  # Temporary API clone location
SWAGGER_FILE = "swagger.json"
CHANGE_LOG_FILE = "apichangessensedbyjenkins.txt"

def clone_api_repo():
    """Clone the API repository to fetch the latest swagger.json."""
    if os.path.exists(TEMP_CLONE_PATH):
        subprocess.run(["rm", "-rf", TEMP_CLONE_PATH], check=True)
    
    print("Cloning API repository...")
    git.Repo.clone_from(API_REPO_URL, TEMP_CLONE_PATH)
    
def fetch_swagger_file():
    """Fetch the latest swagger.json from the API repo."""
    api_swagger_path = os.path.join(TEMP_CLONE_PATH, SWAGGER_FILE)
    
    if not os.path.exists(api_swagger_path):
        raise FileNotFoundError("Swagger file not found in API repository!")
    
    with open(api_swagger_path, "r") as f:
        return json.load(f)

def load_current_swagger():
    """Load the existing swagger.json from the docs repo."""
    docs_swagger_path = os.path.join(DOCS_REPO_PATH, SWAGGER_FILE)
    
    if not os.path.exists(docs_swagger_path):
        print("No existing swagger.json found. Creating a new one...")
        return {}
    
    with open(docs_swagger_path, "r") as f:
        return json.load(f)

def detect_changes(old, new):
    """Detect changes between old and new Swagger JSON."""
    return diff(old, new, syntax="symmetric")

def update_swagger_file(new_swagger):
    """Update the local swagger.json file in the documentation repo."""
    docs_swagger_path = os.path.join(DOCS_REPO_PATH, SWAGGER_FILE)
    
    with open(docs_swagger_path, "w") as f:
        json.dump(new_swagger, f, indent=2)
    
    print(f"Updated {SWAGGER_FILE} with the latest API changes.")

def append_to_changelog(changes):
    """Append detected changes to the Jenkins change log file."""
    changelog_path = os.path.join(DOCS_REPO_PATH, CHANGE_LOG_FILE)
    
    with open(changelog_path, "a") as f:
        f.write("\n----------------------------\n")
        f.write(f"Date: {subprocess.getoutput('date')}\n")
        f.write(f"Changes detected:\n{json.dumps(changes, indent=2)}\n")
    
    print(f"Changes appended to {CHANGE_LOG_FILE}.")

def commit_and_push():
    """Commit and push the updated swagger.json to prevent Jenkins build failure."""
    repo = git.Repo(DOCS_REPO_PATH)
    
    repo.git.add(SWAGGER_FILE)
    repo.git.add(CHANGE_LOG_FILE)
    
    commit_message = "Updated Swagger JSON to match API changes."
    repo.git.commit("-m", commit_message)
    
    print("Pushing changes to documentation repository...")
    repo.git.push("origin", "main")
    
    print("Swagger JSON updated and pushed successfully!")

if __name__ == "__main__":
    try:
        clone_api_repo()
        
        new_swagger = fetch_swagger_file()
        old_swagger = load_current_swagger()
        
        changes = detect_changes(old_swagger, new_swagger)
        
        if changes:
            print("Changes detected! Updating documentation...")
            update_swagger_file(new_swagger)
            append_to_changelog(changes)
            commit_and_push()
            print("✅ Documentation successfully updated.")
        else:
            print("No changes detected. Documentation is already up to date.")
    
    except Exception as e:
        print(f"❌ Error: {e}")
        exit(1)

📌 Step 3: Run the Script

The documentation team can now update the API docs with:

1
python update_swagger.py

🔥 Step 4: Automate Updates with Jenkins

If the docs team wants to automate this, add it to Jenkins:

  1. Open Jenkins DashboardNew ItemFreestyle Project
  2. Name it Update-Swagger-Docs
  3. Under Source Code Management, choose Git, and add the documentation repo URL
  4. Under Build Triggers, enable Poll SCM (H/10 * * * *).
  5. Under Build Steps → Execute Shell, add:
1
2
3
4
5
#!/bin/bash

cd /var/lib/jenkins/workspace/API-Docs
git pull origin main
python3 update_swagger.py