way_of_working-code_linting-hdi 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }