Skip to content

Commit

Permalink
[Tools] Added JIRA Reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
leandromonaco committed Feb 4, 2022
1 parent ea3dbad commit ceb4d7c
Show file tree
Hide file tree
Showing 17 changed files with 323 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Tools/Tools.sln
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationConnectors.Commo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OctopusCertificateReferenceFinder", "src\OctopusCertificateReferenceFinder\OctopusCertificateReferenceFinder.csproj", "{41DB617A-081F-496E-9DDB-93948488FD21}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JiraReporting", "src\JiraReporting\JiraReporting.csproj", "{EB5D47D5-6702-4EC0-A1E3-CD48A16C1ECE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -41,6 +43,10 @@ Global
{41DB617A-081F-496E-9DDB-93948488FD21}.Debug|Any CPU.Build.0 = Debug|Any CPU
{41DB617A-081F-496E-9DDB-93948488FD21}.Release|Any CPU.ActiveCfg = Release|Any CPU
{41DB617A-081F-496E-9DDB-93948488FD21}.Release|Any CPU.Build.0 = Release|Any CPU
{EB5D47D5-6702-4EC0-A1E3-CD48A16C1ECE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB5D47D5-6702-4EC0-A1E3-CD48A16C1ECE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB5D47D5-6702-4EC0-A1E3-CD48A16C1ECE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB5D47D5-6702-4EC0-A1E3-CD48A16C1ECE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
18 changes: 18 additions & 0 deletions Tools/src/JiraReporting/JiraReporting.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Ardalis.GuardClauses" Version="4.0.0" />
<PackageReference Include="CommandLineParser" Version="2.8.0" />
<PackageReference Include="NPOI" Version="2.5.5" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\IntegrationConnectors\src\IntegrationConnectors.Common\IntegrationConnectors.Common.csproj" />
</ItemGroup>

</Project>
7 changes: 7 additions & 0 deletions Tools/src/JiraReporting/Model/Assignee.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace JiraReport
{
public class Assignee
{
public string DisplayName { get; set; }
}
}
6 changes: 6 additions & 0 deletions Tools/src/JiraReporting/Model/Field.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace JiraReport
{
public class Field
{
}
}
24 changes: 24 additions & 0 deletions Tools/src/JiraReporting/Model/Fields.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;

namespace JiraReport
{
public class Fields
{
public string Summary { get; set; }
public Parent Parent { get; set; }
public Status Status { get; set; }
public IssueType IssueType { get; set; }
public Assignee Assignee { get; set; }

[JsonPropertyName("customfield_10263")]
public Severity Severity { get; set; }

[JsonPropertyName("customfield_10018")]
public List<Sprint> Sprints { get; set; }

[JsonPropertyName("customfield_10281")]
public Points Points { get; set; }

}
}
10 changes: 10 additions & 0 deletions Tools/src/JiraReporting/Model/Issue.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Collections.Generic;

namespace JiraReport
{
public class Issue
{
public Fields Fields { get; set; }
public string Key { get; set; }
}
}
7 changes: 7 additions & 0 deletions Tools/src/JiraReporting/Model/IssueType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace JiraReport
{
public class IssueType
{
public string Name { get; set; }
}
}
12 changes: 12 additions & 0 deletions Tools/src/JiraReporting/Model/JqlQueryResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Collections.Generic;

namespace JiraReport
{
internal class JqlQueryResult
{
public int StartAt { get; set; }
public int MaxResults { get; set; }
public int Total { get; set; }
public List<Issue> Issues { get; set; }
}
}
7 changes: 7 additions & 0 deletions Tools/src/JiraReporting/Model/Parent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace JiraReport
{
public class Parent
{
public Fields Fields { get; set; }
}
}
7 changes: 7 additions & 0 deletions Tools/src/JiraReporting/Model/Points.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace JiraReport
{
public class Points
{
public string Value { get; set; }
}
}
7 changes: 7 additions & 0 deletions Tools/src/JiraReporting/Model/Severity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace JiraReport
{
public class Severity
{
public string Value { get; set; }
}
}
10 changes: 10 additions & 0 deletions Tools/src/JiraReporting/Model/Sprint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace JiraReport
{
public class Sprint
{
public string Name { get; set; }
public string State { get; set; }
public string StartDate { get; set; }
public string EndDate { get; set; }
}
}
7 changes: 7 additions & 0 deletions Tools/src/JiraReporting/Model/Status.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace JiraReport
{
public class Status
{
public string Name { get; set; }
}
}
23 changes: 23 additions & 0 deletions Tools/src/JiraReporting/Options.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using CommandLine;

namespace JiraReport
{
public class Options
{
[Option("JiraEndpoint", Required = true, HelpText = "JIRA Endpoint")]
public string JiraEndpoint { get; set; }

[Option("JiraProject", Required = true, HelpText = "JIRA Project")]
public string JiraProject { get; set; }

[Option("JiraUsername", Required = true, HelpText = "JIRA Username")]
public string JiraUsername { get; set; }

[Option("JiraAuthenticationToken", Required = true, HelpText = "JIRA Authentication Token")]
public string JiraAuthenticationToken { get; set; }

[Option("PowerBiDatasetEndpoint", Required = true, HelpText = "PowerBI Endpoint")]
public string PowerBiDatasetEndpoint { get; set; }

}
}
92 changes: 92 additions & 0 deletions Tools/src/JiraReporting/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using Ardalis.GuardClauses;
using CommandLine;
using IntegrationConnectors.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace JiraReport
{
class Program
{
static void Main(string[] args)
{
string jiraEndpoint = string.Empty;
string jiraProject = string.Empty;
string jiraUsername = string.Empty;
string jiraAuthenticationToken = string.Empty;
string powerBiDatasetEndpoint = string.Empty;

Parser.Default.ParseArguments<Options>(args)
.WithParsed(o =>
{
jiraEndpoint = Guard.Against.NullOrEmpty(o.JiraEndpoint, nameof(o.JiraEndpoint));
jiraProject = Guard.Against.NullOrEmpty(o.JiraProject, nameof(o.JiraProject));
jiraUsername = Guard.Against.NullOrEmpty(o.JiraUsername, nameof(o.JiraUsername));
jiraAuthenticationToken = Guard.Against.NullOrEmpty(o.JiraAuthenticationToken, nameof(o.JiraAuthenticationToken));
powerBiDatasetEndpoint = Guard.Against.NullOrEmpty(o.PowerBiDatasetEndpoint, nameof(o.PowerBiDatasetEndpoint));
});

var credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{jiraUsername}:{jiraAuthenticationToken}"));

HttpConnector httpConnector = new("", credentials, AuthenticationType.Basic);

var _jsonSerializerOptions = new JsonSerializerOptions()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNameCaseInsensitive = true,
MaxDepth = 0
};

var report = new List<BacklogReportRow>();

var increment = 100;
var startAt = 0;
var finishAt = 1;

while (startAt <= finishAt)
{
var query = $@"{{
""jql"": ""project={jiraProject}"",
""maxResults"": {increment},
""startAt"": {startAt}
}}";

var response = httpConnector.PostAsync($"{jiraEndpoint}/rest/api/2/search", query).Result;
var jqlQueryResult = JsonSerializer.Deserialize<JqlQueryResult>(response, _jsonSerializerOptions);

startAt += increment;
finishAt = jqlQueryResult.Total - 1;

foreach (var issue in jqlQueryResult.Issues)
{
var row = new BacklogReportRow
{
Date = DateTime.Now.Date,
JiraId = issue.Key,
Sprint = issue.Fields.Sprints?.OrderByDescending(s => s.StartDate).FirstOrDefault().Name,
JiraDescription = issue.Fields.Summary,
Epic = issue.Fields.Parent?.Fields.Summary,
IssueType = issue.Fields.IssueType.Name,
Severity = issue.Fields.Severity?.Value,
Status = issue.Fields.Status.Name,
Points = issue.Fields.Points?.Value,
AssignedTo = issue.Fields.Assignee == null ? "Unassigned" : issue.Fields.Assignee.DisplayName
};

report.Add(row);
}
}

Helper.ExportExcel(report);

File.WriteAllText($"{Environment.CurrentDirectory}\\report_{DateTime.Now.Date.ToString("yyyy-MM-dd")}.json", JsonSerializer.Serialize(report));

var result = httpConnector.PostAsync(powerBiDatasetEndpoint, JsonSerializer.Serialize(report)).Result;
}
}
}
23 changes: 23 additions & 0 deletions Tools/src/JiraReporting/Report/BacklogReportRow.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;

namespace JiraReport
{
internal class BacklogReportRow
{
public BacklogReportRow()
{
}

public string Epic { get; internal set; }
public string IssueType { get; internal set; }
public string Sprint { get; internal set; }
public string Status { get; internal set; }
public string Points { get; internal set; }
public string AssignedTo { get; internal set; }
public DateTime Date { get; internal set; }
public string JiraId { get; internal set; }
public string JiraDescription { get; internal set; }
public string Severity { get; internal set; }

}
}
57 changes: 57 additions & 0 deletions Tools/src/JiraReporting/Report/Helper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.IO;

namespace JiraReport
{
class Helper
{

public static void ExportExcel(List<BacklogReportRow> backlogReportRows)
{
var outputFile = Path.Combine(Directory.GetCurrentDirectory(), "JiraData.xlsx");
using (var fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write))
{
IWorkbook workbook;
workbook = new XSSFWorkbook();
ISheet excelSheet = workbook.CreateSheet("Variables");

IRow row = excelSheet.CreateRow(0);
row.CreateCell(0).SetCellValue("Date");
row.CreateCell(1).SetCellValue("Epic");
row.CreateCell(2).SetCellValue("JIRA ID");
row.CreateCell(3).SetCellValue("Description");
row.CreateCell(4).SetCellValue("IssueType");
row.CreateCell(5).SetCellValue("Severity");
row.CreateCell(6).SetCellValue("Status");
row.CreateCell(7).SetCellValue("Sprint");
row.CreateCell(8).SetCellValue("Points");
row.CreateCell(9).SetCellValue("Assigned To");

var rowCount = 1;


foreach (var backlogReportRow in backlogReportRows)
{
row = excelSheet.CreateRow(rowCount);
row.CreateCell(0).SetCellValue(backlogReportRow.Date);
row.CreateCell(1).SetCellValue(backlogReportRow.Epic);
row.CreateCell(2).SetCellValue(backlogReportRow.JiraId);
row.CreateCell(3).SetCellValue(backlogReportRow.JiraDescription);
row.CreateCell(4).SetCellValue(backlogReportRow.IssueType);
row.CreateCell(5).SetCellValue(backlogReportRow.Severity);
row.CreateCell(6).SetCellValue(backlogReportRow.Status);
row.CreateCell(7).SetCellValue(backlogReportRow.Sprint);
row.CreateCell(8).SetCellValue(Convert.ToDouble(backlogReportRow.Points));
row.CreateCell(9).SetCellValue(backlogReportRow.AssignedTo);
rowCount++;
}

workbook.Write(fs);

}
}
}
}

0 comments on commit ceb4d7c

Please sign in to comment.