diff --git a/Src/AiCommitMessage/Services/GenerateCommitMessageService.cs b/Src/AiCommitMessage/Services/GenerateCommitMessageService.cs
index c47f389b..e49d0748 100644
--- a/Src/AiCommitMessage/Services/GenerateCommitMessageService.cs
+++ b/Src/AiCommitMessage/Services/GenerateCommitMessageService.cs
@@ -63,11 +63,19 @@ public string GenerateCommitMessage(GenerateCommitMessageOptions options)
if (provider == GitProvider.GitHub)
{
var issueNumber = BranchNameUtility.ExtractIssueNumber(options.Branch);
- if (!string.IsNullOrEmpty(issueNumber))
+ if (!string.IsNullOrWhiteSpace(issueNumber))
{
text = $"#{issueNumber} {text}";
}
}
+ else
+ {
+ var jiraTicketNumber = BranchNameUtility.ExtractJiraTicket(options.Branch);
+ if (!string.IsNullOrWhiteSpace(jiraTicketNumber))
+ {
+ text = $"[{jiraTicketNumber}] {text}";
+ }
+ }
if (!options.Debug)
{
diff --git a/Src/AiCommitMessage/Utility/BranchNameUtility.cs b/Src/AiCommitMessage/Utility/BranchNameUtility.cs
index 90837050..f14290f3 100644
--- a/Src/AiCommitMessage/Utility/BranchNameUtility.cs
+++ b/Src/AiCommitMessage/Utility/BranchNameUtility.cs
@@ -2,9 +2,20 @@
namespace AiCommitMessage.Utility;
+///
+/// Class BranchNameUtility.
+///
public static class BranchNameUtility
{
- private const string Pattern = @"(?:issue)?[-/]?(\d+)";
+ ///
+ /// The GitHub issue pattern.
+ ///
+ private const string GitHubIssuePattern = @"(?:issue)?[-/]?(\d+)";
+
+ ///
+ /// The Jira ticket pattern.
+ ///
+ private const string JiraTicketPattern = @"(?i)([A-Z]+)-?(\d+)";
///
/// Extracts the GitHub issue number from a branch name.
@@ -15,11 +26,35 @@ public static string ExtractIssueNumber(string branchName)
{
var match = Regex.Match(
branchName,
- Pattern,
+ GitHubIssuePattern,
RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase,
TimeSpan.FromSeconds(5)
);
return match.Success ? match.Groups[1].Value : string.Empty;
}
+
+ ///
+ /// Extracts the JIRA ticket number from a given branch name.
+ ///
+ /// The branch name to extract the JIRA ticket from.
+ /// The extracted JIRA ticket number in uppercase, or an empty string if not found.
+ public static string ExtractJiraTicket(string branchName)
+ {
+ var match = Regex.Match(
+ branchName,
+ JiraTicketPattern,
+ RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase,
+ TimeSpan.FromSeconds(5)
+ );
+
+ if (!match.Success)
+ {
+ return string.Empty;
+ }
+
+ var projectKey = match.Groups[1].Value.ToUpperInvariant();
+ var issueNumber = match.Groups[2].Value;
+ return $"{projectKey}-{issueNumber}";
+ }
}
diff --git a/Tests/AiCommitMessage.Tests/Utility/BranchNameUtilityTests.cs b/Tests/AiCommitMessage.Tests/Utility/BranchNameUtilityTests.cs
index dfa07065..3cc99a2d 100644
--- a/Tests/AiCommitMessage.Tests/Utility/BranchNameUtilityTests.cs
+++ b/Tests/AiCommitMessage.Tests/Utility/BranchNameUtilityTests.cs
@@ -37,4 +37,38 @@ public void ExtractIssueNumber_ShouldReturnEmptyString(string branchName)
// Assert
result.Should().BeEmpty();
}
+
+ [Theory]
+ [InlineData("feature/XPTO-1234-some-branch-name_with_description", "XPTO-1234")]
+ [InlineData("feature/XPTO1234-some-branch-name_with_description", "XPTO-1234")]
+ [InlineData("XPTO1234-some-branch-name_with_description", "XPTO-1234")]
+ [InlineData("XPTO-1234-some-branch-name_with_description", "XPTO-1234")]
+ [InlineData("bugfix/XPTO-1234--some-branch-name_with_description", "XPTO-1234")]
+ [InlineData("hotfix/xpto-1234-some-branch-name", "XPTO-1234")]
+ [InlineData("release/XPTO1234", "XPTO-1234")]
+ [InlineData("XPTO-1234", "XPTO-1234")]
+ [InlineData("xpto1234", "XPTO-1234")]
+ public void ExtractJiraTicket_ShouldReturnExpectedResult(
+ string branchName,
+ string expectedTicket
+ )
+ {
+ // Act
+ var result = BranchNameUtility.ExtractJiraTicket(branchName);
+
+ // Assert
+ result.Should().NotBeEmpty();
+ result.Should().Be(expectedTicket);
+ }
+
+ [Theory]
+ [InlineData("chore/no-ticket-branch")]
+ public void ExtractJiraTicket_ShouldReturnEmptyString(string branchName)
+ {
+ // Act
+ var result = BranchNameUtility.ExtractJiraTicket(branchName);
+
+ // Assert
+ result.Should().BeEmpty();
+ }
}