How to: Committing project to Git with author and timestamps

I modified the bash script from the best practices guide which has a guide to configuring automatic Git commits on Designer save. I made it so that it adds the author of the change and the timestamp of the change to the commits, and I wanted each resource to be its own commit so it does that too.
The commit is saved under the author as well.
Edit #1: Modified commit comment to use the file saved instead.

image

image

Original guide: Ignition 8 Deployment Best Practices | Inductive Automation

See below!

#!/bin/bash
# this script requires that json library `jq` is installed

# add any new files created to git file tracking
git add .
originalUserName=`git config --list | grep 'user\.name=[\w]*' | sed -e 's/user.name=//g'`

NOW=`date +"%Y-%m-%d %H:%M:%S"`

# find the tracked files that have differences, taking only get their 'resources.json' file
git diff --name-only HEAD | grep -E 'resource.json$' | \
    # ... and loop through each file. Note: what is returned is the relative file path each changed file.
    # This need to be appended onto the working directory held in var $PWD
    while read relFilePath
    do
        # create a variable with the full path of the changed resouce.json file
        filePath="$PWD/$relFilePath"
        folderPath=`echo "$filePath" | sed 's/\/resource.json//g'`
        fileName=`basename "$folderPath"`

        relFilePath_fmt=`echo "$relFilePath" | sed 's/com.inductiveautomation.//g' | sed 's/\/resource.json//g'`       

        # extract out the author of the change and the time using the json library `jq`
        author=`jq -r .attributes.lastModification.actor "$filePath"`
        tstamp=`jq -r .attributes.lastModification.timestamp "$filePath"`
        
        # format the date nicely to put in the commit comment
        tstamp_fmt=`date --date="$tstamp" +"%Y-%m-%d %H:%M:%S"`
        
        git config --global user.name $author
        git commit -m "Modified '$relFilePath_fmt' @ $tstamp_fmt by $author" --date $tstamp -- "$folderPath"
    done

git config --global user.name "Unknown"
# commit everything else that doesn't have a resource.json
git commit -m "Modified resources without resource.json @ $NOW (commit time) - Author could be $author but this is not known"

# push the changes to Git
git push origin master

# set the username back to the original user
git config --global user.name "$originalUserName"
3 Likes

Very cool. Soon :tm: we’ve got plans to give the project update script more useful context via parameters, so hopefully a lot of these hacks aren’t necessary.

1 Like

But I hacked away at piecing together the Bash script for this… :weary: and you know you’re a complete noob at Bash when you run into the old foo = "bar" error :laughing: (can’t have spaces around the =)

Jokes aside, that would be very nice to have! Although I would still want to commit each resource by itself… so I probably still would need some of it

Next thing I need to do is to filter out the resources that were saved but don’t actually have any changes (e.g. Designer saves where you have multiple graphics open but have only made changes to one, but all files get saved)

Our team found that committing on every save caused more headaches than not. Many changes have to be saved to be tested, even if they are broken or we want to revert them a moment later.

We’re still looking for better ways to manage multiple developers contributing to an Ignition project via git, but a big roadblock is all the non-mergeable (binary) items under the projects directory. :frowning:

I know IA was still hoping to convert more of the project files from binary to something text-based. Can anyone on the IA team reading this comment on a timeline for that work?

Can't provide a timeline, but maybe some insight. What particular resource files are causing issues?
'Singleton' resources (project properties, client/gateway event scripts, etc) might happen ~8.2. Vision windows and templates, likely won't ever happen. Named queries just happened in the last couple releases.

1 Like

I most often bump into alarm pipelines, named queries, and reports in our usage patterns. Glad to hear the named queries is already done.

EDIT: To clarify, those are the binary blobs that we change most often. The times we had conflicts were mostly on named queries, so you guys chose well in hitting that one first. If I had to pick which one we would want next, I would say alarm pipelines.

1 Like

This is landing in 8.1.14 via parameters named actor and resources; they'll be covered in the docs soon, but until we migrate gateway functions to 'extension-function' style, they're just magic named parameters available implicitly.

We’ve been enjoying moving information the other way, so Ignition knows what its git directory is looking at. This will require some tweaks to tag paths or if your git root isn’t at the projects level, but the basic idea should be easy to work with. We call this from a project update event and it works well:

def update_git_tags():
    import subprocess
    projects_directory = '/usr/local/bin/ignition/data/projects'
    description_tagpath = '[default]git/description'
    branch_tagpath = '[default]git/branch'
    # If using annotated tags in git for releases, remove the "--tags" on
    # this command line, as it is only there to include non-annotated tags:
    desc_args = '/usr/bin/git -C {pd} describe --broken --always --tags'.split()
    desc_args[2] = projects_directory
    description_string = subprocess.check_output(desc_args)
    description_string = description_string.strip()
    branch_args = '/usr/bin/git -C {pd} branch --show-current'.split()
    branch_args[2] = projects_directory
    branch_string = subprocess.check_output(branch_args)
    branch_string = branch_string.strip()
    #logger.info('git update: branch={} description={}'.format(branch_string, description_string))
    tagpaths = [description_tagpath, branch_tagpath]
    values = [description_string, branch_string]
    system.tag.writeBlocking(tagpaths, values)

I tried to run the attached script from nminchin, but unfortunately with Ignition 8.1.12 it does not run anymore. If I execute the script in a shell locally on the ignition host it runs perfectly. What could be the reason? According to my analysis it breaks at the line starting with the while loop.

I could fix the issue. After adding the following line

cd /usr/local/bin/ignition/data/projects

before git add . the script worked as expected.