private bool TestFile(string fileName) { bool result = true; // See if file name is a valid rule ID and preload default values string defaultId = Path.GetFileNameWithoutExtension(fileName); string[]? languages = null; Rule fileRule = _rules.FirstOrDefault(x => x.Id == defaultId); if (fileRule != null) { languages = fileRule.AppliesTo; } // Load file header and content string fileHeader = string.Empty; string fileContent = File.ReadAllText(fileName); Regex reg = new Regex("^={3,}\\s+", RegexOptions.Multiline); Match match = reg.Match(fileContent); if (match.Success) { fileHeader = fileContent.Substring(0, match.Index); fileContent = fileContent.Substring(match.Index + match.Length); } languages = GetLanguges(fileHeader, languages); Dictionary <int, List <string> > expecations = GetExpectations(fileHeader, defaultId); RuleProcessor processor = new RuleProcessor(_rules); processor.EnableSuppressions = false; processor.SeverityLevel = Severity.Critical | Severity.Important | Severity.Moderate | Severity.BestPractice | Severity.ManualReview; Issue[] issues = processor.Analyze(fileContent, languages); List <KeyValuePair <Location, string> > unexpected = new List <KeyValuePair <Location, string> >(); foreach (Issue issue in issues) { AddToCoverageList(issue.Rule.Id); // if issue on this line was expected remove it from expecations int line = issue.StartLocation.Line; if (expecations.ContainsKey(line) && expecations[line].Contains(issue.Rule.Id)) { expecations[line].Remove(issue.Rule.Id); } // otherwise add it to unexpected else { unexpected.Add(new KeyValuePair <Location, string>(issue.StartLocation, issue.Rule.Id)); } } if (unexpected.Count > 0 || expecations.Any(x => x.Value.Count > 0)) { result = false; Console.Error.WriteLine("file:{0}", fileName); foreach (KeyValuePair <Location, string> pair in unexpected) { Console.Error.WriteLine("\tline:{0},{1} unexpected {2}", pair.Key.Line, pair.Key.Column, pair.Value); } foreach (int line in expecations.Keys) { if (expecations[line].Count > 0) { foreach (string id in expecations[line]) { string exists = string.Empty; if (_rules.FirstOrDefault(x => x.Id == id) == null) { exists = " (no such rule) "; } Console.Error.WriteLine("\tline:{0} expecting {1}{2}", line, id, exists); } } } Console.Error.WriteLine(); } return(result); }
/// <summary> /// Add default and/or custom rules paths /// Iterate paths and add to ruleset /// </summary> void ConfigRules() { WriteOnce.SafeLog("AnalyzeCommand::ConfigRules", LogLevel.Trace); RuleSet rulesSet = new RuleSet(Program.Logger); List <string> rulePaths = new List <string>(); if (!_arg_ignoreDefaultRules) { rulePaths.Add(Utils.GetPath(Utils.AppPath.defaultRules)); } if (!string.IsNullOrEmpty(_arg_customRulesPath)) { rulePaths.Add(_arg_customRulesPath); } foreach (string rulePath in rulePaths) { if (Directory.Exists(rulePath)) { rulesSet.AddDirectory(rulePath); } else if (File.Exists(rulePath)) { rulesSet.AddFile(rulePath); } else { throw new OpException(ErrMsg.FormatString(ErrMsg.ID.CMD_INVALID_RULE_PATH, rulePath)); } } //error check based on ruleset not path enumeration if (rulesSet.Count() == 0) { throw new OpException(ErrMsg.GetString(ErrMsg.ID.CMD_NORULES_SPECIFIED)); } //instantiate a RuleProcessor with the added rules and exception for dependency _rulesProcessor = new RuleProcessor(rulesSet, _arg_confidence, _arg_outputUniqueTagsOnly, _arg_simpleTagsOnly, Program.Logger); if (_arg_outputUniqueTagsOnly) { List <TagException> tagExceptions; if (File.Exists(Utils.GetPath(Utils.AppPath.tagCounterPref))) { tagExceptions = JsonConvert.DeserializeObject <List <TagException> >(File.ReadAllText(Utils.GetPath(Utils.AppPath.tagCounterPref))); string[] exceptions = new string[tagExceptions.Count]; for (int i = 0; i < tagExceptions.Count; i++) { exceptions[i] = tagExceptions[i].Tag; } _rulesProcessor.UniqueTagExceptions = exceptions; } } _appProfile = new AppProfile(_arg_sourcePath, rulePaths, false, _arg_simpleTagsOnly, _arg_outputUniqueTagsOnly); _appProfile.Args = "analyze -f " + _arg_fileFormat + " -u " + _arg_outputUniqueTagsOnly.ToString().ToLower() + " -v " + WriteOnce.Verbosity.ToString() + " -x " + _arg_confidence + " -i " + _arg_ignoreDefaultRules.ToString().ToLower(); }
public int Run() { if (_suppressError) { Console.SetError(StreamWriter.Null); } if (!Directory.Exists(_path) && !File.Exists(_path)) { Console.Error.WriteLine("Error: Not a valid file or directory {0}", _path); return((int)ExitCode.CriticalError); } Verifier verifier = null; if (_rulespath.Count() > 0) { // Setup the rules verifier = new Verifier(_rulespath); if (!verifier.Verify()) { return((int)ExitCode.CriticalError); } if (verifier.CompiledRuleset.Count() == 0 && _ignoreDefaultRules) { Console.Error.WriteLine("Error: No rules were loaded. "); return((int)ExitCode.CriticalError); } } RuleSet rules = new RuleSet(); if (verifier != null) { rules = verifier.CompiledRuleset; } if (!_ignoreDefaultRules) { Assembly assembly = Assembly.GetExecutingAssembly(); string filePath = "Microsoft.DevSkim.CLI.Resources.devskim-rules.json"; Stream resource = assembly.GetManifestResourceStream(filePath); using (StreamReader file = new StreamReader(resource)) { rules.AddString(file.ReadToEnd(), filePath, null); } } // Initialize the processor RuleProcessor processor = new RuleProcessor(rules); if (_severities.Count() > 0) { processor.SeverityLevel = 0; foreach (string severityText in _severities) { Severity severity; if (ParseSeverity(severityText, out severity)) { processor.SeverityLevel |= severity; } else { Console.Error.WriteLine("Invalid severity: {0}", severityText); return((int)ExitCode.CriticalError); } } } Writer outputWriter = WriterFactory.GetWriter(_fileFormat, (string.IsNullOrEmpty(_outputFile)) ? null : "text", _outputFormat); if (string.IsNullOrEmpty(_outputFile)) { outputWriter.TextWriter = Console.Out; } else { outputWriter.TextWriter = File.CreateText(_outputFile); } int filesAnalyzed = 0; int filesSkipped = 0; int filesAffected = 0; int issuesCount = 0; // We can pass either a file or a directory; if it's a file, make an IEnumerable out of it. IEnumerable <string> fileListing; if (!Directory.Exists(_path)) { fileListing = new List <string>() { _path }; } else { fileListing = Directory.EnumerateFiles(_path, "*.*", SearchOption.AllDirectories); } // Iterate through all files foreach (string filename in fileListing) { string language = Language.FromFileName(filename); // Skip files written in unknown language if (string.IsNullOrEmpty(language)) { filesSkipped++; continue; } filesAnalyzed++; string fileText = File.ReadAllText(filename); Issue[] issues = processor.Analyze(fileText, language); if (issues.Count() > 0) { filesAffected++; issuesCount += issues.Count(); Console.Error.WriteLine("file:{0}", filename); // Iterate through each issue foreach (Issue issue in issues) { Console.Error.WriteLine("\tregion:{0},{1},{2},{3} - {4} [{5}] - {6}", issue.StartLocation.Line, issue.StartLocation.Column, issue.EndLocation.Line, issue.EndLocation.Column, issue.Rule.Id, issue.Rule.Severity, issue.Rule.Name); IssueRecord record = new IssueRecord() { Filename = filename, Filesize = fileText.Length, TextSample = fileText.Substring(issue.Boundary.Index, issue.Boundary.Length), Issue = issue }; outputWriter.WriteIssue(record); } Console.Error.WriteLine(); } } outputWriter.FlushAndClose(); Console.Error.WriteLine("Issues found: {0} in {1} files", issuesCount, filesAffected); Console.Error.WriteLine("Files analyzed: {0}", filesAnalyzed); Console.Error.WriteLine("Files skipped: {0}", filesSkipped); return((int)ExitCode.NoIssues); }