diff --git a/Tools/Tools.sln b/Tools/Tools.sln
index 3b02c0c..f1c721e 100644
--- a/Tools/Tools.sln
+++ b/Tools/Tools.sln
@@ -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
@@ -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
diff --git a/Tools/src/JiraReporting/JiraReporting.csproj b/Tools/src/JiraReporting/JiraReporting.csproj
new file mode 100644
index 0000000..40d2c0c
--- /dev/null
+++ b/Tools/src/JiraReporting/JiraReporting.csproj
@@ -0,0 +1,18 @@
+
+
+
+ Exe
+ net5.0
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tools/src/JiraReporting/Model/Assignee.cs b/Tools/src/JiraReporting/Model/Assignee.cs
new file mode 100644
index 0000000..e4e1ffe
--- /dev/null
+++ b/Tools/src/JiraReporting/Model/Assignee.cs
@@ -0,0 +1,7 @@
+namespace JiraReport
+{
+ public class Assignee
+ {
+ public string DisplayName { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Tools/src/JiraReporting/Model/Field.cs b/Tools/src/JiraReporting/Model/Field.cs
new file mode 100644
index 0000000..4e7ef5f
--- /dev/null
+++ b/Tools/src/JiraReporting/Model/Field.cs
@@ -0,0 +1,6 @@
+namespace JiraReport
+{
+ public class Field
+ {
+ }
+}
\ No newline at end of file
diff --git a/Tools/src/JiraReporting/Model/Fields.cs b/Tools/src/JiraReporting/Model/Fields.cs
new file mode 100644
index 0000000..8e7c64e
--- /dev/null
+++ b/Tools/src/JiraReporting/Model/Fields.cs
@@ -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 Sprints { get; set; }
+
+ [JsonPropertyName("customfield_10281")]
+ public Points Points { get; set; }
+
+ }
+}
\ No newline at end of file
diff --git a/Tools/src/JiraReporting/Model/Issue.cs b/Tools/src/JiraReporting/Model/Issue.cs
new file mode 100644
index 0000000..ea3c94e
--- /dev/null
+++ b/Tools/src/JiraReporting/Model/Issue.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+
+namespace JiraReport
+{
+ public class Issue
+ {
+ public Fields Fields { get; set; }
+ public string Key { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Tools/src/JiraReporting/Model/IssueType.cs b/Tools/src/JiraReporting/Model/IssueType.cs
new file mode 100644
index 0000000..f57fa41
--- /dev/null
+++ b/Tools/src/JiraReporting/Model/IssueType.cs
@@ -0,0 +1,7 @@
+namespace JiraReport
+{
+ public class IssueType
+ {
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Tools/src/JiraReporting/Model/JqlQueryResult.cs b/Tools/src/JiraReporting/Model/JqlQueryResult.cs
new file mode 100644
index 0000000..a08d546
--- /dev/null
+++ b/Tools/src/JiraReporting/Model/JqlQueryResult.cs
@@ -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 Issues { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Tools/src/JiraReporting/Model/Parent.cs b/Tools/src/JiraReporting/Model/Parent.cs
new file mode 100644
index 0000000..444baba
--- /dev/null
+++ b/Tools/src/JiraReporting/Model/Parent.cs
@@ -0,0 +1,7 @@
+namespace JiraReport
+{
+ public class Parent
+ {
+ public Fields Fields { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Tools/src/JiraReporting/Model/Points.cs b/Tools/src/JiraReporting/Model/Points.cs
new file mode 100644
index 0000000..f8d078c
--- /dev/null
+++ b/Tools/src/JiraReporting/Model/Points.cs
@@ -0,0 +1,7 @@
+namespace JiraReport
+{
+ public class Points
+ {
+ public string Value { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Tools/src/JiraReporting/Model/Severity.cs b/Tools/src/JiraReporting/Model/Severity.cs
new file mode 100644
index 0000000..d322221
--- /dev/null
+++ b/Tools/src/JiraReporting/Model/Severity.cs
@@ -0,0 +1,7 @@
+namespace JiraReport
+{
+ public class Severity
+ {
+ public string Value { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Tools/src/JiraReporting/Model/Sprint.cs b/Tools/src/JiraReporting/Model/Sprint.cs
new file mode 100644
index 0000000..6f3cf54
--- /dev/null
+++ b/Tools/src/JiraReporting/Model/Sprint.cs
@@ -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; }
+ }
+}
\ No newline at end of file
diff --git a/Tools/src/JiraReporting/Model/Status.cs b/Tools/src/JiraReporting/Model/Status.cs
new file mode 100644
index 0000000..db62d3a
--- /dev/null
+++ b/Tools/src/JiraReporting/Model/Status.cs
@@ -0,0 +1,7 @@
+namespace JiraReport
+{
+ public class Status
+ {
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Tools/src/JiraReporting/Options.cs b/Tools/src/JiraReporting/Options.cs
new file mode 100644
index 0000000..8604f8f
--- /dev/null
+++ b/Tools/src/JiraReporting/Options.cs
@@ -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; }
+
+ }
+}
\ No newline at end of file
diff --git a/Tools/src/JiraReporting/Program.cs b/Tools/src/JiraReporting/Program.cs
new file mode 100644
index 0000000..fbc1f2b
--- /dev/null
+++ b/Tools/src/JiraReporting/Program.cs
@@ -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(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();
+
+ 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(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;
+ }
+ }
+}
diff --git a/Tools/src/JiraReporting/Report/BacklogReportRow.cs b/Tools/src/JiraReporting/Report/BacklogReportRow.cs
new file mode 100644
index 0000000..014bffd
--- /dev/null
+++ b/Tools/src/JiraReporting/Report/BacklogReportRow.cs
@@ -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; }
+
+ }
+}
\ No newline at end of file
diff --git a/Tools/src/JiraReporting/Report/Helper.cs b/Tools/src/JiraReporting/Report/Helper.cs
new file mode 100644
index 0000000..33240d5
--- /dev/null
+++ b/Tools/src/JiraReporting/Report/Helper.cs
@@ -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 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);
+
+ }
+ }
+ }
+}