Files
linqpad/SonarQube API/SonarQube WebService API.linq
T

1071 lines
30 KiB
C#

<Query Kind="Program">
<NuGetReference>Newtonsoft.Json</NuGetReference>
<NuGetReference>RestSharp</NuGetReference>
<Namespace>RestSharp</Namespace>
<Namespace>Newtonsoft.Json</Namespace>
<Namespace>Newtonsoft.Json.Linq</Namespace>
<Namespace>RestSharp.Authenticators</Namespace>
<Namespace>Newtonsoft.Json.Converters</Namespace>
<Namespace>System.Dynamic</Namespace>
<Namespace>System</Namespace>
<Namespace>System.Linq.Dynamic</Namespace>
<Namespace>System.Web</Namespace>
</Query>
private string BaseUrl = "https://sonarqube.sdt.local";
private Dictionary<string, string> ruleDictionary;
//private DateTime BeginningOfTheYear = new DateTime(DateTime.Now.Year, 1, 1);
private static DateTime CreatedBefore = new DateTime(2020, 8, 13);
private static DateTime StartOfSprint = CreatedBefore.AddDays(1);
private static DateTime EndOfSprint = CreatedBefore.AddDays(15);
private Dictionary<string, string> Parameters = new Dictionary<string, string>
{
{ "projects", ""},
// {"types","BUG,VULNERABILITY,SECURITY_HOTSPOT"},
// {"severities","BLOCKER,CRITICAL,MAJOR"},
// {"statuses", "OPEN,CONFIRMED,REOPENED,TO_REVIEW,IN_REVIEW"},
{"resolutions", "FIXED"},
{"s", "CLOSE_DATE"},
{"languages", null},
{"createdBefore", $"{CreatedBefore:yyyy-MM-dd}"},
//{"createdAfter", null}, // $"{BeginningOfTheYear:yyyy-MM-dd}"
{"assignees", null}
};
#region Enumerations
public string GetName(Type enumType, int value)
{
return Enum.GetName(enumType, value);
}
public enum SonarType
{
BUG,
VULNERABILITY,
CODE_SMELL,
SECURITY_HOTSPOT
}
public enum SonarSeverity
{
BLOCKER,
CRITICAL,
MAJOR,
MINOR,
INFO
}
public enum QubooSeverity
{
BLOCKER = 10,
CRITICAL = 7,
MAJOR = 5,
MINOR = 2,
INFO = 1
}
public enum SonarResolution
{
UNRESOLVED,
FIXED,
WONTFIX,
FALSE_POSITIVE,
REMOVED
}
public enum SonarStatus
{
OPEN,
TO_REVIEW,
IN_REVIEW,
REVIEWED,
REOPENED,
CONFIRMED,
RESOLVED,
CLOSED
}
#endregion
public Dictionary<string, List<string>> GroupUsers = new Dictionary<string, System.Collections.Generic.List<string>>();
void Main()
{
RestClient client = new RestClient();
// var projects = ListProjects(client);
// projects.Dump();
// return;
new { CreatedBefore, StartOfSprint, EndOfSprint}.Dump("Campaign");
PopulateUserGroups();
var value = GetName(typeof(SonarType), (int)SonarType.BUG);
//GetJson(client, "/api/languages/list").Dump();
//ListWebServices(client).Dump("List WebServices");
var rules = GetRules(client)
.OrderBy(l => l.repo).ThenBy(l => l.key);
ruleDictionary = rules
.ToDictionary(r => r.key, r => $"{r.name} ({r.severity})");
var parameters = new List<Parameter> {
new RestSharp.Parameter("additionalFields","_all", ParameterType.QueryString)
};
parameters.AddRange(Parameters.Where(p => !string.IsNullOrEmpty(p.Value))
.Select(p => new RestSharp.Parameter(p.Key, p.Value, ParameterType.QueryString)));
var issues = GetIssues(client, parameters)
.Where(i => i.closeDate >= StartOfSprint && i.closeDate <= EndOfSprint)
// .Where(i => i.closeDate >= CreatedBefore.AddDays(-14) && i.closeDate <= CreatedBefore)
;
if (1 == 0)
{
if (parameters.Select(p => p.Name).Contains("projects"))
{
$"{parameters.First(p => p.Name == "projects").Value} ({issues.Count()} Issues)".Dump();
}
else
{
$"{issues.Count()} Issues".Dump();
}
}
issues
.Where(i => i.assignee != null)
.Select(i => new
{
i.severity,
i.project,
i.type,
i.status,
i.resolution,
i.assignee,
team = GetUserGroup(i.assignee),
i.debt,
i.effort,
i.closeDate,
score = Score(i.severity, i.debt)
})
//.GroupBy(i => new {i.assignee, i.severity, i.type}, (g,d) => d)
.OrderBy(i => i.team)
.ThenBy(i => i.project)
.ThenBy(i => i.assignee)
.ThenBy(i => i.severity)
.ThenBy(i => i.type)
.Dump();
//issues.Take(10).Dump("Dump 10 issues");
//ReportIssues(issues);
}
public int Score(string severity, string debt, int items = 1)
{
if (debt == null || severity == null) return 0;
var qSeverity = (QubooSeverity)Enum.Parse(typeof(QubooSeverity), severity);
var iDebt = int.Parse(Regex.Replace(debt, @"[^\d]", ""));
return Score(qSeverity, iDebt, items);
}
public int Score(QubooSeverity severity, int debt, int items = 1)
{
//$"Math.Max(1, {debt} / 10 * {(int)severity}) * {items} items".Dump();
return Math.Max(1, debt / 10 * (int)severity) * items;
}
void ReportIssues(IEnumerable<Issue> issues)
{
var byTeam = issues
.OrderBy(i => GetUserGroup(i.assignee ?? i.author ?? ""))
.ThenBy(i => i.component)
.ThenBy(i => i.type)
.ThenBy(i => i.severity)
.Select(i => new
{
assignee = GetUserGroup(i.assignee ?? i.author ?? "Not assigned"),
i.component,
i.message,
i.type,
i.status,
i.severity,
i.effort,
i.creationDate,
i.closeDate,
lineNumber = i.line,
i.taglist
})
.GroupBy(i => i.assignee, (g, d) => new TeamGrouper(
g,
d.GroupBy(dd => new { type = Path.GetExtension(dd.component), dd.component }, (gg, gd) =>
new ComponentGrouper(
gg.type,
gg.component,
gd.GroupBy(yy => new
{
yy.creationDate.Year,
yy.creationDate.Month,
yy.type,
yy.status,
yy.severity
}, (gdk, gdd) =>
new SummaryGrouper(
gdk.Year,
gdk.Month,
gdk.status,
gdk.type,
gdk.severity,
gdd.Count()
)).OrderByDescending(yy => yy.Year)
.ThenByDescending(yy => yy.Month)
))
.GroupBy(dd => dd.Solution, (xg, xd) => new SolutionGrouper
(
xg,
xd.GroupBy(y => y.Project, (yg, yd) => new ProjectGrouper
(
yg,
yd.OrderBy(x => x.Path).ThenBy(x => x.FileName)
)).OrderBy(x => x.Project)
))
.OrderBy(dd => dd.Solution)
))
.OrderBy(i => i.Team).ToList();
byTeam.ForEach(team =>
{
team.Solutions.ForEach(solution =>
{
solution.Solution.Dump().DumpX(team.Team); ;
solution.Projects.Dump(10).DumpX(team.Team);
});
});
}
#region User Group Definition
public void PopulateUserGroups()
{
GroupUsers.Add("Architecture", new List<string> { });
GroupUsers.Add("The A-Team", new List<string> { "tlamb", "tdebolt" });
GroupUsers.Add("Ryan King", new List<string> { "rreimer", "jpollard", "chelm", "aschey" });
GroupUsers.Add("Cube Killers", new List<string> { "yrhee", "dforero", "lbehmer" });
GroupUsers.Add("Kobra Kaizer", new List<string> { "mschmidt", "nbuckle", "fsweis", "jmorales" });
GroupUsers.Add("Team Sloth", new List<string> { "myoung", "bkrehl", "nnawale", "lrenadesouza", "nleroy" });
GroupUsers.Add("Team Thanos", new List<string> { "bwells", "zbruin", "zhare", "mwynne", "mdeboer", "jnarofsky" });
GroupUsers.Add("Platform", new List<string> { "mleitch", "awolek", "jrapp", "cbello", "jchau", "hgutta", "ljian" });
GroupUsers.Add("Boo", new List<string> { "kferchuk", "akuten", "hvladyka", "vfay" });
GroupUsers.Add("Jedi", new List<string> { "akost", "sdominska", "tparashchak", "opalamar" });
GroupUsers.Add("Pokemon", new List<string> { "okrainyk", "mstepanov", "yantoniuk" });
GroupUsers.Add("Tropic Thunder", new List<string> { "ainzhyievskyi", "ihalenok", "dpanteliuk", "akorchynskyi" });
GroupUsers.Add("Bee Swarmers", new List<string> { "tscanlan", "cburke", "sxie" });
GroupUsers.Add("The Moustache", new List<string> { "wrusinko" });
}
public string GetUserGroup(string user)
{
var group = GroupUsers.Where(gu => gu.Value.Contains(user)).FirstOrDefault();
return group.Key ?? $"unknown {user}";
}
#endregion
#region Issues Report
public class SolutionGrouper
{
public string Solution { get; set; }
public List<ProjectGrouper> Projects { get; set; }
public SolutionGrouper(string solution, IOrderedEnumerable<ProjectGrouper> projects)
{
Solution = solution;
Projects = projects.ToList();
}
}
public class ProjectGrouper
{
public string Project { get; set; }
public IOrderedEnumerable<ComponentGrouper> Issues { get; set; }
public ProjectGrouper(string project, IOrderedEnumerable<ComponentGrouper> issues)
{
Project = project;
Issues = issues;
}
}
public class TeamGrouper
{
public string Team { get; set; }
public List<SolutionGrouper> Solutions { get; set; }
public TeamGrouper(string team, IOrderedEnumerable<SolutionGrouper> solutions)
{
Team = team;
Solutions = solutions.ToList();
}
}
public class ComponentGrouper
{
public string Solution { get; set; }
public List<SummaryGrouper> Issues { get; set; }
public string Component { get; set; }
public string Path { get; set; }
public string Project { get; set; }
public string FileName { get; set; }
public string Extension { get; set; }
public string Url { get; set; }
public ComponentGrouper()
{
}
public ComponentGrouper(string type, string component, IOrderedEnumerable<SummaryGrouper> issues)
{
Component = component.Split(new[] { ':' }).Last().Replace('/', '\\');
Solution = component.Split(new[] { ':' }).First();
Extension = type.TrimStart(new[] { '.' });
var filePath = $@"D:\{Component}";
Path = System.IO.Path.GetDirectoryName(filePath);
var pathParts = Path.Split(System.IO.Path.DirectorySeparatorChar);
//pathParts.Dump();
if (new[] { "Code", "Internal Tools", "src" }.Contains(pathParts[1]))
{
Project = pathParts.Skip(2).First();
Path = string.Join($"{System.IO.Path.DirectorySeparatorChar}", pathParts.Skip(2));
}
else
{
Project = pathParts.Skip(1).First();
Path = string.Join($"{System.IO.Path.DirectorySeparatorChar}", pathParts.Skip(1));
}
FileName = System.IO.Path.GetFileName(filePath);
Issues = issues.ToList();
Url = HttpUtility.HtmlEncode($@"{component}");
}
object ToDump() => new
{
Issues,
Path,
FileName = new Hyperlinq($@"https://sonarqube.sdt.local/code?id={Url}", FileName)
};
}
public class SummaryGrouper
{
public int Year { get; set; }
public int Month { get; set; }
public string Status { get; set; }
public string Type { get; set; }
public string Severity { get; set; }
public int Items { get; set; }
public SummaryGrouper()
{
}
public SummaryGrouper(int year, int month, string status, string type, string severity, int count)
{
Year = year;
Month = month;
Status = status;
Type = type;
Severity = severity;
Items = count;
}
object ToDump() => new
{
Date = $"{(new DateTime(Year, Month, 1)):yyyy/MM}",
Status,
Type,
Severity,
Count = $"{Items}"
};
}
#endregion
public void WriteReport(List<Issue> issues)
{
var reports = issues
.GroupBy(sdm => new
{
author = sdm.author ?? sdm.assignee ?? "",
project = sdm.project,
componentKey = sdm.componentKey,
status = sdm.status ?? "",
severity = sdm.severity ?? "",
resolution = sdm.resolution ?? "",
type = sdm.type,
rule = sdm.rule
}, (g, d) => new IssueReport
{
group = new IssueGroup
{
author = g.author,
project = g.project,
componentKey = g.componentKey,
status = g.status,
severity = g.severity,
resolution = g.resolution,
type = g.type,
rule = g.rule,
issues = d.Count()
},
issues = d.Select(issue => (IssueReportIssue)issue).ToList()
})
.OrderBy(r => r.group.author)
.ThenBy(r => r.group.project)
.ToList();
reports.ForEach(report =>
{
//"".PadLeft(40, '―').Dump();
// report.group.Dump();
var issueList = report.issues
.GroupBy(i => new { i.message, i.debt, i.effort, i.fileType, i.assignee, i.comment }, (g, d) => new
{
g.message,
debt = g.debt * d.Count(),
effort = g.effort * d.Count(),
g.fileType,
g.assignee,
g.comment,
createdAt = $"{d.Min(i => i.createdAt):d}",
closedAt = $"{d.Max(i => i.closedAt):d}",
daysToClose = (int)d.Max(i => i.closedAt).Subtract(d.Min(i => i.createdAt)).TotalDays,
occurred = d.Count()
});
new
{
report.group,
issueList
}.Dump();
// if (issueList.Count() > 1000)
// {
// issueList
// .Select((issue, index) => new { issue, index })
// .GroupBy(x => x.index / 1000, (key, y) => y.Select(z => z.issue))
// .Dump();
// }
// else
// {
// issueList.Dump();
// }
});
}
public void SummarizeIssues(RestClient client)
{
var types = new[] { "VULNERABILITY", "BUG", "CODE_SMELL" };
var severities = new[] { "BLOCKER", "CRITICAL", "MAJOR" };
var issues = GetIssues(client);
var CiStarterSet = issues
.Where(i => i.status != "CLOSED"
&& new[] { "BLOCKER", "CRITICAL", "MAJOR" }.Contains(i.severity)
);
CiStarterSet
.OrderBy(i => i.rule == "csharpsquid:S3776" ? 99
: i.severity == "MAJOR" ? 2
: i.severity == "BLOCKER" ? 0
: i.severity == "CRITICAL" ? 1 : 99)
.GroupBy(i => i.component
, (g, d) => new
{
key = g,
critical = d.Count(x => x.severity == "CRITICAL"),
ageInYears = (int)(d.Min(x => DateTime.Now.Subtract(x.creationDate).TotalDays) / 365),
team = ""
})
.OrderByDescending(i => i.ageInYears)
.ThenBy(i => i.critical)
.ThenBy(i => i.key)
//.ThenBy(i => i.key)
.Dump();
}
JObject GetVersion(RestClient client)
{
return GetJson(client, "/api/server/system");
}
#region Rule Management
List<Rule> GetRules(RestClient client)
{
List<Rule> rules = new List<Rule>();
var pageNo = 1;
while (true)
{
var info = ListRules(client, pageNo);
if (info == null) break;
var deserialized = JsonConvert.DeserializeObject<RootObject>(JsonConvert.SerializeObject(info)).rules;
if (deserialized == null || !deserialized.Any()) break;
pageNo += 1;
var page = deserialized; //.Where(i => i.rule.StartsWith("csharpsquid:"));
if (!page.Any()) continue;
rules.AddRange(page);
}
return rules;
}
JObject ListRules(RestClient client, int page = 1, int pageSize = 500)
{
return GetJson(client, "/api/rules/search", new List<Parameter> {
new Parameter("ps", pageSize, ParameterType.QueryString),
new Parameter("p", page, ParameterType.QueryString)
});
}
public class Rule
{
public string key { get; set; }
public string repo { get; set; }
public string name { get; set; }
public DateTime createdAt { get; set; }
public string htmlDesc { get; set; }
public string mdDesc { get; set; }
public string severity { get; set; }
public bool isBlockerIssue => severity == "BLOCKER";
public bool isCriticalIssue => severity == "CRITICAL";
public bool isMajorIssue => severity == "MAJOR";
public string status { get; set; }
public string internalKey { get; set; }
public bool isTemplate { get; set; }
public List<object> tags { get; set; }
public List<object> sysTags { get; set; }
public string lang { get; set; }
public string langName { get; set; }
public List<object> @params { get; set; }
public string defaultDebtRemFnType { get; set; }
public string defaultDebtRemFnCoeff { get; set; }
public bool debtOverloaded { get; set; }
public string debtRemFnType { get; set; }
public string debtRemFnCoeff { get; set; }
public string defaultRemFnType { get; set; }
public string defaultRemFnGapMultiplier { get; set; }
public string remFnType { get; set; }
public string remFnGapMultiplier { get; set; }
public bool remFnOverloaded { get; set; }
public string scope { get; set; }
public bool isExternal { get; set; }
public string type { get; set; }
public bool isVulnerability => type == "VULNERABILITY";
public bool isBug => type == "BUG";
public bool isCodeSmell => type == "CODE_SMELL";
}
#endregion
#region User Management
JObject ListUsers(RestClient client)
{
return GetJson(client, "/api/users/search");
}
public void AddNewUsers(RestClient client)
{
var names = @"User Name Email First Name Last Name
sdt\ainzhyievskyi ainzhyievskyi@stratadecision.com Artur Inzhyievskyi
sdt\dpanteliuk dpanteliuk@stratadecision.com Dmytro Panteliuk
sdt\vivanov vivanov@stratadecision.com Vadym Ivanov
sdt\akorchynskyi akorchynskyi@stratadecision.com Andrii Korchynskyi
sdt\akost aksot@stratadecision.com Andrii Kost
sdt\tparashchak tparashchak@stratadecision.com Taras Parashchak
sdt\sdominska sdominska@stratadecision.com Svitlana Dominska
sdt\opalamar opalamar@stratadecision.com Oleksii Palamar
sdt\vfay vfay@stratadecision.com Vasyl Fay
sdt\kferchuk kferchuk@stratadecision.com Kostyantyn Ferchuk
sdt\hvladyka hvladyka@stratadecision.com Halyna Vladyka
sdt\ihalenok ihalenok@stratadecision.com Iryna Halenok
sdt\akuten akuten@stratadecision.com Andrii Kuten
sdt\yantoniuk yantoniuk@stratadecision.com Yurii Antoniuk
sdt\mstepanov mstepanov@stratadecision.com Mykhailo Stepanov"
.Replace("\r\n", "\r").Split('\r').Skip(1)
.Select(x => x.Split('\t')).ToList()
.ConvertAll(x => new NewUser
{
name = $"{x[2]} {x[3]}",
login = x[0].Replace(@"sdt\", ""),
password = "Password1",
email = x[1]
});
var users = ListUsers(client);
var logins = JsonConvert.DeserializeObject<RootObject>(JsonConvert.SerializeObject(users)).users;
names.Where(n => !logins.Select(l => l.login).Contains(n.login)).Dump();
names.Where(n => !logins.Select(l => l.login).Contains(n.login)).ToList()
.ForEach(n => CreateUser(client, n));
}
void CreateUser(RestClient client, NewUser user)
{
client.BaseUrl = new Uri(BaseUrl);
client.Authenticator = new HttpBasicAuthenticator("admin", "admin");
var request = new RestRequest();
request.Resource = "/api/users/create";
request.Method = Method.POST;
request.RequestFormat = DataFormat.Json;
request.AddParameter(new Parameter("login", user.login, ParameterType.QueryString));
request.AddParameter(new Parameter("password", user.password, ParameterType.QueryString));
request.AddParameter(new Parameter("password_confirmation", user.password, ParameterType.QueryString));
request.AddParameter(new Parameter("name", user.name, ParameterType.QueryString));
request.AddParameter(new Parameter("email", user.email, ParameterType.QueryString));
request.Dump();
var response = client.Execute(request);
response.Dump();
}
public class User
{
public string login { get; set; }
public string name { get; set; }
}
public class NewUser : User
{
public string email { get; set; }
public string password { get; set; }
}
#endregion
#region Web Services
public void DumpWebServices(RestClient client)
{
var services = JsonConvert.DeserializeObject<WebServices>(JsonConvert.SerializeObject(ListWebServices(client))).webServices;
services.Dump();
}
JObject ListWebServices(RestClient client)
{
return GetJson(client, "/api/webservices/list");
}
#endregion
#region Issue Management
List<Issue> GetIssues(RestClient client, List<Parameter> parameters = null)
{
List<Issue> issues = new List<Issue>();
var pageNo = 1;
while (true)
{
var info = ListIssues(client, pageNo, parameters);
if (info == null) break;
pageNo += 1;
var root = JsonConvert.DeserializeObject<RootObject>(JsonConvert.SerializeObject(info));
if (root.errors?.Any() ?? false)
{
root.errors.Dump();
break;
}
var deserialized = root.issues;
if (deserialized == null || !deserialized.Any()) break;
issues.AddRange(deserialized);
}
return issues;
}
JObject ListIssues(RestClient client, int page = 1, List<Parameter> parameters = null, int pageSize = 500)
{
var queryParameters = new List<Parameter> {
new Parameter("ps", pageSize, ParameterType.QueryString),
new Parameter("p", page, ParameterType.QueryString),
new Parameter("additionalFields", "comments", ParameterType.QueryString)
};
if (parameters?.Any() ?? false)
queryParameters.RemoveAll(qp => parameters.Select(p => p.Name).Contains(qp.Name));
if (parameters != null)
queryParameters.AddRange(parameters);
return GetJson(client, "/api/issues/search", queryParameters);
}
#endregion
#region Project Management
//List<Project> GetProjects(RestClient client, List<Parameter> parameters = null)
//{
// List<Project> issues = new List<Project>();
// var pageNo = 1;
// while (true)
// {
// var info = ListProjects(client, pageNo, parameters);
// if (info == null) break;
// pageNo += 1;
// var root = JsonConvert.DeserializeObject<RootObject>(JsonConvert.SerializeObject(info));
// if (root.errors?.Any() ?? false)
// {
// root.errors.Dump();
// break;
// }
// var deserialized = root.issues;
// if (deserialized == null || !deserialized.Any()) break;
// issues.AddRange(deserialized);
// }
// return issues;
//}
JObject ListProjects(RestClient client, int page = 1, List<Parameter> parameters = null, int pageSize = 500)
{
var queryParameters = new List<Parameter> {
new Parameter("ps", pageSize, ParameterType.QueryString),
new Parameter("p", page, ParameterType.QueryString)
};
if (parameters?.Any() ?? false)
queryParameters.RemoveAll(qp => parameters.Select(p => p.Name).Contains(qp.Name));
if (parameters != null)
queryParameters.AddRange(parameters);
return GetJson(client, "/api/projects/search", queryParameters);
}
#endregion
#region Data Classes
public class IssueComment
{
public string key { get; set; }
public string login { get; set; }
public string htmlText { get; set; }
public string markdown { get; set; }
public bool updatable { get; set; }
public DateTime createdAt { get; set; }
}
public class IssueGroup
{
public string project { get; set; }
public string componentKey { get; set; }
public string author { get; set; }
public string severity { get; set; }
public string status { get; set; }
public string type { get; set; }
public string resolution { get; set; }
public string rule { get; set; }
public int issues { get; set; }
public object ToDump() => new[] { this };
}
public class Issue
{
public string severity { get; set; }
public SonarSeverity severityId => (SonarSeverity)Enum.Parse(typeof(SonarSeverity), severity);
public bool isBlocker => severityId == SonarSeverity.BLOCKER;
public bool isCritical => severityId == SonarSeverity.CRITICAL;
public bool isMajor => severityId == SonarSeverity.MAJOR;
public bool isMinor => severityId == SonarSeverity.MINOR;
public bool isInfo => severityId == SonarSeverity.INFO;
public string status { get; set; }
public SonarStatus statusId => (SonarStatus)Enum.Parse(typeof(SonarStatus), status);
public bool isOpen => statusId == SonarStatus.OPEN;
public bool isClosed => statusId == SonarStatus.CLOSED;
public bool isReviewed => statusId == SonarStatus.REVIEWED;
public bool isResolved => statusId == SonarStatus.RESOLVED;
public bool isInReview => statusId == SonarStatus.TO_REVIEW;
public string type { get; set; }
public SonarType typeId => (SonarType)Enum.Parse(typeof(SonarType), type);
public bool isVulnerability => typeId == SonarType.VULNERABILITY;
public bool isSecurityHotspot => typeId == SonarType.SECURITY_HOTSPOT;
public bool isBug => typeId == SonarType.BUG;
public bool isCodeSmell => typeId == SonarType.CODE_SMELL;
public string resolution { get; set; }
public SonarResolution resolutionId => (SonarResolution)Enum.Parse(typeof(SonarResolution), resolution);
public bool wontfix => resolutionId == SonarResolution.WONTFIX;
public List<IssueComment> comments { get; set; }
public string message { get; set; }
public string key { get; set; }
public string rule { get; set; }
public string debt { get; set; }
public string project { get; set; }
public string component { get; set; }
internal string[] componentParts => component.Split('/');
public string componentKey => componentParts.Count() > 3 && componentParts[1] == "Strata.Jazz.Web" && componentParts[2] == "Areas"
? Regex.Replace(componentParts[3], "^Strata.", "")
: componentParts.Count() > 3 && componentParts[1] == "Strata.Jazz.Web" && componentParts[2] != "Areas"
? Regex.Replace(componentParts[2], "^Strata.", "")
: componentParts.Count() > 1
? Regex.Replace(componentParts[1], "^Strata.", "")
: component;
public string fileType => component.Substring(component.LastIndexOf('.') + 1);
public int line { get; set; }
public TextRange textRange { get; set; }
public List<Flow> flows { get; set; }
public string effort { get; set; }
public string assignee { get; set; }
public string author { get; set; }
// public string hash { get; set; }
public List<string> tags { get; set; }
public string taglist => string.Join(", ", tags);
public DateTime creationDate { get; set; }
public int ageInYears => (int)DateTime.Now.Subtract(creationDate).TotalDays / 365;
public DateTime updateDate { get; set; }
// public string organization { get; set; }
public bool fromHotspot { get; set; }
public DateTime? closeDate { get; set; }
// public string __invalid_name__effort { get; set; }
public static explicit operator UserQuery.IssueReportIssue(Issue issue)
{
var debt = issue.debt ?? "0";
var effort = issue.effort ?? "0";
var r1 = new Regex(@"[^\d]*");
var r2 = new Regex(@"[\d]*");
var debtInterval = 1;
switch (r2.Replace(debt, ""))
{
case "min": debtInterval = 1; break;
case "day": debtInterval = 60 * 24; break;
default: debtInterval = Int32.MaxValue; break;
}
var effortInterval = 1;
switch (r2.Replace(effort, ""))
{
case "min": effortInterval = 1; break;
case "day": effortInterval = 60 * 24; break;
default: effortInterval = Int32.MaxValue; break;
}
var i = new UserQuery.IssueReportIssue
{
message = issue.message,
debt = Convert.ToInt32(r1.Replace(debt, "")) * debtInterval,
effort = Convert.ToInt32(r1.Replace(effort, "")) * effortInterval,
fileType = issue.fileType,
assignee = issue.comments.FirstOrDefault()?.login ?? "",
comment = issue.comments.FirstOrDefault()?.markdown ?? "",
createdAt = issue.creationDate,
closedAt = issue.comments.FirstOrDefault()?.createdAt ?? issue.closeDate ?? DateTime.Now
};
return i;
}
}
public class IssueReportGroup
{
public string message { get; set; }
public int debt { get; set; }
public int effort { get; set; }
public string fileType { get; set; }
public string assignee { get; set; }
public string comment { get; set; }
}
public class IssueReportIssue : IssueReportGroup
{
public DateTime createdAt { get; set; }
public DateTime closedAt { get; set; }
public int daysToClose { get; set; }
public int occurred { get; set; }
}
public class IssueReport
{
public IssueGroup group;
public List<IssueReportIssue> issues;
}
#endregion
void Other(RestClient client)
{
var issues = GetJson(client, "/api/issues/search?assignees=tlamb&severities=BLOCKER,CRITICAL");
JsonConvert.DeserializeObject<RootObject>(JsonConvert.SerializeObject(issues)).issues
.GroupBy(i => new
{
i.rule,
i.project,
i.type
}, (g, d) => new
{
issue = new
{
type = g.type,
id = g.rule,
project = g.project,
severity = d.First().severity,
message = d.First().message,
issues = d.Count()
},
issues = d.Select(i => new
{
i.status,
i.component,
i.line,
i.message,
i.textRange,
i.effort,
i.debt,
i.key
})
})
.Dump();
}
// Define other methods and classes here
#region RestSharp Helpers
JObject GetJson(RestClient client, string something, List<Parameter> parameters = null)
{
client.BaseUrl = new Uri(BaseUrl);
RestRequest request = new RestRequest();
request.Resource = something;
request.Method = Method.GET;
if (parameters?.Any() ?? false)
request.Parameters.AddRange(parameters);
return JObject.Parse(client.Execute(request).Content);
}
dynamic GetList(RestClient client, string something)
{
client.BaseUrl = new Uri(BaseUrl + something);
RestRequest request = new RestRequest();
request.Method = Method.GET;
var converter = new ExpandoObjectConverter();
return JsonConvert.DeserializeObject<ExpandoObject>(client.Execute(request).Content, converter);
}
IEnumerable<T> GetList<T>(RestClient client, string something)
{
return Get<List<T>>(client, something);
}
T Get<T>(RestClient client, string something)
{
client.BaseUrl = new Uri(BaseUrl + something);
RestRequest request = new RestRequest();
request.Method = Method.GET;
return JsonConvert.DeserializeObject<T>(client.Execute(request).Content,
new JsonSerializerSettings
{
Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args)
{
args.ErrorContext.Error.Message.Dump();
args.ErrorContext.Handled = true;
}
});
}
#endregion
#region json2csharp
public class Paging
{
public int pageIndex { get; set; }
public int pageSize { get; set; }
public int total { get; set; }
}
public class TextRange
{
public int startLine { get; set; }
public int endLine { get; set; }
public int startOffset { get; set; }
public int endOffset { get; set; }
object ToDump() => startLine != endLine
? $"L{startLine}:{endLine},O{startOffset}:{endOffset}"
: $"L{startLine},O{startOffset}:{endOffset}";
}
public class FlowComponent
{
public string component { get; set; }
public TextRange textRange { get; set; }
public string msg { get; set; }
}
public class Flow
{
public List<FlowComponent> locations { get; set; }
}
public class SonarError
{
public string msg { get; set; }
}
public class Component
{
public string organization { get; set; }
public string key { get; set; }
public string uuid { get; set; }
public bool enabled { get; set; }
public string qualifier { get; set; }
public string name { get; set; }
public string longName { get; set; }
public string path { get; set; }
}
public class RootObject
{
public int total { get; set; }
public int p { get; set; }
public int ps { get; set; }
public UserQuery.Paging paging { get; set; }
public int effortTotal { get; set; }
public int debtTotal { get; set; }
// public int majorIssues => issues.Count(i => i.severity == "MAJOR");
// public int criticalIssues => issues.Count(i => i.severity == "CRITICAL");
public int vulnerabilityIssues => issues.Count(i => i.type == "VULNERABILITY");
public int bugIssues => issues.Count(i => i.type == "BUG");
public int codeSmells => issues.Count(i => i.type == "CODE_SMELL");
public List<SonarError> errors { get; set; }
public List<UserQuery.Issue> issues { get; set; }
public List<Component> components { get; set; }
public List<object> facets { get; set; }
public List<Rule> rules { get; set; }
public List<User> users { get; set; }
}
#endregion
#region WebServices
public class WSActionParam
{
public string key { get; set; }
public string description { get; set; }
public bool required { get; set; }
public bool @internal { get; set; }
public object exampleValue { get; set; }
public string defaultValue { get; set; }
public List<string> possibleValues { get; set; }
public string deprecatedKey { get; set; }
public string deprecatedKeySince { get; set; }
public int? maximumValue { get; set; }
public string since { get; set; }
public string deprecatedSince { get; set; }
public int? minimumLength { get; set; }
public int? maxValuesAllowed { get; set; }
public int? maximumLength { get; set; }
}
public class WSAction
{
public string key { get; set; }
public string description { get; set; }
public string since { get; set; }
public bool @internal { get; set; }
public bool post { get; set; }
public bool hasResponseExample { get; set; }
public List<object> changlog { get; set; }
public List<WSActionParam> Params { get; set; }
public string deprecatedSince { get; set; }
}
public class WebService
{
public string path { get; set; }
public string description { get; set; }
public List<WSAction> actions { get; set; }
public string since { get; set; }
}
public class WebServices
{
public List<WebService> webServices { get; set; }
}
#endregion