How to Write a Bash Script to Create and Update a Changelog | by Matthew Croak | Apr, 2022

No extra turbines, logs, or dependencies

Picture by Christopher Gower on Unsplash

A changelog is a useful gizmo to point out different contributors and customers what updates had been made to your mission, when, in addition to what these updates entail. Whilst you may assume that conserving a changelog is tedious or time consuming, it may be extra informative and enhance accountability in the long term.

That being mentioned, it could be good to trim among the time spent in your changelog should you may. That’s what I wished to do after I created my very own bash script for creating and updating my very own changelog.

There are a few pre-existing ways to generate a changelog, however they both didn’t fairly match what I used to be searching for when it comes to readability (together with the model quantity supplied by git tagging for instance), or they encompassed an excessive amount of data. What I imply by an excessive amount of data is that these different era strategies grabbed ALL of your commits out of your git logs and primarily listed them in a extra organized method.

It is a good trick to know, however I wished to create a extra deliberate changelog and never merely re-organize my varied commits.

“The aim of a changelog entry is to doc the noteworthy distinction, typically throughout a number of commits, to speak them clearly to finish customers.”

— Hold A Changelog

Our changelog

Having our personal script for producing a changelog permits the flexibleness to determine what data is included in addition to the way it ought to look. On this submit, we’ll generate a changelog that has the fundamental construction that appears like the next.

The changelog on your mission doesn’t HAVE to appear like this however I prefer it because it follows the Keep A Changelog conference and gives quantity of knowledge with out being overwhelming. Every level of the changelog comprises the model quantity, adopted by the date in ISO format. Below every is a piece pertaining to the adjustments that had been made, resembling Added, Fastened and Eliminated (these are the change varieties I personally use essentially the most). For extra on these conventions, please see the Hold A Changlog initiative.

Now, let’s get into producing our first Changelog with bash.

Within the root of your mission listing, create a bash shell script file on your changelog logic.

root:~ > contact changelog.sh

Now that you’ve your shell script file, we will make it executable by merely working this command in our terminal.

root:changelog-script > chmod u+x changelog.sh

What this line does is it permits us to easily kind the file title within the command line, press enter, and execute the script that it comprises. Now we will begin engaged on our logic. We are going to write three features: new_changelog, new_changelog_item, and init.

new_changelog()

echo 'new changelog'
new_changelog_item()

echo 'including changelog merchandise'
init()

echo 'provoke script'

The aim of our script is that once we execute our shell script (person varieties ./changelog.sh and clicks enter), the script will decide if we have to create a changelog earlier than including an merchandise. If a changelog doesn’t exist, make it, then add the primary merchandise. If it does exist, simply add a brand new changelog merchandise — ONLY if a changelog merchandise doesn’t exist already for the present model.

Extra on that later.

First, let’s initialize an necessary variable: changelog. This variable will probably be on the high of our script and can reference, because the title suggests, our changelog file. Add changelog=CHANGELOG.md to the highest of your file. As soon as that’s within the script file, we will replace our init operate to examine if the file exists. If it does, then merely add a brand new merchandise. If it doesn’t, we have to create it first after which add a brand new merchandise. How can we inform if a file exists in our mission?

We can implement an if statement in our init function.

The situation we will probably be checking is if take a look at -f "$changelog". This line makes use of the built-in take a look at command which is used t take a look at a file’s attributes and carry out different operations. The -f operator merely tells the situation to search for a file and examine if it’s a traditional file (not a listing or exterior gadget). Let’s take a look at our up to date init operate now that we all know easy methods to examine if a file exists.

init()

if take a look at -f "$changelog" ; then
echo "$changelog exists."
else
echo "$changelog doesn't exist."
fi

Superior, half one is finished. Now we have to work on our different features that can substitute these echo strains. The primary one is new_changelog. This one would require the least quantity of effort as all we have to do is make the file. How can we make a file in bash? All we have to do for that’s to make use of echo after which point out that this echoed output needs to be directed into a brand new file. We do that through the use of >, which is a file descriptor redirection. Let’s see this in motion.

new_changelog()

echo "right here is my changelog" > CHANGELOG.md

It will create a changelog file in your mission listing. I personally like to incorporate the Hold A Changelog header in my changelog information. So we will substitute 'right here is my changelog' with the beneath code.

"# Changelog
All notable adjustments to this mission will probably be documented on this file.
The format relies on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this mission adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]"

Good. If our init situation finds {that a} changelog does not exist, our new_changelog operate will make one. We’re virtually completed, however I believe we must always save the developer an additional step. What I imply is, as an alternative of ending the script right here and making the developer run it once more so as to add a brand new changelog merchandise, we simply name new_changelog_item on the finish of new_changelog. This implies we’ll want to begin work on new_changelog_item.

The very first thing we have to do on this operate, is locate our mission’s present model. To do that, you possibly can the next line underneath your changelog variable.

model="$(git describe --long)"

It will print your tagged model like this:

1.2.1-2-gabc12d34

What we’ve right here is the mission model (1.2.1), adopted by the variety of commits for this model (-2), and eventually an abbreviated title for the commit itself (-gfa17e39). There are methods you possibly can condense the entire model right into a extra readable model (resembling representing the above as 1.2.3) however I gained’t get into that right here.

For extra on git tagging, take a look at this post.

Now that we’ve the model, we have to get the date. That is one other variable we will add just below model. In Bash, you may get the date just by utilizing date. However it will give us the beneath consequence.

Tue Mar 29 13:10:19 EDT 2022

On this changelog, we will probably be adhering to the ISO format, which is principally the yr, adopted by the month, then the day. You may embody the time however on this script we’ll simply be utilizing the year-month-day format. To be able to format our date to stick to the ISO format, we will use the beneath code.

immediately="$(date '+%Y-%m-%d')"

Now that we’ve the date appropriately formatted, we will get to the toughest a part of the script: truly including a line to the changelog file at a particular line. To be able to do that, we’ll have to learn the changelog.

whereas learn line; do
echo $line
completed < CHANGELOG.md

The above code iterates by means of every line (represented by $line) of the changelog and echo’s it in your command line. Now that we will learn every line, we simply want to seek out which line is the one we wish to add a newS changelog merchandise after. Provided that ## [Unreleased] is a typical fixture our changelog, beneath which is our launched adjustments, it is a good line to search for when including a brand new changelog merchandise.

Because the ## [Unreleased] adjustments (not related to present date or model) are eliminated on the time of launch anyway, including assist for checking for unreleased adjustments isn’t presently a precedence.

Beneath is an if assertion to examine for the road ## [Unreleased].

if [[ $line == "## [Unreleased]"* ]]; then
echo "LINE FOUND"
fi

Good. We will now know at which line to insert our new changelog merchandise. Which begs the subsequent query, how can we truly insert the changelog merchandise? For this, we’ll use sed.

sed is a textual content stream editor that has a whole lot of nice makes use of, however for now, we’re solely utilizing it for locating and mutating textual content in a file. We will use the sed command with the -i flag to edit the file in place. That is good as a result of we wish to truly edit the present file, not merely printing to plain output.

To be able to use sed to insert textual content, we might want to comply with the beneath format.

sed -i "" "s/old_line/new_line" FILE.ext

To interrupt this down, first you must embody "" after -i due to how the road is parsed (No less than on Mac OS X it’s wanted. It won’t be wanted on different working programs). Then you possibly can present the previous line, adopted by its substitute, following by the file itself. The s to start with of that string stands for “substitute”, so the command is aware of to interchange old_line with new_line.

For our case, the above will be rewritten like so:

sed -i "" "s/$newvar/## [Unreleased]nn## [$version] - $daten### Addedn - ADD CHANGE HERE!/" CHANGELOG.md

Now, you might need observed $newvar rather than $line. It’s because our authentic line comprises brackets ([]). These are reserved for bracket expressions and subsequently will not be evaluated the identical as straight textual content. So with the intention to resolve this, we’ve to create a brand new variable that primarily replaces the brackets with escaped brackets. We will discover the road with common brackets, however we’ll want to flee these brackets to ensure that the sed command to correctly substitute it. See $newvar beneath.

newvar=$(<<<"$line" sed 's/[].*[]/&/g')

For the sake of this submit and brevity, I gained’t go too in-depth on the construction of this syntax. Simply know that this line replaces the brackets in $line with escaped brackets in order that they’re handled as a part of the textual content and not as a bracket expression.

Right here is our up to date new_changelog_item operate:

Nice! We’re virtually completed.

We have now most of our code in place. All we have to do is now could be examine if there may be already a line that coincides with our present model. To try this, we will merely see if there’s a line anyplace within the changelog that has a line just like the beneath:

## [$version] - $date

To do that, we will add the beneath conditional to our new_changelog_item.

merchandise="## [$version] - $date"
if grep -Fxq "$merchandise" CHANGELOG.md; then
echo "Changelog merchandise already exists for $merchandise."
else
# remainder of operate

-Fxq is a flag that permits us to examine for the supplied sample (in our case, the changelog merchandise header) as a set string, actual match, or quiet output. Basically, it’s a really thorough flag to assist us catch a sample no matter kind. As soon as we’ve this, we will put the remainder of our earlier features within the else assertion. It’s because if a changelog merchandise for this model/date mixture does NOT exist, we must always add a brand new one.

And there you will have it! A pure bash script to include in your app to generate a changelog, add changelog objects, and presents you flexibility when it comes to format and changelog content material with out the necessity for turbines, logs, or different dependencies. The complete code is on GitHub.

https://linuxize.com/post/bash-check-if-file-exists

More Posts