public void OnDataReceived(object sender, ProcessDataReceivedEventArgs e) { var line = e.Data; // ## commands if (!String.IsNullOrEmpty(line) && (line.IndexOf(ActionCommand.Prefix) >= 0 || line.IndexOf(ActionCommand._commandKey) >= 0)) { // This does not need to be inside of a critical section. // The logging queues and command handlers are thread-safe. if (_commandManager.TryProcessCommand(_executionContext, line, _container)) { return; } } // Problem matchers if (_matchers.Length > 0) { // Copy the reference var matchers = _matchers; // Strip color codes var stripped = line.Contains(_colorCodePrefix) ? _colorCodeRegex.Replace(line, string.Empty) : line; foreach (var matcher in matchers) { IssueMatch match = null; for (var attempt = 1; attempt <= _maxAttempts; attempt++) { // Match try { match = matcher.Match(stripped); break; } catch (RegexMatchTimeoutException ex) { if (attempt < _maxAttempts) { // Debug _executionContext.Debug($"Timeout processing issue matcher '{matcher.Owner}' against line '{stripped}'. Exception: {ex.ToString()}"); } else { // Warn _executionContext.Warning($"Removing issue matcher '{matcher.Owner}'. Matcher failed {_maxAttempts} times. Error: {ex.Message}"); // Remove Remove(matcher); } } } if (match != null) { // Reset other matchers foreach (var otherMatcher in matchers.Where(x => !object.ReferenceEquals(x, matcher))) { otherMatcher.Reset(); } // Convert to issue var issue = ConvertToIssue(match); if (issue != null) { // Log issue _executionContext.AddIssue(issue, stripped); return; } } } } // Regular output _executionContext.Output(line); }
private DTWebApi.Issue ConvertToIssue(IssueMatch match) { // Validate the message if (string.IsNullOrWhiteSpace(match.Message)) { _executionContext.Debug("Skipping logging an issue for the matched line because the message is empty."); return(null); } // Validate the severity DTWebApi.IssueType issueType; if (string.IsNullOrEmpty(match.Severity) || string.Equals(match.Severity, "error", StringComparison.OrdinalIgnoreCase)) { issueType = DTWebApi.IssueType.Error; } else if (string.Equals(match.Severity, "warning", StringComparison.OrdinalIgnoreCase)) { issueType = DTWebApi.IssueType.Warning; } else if (string.Equals(match.Severity, "notice", StringComparison.OrdinalIgnoreCase)) { issueType = DTWebApi.IssueType.Notice; } else { _executionContext.Debug($"Skipped logging an issue for the matched line because the severity '{match.Severity}' is not supported."); return(null); } var issue = new DTWebApi.Issue { Message = match.Message, Type = issueType, }; // Line if (!string.IsNullOrEmpty(match.Line)) { if (int.TryParse(match.Line, NumberStyles.None, CultureInfo.InvariantCulture, out var line)) { issue.Data["line"] = line.ToString(CultureInfo.InvariantCulture); } else { _executionContext.Debug($"Unable to parse line number '{match.Line}'"); } } // Column if (!string.IsNullOrEmpty(match.Column)) { if (int.TryParse(match.Column, NumberStyles.None, CultureInfo.InvariantCulture, out var column)) { issue.Data["col"] = column.ToString(CultureInfo.InvariantCulture); } else { _executionContext.Debug($"Unable to parse column number '{match.Column}'"); } } // Code if (!string.IsNullOrWhiteSpace(match.Code)) { issue.Data["code"] = match.Code.Trim(); } // File try { if (!string.IsNullOrWhiteSpace(match.File)) { var file = match.File; var translate = _container != null; // Root using fromPath if (!string.IsNullOrWhiteSpace(match.FromPath) && !Path.IsPathFullyQualified(file)) { var fromDirectory = Path.GetDirectoryName(match.FromPath); if (!string.IsNullOrWhiteSpace(fromDirectory)) { file = Path.Combine(fromDirectory, file); } } // Root using workspace if (!Path.IsPathFullyQualified(file)) { var workspace = _executionContext.GetGitHubContext("workspace"); ArgUtil.NotNullOrEmpty(workspace, "workspace"); file = Path.Combine(workspace, file); translate = false; } // Remove relative pathing and normalize slashes file = Path.GetFullPath(file); // Translate to host if (translate) { file = _container.TranslateToHostPath(file); file = Path.GetFullPath(file); } // Check whether the file exists if (File.Exists(file)) { // Check whether the file is under the workflow repository var repositoryPath = GetRepositoryPath(file); if (!string.IsNullOrEmpty(repositoryPath)) { // Get the relative file path var relativePath = file.Substring(repositoryPath.Length).TrimStart(Path.DirectorySeparatorChar); // Prefer `/` on all platforms issue.Data["file"] = relativePath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); } else { _executionContext.Debug($"Dropping file value '{file}'. Path is not under the workflow repo."); } } else { _executionContext.Debug($"Dropping file value '{file}'. Path does not exist"); } } } catch (Exception ex) { _executionContext.Debug($"Dropping file value '{match.File}' and fromPath value '{match.FromPath}'. Exception during validation: {ex.ToString()}"); } return(issue); }