USoft Delivery Manager integration with Git


In our delivery/deployment process, we use various types of external artefacts, such as XSLT and XSD files which are used in the processing of XML data. Version control for these files is done using Git.

 

Also, we keep a complete history of all our releases, created by UDeliver, in Git repositories.

 

Rather than having to handle these Git-related activities manually or by scripts, as we do now, it would be very useful if UDeliver would support pulling from and pushing to Git repositories.
 

Hi Marc,

I can imagine that would be nice to have integrated into UDeliver instead of combining it as explained in this article. maybe @Rob.van.Haarst  can elaborate on the possibilites, challenges involved? A Git client will need to be included/shipped along I suppose or maybe you could specify a location of the Git client to use with UDeliver?


More on USoft Delivery manager:

 


Yes, the link describes what we do now, but it would be nice to have proper ‘Git pull’ and ‘Git push’ actions in UDeliver.


Hi Dara and Marc,

This is an interesting suggestion and part of a much larger discussion about sourcing. When USoft started out all those years ago, the idea was to have a central database repository, with some additional features for deliverables that really had to be files and not database records. But in 2021, we are in a reality where Git file-based repositories are the leading delivery model for business software, and USoft database repositories will just have to fit into this larger framework. UDeliver is a step in this direction, because it automates conversion from database repositories to file-based deliverables.

More concretely, at USoft, when we create PDF documentation for our USoft Studio product, we use UDeliver to pull and push directly to and from Git, using task steps like the following.

This solution uses RDMI components. The USWTW_WINFILES performs common file system operations such as building filepaths for copying, moving and deleting files and folders. The code for the USWTW_SYSTEM component appears at the end of this reply.

Step 1: Hard reset and pull

This is risky in that any locally outstanding uncommitted work is automatically discarded. But this is necessary to avoid running into Git merge conflicts when these UDeliver steps are carried out as an automated routine.

UDeliver Action: Run SQL Command

SQL command:

(Note: ‘${git_local_folder}’ is something called a ‘user-defined source variable’ in UDeliver.)

INVOKE	
USWTW_System.Execute
WITH SELECT
'git.exe', '--git-dir="${git_local_folder}"\.git --work-tree="${git_local_folder}" reset --hard -q origin/develop'

Step 2: Upload edits

UDeliver Action: Copy Folder

Source folder:

${my_edited_folder}\pdf

Destination folder:

${git_local_folder}\Alt\Website\pdf

Step 3: Commit PDFs

UDeliver Action: Run SQL Command

SQL command:

INVOKE	USWTW_System.Execute
WITH
SELECT 'git.exe', '--git-dir=' || '${git_local_folder}' || '\.git --work-tree=' || '${git_local_folder}' || ' commit -a -q -m "URequire ' || '${curr_vs}' || ' PDF files"'
WHERE /* Only commit/push if pdf's have been successfully created s*/
TO_DATE(
USWTW_WINFILES.MODIFIED(
'${git_local_folder}' || '\Alt\Website\PDF\workspace.pdf'
),
'YYYY/MMDDHH24MISS'
) > ( current_date() - 1 )

Step 4: Push PDFs

UDeliver Action: Run SQL Command

SQL command:

INVOKE	USWTW_System.Execute
WITH
SELECT 'git.exe', '--git-dir=' || '${git_local_folder}' || '\.git --work-tree=' || '${git_local_folder}' || ' push -q'
WHERE /* Only commit/push if pdf's have been successfully created */
TO_DATE(USWTW_WINFILES.MODIFIED('${git_local_folder}' || '\Alt\WebSite\pdf\workspace.pdf'), 'YYYY/MMDDHH24MISS') > ( current_date() - 1 )

.NET Component: USWTW_SYSTEM

using System;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
using System.Diagnostics;
using System.Threading;

class USWTW_SYSTEM
{
public string Execute(string cmd, string arguments)
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.FileName = cmd;
startInfo.Arguments = arguments;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;
startInfo.UseShellExecute = false;
process.StartInfo = startInfo;
process.Start();
string errors = process.StandardError.ReadToEnd();
if( errors != "")
throw new Exception(errors);
return process.StandardOutput.ReadToEnd();
}

public string ExecuteReturnError(string cmd, string arguments)
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.FileName = cmd;
startInfo.Arguments = arguments;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
process.StartInfo = startInfo;
process.Start();
return process.StandardError.ReadToEnd();
}

public int ExecuteReturnExitCode(string cmd, string arguments)
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.FileName = cmd;
startInfo.Arguments = arguments;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;
startInfo.UseShellExecute = false;
process.StartInfo = startInfo;
process.Start();
string errors = process.StandardError.ReadToEnd();
if( errors != "")
throw new Exception(errors);
return process.ExitCode;
}

public void ExecuteShell(string cmd, string arguments, string error_string)
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.FileName = cmd;
startInfo.Arguments = arguments;
startInfo.UseShellExecute = true;
process.StartInfo = startInfo;
process.Start();
process.WaitForExit();
if( process.ExitCode != 0)
throw new Exception(error_string);
}

public void Exit(string dummy)
{
Process.GetCurrentProcess().Kill();
}

}

 


Rob, thanks for the detailed information! I’ll play around with this when I have some time.