‹ SimDiff Automation Support

Integrating SimDiff in Azure DevOps workflows

An Azure pipeline on a self-hosted Windows agent runs SimDiff Automation and publishes a peer review file.

Introduction

These steps put SimDiff Automation in an Azure DevOps workflow with Simulink model files and Git.

When a change to a Simulink file is pushed, a pipeline uses SimDiff to create a peer review file of the changes and uploads it to Azure DevOps as an artifact. This example uses a self-hosted agent on a local Windows PC.

Getting started with a simple example

Prerequisites

  • An Azure DevOps account
  • A repo in Azure DevOps Repos with your Simulink files
  • A Windows PC with Simulink, Git, and SimDiff Automation installed

Access an Azure DevOps repo

You need an Azure DevOps account and a repo that contains Simulink files. Import the sample repository into your Azure DevOps organization:

  1. Click Import repository.
Azure DevOps repository menu with Import repository circled
  1. In the Clone URL field, type https://github.com/EnSoftCorp/devops-integration.git.
Import a Git repository dialog with Clone URL https://github.com/EnSoftCorp/devops-integration.git and name devops-integration.git
  1. Click Import. The repository is imported.

The repository has two branches, main and dev. The main branch has aero_radmod.slx and a YAML file that tells the pipeline what to run. That YAML file is already set up to use SimDiff to report changes between file versions.

Azure DevOps Files list on the main branch, showing aero_radmod.slx, azure-pipelines.yml, and README.md

Clone the repo on your computer

Clone the same Git repository on a local Windows PC. The clone URL is under the Clone button, usually at the top right of the Repos page in Azure DevOps.

git clone git@ssh.dev.azure.com:##YourRepoURLinGit

Set up Git credentials for Azure DevOps. Clone your Azure DevOps repo, not the GitHub repo that was imported into Azure DevOps.

Configure and run a self-hosted agent

When an Azure pipeline runs, it starts a job. An agent is the computer and software that runs the job. This example uses a self-hosted agent on the local PC. Microsoft documents the setup in Self-hosted Windows agents. The steps below cover the parts this example uses.

  1. Open Settings for your organization and click Agent pools. Click Add pool.
Azure DevOps Project Settings, Agent pools, listing Azure Pipelines and Default, with Add pool at the top right
  1. Select an agent pool, or create one: click Add pool, set Pool type to Self-hosted, give the pool a name, and click Create.
Add agent pool dialog with Pool type Self-hosted selected, name New Pool, and the Create button
  1. Select the agent pool and click New agent.
Agent pool page with the Jobs tab selected and the New agent button
  1. Select Windows and download the agent.
Azure DevOps Windows agent page with Download, and PowerShell steps for creating the agent, config.cmd, and run.cmd
  1. Create a personal access token (PAT) before you configure the agent. Microsoft documents that in personal access tokens for agent registration.
  2. Create and configure the agent on Windows by following the instructions on that page. This example uses Windows PowerShell. Start an elevated PowerShell window, go to the folder where you unpacked the agent (the recommended location is C:\agents), and run .\config.cmd. It asks a series of questions.
  1. Run the agent in interactive mode with .\run.cmd.

Push a change in Git

With the agent configured, check the items below, then push a change to trigger the pipeline.

Verify the SimDiff Automation installation. The YAML file assumes SimDiff Automation is installed at C:\Program Files\EnSoft\SimDiff Automation. Change that location in the YAML file if it is not.

Configure SimDiff Automation. Configure the license and MATLAB installations by running sd4.exe with the -license and -matlabSetup command-line options. Then check that a report can be generated from the command line.

Review the YAML file. This sample triggers SimDiff to generate a report. When a change to aero_radmod.slx is pushed, the pipeline generates the report and uploads it. A later section extends this so every changed model file gets a report.

trigger:  
branches:  
 include:  
   - "*"   # all branches  
pool:  
name: Default   # your self-hosted Windows agent  


stages:  
- stage: peer_review_file_generation  
displayName: "Peer Review File Generation"  


jobs:  
- job: SimDiff_PeerReview  
 displayName: "Generate SimDiff Peer Review File"  


 steps:  
 - checkout: self  
   fetchDepth: 2 #fetch previous commit  


 # ============ Set up DiffTool ===============  
 - powershell: |  
     git config --local difftool.simdiff.cmd '\"C:/Program Files/EnSoft/SimDiff Automation/sd4.exe\" -l \"$LOCAL\" -r \"$REMOTE\" -export aero_radmod_peerreview.html'  
   displayName: "Prepare SimDiff command (Powershell)"  


 # ============ Invoke SimDiff to Produce a Peer Review File ===============  
 - powershell: |  
     echo Comparing with SimDiff...  
     git difftool -y -t simdiff HEAD~1 HEAD .\aero_radmod.slx  
   displayName: "Run SimDiff comparison (Powershell)"  


 # ============ Publish Artifact ===============  
 - publish: $(System.DefaultWorkingDirectory)/aero_radmod_peerreview.html  
   artifact: aero_radmod_peerreview.html  
   displayName: "Publish SimDiff Peer Review File"

Change the model file and push. Change aero_radmod.slx, commit it, and push.

That starts a pipeline on Azure DevOps. The self-hosted agent on the local PC generates a SimDiff peer review file and uploads it as an artifact.

Observe the report artifact on Azure DevOps

  1. Go to Pipelines and open the run that just finished. Open the most recent run, go to Jobs, and check that the job succeeded.
Azure DevOps run of SimDiff_report_generation on main, with the Generate SimDiff Peer Review File job marked Success
  1. Click the job (Generate SimDiff Peer Review File in this example) to see the details.
Azure DevOps job steps for Generate SimDiff Peer Review File, including Prepare SimDiff command, Run SimDiff comparison, and Publish SimDiff Peer Review File
  1. Click the artifact for a run, then click the report to download it.
Azure DevOps stage Peer Review File Generation with 1 artifact circled in red

Comparing all changed model files in a commit

The earlier example assumed that a file named aero_radmod.slx was changed. To report every model file that changed in a commit, change the YAML file so it calls a Python script. A push that changes model files then creates a report for each changed file and uploads the reports as an artifact. The sample script compares the current version of the file (HEAD) with the version in the previous commit.

Prerequisites

Install Python on the local machine, in addition to the prerequisites above. Switch to the dev branch of the sample repository to see the updated files.

Azure DevOps Files list on the dev branch, showing aero_radmod.slx, azure-pipelines.yml, diff.py, and README.md

Repository changes

The dev branch has a modified YAML file that calls a new Python script.

Updated YAML:

trigger:  
branches:  
 include:  
   - "*"   # all branches  


pool:  
name: Default   # your self-hosted Windows agent  


stages:  
- stage: peer_review_file_generation  
displayName: "Peer Review File Generation"  


jobs:  
- job: SimDiff_PeerReview  
 displayName: "Generate SimDiff Peer Review File"  


 steps:  
 - checkout: self  
   fetchDepth: 2 #fetch previous commit  
  
 # ============ Invoke SimDiff to Produce a Peer Review File ===============  
 - powershell: |  
     echo Comparing with SimDiff...  
     python .\diff.py reports HEAD~1 HEAD  
   displayName: "Run SimDiff comparison (Powershell)"  


 # ============ Publish Artifact ===============  
 - publish: $(System.DefaultWorkingDirectory)/reports  
   artifact: SimDiff_Peer_Review_Files  
   displayName: "Publish SimDiff Peer Review Files"

Python script. The listing for diff.py is below.

import subprocess  
import os  
import sys  


# Function to get the list of modified files in the commit  
def get_modified_files():  
 try:  
     # Get the list of modified files (slx files) in the current commit  
     result = subprocess.run(['git', 'diff', commit1, commit2, '--name-only', '--diff-filter=M'], stdout=subprocess.PIPE,  
                             text=True,      # Ensure output is in string format  
                             check=True)     # Raise an error if the command fails  
     # Filter to include only Simulink model files (.slx or .mdl)  
     modified_files = [line for line in result.stdout.splitlines() if (line.endswith('.slx') or line.endswith('.mdl'))]  
     return modified_files  
 except subprocess.CalledProcessError as e:  
     print(f"Error getting modified files: {e}")  
     return []  


# Function to call SimDiff for each file  
def run_simdiff_for_files(file):  
     try:  
         # Call the difftool (replace 'simdiff' with the actual command if different)  
         report_file = f"{reportsDir}/" + file.removesuffix(".slx") + ".peerreview.html"  
         print(f"    report_file= {report_file}")  


         # Ensure report directory is created if it doesn't exist  
         report_path = os.path.dirname(report_file)  
         os.makedirs(report_path, exist_ok=True)  
          
         path_to_diff_tool = f'"\'C:/Program Files/EnSoft/SimDiff Automation/sd4.exe\' -l $LOCAL -r $REMOTE -export {report_file}"'  
         config_cmd = f'git config --local difftool.sd4.cmd {path_to_diff_tool}'  
         #print(f"    config_cmd= {config_cmd}")  
         subprocess.run(config_cmd, text=True, check=True, shell=True)  
         diff_cmd = f'git difftool -y -t sd4 {commit1} {commit2} {file}'  
         #print(f"    diff_cmd= {diff_cmd}")  
         subprocess.run(diff_cmd, text=True, shell=True)  
          
         #print(f"    SimDiff ran successfully for {file}\n")  
     except subprocess.CalledProcessError as e:  
         print(f"Error running SimDiff on {file}: {e}")  


def main():  
 modified_files = get_modified_files()  
 if modified_files:  
     print("Modified Simulink models:")  
     for file in modified_files:  
         print(f" - {file}")  
         run_simdiff_for_files(file)  
 else:  
     print("No modified Simulink models found.")  


if __name__ == '__main__':  
 reportsDir = sys.argv[1]  
 commit1 = sys.argv[2]  
 commit2 = sys.argv[3]  
 main()

Make changes to model files and push

When you push changes, a report is created for each changed model file and uploaded as an artifact to Azure DevOps.

Contact

Questions about these steps: support@ensoftcorp.com.