public BitBucketIssueTracker(IRepository gitRepository, BitBucketApi bitBucketApi, ILog log, GitReleaseNotesArguments arguments) { this.gitRepository = gitRepository; this.bitBucketApi = bitBucketApi; this.log = log; this.arguments = arguments; }
public GitHubIssueTracker(IRepository gitRepository, Func <IGitHubClient> gitHubClientFactory, ILog log, GitReleaseNotesArguments arguments) { this.gitRepository = gitRepository; this.log = log; this.arguments = arguments; this.gitHubClientFactory = gitHubClientFactory; }
public Dictionary <ReleaseInfo, List <string> > GetIssueNumbers(GitReleaseNotesArguments arguments, Dictionary <ReleaseInfo, List <Commit> > releases, Regex issueRegex) { var result = new Dictionary <ReleaseInfo, List <string> >(); foreach (var release in releases) { var issueNumbersToScan = new List <string>(); foreach (var commit in release.Value) { var matches = issueRegex.Matches(commit.Message).Cast <Match>(); foreach (var match in matches) { var issueNumber = match.Groups["issueNumber"].Value; if (arguments.Verbose) { Log.WriteLine("Found issues {0} in commit {1}", issueNumber, commit.Sha); } issueNumbersToScan.Add(issueNumber); } } result.Add(release.Key, issueNumbersToScan); } return(result); }
public SemanticReleaseNotes ScanCommitMessagesForReleaseNotes(GitReleaseNotesArguments arguments, Commit[] commitsToScan) { var repoParts = arguments.Repo.Split('/'); var organisation = repoParts[0]; var repository = repoParts[1]; var issueNumbersToScan = _issueNumberExtractor.GetIssueNumbers(arguments, commitsToScan, @"#(?<issueNumber>\d+)"); var since = commitsToScan.Select(c=>c.Author.When).Min(); var potentialIssues = _gitHubClient.Issue.GetForRepository(organisation, repository, new RepositoryIssueRequest { Filter = IssueFilter.All, Since = since, State = ItemState.Closed }).Result; var closedMentionedIssues = potentialIssues .Where(i => issueNumbersToScan.Contains(i.Number.ToString(CultureInfo.InvariantCulture))) .ToArray(); return new SemanticReleaseNotes(closedMentionedIssues.Select(i=> { var labels = i.Labels == null ? new string[0] : i.Labels.Select(l=>l.Name).ToArray(); return new ReleaseNoteItem(i.Title, string.Format("#{0}", i.Number), i.HtmlUrl, labels); })); }
public GitHubIssueTracker(IRepository gitRepository, Func<IGitHubClient> gitHubClientFactory, ILog log, GitReleaseNotesArguments arguments) { this.gitRepository = gitRepository; this.log = log; this.arguments = arguments; this.gitHubClientFactory = gitHubClientFactory; }
public Dictionary<ReleaseInfo, List<string>> GetIssueNumbers(GitReleaseNotesArguments arguments, Dictionary<ReleaseInfo, List<Commit>> releases, Regex issueRegex) { var result = new Dictionary<ReleaseInfo, List<string>>(); foreach (var release in releases) { var issueNumbersToScan = new List<string>(); foreach (var commit in release.Value) { var matches = issueRegex.Matches(commit.Message).Cast<Match>(); foreach (var match in matches) { var issueNumber = match.Groups["issueNumber"].Value; if (arguments.Verbose) Console.WriteLine("Found issues {0} in commit {1}", issueNumber, commit.Sha); issueNumbersToScan.Add(issueNumber); } } result.Add(release.Key, issueNumbersToScan); } return result; }
public IEnumerable<OnlineIssue> GetClosedIssues(GitReleaseNotesArguments arguments, DateTimeOffset? since) { string jql; if (since.HasValue) { var sinceFormatted = since.Value.ToString("yyyy-MM-d HH:mm"); jql = string.Format("{0} AND updated > '{1}'", arguments.Jql, sinceFormatted).Replace("\"", "\\\""); } else { jql = arguments.Jql; } var baseUrl = new Uri(arguments.JiraServer, UriKind.Absolute); var searchUri = new Uri(baseUrl, "/rest/api/latest/search"); var httpRequest = WebRequest.CreateHttp(searchUri); var usernameAndPass = string.Format("{0}:{1}", arguments.Username, arguments.Password); var token = Convert.ToBase64String(Encoding.UTF8.GetBytes(usernameAndPass)); httpRequest.Headers.Add("Authorization", string.Format("Basic {0}", token)); httpRequest.Method = "POST"; httpRequest.ContentType = "application/json"; using (var streamWriter = new StreamWriter(httpRequest.GetRequestStream())) { string json = "{\"jql\": \"" + jql + "\",\"startAt\": 0, \"maxResults\": 100, \"fields\": [\"summary\",\"issuetype\"]}"; streamWriter.Write(json); streamWriter.Flush(); streamWriter.Close(); } var response = (HttpWebResponse)httpRequest.GetResponse(); if ((int)response.StatusCode == 400) { throw new Exception("Jql query error, please review your Jql"); } if (response.StatusCode != HttpStatusCode.OK) throw new Exception("Failed to query Jira: " + response.StatusDescription); using (var responseStream = response.GetResponseStream()) using (var responseReader = new StreamReader(responseStream)) { var responseObject = Json.Decode(responseReader.ReadToEnd()); foreach (var issue in responseObject.issues) { string summary = issue.fields.summary; string id = issue.key; string issueType = issue.fields.issuetype.name; yield return new OnlineIssue { Id = id, Title = summary, IssueType = IssueType.Issue, HtmlUrl = new Uri(baseUrl, string.Format("browse/{0}", id)) }; } } }
private static void GenerateClassicalRequest(GitReleaseNotesArguments arguments, RestRequest request, string MethodLocation) { var usernameAndPass = string.Format("{0}:{1}", arguments.Username, arguments.Password); var token = Convert.ToBase64String(Encoding.UTF8.GetBytes(usernameAndPass)); request.Resource = string.Format(MethodLocation); request.AddHeader("Authorization", string.Format("Basic {0}", token)); }
public IEnumerable<OnlineIssue> GetClosedIssues(GitReleaseNotesArguments arguments, DateTimeOffset? since) { var authenticationCookies = ConnectToYouTrack(arguments.Username, arguments.Password, arguments.YouTrackServer); return IssuesClosedSinceDate( authenticationCookies, arguments.YouTrackFilter, arguments.YouTrackServer, arguments.ProjectId, since); }
public GitHubIssueTrackerTests() { _gitHubClient = Substitute.For<IGitHubClient>(); _sut = new GitHubIssueTracker(new IssueNumberExtractor(), _gitHubClient); _gitReleaseNotesArguments = new GitReleaseNotesArguments { Repo = "Org/Repo", Token = "213" }; _issuesClient = Substitute.For<IIssuesClient>(); }
public IEnumerable <OnlineIssue> GetClosedIssues(GitReleaseNotesArguments arguments, DateTimeOffset?since) { var authenticationCookies = ConnectToYouTrack(arguments.Username, arguments.Password, arguments.YouTrackServer); return(IssuesClosedSinceDate( authenticationCookies, arguments.YouTrackFilter, arguments.YouTrackServer, arguments.ProjectId, since)); }
public static Context ToContext(this GitReleaseNotesArguments arguments) { var context = new Context(); context.WorkingDirectory = arguments.WorkingDirectory; context.Verbose = arguments.Verbose; context.IssueTracker = arguments.IssueTracker; context.OutputFile = arguments.OutputFile; context.ProjectId = arguments.ProjectId; context.Categories = arguments.Categories; context.Version = arguments.Version; context.AllTags = arguments.AllTags; context.AllLabels = arguments.AllLabels; var authentication = context.Authentication; authentication.Username = arguments.Username; authentication.Password = arguments.Password; var repository = context.Repository; repository.Url = arguments.RepoUrl; repository.Branch = arguments.RepoBranch; repository.Username = arguments.RepoUsername; repository.Password = arguments.RepoPassword; var gitHub = context.GitHub; gitHub.Repo = arguments.Repo; gitHub.Token = arguments.Token; var jira = context.Jira; jira.JiraServer = arguments.JiraServer; jira.Jql = arguments.Jql; var youTrack = context.YouTrack; youTrack.YouTrackServer = arguments.YouTrackServer; youTrack.YouTrackFilter = arguments.YouTrackFilter; var bitBucket = context.BitBucket; bitBucket.Repo = arguments.Repo; bitBucket.ConsumerKey = arguments.ConsumerKey; bitBucket.ConsumerSecretKey = arguments.ConsumerSecretKey; return(context); }
public static bool VerifyArguments(GitReleaseNotesArguments arguments) { if (string.IsNullOrEmpty(arguments.OutputFile)) { Log.WriteLine("WARN: No Output file specified (*.md) [/OutputFile ...]"); } if (!string.IsNullOrEmpty(arguments.OutputFile) && !arguments.OutputFile.EndsWith(".md")) { Log.WriteLine("WARN: Output file should have a .md extension [/OutputFile ...]"); arguments.OutputFile = null; } return(true); }
public static bool VerifyArguments(GitReleaseNotesArguments arguments) { if (string.IsNullOrEmpty(arguments.OutputFile)) { Log.WriteLine("WARN: No Output file specified (*.md) [/OutputFile ...]"); } if (!string.IsNullOrEmpty(arguments.OutputFile) && !arguments.OutputFile.EndsWith(".md")) { Log.WriteLine("WARN: Output file should have a .md extension [/OutputFile ...]"); arguments.OutputFile = null; } return true; }
public void ApproveSimpleTests() { var arguments = new GitReleaseNotesArguments { OutputFile = "ReleaseFile.md" }; var releaseNotes = new SemanticReleaseNotes(new[] { new ReleaseNoteItem("Issue 1", "#1", new Uri("http://github.com/org/repo/issues/1"), new string[0]) }); _sut.WriteReleaseNotes(arguments, releaseNotes); Approvals.Verify(GetContent()); }
public void AdditionalCategoriesCanBeSpecifiedOnCommandLine() { var arguments = new GitReleaseNotesArguments { Categories = "internal refactoring", OutputFile = "ReleaseFile.md" }; var releaseNotes = new SemanticReleaseNotes(new[] { new ReleaseNoteItem("Issue 1", "#1", new Uri("http://github.com/org/repo/issues/1"), new[]{"internal refactoring"}) }); _sut.WriteReleaseNotes(arguments, releaseNotes); Approvals.Verify(GetContent()); }
public GitHubIssueTrackerTests() { _log = Substitute.For<ILog>(); _gitHubClient = Substitute.For<IGitHubClient>(); _issuesClient = Substitute.For<IIssuesClient>(); _gitHubClient.Issue.Returns(_issuesClient); _arguments = new GitReleaseNotesArguments { Repo = "Org/Repo", Token = "213" }; _repo = Substitute.For<IRepository>(); _repo.Network.Returns(new NetworkEx()); _sut = new GitHubIssueTracker(_repo, () => _gitHubClient, _log, _arguments); }
public GitHubIssueTrackerTests() { log = Substitute.For <ILog>(); gitHubClient = Substitute.For <IGitHubClient>(); issuesClient = Substitute.For <IIssuesClient>(); gitHubClient.Issue.Returns(issuesClient); arguments = new GitReleaseNotesArguments { Repo = "Org/Repo", Token = "213" }; repo = Substitute.For <IRepository>(); repo.Network.Returns(new NetworkEx()); sut = new GitHubIssueTracker(repo, () => gitHubClient, log, arguments); }
public void AbsolutePathIsWrittenToRepositoryRoot() { var arguments = new GitReleaseNotesArguments { Categories = "internal refactoring", OutputFile = "c:\\AnotherDir\\ReleaseFile.md" }; var releaseNotes = new SemanticReleaseNotes(new[] { new ReleaseNoteItem("Issue 1", "#1", new Uri("http://github.com/org/repo/issues/1"), new string[0]) }); _sut.WriteReleaseNotes(arguments, releaseNotes); var fileName = _fileSystem.ReceivedCalls().Single(c => c.GetMethodInfo().Name == "WriteAllText").GetArguments()[0]; Assert.Equal("c:\\AnotherDir\\ReleaseFile.md", fileName); }
public IEnumerable <OnlineIssue> GetClosedIssues(GitReleaseNotesArguments arguments, DateTimeOffset?since, string accountName, string repoSlug, bool oauth) { var baseUrl = new Uri(ApiUrl, UriKind.Absolute); var restClient = new RestClient(baseUrl.AbsoluteUri); var issuesUrl = string.Format("repositories/{0}/{1}/issues/", accountName, repoSlug); var request = new RestRequest(issuesUrl); if (oauth) { GenerateOauthRequest(arguments, baseUrl, issuesUrl, request); } else { GenerateClassicalRequest(arguments, request, issuesUrl); } var response = restClient.Execute(request); if (response.StatusCode != HttpStatusCode.OK) { throw new Exception("Failed to query BitBucket: " + response.StatusDescription); } dynamic responseObject = SimpleJson.DeserializeObject(response.Content); var issues = new List <OnlineIssue>(); foreach (var issue in responseObject.issues) { DateTimeOffset lastChange = DateTimeOffset.Parse(issue.utc_last_updated); if (issue.status != IssueClosed || lastChange <= since) { continue; } string summary = issue.content; string id = issue.local_id.ToString(); string title = issue.title; issues.Add(new OnlineIssue { Id = id, Title = summary, IssueType = IssueType.Issue, HtmlUrl = new Uri(baseUrl, string.Format("/repositories/{0}/{1}/issue/{2}/{3}", accountName, repoSlug, id, title)), DateClosed = lastChange }); } return(issues); }
public GitHubIssueTrackerTests() { gitHubClient = Substitute.For<IGitHubClient>(); issuesClient = Substitute.For<IIssuesClient>(); gitHubClient.Issue.Returns(issuesClient); arguments = new GitReleaseNotesArguments { Repo = "Org/Repo", Token = "213" }; var context = arguments.ToContext(); repo = Substitute.For<IRepository>(); repo.Network.Returns(new NetworkEx()); sut = new GitHubIssueTracker(repo, () => gitHubClient, context); }
/// <param name="issueNumberRegexPattern">Must have a named group called 'issueNumber'</param> public List<string> GetIssueNumbers(GitReleaseNotesArguments arguments, Commit[] commitsToScan, string issueNumberRegexPattern) { var issueNumbersToScan = new List<string>(); var issueRegex = new Regex(issueNumberRegexPattern, RegexOptions.Compiled); foreach (var commit in commitsToScan) { var matches = issueRegex.Matches(commit.Message).Cast<Match>(); foreach (var match in matches) { var issueNumber = match.Groups["issueNumber"].Value; if (arguments.Verbose) Console.WriteLine("Found issues {0} in commit {1}", issueNumber, commit.Sha); issueNumbersToScan.Add(issueNumber); } } return issueNumbersToScan; }
public GitHubIssueTrackerTests() { gitHubClient = Substitute.For <IGitHubClient>(); issuesClient = Substitute.For <IIssuesClient>(); gitHubClient.Issue.Returns(issuesClient); arguments = new GitReleaseNotesArguments { IssueTracker = IssueTracker.GitHub, IssueTrackerProjectId = "Org/Repo", IssueTrackerToken = "213" }; var context = arguments.ToContext(); repo = Substitute.For <IRepository>(); repo.Network.Returns(new NetworkEx()); sut = new GitHubIssueTracker(repo, () => gitHubClient, context); }
private static void GenerateOauthRequest(GitReleaseNotesArguments arguments, Uri baseUrl, string MethodLocation, RestRequest request) { var consumerKey = arguments.Username; var consumerSecret = arguments.Password; var oAuth = new OAuthBase(); var nonce = oAuth.GenerateNonce(); var timeStamp = oAuth.GenerateTimeStamp(); string normalizedUrl; string normalizedRequestParameters; var sig = oAuth.GenerateSignature(new Uri(baseUrl + MethodLocation), consumerKey, consumerSecret, null, null, "GET", timeStamp, nonce, out normalizedUrl, out normalizedRequestParameters); request.Resource = string.Format(MethodLocation); request.Method = Method.GET; request.AddParameter("oauth_consumer_key", consumerKey); request.AddParameter("oauth_nonce", nonce); request.AddParameter("oauth_timestamp", timeStamp); request.AddParameter("oauth_signature_method", "HMAC-SHA1"); request.AddParameter("oauth_version", "1.0"); request.AddParameter("oauth_signature", sig); }
public bool VerifyArgumentsAndWriteErrorsToConsole(GitReleaseNotesArguments arguments) { if (arguments.Repo == null) { Console.WriteLine("GitHub repository cannot be null"); return false; } var repoParts = arguments.Repo.Split('/'); if (repoParts.Length != 2) { Console.WriteLine("GitHub repository name should be in format Organisation/RepoName"); return false; } if (string.IsNullOrEmpty(arguments.Token)) { Console.WriteLine("You must specify a GitHub Authentication token with the /Token argument"); return false; } return true; }
private void GetRepository(GitReleaseNotesArguments arguments, out string organisation, out string repository) { if (RemotePresentWhichMatches) { if (TryRemote(out organisation, out repository, "upstream")) { return; } if (TryRemote(out organisation, out repository, "origin")) { return; } var remoteName = gitRepository.Network.Remotes.First(r => r.Url.ToLower().Contains("github.com")).Name; if (TryRemote(out organisation, out repository, remoteName)) { return; } } var repoParts = arguments.Repo.Split('/'); organisation = repoParts[0]; repository = repoParts[1]; }
public JiraIssueTracker(IJiraApi jiraApi, GitReleaseNotesArguments arguments) { this.jiraApi = jiraApi; this.arguments = arguments; }
public YouTrackIssueTracker(IYouTrackApi youTrackApi, ILog log, GitReleaseNotesArguments arguments) { this.youTrackApi = youTrackApi; this.log = log; this.arguments = arguments; }
public void ItemIsCategorised() { var arguments = new GitReleaseNotesArguments { OutputFile = "ReleaseFile.md" }; var releaseNotes = new SemanticReleaseNotes(new[] { new ReleaseNoteItem("Issue 1", "#1", new Uri("http://github.com/org/repo/issues/1"), new[]{"feature"}) }); _sut.WriteReleaseNotes(arguments, releaseNotes); Approvals.Verify(GetContent()); }
public JiraIssueTracker(IJiraApi jiraApi, ILog log, GitReleaseNotesArguments arguments) { this.jiraApi = jiraApi; this.log = log; this.arguments = arguments; }
public YouTrackIssueTracker(IYouTrackApi youTrackApi, GitReleaseNotesArguments arguments) { this.youTrackApi = youTrackApi; this.arguments = arguments; }
private void GetRepository(GitReleaseNotesArguments arguments, out string organisation, out string repository) { if (RemotePresentWhichMatches) { if (TryRemote(out organisation, out repository, "upstream")) return; if (TryRemote(out organisation, out repository, "origin")) return; var remoteName = gitRepository.Network.Remotes.First(r => r.Url.ToLower().Contains("github.com")).Name; if (TryRemote(out organisation, out repository, remoteName)) return; } var repoParts = arguments.Repo.Split('/'); organisation = repoParts[0]; repository = repoParts[1]; }
public IEnumerable <OnlineIssue> GetClosedIssues(GitReleaseNotesArguments arguments, DateTimeOffset?since) { string jql; if (since.HasValue) { var sinceFormatted = since.Value.ToString("yyyy-MM-d HH:mm"); jql = string.Format("{0} AND updated > '{1}'", arguments.Jql, sinceFormatted).Replace("\"", "\\\""); } else { jql = arguments.Jql; } var baseUrl = new Uri(arguments.JiraServer, UriKind.Absolute); var searchUri = new Uri(baseUrl, "/rest/api/latest/search"); var httpRequest = WebRequest.CreateHttp(searchUri); var usernameAndPass = string.Format("{0}:{1}", arguments.Username, arguments.Password); var token = Convert.ToBase64String(Encoding.UTF8.GetBytes(usernameAndPass)); httpRequest.Headers.Add("Authorization", string.Format("Basic {0}", token)); httpRequest.Method = "POST"; httpRequest.ContentType = "application/json"; using (var streamWriter = new StreamWriter(httpRequest.GetRequestStream())) { string json = "{\"jql\": \"" + jql + "\",\"startAt\": 0, \"maxResults\": 100, \"fields\": [\"summary\",\"issuetype\"]}"; streamWriter.Write(json); streamWriter.Flush(); streamWriter.Close(); } var response = (HttpWebResponse)httpRequest.GetResponse(); if ((int)response.StatusCode == 400) { throw new Exception("Jql query error, please review your Jql"); } if (response.StatusCode != HttpStatusCode.OK) { throw new Exception("Failed to query Jira: " + response.StatusDescription); } using (var responseStream = response.GetResponseStream()) using (var responseReader = new StreamReader(responseStream)) { var responseObject = Json.Decode(responseReader.ReadToEnd()); foreach (var issue in responseObject.issues) { string summary = issue.fields.summary; string id = issue.key; string issueType = issue.fields.issuetype.name; yield return(new OnlineIssue { Id = id, Title = summary, IssueType = IssueType.Issue, HtmlUrl = new Uri(baseUrl, string.Format("browse/{0}", id)) }); } } }