way_of_working-code_linting-hdi 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +7 -0
  2. data/.alexrc +3 -0
  3. data/.mega-linter.yml +145 -0
  4. data/.rubocop +1 -0
  5. data/CHANGELOG.md +20 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +58 -0
  8. data/Rakefile +16 -0
  9. data/code_safety.yml +186 -0
  10. data/docs/way_of_working/code-linting/index.md +39 -0
  11. data/docs/way_of_working/code-linting/linters.md +153 -0
  12. data/lib/way_of_working/code_linting/hdi/generators/document_linters.rb +81 -0
  13. data/lib/way_of_working/code_linting/hdi/generators/exec.rb +79 -0
  14. data/lib/way_of_working/code_linting/hdi/generators/init.rb +23 -0
  15. data/lib/way_of_working/code_linting/hdi/generators/init_linters.rb +103 -0
  16. data/lib/way_of_working/code_linting/hdi/github_audit_rule.rb +60 -0
  17. data/lib/way_of_working/code_linting/hdi/paths.rb +20 -0
  18. data/lib/way_of_working/code_linting/hdi/plugin.rb +1 -0
  19. data/lib/way_of_working/code_linting/hdi/supported_linter.rb +91 -0
  20. data/lib/way_of_working/code_linting/hdi/templates/.github/linters/.markdown-link-check.json +13 -0
  21. data/lib/way_of_working/code_linting/hdi/templates/.github/linters/rubocop_defaults.yml +55 -0
  22. data/lib/way_of_working/code_linting/hdi/templates/.github/workflows/mega-linter.yml +88 -0
  23. data/lib/way_of_working/code_linting/hdi/templates/.mega-linter.yml +145 -0
  24. data/lib/way_of_working/code_linting/hdi/templates/.rubocop +1 -0
  25. data/lib/way_of_working/code_linting/hdi/templates/docs/way_of_working/code-linting/index.md +39 -0
  26. data/lib/way_of_working/code_linting/hdi/templates/docs/way_of_working/code-linting/linters.md.tt +24 -0
  27. data/lib/way_of_working/code_linting/hdi/version.rb +9 -0
  28. data/lib/way_of_working/code_linting/hdi.rb +54 -0
  29. metadata +103 -0
@@ -0,0 +1,153 @@
1
+ ---
2
+ layout: page
3
+ nav_order: 1
4
+ parent: Code Linting
5
+ ---
6
+
7
+ # Linters
8
+
9
+ The following tables detail the linters that we are currently using:
10
+
11
+ ## Languages
12
+
13
+ | Language | Linter | Details |
14
+ |:-------------|:--------------------------------------|:--------------------------------------------------------------------------------|
15
+ | Bash | BASH_EXEC | [bash-exec](https://megalinter.io/latest/descriptors/bash_bash_exec/) |
16
+ | Bash | BASH_SHELLCHECK | [shellcheck](https://megalinter.io/latest/descriptors/bash_shellcheck/) |
17
+ | Bash | BASH_SHFMT | [shfmt](https://megalinter.io/latest/descriptors/bash_shfmt/) |
18
+ | C | C_CLANG_FORMAT | [clang-format](https://megalinter.io/latest/descriptors/c_clang_format/) |
19
+ | C | C_CPPLINT | [cpplint](https://megalinter.io/latest/descriptors/c_cpplint/) |
20
+ | C# | CSHARP_CSHARPIER | [csharpier](https://megalinter.io/latest/descriptors/csharp_csharpier/) |
21
+ | C# | CSHARP_DOTNET_FORMAT | [dotnet-format](https://megalinter.io/latest/descriptors/csharp_dotnet_format/) |
22
+ | C# | CSHARP_ROSLYNATOR | [roslynator](https://megalinter.io/latest/descriptors/csharp_roslynator/) |
23
+ | C++ | CPP_CLANG_FORMAT | [clang-format](https://megalinter.io/latest/descriptors/cpp_clang_format/) |
24
+ | C++ | CPP_CPPLINT | [cpplint](https://megalinter.io/latest/descriptors/cpp_cpplint/) |
25
+ | Clojure | ~~CLOJURE_CLJSTYLE~~ | Not Used |
26
+ | Clojure | ~~CLOJURE_CLJ_KONDO~~ | Not Used |
27
+ | CoffeeScript | COFFEE_COFFEELINT | [coffeelint](https://megalinter.io/latest/descriptors/coffee_coffeelint/) |
28
+ | Dart | DART_DARTANALYZER | [dartanalyzer](https://megalinter.io/latest/descriptors/dart_dartanalyzer/) |
29
+ | Go | GO_GOLANGCI_LINT | [golangci-lint](https://megalinter.io/latest/descriptors/go_golangci_lint/) |
30
+ | Go | GO_REVIVE | [revive](https://megalinter.io/latest/descriptors/go_revive/) |
31
+ | Groovy | ~~GROOVY_NPM_GROOVY_LINT~~ | Not Used |
32
+ | Java | JAVA_CHECKSTYLE | [checkstyle](https://megalinter.io/latest/descriptors/java_checkstyle/) |
33
+ | Java | JAVA_PMD | [pmd](https://megalinter.io/latest/descriptors/java_pmd/) |
34
+ | JavaScript | JAVASCRIPT_ES | [eslint](https://megalinter.io/latest/descriptors/javascript_eslint/) |
35
+ | JavaScript | ~~JAVASCRIPT_PRETTIER~~ | Not Used |
36
+ | JavaScript | JAVASCRIPT_STANDARD | [standard](https://megalinter.io/latest/descriptors/javascript_standard/) |
37
+ | JSX | JSX_ESLINT | [eslint](https://megalinter.io/latest/descriptors/jsx_eslint/) |
38
+ | Kotlin | KOTLIN_DETEKT | [detekt](https://megalinter.io/latest/descriptors/kotlin_detekt/) |
39
+ | Kotlin | KOTLIN_KTLINT | [ktlint](https://megalinter.io/latest/descriptors/kotlin_ktlint/) |
40
+ | Lua | ~~LUA_LUACHECK~~ | Not Used |
41
+ | Lua | ~~LUA_SELENE~~ | Not Used |
42
+ | Lua | ~~LUA_STYLUA~~ | Not Used |
43
+ | Makefile | MAKEFILE_CHECKMAKE | [checkmake](https://megalinter.io/latest/descriptors/makefile_checkmake/) |
44
+ | Perl | ~~PERL_PERLCRITIC~~ | Not Used |
45
+ | PHP | ~~PHP_PHPCS~~ | Not Used |
46
+ | PHP | ~~PHP_PHPCSFIXER~~ | Not Used |
47
+ | PHP | ~~PHP_PHPLINT~~ | Not Used |
48
+ | PHP | ~~PHP_PHPSTAN~~ | Not Used |
49
+ | PHP | ~~PHP_PSALM~~ | Not Used |
50
+ | Powershell | ~~POWERSHELL_POWERSHELL~~ | Not Used |
51
+ | Powershell | ~~POWERSHELL_POWERSHELL_FORMATTER~~ | Not Used |
52
+ | Python | PYTHON_BANDIT | [bandit](https://megalinter.io/latest/descriptors/python_bandit/) |
53
+ | Python | PYTHON_BLACK | [black](https://megalinter.io/latest/descriptors/python_black/) |
54
+ | Python | PYTHON_FLAKE8 | [flake8](https://megalinter.io/latest/descriptors/python_flake8/) |
55
+ | Python | PYTHON_ISORT | [isort](https://megalinter.io/latest/descriptors/python_isort/) |
56
+ | Python | PYTHON_MYPY | [mypy](https://megalinter.io/latest/descriptors/python_mypy/) |
57
+ | Python | PYTHON_PYLINT | [pylint](https://megalinter.io/latest/descriptors/python_pylint/) |
58
+ | Python | PYTHON_PYRIGHT | [pyright](https://megalinter.io/latest/descriptors/python_pyright/) |
59
+ | Python | PYTHON_RUFF | [ruff](https://megalinter.io/latest/descriptors/python_ruff/) |
60
+ | R | R_LINTR | [lintr](https://megalinter.io/latest/descriptors/r_lintr/) |
61
+ | Raku | ~~RAKU_RAKU~~ | Not Used |
62
+ | Ruby | ~~RUBY_RUBOCOP~~ | Not Used (RuboCop is used directly) |
63
+ | Rust | RUST_CLIPPY | [clippy](https://megalinter.io/latest/descriptors/rust_clippy/) |
64
+ | Salesforce | ~~SALESFORCE_LIGHTNING_FLOW_SCANNER~~ | Not Used |
65
+ | Salesforce | ~~SALESFORCE_SFDX_SCANNER_APEX~~ | Not Used |
66
+ | Salesforce | ~~SALESFORCE_SFDX_SCANNER_AURA~~ | Not Used |
67
+ | Salesforce | ~~SALESFORCE_SFDX_SCANNER_LWC~~ | Not Used |
68
+ | Scala | SCALA_SCALAFIX | [scalafix](https://megalinter.io/latest/descriptors/scala_scalafix/) |
69
+ | SQL | SQL_SQLFLUFF | [sqlfluff](https://megalinter.io/latest/descriptors/sql_sqlfluff/) |
70
+ | SQL | SQL_TSQLLINT | [tsqllint](https://megalinter.io/latest/descriptors/sql_tsqllint/) |
71
+ | Swift | SWIFT_SWIFTLINT | [swiftlint](https://megalinter.io/latest/descriptors/swift_swiftlint/) |
72
+ | TSX | TSX_ESLINT | [eslint](https://megalinter.io/latest/descriptors/tsx_eslint/) |
73
+ | TypeScript | TYPESCRIPT_ES | [eslint](https://megalinter.io/latest/descriptors/typescript_eslint/) |
74
+ | TypeScript | ~~TYPESCRIPT_PRETTIER~~ | Not Used |
75
+ | TypeScript | TYPESCRIPT_STANDARD | [ts-standard](https://megalinter.io/latest/descriptors/typescript_ts_standard/) |
76
+ | VB.Net | ~~VBDOTNET_DOTNET_FORMAT~~ | Not Used |
77
+
78
+ ## Formats
79
+
80
+ | Format | Linter | Details |
81
+ |:-----------------|:----------------------------------|:--------------------------------------------------------------------------------------------------------|
82
+ | CSS | CSS_STYLELINT | [stylelint](https://megalinter.io/latest/descriptors/css_stylelint/) |
83
+ | ENV | ENV_DOTENV_LINTER | [dotenv-linter](https://megalinter.io/latest/descriptors/env_dotenv_linter/) |
84
+ | GraphQL | ~~GRAPHQL_GRAPHQL_SCHEMA_LINTER~~ | Not Used |
85
+ | HTML | ~~HTML_DJLINT~~ | Not Used (Refuses to see config file) |
86
+ | HTML | HTML_HTMLHINT | [htmlhint](https://megalinter.io/latest/descriptors/html_htmlhint/) |
87
+ | JSON | JSON_ESLINT_PLUGIN_JSONC | [eslint-plugin-jsonc](https://megalinter.io/latest/descriptors/json_eslint_plugin_jsonc/) |
88
+ | JSON | JSON_JSONLINT | [jsonlint](https://megalinter.io/latest/descriptors/json_jsonlint/) |
89
+ | JSON | JSON_NPM_PACKAGE_JSON_LINT | [npm-package-json-lint](https://megalinter.io/latest/descriptors/json_npm_package_json_lint/) |
90
+ | JSON | ~~JSON_PRETTIER~~ | Not Used |
91
+ | JSON | JSON_V8R | [v8r](https://megalinter.io/latest/descriptors/json_v8r/) |
92
+ | LaTeX | ~~LATEX_CHKTEX~~ | Not Used |
93
+ | Markdown | MARKDOWN_MARKDOWNLINT | [markdownlint](https://megalinter.io/latest/descriptors/markdown_markdownlint/) |
94
+ | Markdown | MARKDOWN_MARKDOWN_LINK_CHECK | [markdown-link-check](https://megalinter.io/latest/descriptors/markdown_markdown_link_check/) |
95
+ | Markdown | MARKDOWN_MARKDOWN_TABLE_FORMATTER | [markdown-table-formatter](https://megalinter.io/latest/descriptors/markdown_markdown_table_formatter/) |
96
+ | Markdown | MARKDOWN_REMARK_LINT | [remark-lint](https://megalinter.io/latest/descriptors/markdown_remark_lint/) |
97
+ | Protocol Buffers | ~~PROTOBUF_PROTOLINT~~ | Not Used |
98
+ | reStructuredText | ~~RST_RSTCHECK~~ | Not Used |
99
+ | reStructuredText | ~~RST_RSTFMT~~ | Not Used |
100
+ | reStructuredText | ~~RST_RST_LINT~~ | Not Used |
101
+ | XML | XML_XMLLINT | [xmllint](https://megalinter.io/latest/descriptors/xml_xmllint/) |
102
+ | YAML | ~~YAML_PRETTIER~~ | Not Used |
103
+ | YAML | YAML_V8R | [v8r](https://megalinter.io/latest/descriptors/yaml_v8r/) |
104
+ | YAML | YAML_YAMLLINT | [yamllint](https://megalinter.io/latest/descriptors/yaml_yamllint/) |
105
+
106
+ ## Tooling formats
107
+
108
+ | Tooling format | Linter | Details |
109
+ |:---------------|:----------------------------------|:----------------------------------------------------------------------------------------------------|
110
+ | GitHub Action | ACTION_ACTIONLINT | [actionlint](https://megalinter.io/latest/descriptors/action_actionlint/) |
111
+ | Ansible | ANSIBLE_ANSIBLE_LINT | [ansible-lint](https://megalinter.io/latest/descriptors/ansible_ansible_lint/) |
112
+ | Api | API_SPECTRAL | [spectral](https://megalinter.io/latest/descriptors/api_spectral/) |
113
+ | ARM Templates | ARM_ARM_TTK | [arm-ttk](https://megalinter.io/latest/descriptors/arm_arm_ttk/) |
114
+ | Bicep | ~~BICEP_BICEP_LINTER~~ | Not Used |
115
+ | CloudFormation | CLOUDFORMATION_CFN_LINT | [cfn-lint](https://megalinter.io/latest/descriptors/cloudformation_cfn_lint/) |
116
+ | Dockerfile | DOCKERFILE_HADOLINT | [hadolint](https://megalinter.io/latest/descriptors/dockerfile_hadolint/) |
117
+ | EditorConfig | EDITORCONFIG_EDITORCONFIG_CHECKER | [editorconfig-checker](https://megalinter.io/latest/descriptors/editorconfig_editorconfig_checker/) |
118
+ | Gherkin | ~~GHERKIN_GHERKIN_LINT~~ | Not Used |
119
+ | Kubernetes | KUBERNETES_HELM | [helm](https://megalinter.io/latest/descriptors/kubernetes_helm/) |
120
+ | Kubernetes | KUBERNETES_KUBECONFORM | [kubeconform](https://megalinter.io/latest/descriptors/kubernetes_kubeconform/) |
121
+ | Kubernetes | KUBERNETES_KUBESCAPE | [kubescape](https://megalinter.io/latest/descriptors/kubernetes_kubescape/) |
122
+ | Puppet | PUPPET_PUPPET_LINT | [puppet-lint](https://megalinter.io/latest/descriptors/puppet_puppet_lint/) |
123
+ | Snakemake | ~~SNAKEMAKE_LINT~~ | Not Used |
124
+ | Snakemake | ~~SNAKEMAKE_SNAKEFMT~~ | Not Used |
125
+ | Tekton | ~~TEKTON_TEKTON_LINT~~ | Not Used |
126
+ | Terraform | TERRAFORM_TERRAFORM_FMT | [terraform-fmt](https://megalinter.io/latest/descriptors/terraform_terraform_fmt/) |
127
+ | Terraform | TERRAFORM_TERRAGRUNT | [terragrunt](https://megalinter.io/latest/descriptors/terraform_terragrunt/) |
128
+ | Terraform | TERRAFORM_TERRASCAN | [terrascan](https://megalinter.io/latest/descriptors/terraform_terrascan/) |
129
+ | Terraform | TERRAFORM_TFLINT | [tflint](https://megalinter.io/latest/descriptors/terraform_tflint/) |
130
+
131
+ ## Other
132
+
133
+ | Other | Linter | Details |
134
+ |:-----------|:----------------------|:------------------------------------------------------------------------------|
135
+ | Copypaste | COPYPASTE_JSCPD | [jscpd](https://megalinter.io/latest/descriptors/copypaste_jscpd/) |
136
+ | Repository | REPOSITORY_CHECKOV | [checkov](https://megalinter.io/latest/descriptors/repository_checkov/) |
137
+ | Repository | REPOSITORY_DEVSKIM | [devskim](https://megalinter.io/latest/descriptors/repository_devskim/) |
138
+ | Repository | REPOSITORY_DUSTILOCK | [dustilock](https://megalinter.io/latest/descriptors/repository_dustilock/) |
139
+ | Repository | REPOSITORY_GITLEAKS | [gitleaks](https://megalinter.io/latest/descriptors/repository_gitleaks/) |
140
+ | Repository | REPOSITORY_GIT_DIFF | [git_diff](https://megalinter.io/latest/descriptors/repository_git_diff/) |
141
+ | Repository | REPOSITORY_GRYPE | [grype](https://megalinter.io/latest/descriptors/repository_grype/) |
142
+ | Repository | REPOSITORY_KICS | [kics](https://megalinter.io/latest/descriptors/repository_kics/) |
143
+ | Repository | REPOSITORY_LS_LINT | [ls-lint](https://megalinter.io/latest/descriptors/repository_ls_lint/) |
144
+ | Repository | REPOSITORY_SECRETLINT | [secretlint](https://megalinter.io/latest/descriptors/repository_secretlint/) |
145
+ | Repository | REPOSITORY_SEMGREP | [semgrep](https://megalinter.io/latest/descriptors/repository_semgrep/) |
146
+ | Repository | REPOSITORY_SYFT | [syft](https://megalinter.io/latest/descriptors/repository_syft/) |
147
+ | Repository | REPOSITORY_TRIVY | [trivy](https://megalinter.io/latest/descriptors/repository_trivy/) |
148
+ | Repository | REPOSITORY_TRIVY_SBOM | [trivy-sbom](https://megalinter.io/latest/descriptors/repository_trivy_sbom/) |
149
+ | Repository | REPOSITORY_TRUFFLEHOG | [trufflehog](https://megalinter.io/latest/descriptors/repository_trufflehog/) |
150
+ | Spelling | ~~SPELL_CSPELL~~ | Not Used |
151
+ | Spelling | SPELL_LYCHEE | [lychee](https://megalinter.io/latest/descriptors/spell_lychee/) |
152
+ | Spelling | SPELL_PROSELINT | [proselint](https://megalinter.io/latest/descriptors/spell_proselint/) |
153
+ | Spelling | SPELL_VALE | [vale](https://megalinter.io/latest/descriptors/spell_vale/) |
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require 'active_support/core_ext/string'
5
+ require 'nokogiri'
6
+ require 'open-uri'
7
+ require 'thor'
8
+ require 'way_of_working/paths'
9
+
10
+ module WayOfWorking
11
+ module CodeLinting
12
+ module Hdi
13
+ module Generators
14
+ # This class is responsible for generating linter documentation
15
+ class DocumentLinters < Thor::Group
16
+ include Thor::Actions # Mixin for action methods provided by Thor
17
+
18
+ # Set the source root for the templates
19
+ source_root ::WayOfWorking::CodeLinting::Hdi.source_root
20
+
21
+ # URL of the supported linters
22
+ SUPPORTED_LINTERS_URL = 'https://megalinter.io/latest/supported-linters/'
23
+
24
+ # Method to prepare the list of linters from the supported linters URL
25
+ def prepare_linter_lists
26
+ # Initialize an empty hash for linter types
27
+ @types = {}
28
+
29
+ # Iterate over each linter type in the parsed HTML
30
+ parse_linter_types_html do |type, html_rows|
31
+ @types[type] = []
32
+
33
+ parse_linter_rows(html_rows) do |constant_name, language, name, link|
34
+ # Create a new linter object and add it to the list
35
+ @types[type] << SupportedLinter.new(language, constant_name, name, link,
36
+ enabled_linters)
37
+ end
38
+ end
39
+ end
40
+
41
+ # Method to create the linter documentation using a template
42
+ def create_linters_documentation
43
+ template 'docs/way_of_working/code-linting/linters.md'
44
+ copy_file 'docs/way_of_working/code-linting/index.md'
45
+ end
46
+
47
+ private
48
+
49
+ def parse_linter_types_html
50
+ # Parse HTML from the supported linters URL
51
+ doc = Nokogiri::HTML(URI.parse(SUPPORTED_LINTERS_URL).read)
52
+
53
+ doc.css('article h2').each do |h2|
54
+ type = h2.text.strip
55
+
56
+ yield type, h2.next_element.css('tbody tr')
57
+ end
58
+ end
59
+
60
+ def parse_linter_rows(html_rows)
61
+ # Iterate over each linter in the current type
62
+ html_rows.each do |tr|
63
+ tds = tr.css('td')
64
+ constant_name = tds[2].css('a')[1].text
65
+ language = tds[1].text.sub(/\s\([^)]+\)\z/, '')
66
+ name = tds[2].css('a')[0].text
67
+ link = tds[2].css('a')[0].attributes['href'].value.sub(/\A\.\./, 'https://megalinter.io/latest')
68
+
69
+ yield constant_name, language, name, link
70
+ end
71
+ end
72
+
73
+ # Load enabled linters from the YAML config file
74
+ def enabled_linters
75
+ @enabled_linters ||= YAML.load_file('.mega-linter.yml')['ENABLE_LINTERS']
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require 'rainbow'
5
+
6
+ module WayOfWorking
7
+ module CodeLinting
8
+ module Hdi
9
+ module Generators
10
+ # This generator runs the linter
11
+ class Exec < Thor::Group
12
+ argument :path, type: :string, required: false, desc: 'Optional path of the file to lint'
13
+
14
+ desc 'This runs the linter on this project'
15
+
16
+ def run_first
17
+ @start_time = Time.now
18
+
19
+ say(Rainbow("Limiting linters to #{path}\n").yellow) if path
20
+ end
21
+
22
+ # Run RuboCop
23
+ def prep_and_run_rubocop
24
+ say(Rainbow('Running RuboCop...').yellow)
25
+
26
+ @rubocop_ok = run_rubocop(ARGV[2..])
27
+ end
28
+
29
+ # Run MegaLinter
30
+ def prep_and_run_megalinter
31
+ command = ['npx', 'mega-linter-runner', '--remove-container']
32
+ # Configure MegaLinter to only lint a specific file or folder, if defined
33
+ command.prepend("MEGALINTER_FILES_TO_LINT=\"#{path}\"") if path
34
+ # We only want reports created in the working directory
35
+ command.prepend('env', "GITHUB_WORKSPACE=\"#{Dir.pwd}\"")
36
+
37
+ say(Rainbow("\nRunning MegaLinter...").yellow)
38
+
39
+ @megalinter_ok = run_megalinter(command)
40
+ end
41
+
42
+ # We run this last to enable all the linters to run first
43
+ def run_last
44
+ say(Rainbow("\nTotal time taken: #{(Time.now - @start_time).to_i} seconds").yellow)
45
+
46
+ if !@rubocop_ok || !@megalinter_ok
47
+ abort(Rainbow("\nLinter failed!").red)
48
+ else
49
+ say(Rainbow("\nLinter Succeeded!").green)
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def path_directory
56
+ return path if File.directory?(path)
57
+
58
+ File.dirname(path)
59
+ end
60
+
61
+ def run_rubocop(arguments)
62
+ # We lazy-load RuboCop so that the task doesn't dramatically impact the
63
+ # load time of our commands.
64
+ require 'rubocop'
65
+
66
+ cli = RuboCop::CLI.new
67
+ !cli.run(arguments).nonzero?
68
+ end
69
+
70
+ def run_megalinter(arguments)
71
+ arguments.prepend('time')
72
+
73
+ system(*arguments)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require 'way_of_working/paths'
5
+
6
+ module WayOfWorking
7
+ module CodeLinting
8
+ module Hdi
9
+ module Generators
10
+ # This generator initialises the linter
11
+ class Init < Thor::Group
12
+ # include Thor::Actions
13
+
14
+ # Intialise the linters
15
+ invoke InitLinters
16
+
17
+ # Document the linters
18
+ invoke DocumentLinters
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require 'way_of_working/paths'
5
+
6
+ module WayOfWorking
7
+ module CodeLinting
8
+ module Hdi
9
+ module Generators
10
+ # This generator initialises the linter
11
+ class InitLinters < Thor::Group
12
+ include Thor::Actions
13
+
14
+ source_root ::WayOfWorking::CodeLinting::Hdi.source_root
15
+
16
+ LINTING_BUILD_PHASE =
17
+ " 2F0882F42AAB152D00DB0B2B /* ShellScript */,\n"
18
+ LINTING_BUILD_PHASE_DETAILS = <<~CONFIG
19
+ /* Begin PBXShellScriptBuildPhase section */
20
+ \t\t2F0882F42AAB152D00DB0B2B /* ShellScript */ = {
21
+ \t\t\tisa = PBXShellScriptBuildPhase;
22
+ \t\t\tbuildActionMask = 2147483647;
23
+ \t\t\tfiles = (
24
+ \t\t\t);
25
+ \t\t\tinputFileListPaths = (
26
+ \t\t\t);
27
+ \t\t\tinputPaths = (
28
+ \t\t\t);
29
+ \t\t\toutputFileListPaths = (
30
+ \t\t\t);
31
+ \t\t\toutputPaths = (
32
+ \t\t\t);
33
+ \t\t\trunOnlyForDeploymentPostprocessing = 0;
34
+ \t\t\tshellPath = /bin/sh;
35
+ \t\t\tshellScript = "if [[ \\"$(uname -m)\\" == arm64 ]]; then\\n export PATH=\\"/opt/homebrew/bin:$PATH\\"\\nfi\\n\\nif which swiftlint > /dev/null; then\\n swiftlint\\nelse\\n echo \\"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\\"\\nfi\\n";
36
+ \t\t};
37
+ /* End PBXShellScriptBuildPhase section */
38
+
39
+ CONFIG
40
+
41
+ # TODO: copy_rubocop_github_workflow_action
42
+
43
+ def copy_github_linters_rubocop_config_file
44
+ copy_file '.github/linters/rubocop_defaults.yml'
45
+ end
46
+
47
+ def copy_github_linters_markdown_link_check_config_file
48
+ copy_file '.github/linters/.markdown-link-check.json'
49
+ end
50
+
51
+ def copy_megalinter_github_workflow_action
52
+ copy_file '.github/workflows/mega-linter.yml'
53
+ end
54
+
55
+ def copy_megalinter_dot_file
56
+ copy_file '.mega-linter.yml'
57
+ end
58
+
59
+ def create_gitignore_if_missing
60
+ create_file_if_missing '.gitignore'
61
+ end
62
+
63
+ def gitignore_reports_folder
64
+ append_to_file '.gitignore', "megalinter-reports/\n"
65
+ end
66
+
67
+ def gitignore_rubocop_cached_file
68
+ append_to_file '.gitignore', ".rubocop-https---*\n"
69
+ end
70
+
71
+ def copy_rubocop_options_file
72
+ copy_file '.rubocop'
73
+ end
74
+
75
+ def inject_swiftlint_into_xcode_project_build_process
76
+ return unless xcode_project_file && File.exist?(xcode_project_file)
77
+
78
+ inject_into_file xcode_project_file,
79
+ LINTING_BUILD_PHASE,
80
+ after: "buildPhases = (\n"
81
+
82
+ inject_into_file xcode_project_file,
83
+ LINTING_BUILD_PHASE_DETAILS,
84
+ after: "/* End PBXResourcesBuildPhase section */\n\n"
85
+ end
86
+
87
+ private
88
+
89
+ def xcode_project_file
90
+ Dir.glob(File.join(destination_root, '*.xcodeproj/project.pbxproj')).first
91
+ end
92
+
93
+ def create_file_if_missing(path)
94
+ path = File.join(destination_root, path)
95
+ return if behavior == :revoke || File.exist?(path)
96
+
97
+ File.open(path, 'w', &:write)
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'way_of_working/audit/github/rules/base'
4
+
5
+ module WayOfWorking
6
+ module CodeLinting
7
+ # The namespace for this plugin
8
+ module Hdi
9
+ # This rule checks for the MegaLinter workflow action and README badge.
10
+ class GithubAuditRule < ::WayOfWorking::Audit::Github::Rules::Base
11
+ source_root WayOfWorking::CodeLinting::Hdi.source_root
12
+
13
+ def validate
14
+ workflows = @client.workflows(@repo_name).workflows
15
+ @errors << 'No HDI MegaLinter GitHub Action' unless workflows.map(&:name).include?('MegaLinter')
16
+
17
+ @errors << 'No HDI MegaLinter README Badge' unless megalinter_badge?
18
+
19
+ validate_repo_file_contains_source_file(
20
+ '.github/linters/rubocop_defaults.yml',
21
+ '.mega-linter.yml',
22
+ '.rubocop'
23
+ )
24
+ end
25
+
26
+ private
27
+
28
+ def repo_file_contains_source_file?(path)
29
+ repo_file_contains?(path, File.read(self.class.source_root.join(path)))
30
+ end
31
+
32
+ def repo_file_contains?(path, text)
33
+ remote_content = repo_file_contents(path)
34
+ return false if remote_content.nil?
35
+
36
+ remote_content.include?(text)
37
+ end
38
+
39
+ def validate_repo_file_contains_source_file(*paths)
40
+ paths.each do |path|
41
+ if repo_file_contents(path).nil?
42
+ @errors << "#{path} missing"
43
+ next
44
+ end
45
+
46
+ @errors << "#{path} does not match the source template" unless repo_file_contains_source_file?(path)
47
+ end
48
+ end
49
+
50
+ def megalinter_badge?
51
+ readme_content.include?("[![MegaLinter](https://github.com/#{@repo_name}/workflows/MegaLinter/badge.svg")
52
+ end
53
+ end
54
+
55
+ ::WayOfWorking::Audit::Github::Rules::Registry.register(
56
+ GithubAuditRule, 'HDI MegaLinter GitHub Action and README badge'
57
+ )
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname'
4
+
5
+ module WayOfWorking
6
+ module CodeLinting
7
+ # Mixin that provides a couple of pathname convenience methods
8
+ module Hdi
9
+ class << self
10
+ def root
11
+ Pathname.new(File.expand_path('../../../..', __dir__))
12
+ end
13
+
14
+ def source_root
15
+ root.join('lib', 'way_of_working', 'code_linting', 'hdi', 'templates')
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1 @@
1
+ require 'way_of_working/code_linting/hdi'
@@ -0,0 +1,91 @@
1
+ module WayOfWorking
2
+ module CodeLinting
3
+ module Hdi
4
+ # Struct to hold linter data
5
+ class SupportedLinter
6
+ # Reasons why certain linters are not used
7
+ NOT_USED_REASON = {
8
+ 'CSS_SCSS_LINT' => 'scss-lint recommends using stylelint',
9
+ 'HTML_DJLINT' => 'Refuses to see config file',
10
+ 'RUBY_RUBOCOP' => 'RuboCop is used directly'
11
+ }.freeze
12
+
13
+ # Acronyms for languages
14
+ TLA_LANGUAGES = %w[
15
+ CSS
16
+ ENV
17
+ HTML
18
+ JSON
19
+ JSX
20
+ PHP
21
+ SQL
22
+ TSX
23
+ XML
24
+ YAML
25
+ ].freeze
26
+
27
+ # Mapping for languages
28
+ LANGUAGE_MAPPINGS = {
29
+ 'Action' => 'GitHub Action',
30
+ 'Arm' => 'ARM Templates',
31
+ 'Cloudformation' => 'CloudFormation',
32
+ 'Coffee' => 'CoffeeScript',
33
+ 'Editorconfig' => 'EditorConfig',
34
+ 'Graphql' => 'GraphQL',
35
+ 'Javascript' => 'JavaScript',
36
+ 'Latex' => 'LaTeX',
37
+ 'Protobuf' => 'Protocol Buffers',
38
+ 'Rst' => 'reStructuredText',
39
+ 'Spell' => 'Spelling',
40
+ 'Typescript' => 'TypeScript',
41
+ 'Visual Basic .Net' => 'VB.Net'
42
+ }.freeze
43
+
44
+ attr_accessor :name, :link, :enabled_linters, :sorter
45
+
46
+ def initialize(language, constant_name, name, link, enabled_linters)
47
+ @original_language = language
48
+ @original_constant_name = constant_name
49
+ @name = name
50
+ @link = link
51
+ @enabled_linters = enabled_linters
52
+
53
+ # Array used for sorting
54
+ @sorter = [@original_language, @original_constant_name]
55
+ end
56
+
57
+ def language
58
+ language = @original_language
59
+
60
+ # Titleize language unless it is an acronym
61
+ language = language.titleize unless TLA_LANGUAGES.include?(language)
62
+
63
+ # Use mapped language name if available
64
+ language = LANGUAGE_MAPPINGS[language] if LANGUAGE_MAPPINGS.key?(language)
65
+
66
+ language
67
+ end
68
+
69
+ def constant_name
70
+ return @original_constant_name if enabled_linters.include?(@original_constant_name)
71
+
72
+ # Strike-through the constant name if the linter is not used
73
+ "~~#{@original_constant_name}~~"
74
+ end
75
+
76
+ def details
77
+ return "[#{name}](#{link})" if enabled_linters.include?(@original_constant_name)
78
+
79
+ details = 'Not Used'
80
+
81
+ # Add reason if available
82
+ if NOT_USED_REASON.key?(@original_constant_name)
83
+ details = "#{details} (#{NOT_USED_REASON[@original_constant_name]})"
84
+ end
85
+
86
+ details
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,13 @@
1
+ {
2
+ "ignorePatterns": [
3
+ {
4
+ "pattern": "^0005-example.md"
5
+ },
6
+ {
7
+ "pattern": "^adr-template.md"
8
+ }
9
+ ],
10
+ "retryOn429": true,
11
+ "retryCount": 5,
12
+ "aliveStatusCodes": [ 200, 203 ]
13
+ }