Date:

Share:

How to customize Conventional Commits in a .NET application using GitHooks

Related Articles

Establishing team conventions is a crucial step for the project to be ready to live a long time and prosper 🖖

A good way to set some clarity is by enforcing rules on GIT commit messages: you can enforce developers to state the reason behind some code changes so you can understand the history and reason for each of these commits. also, If you have well-formed commit messages, pull requests become easier to understand, which leads to better code.

Conventional commits help you set such rules, helping you level up your commit history. In this article we will learn how to add conventional commits in a .NET application.

Conventional obligations

Conventional commits are a set of rules that help you write commit messages using a format that has several purposes:

  • They help developers understand the history of a git branch;
  • They help PR testers focus on the Pull Request by understanding the changes proposed by the developer;
  • Using automated tools, they help version management of the application – this is useful when using semantic versioning;
  • They allow you to create automatic changelog files.

So what does an average conventional commitment look like?

There is not just one way to specify such formats.

For example, you can specify that adding a new feature (More than) to your APIs and describe it soon:

feat(api): send an email to the customer

Or you can explain that you fixed a bug (using Correct) and add a full description of the scope of the commitment.

fix: prevent racing condition

Introduce a request id and a reference to latest request. Dismiss
incoming responses other than from latest request.

There are several types of pledges you can support, such as:

  • More thanUsed when you add a new feature to an application;
  • CorrectWhen you fix a bug;
  • documentsUsed to add or improve documentation to a project;
  • RefactorUsed – well – after some restoration;
  • TestWhen adding tests or fixing a broken one

All this prevents developers from writing commit messages such as “something”, “bug fixed”, “Stuff”.


So, now, it’s time to include conventional commits in our .NET applications.

What is our goal?

For the sake of this article, I’m going to add conventional commits in the .NET 7 API project. The same approach works for all other types of .NET projects: as long as you have a solution to work with, I’ve got you covered.

well actually The following approach can be used in any projectNot only those based on .NET: the reason I wrote this article is that many Donet developers are not confident in using and configuring NPM packages, so my personal goal with this article is to give you the basics of such tools and configurations.

For the sake of this article, I’m going to explain how to add conventional commits with a custom format.

Say you want to associate each commit with a Jira task. As you may know, Jira tasks have an ID consisting of a project prefix and a numeric ID. So, for a project called FOO, you can execute a task with an Id FOO-123.

The goal of this article is, therefore, to force developers to create commit messages such as

feat/FOO-123: commit short description

Or, if you wish to add a full description of the undertaking,

feat/FOO-123: commit short description

Here we can have the full description of the task.
And it can also be on multiple lines.

We are going to work at the solution level; You don’t even need an IDE: just notepad and terminal are fine. Before proceeding, open your solutions folder and a terminal pointing to that folder.

Install NPM in your folder

Yes, even if the main app is built with .NET, we’ll need some NPM packages to set up our conventional commits.

First thing: go to the command line and run

After specifying some configurations (package name? license? author?), you will have a brand new one package.json file.

Now we can go ahead and add GIT Hook.

Husky: Integrate GIT Hooks to improve commit messages

To use conventional commits we need to “intercept” our GIT operations: we will have to run a specific tool immediately after writing a commit message; We must verify it, and in case it does not comply with the rules we have established, cancel the operations.

we will use Husky 🔗: This is a package of facilities that allows us do things With our commit messages and in general, integrate work with Git Hooks.

Head to the terminal, and Install Husky by running

npm install husky --save-dev

This command will add a dependency to Husky, as you can see from the new item listed in package.json file:

"devDependencies": {
    "husky": "^8.0.3"
}

Finally, L Enable Git Hookswe have to run

npm pkg set scripts.prepare="husky install"

and notice the new section in package.json.

"scripts": {
    "prepare": "husky install"
},

Even with these simple steps, we can see a first result: if you run git commit You will see a text editor open. Here you can write your commitment message.


Git commit message editor

Save and close the file. The commit message has been applied, as seen in the session git log --oneline.

CommitLint: A package for verifying Commit messages

We need to install and configure CommitLint, the NPM package that does the dirty work.

In the same terminal as before, run

npm install --save-dev @commitlint/config-conventional @commitlint/cli

install both commitlint/config-conventionalwhich add the generic functions, and commitlint/cliwhich allows us to run the scripts using the CLI.

You’ll see both packages listed in your package.json file:

"devDependencies": {
    "@commitlint/cli": "^17.4.2",
    "@commitlint/config-conventional": "^17.4.2",
    "husky": "^8.0.3"
}

Next step: the scaffolding file that handles the configuration of how we want our commit messages to be structured.

on the root, create a brand new file, commitlint.config.js, And paste this section:

module.exports = {
    extends: ['@commitlint/config-conventional']
};

This section tells Commitlint to use the default conventions, such as feat(api): send email.

To test the default rules without issuing any real commits, we need to install the previous packages globally so that they can be accessed outside the scope of the git hooks:

npm install -g @commitlint/cli @commitlint/config-conventional

And on the console, we can run

echo 'foo: a message with wrong format' | commitlint

and see the error messages


Check commitment with errors

At this point, we don’t have CommitLint ready to validate our commit messages yet. In fact, if you try to make your changes to an invalid message, you’ll see that the message passes the checks (because there No tests!), and your changes will be made.

We need to take a few more steps.

First of all, we must Create a folder named .husky to be used by Husky to understand which commands are supported.

Please note: you must keep the dot at the beginning of the folder name: this .hoarseNo hoarse.

So we need to add a new file inside this folder Tell Husky that it needs to run CommitLint.

npx husky add .husky/commit-msg  'npx --no -- commitlint --edit ${1}'

We are almost ready: everything is ready, but we need to activate the functionality. So you just have to run

To see it working:


CommitLint correctly validates the commit message

Commitlint.config.js: Define explicit rules in Git messages

Now, remember that we want to enforce certain rules on the commit message.

We don’t want them to be like

feat(api): send an email to the customer when a product is shipped

but like

feat/FOO-123: commit short description

Here we can have the full description of the task.
And it can also be on multiple lines.

This means we have to define the commitlint.config.js file to override default values.

Let’s look at a valid commitlint file:

module.exports = {
  extends: ["./node_modules/@commitlint/config-conventional"],
  parserPreset: {
    parserOpts: {
            headerPattern: /^(w*)/FOO-(w*): (.*)$/,
            headerCorrespondence: ["type", "scope", "subject"],
        },
    },
    rules: {
        "type-enum": [2, "always", ["feat", "fix", "hot", "chore"]],
        "header-min-length": [2, "always", 10],
        "header-max-length": [2, "always", 50],
        "body-max-line-length": [2, "always", 72],
        "subject-case": [
        2,
        "never",
        ["sentence-case", "start-case", "pascal-case", "upper-case"],
        ],
    },
};

It’s time to dive deep into these sections:

ParserOpts section: Define how CommitList should parse text

The first part tells the parser how to parse the header message:

parserOpts: {
    headerPattern: /^(w*)/FOO-(w*): (.*)$/,
    headerCorrespondence: ["type", "scope", "subject"],
},

It is a regular expression, where each matching part has its correspondence in headerCorrespondence array:

So in the message Hello/FOO-123: My little messageWe will have type=Hello, scope=123, subject=My little message.

Rules: Set specific rules for each message section

God rules The section defines the rules to be applied to each part of the message structure.

rules: 
{
    "type-enum": [2, "always", ["feat", "fix", "hot", "chore"]],
    "header-min-length": [2, "always", 10],
    "header-max-length": [2, "always", 50],
    "body-max-line-length": [2, "always", 72],
    "subject-case": [
        2,
        "never",
        ["sentence-case", "start-case", "pascal-case", "upper-case"],
    ],
},

The first value is a number expressing the severity of the rule:

  • 0: the rule is disabled;
  • 1: show warning;
  • 2: This is an error.

The second value defines whether the rule should be applied (via Always), or if it should be reversed (using Never).

The third entry provides general arguments for the associated rule. for example, "header-max-length": [2, "always", 50], says that the title must always be of length with <= 50 characters.

You can read more about each and every configuration at The official documentation 🔗.

Setting the commit structure using .gitmessage

Now that everything is set up, we can test it.

But not before helping the developers with a simple trick! As you remember, when you run git commit Without specifying the message, an editor appears with some hints about the structure of the commit message.


Default commit editor

You can define your own text with hints about the message structure.

You just need to create a file called .gitmessage and put some text in it, such as:

# <type>/FOO-<jira-ticket-id>: <title>
# YOU CAN WRITE WHATEVER YOU WANT HERE
# allowed types: feat | fix | hot | chore
# Example:
#
# feat/FOO-01: first commit
#
# No more than 50 chars. #### 50 chars is here:  #

# Remember blank line between title and body.

# Body: Explain *what* and *why* (not *how*)
# Wrap at 72 chars. ################################## which is here:  #
#

Now, we need to tell Git to use this file as a template:

git config commit.template ./.gitmessage

And.. TA-DA! Here is your message template!


Custom message template

Put everything together

Finally, we have everything in place: git hooks, commit template and template hints.

if we run git commit, we will see IDE open and the message we defined previously. Now, type Message with wrong formatSave, close the editor, and you’ll see the commit undone.


A badly formatted commit message is rejected

now you run git commit Again, look at the IDE again and type feat/FOO-123: Legal noticeAnd see if it works

Additional readings

Conventional Commits is a project that specifies a set of specifications for writing such good commits. You can read more here:

🔗 Conventional undertakers

As we saw earlier, there are many configurations you can set for your commits. You can see the full list here:

🔗 CommitLint rules

This article first appeared on Code4IT 🐧

This new type of commit message works well with semantic versioning, which can be useful for releasing package versions with a significant version number, such as 2.0.1:
🔗 Semantic version

And to close the loop, semantic versions can be easily combined with CI pipelines. If you use .NET APIs and want to deploy your APIs to Azure using GitHub Actions, you can start from this article and add SemVer: 🔗 How to deploy .NET APIs to Azure using GitHub Actions

finishing

In this article, we learned what conventional commits are, how to add them using Husky and NPM, and how to configure our folder to use such tools.

The steps we’ve seen before work for any kind of application, not even dotnet related.

So, to sum it all up, we must:

  1. Install NPM: npm init;
  2. Install Husky: npm install husky --save-dev;
  3. Enable husky: npm pkg set scripts.prepare="husky install";
  4. Install CommitLint: npm install --save-dev @commitlint/config-conventional @commitlint/cli;
  5. Create the commitlint.config.js file: module.exports = { extends: '@commitlint/config-conventional']};;
  6. Create the husky folder: mkdir .husky;
  7. Link between Husky and CommitLint: npx husky add .husky/commit-msg 'npx --no -- commitlint --edit ${1}';
  8. Enable all functionality: npx husky install;

After that, you can customize the commitlint.config.js file and, if you want, create a better .gitmessage file.

I hope you enjoyed this article! Let’s keep in touch Twitter or on LinkedIn, If you want! 🤜🤛

Happy coding!

🐧

.

Source

Popular Articles