mega-linter-runner 8.8.1-beta202507270753.0 → 8.8.1-beta202507270946.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.
@@ -0,0 +1,163 @@
1
+ import { asciiArt } from "../../lib/ascii.js";
2
+ import Generator from 'yeoman-generator';
3
+ import { simpleGit } from 'simple-git';
4
+ import c from 'chalk';
5
+ import fs from "fs"
6
+ import yaml from "js-yaml";
7
+
8
+ export default class GeneratorMegaLinter extends Generator {
9
+ async prompting() {
10
+ console.log(asciiArt());
11
+ this.log(c.cyan(
12
+ `Welcome to the MegaLinter Custom Flavor generator !
13
+ When you don't know what option to select, please use default values`
14
+ ));
15
+
16
+ // Verify that the repo name contains "megalinter-custom-flavor"
17
+ const git = simpleGit();
18
+ const remote = await git.getRemotes(true);
19
+ if (!remote[0].refs.fetch.includes("megalinter-custom-flavor")) {
20
+ const errorMessage = `
21
+ ERROR: This generator must be run in a repository whose name includes 'megalinter-custom-flavor'
22
+ Example: 'megalinter-custom-flavor-python-light'
23
+ `
24
+ this.log(c.red(c.bold(errorMessage)));
25
+ throw new Error(errorMessage);
26
+ }
27
+ // Fetch https://raw.githubusercontent.com/megalinter/megalinter/main/megalinter/descriptors/schemas/megalinter-configuration.jsonschema.json
28
+ this.log("Fetching MegaLinter configuration schema...");
29
+ const url = 'https://raw.githubusercontent.com/megalinter/megalinter/main/megalinter/descriptors/schemas/megalinter-configuration.jsonschema.json';
30
+ const response = await fetch(url);
31
+ if (!response.ok) {
32
+ throw new Error(`Failed to fetch schema from ${url}`);
33
+ }
34
+ const schema = await response.json();
35
+ const linterKeys = schema.definitions.enum_linter_keys.enum || [];
36
+
37
+ let defaultFlavorLabel = "MyCustomFlavor";
38
+ let defaultSelectedLinters = [];
39
+ if (globalThis.customFlavorLinters) {
40
+ // Check if linters are valid , and crash if there is an invalid linter key
41
+ globalThis.customFlavorLinters.forEach((linter) => {
42
+ if (!linterKeys.includes(linter)) {
43
+ throw new Error(`Invalid linter key: ${linter}`);
44
+ }
45
+ });
46
+ defaultSelectedLinters = globalThis.customFlavorLinters;
47
+ }
48
+ else {
49
+ // Initialize data from existing configuration
50
+ const customFlavorConfigPath = this.destinationPath('megalinter-custom-flavor.yml');
51
+ if (fs.existsSync(customFlavorConfigPath)) {
52
+ const customFlavorConfigContent = fs.readFileSync(customFlavorConfigPath, 'utf8');
53
+ const customFlavorConfig = yaml.load(customFlavorConfigContent);
54
+ if (customFlavorConfig.label) {
55
+ defaultFlavorLabel = customFlavorConfig.label;
56
+ }
57
+ if (customFlavorConfig.linters) {
58
+ defaultSelectedLinters = customFlavorConfig.linters.map((linter) => linter.replace(/^\s*-\s*/, '').trim());
59
+ }
60
+ }
61
+ }
62
+
63
+ const prompts = [
64
+ {
65
+ type: 'input',
66
+ name: 'customFlavorLabel',
67
+ message: 'What is the label of your custom flavor?',
68
+ default: defaultFlavorLabel
69
+ },
70
+ {
71
+ type: 'checkbox',
72
+ name: 'selectedLinters',
73
+ message: 'Please select the linters you want to include in your custom flavor:',
74
+ choices: linterKeys,
75
+ default: defaultSelectedLinters
76
+ }
77
+ ];
78
+
79
+ return this.prompt(prompts).then(async (props) => {
80
+ this.props = props;
81
+ await this._computeValues();
82
+ });
83
+ }
84
+
85
+ writing() {
86
+ this._generateFlavorConfig();
87
+ this._generateGitHubWorkflow();
88
+ this._generateGitHubAction();
89
+ this._generateReadme();
90
+ }
91
+
92
+ end() {
93
+ this.log("You're all set !");
94
+ this.log(c.green(
95
+ "Now commit, push then create a GitHub Release to generate your custom flavor !")
96
+ );
97
+ }
98
+
99
+ async _computeValues() {
100
+ // Custom flavor label
101
+ this.customFlavorLabel = this.props.customFlavorLabel;
102
+ // Custom flavor selected linters
103
+ this.selectedLinters = this.props.selectedLinters.map((linter) => ` - ${linter}`).join("\n");
104
+ // Check at least one linter is selected
105
+ if (this.selectedLinters.length === 0) {
106
+ throw new Error("You must select at least one linter for your custom flavor");
107
+ }
108
+ // Custom flavor author is git username
109
+ const git = simpleGit();
110
+ const user = await git.getConfig('user.name');
111
+ this.customFlavorAuthor = user.value;
112
+ // Get remote repo
113
+ const remote = await git.getRemotes(true);
114
+ this.customFlavorRepo = remote[0].refs.fetch.replace('https://github.com/', '').replace('.git', '');
115
+ // Custom flavor docker image version
116
+ this.customFlavorDockerImageVersion = `ghcr.io/${this.customFlavorRepo}/megalinter-custom-flavor:latest`;
117
+ }
118
+
119
+ _generateFlavorConfig() {
120
+ this.fs.copyTpl(
121
+ this.templatePath("megalinter-custom-flavor.yml"),
122
+ this.destinationPath(`megalinter-custom-flavor.yml`),
123
+ {
124
+ CUSTOM_FLAVOR_LABEL: this.customFlavorLabel,
125
+ CUSTOM_FLAVOR_LINTERS: this.selectedLinters,
126
+ }
127
+ );
128
+ }
129
+
130
+ _generateGitHubWorkflow() {
131
+ this.fs.copyTpl(
132
+ this.templatePath("megalinter-custom-flavor-builder.yml"),
133
+ this.destinationPath("./.github/workflows/megalinter-custom-flavor-builder.yml"),
134
+ {}
135
+ );
136
+ }
137
+
138
+ _generateGitHubAction() {
139
+ this.fs.copyTpl(
140
+ this.templatePath("action.yml"),
141
+ this.destinationPath("action.yml"),
142
+ {
143
+ CUSTOM_FLAVOR_LABEL: this.customFlavorLabel,
144
+ CUSTOM_FLAVOR_AUTHOR: this.customFlavorAuthor,
145
+ DOCKER_IMAGE_VERSION: this.customFlavorDockerImageVersion,
146
+ }
147
+ );
148
+ }
149
+
150
+ _generateReadme() {
151
+ this.fs.copyTpl(
152
+ this.templatePath("README.md"),
153
+ this.destinationPath("README.md"),
154
+ {
155
+ CUSTOM_FLAVOR_LABEL: this.customFlavorLabel,
156
+ CUSTOM_FLAVOR_LINTERS: this.selectedLinters,
157
+ DOCKER_IMAGE_VERSION: this.customFlavorDockerImageVersion,
158
+ CUSTOM_FLAVOR_GITHUB_ACTION: this.customFlavorRepo
159
+ }
160
+ );
161
+ }
162
+
163
+ }
@@ -0,0 +1,20 @@
1
+ # MegaLinter Custom Flavor
2
+
3
+ <%= CUSTOM_FLAVOR_LABEL %>
4
+
5
+ ## Embedded linters
6
+
7
+ <%= CUSTOM_FLAVOR_LINTERS %>
8
+
9
+ ## How to generate the flavor
10
+
11
+ Create a GitHub release on your repo, it will generate and publish your custom flavor using the MegaLinter custom Flavor Builder matching the tag name of your release (example: `9.0.0`)
12
+
13
+ You can also generate a custom flavor using MegaLinter Custom Flavor by pushing on any branch or manually run the workflow `megalinter-custom-flavor-builder.yml`.
14
+
15
+ ## How to use the custom flavor
16
+
17
+ Follow [MegaLinter installation guide](https://megalinter.io/latest/install-assisted/), and replace related elements in the workflow.
18
+
19
+ - GitHub Action: On MegaLinter step in .github/workflows/mega-linter.yml, define `uses: <%= CUSTOM_FLAVOR_GITHUB_ACTION %>@main`
20
+ - Docker image: Replace official MegaLinter image by `<%= DOCKER_IMAGE_VERSION %>`
@@ -0,0 +1,16 @@
1
+ name: "MegaLinter Custom Flavor: <%= CUSTOM_FLAVOR_LABEL %>"
2
+ author: "<%= CUSTOM_FLAVOR_AUTHOR %>"
3
+ description: "MegaLinter Custom Flavor <%= CUSTOM_FLAVOR_LABEL %>"
4
+ outputs:
5
+ has_updated_sources:
6
+ description: "0 if no source file has been updated, 1 if source files has been updated"
7
+ runs:
8
+ using: "docker"
9
+ # You can manually update the Docker image version here, or use the latest tag
10
+ image: "docker://<%= DOCKER_IMAGE_VERSION %>"
11
+ args:
12
+ - "-v"
13
+ - "/var/run/docker.sock:/var/run/docker.sock:rw"
14
+ branding:
15
+ icon: "check"
16
+ color: "green"
@@ -0,0 +1,80 @@
1
+ # =============================================================
2
+ # Build MegaLinter Custom Flavor Workflow
3
+ #
4
+ # This workflow builds and publishes a custom MegaLinter Docker image
5
+ # to GitHub Container Registry (ghcr.io) and optionally Docker Hub.
6
+ #
7
+ # Usage:
8
+ # - Triggers on push, release, or manual dispatch.
9
+ # - Tags the image with the release tag (on release) or 'alpha' (otherwise).
10
+ # - Pushes to ghcr.io and, if credentials are set, to Docker Hub.
11
+ #
12
+ # Required repository secrets:
13
+ # - GITHUB_TOKEN: Provided by GitHub Actions (for ghcr.io push)
14
+ # - DOCKERHUB_USERNAME: (optional) Docker Hub username for push
15
+ # - DOCKERHUB_PASSWORD: (optional) Docker Hub password/token for push
16
+ #
17
+ # Optional repository variables:
18
+ # - DOCKERHUB_REPO: Docker Hub repository name (e.g. nvuillam)
19
+ #
20
+ # The MegaLinter custom flavor image will be available at:
21
+ # - ghcr.io/<owner>/<repo>:<tag>
22
+ # - docker.io/<dockerhub_repo>/<repo>:<tag> (if Docker Hub credentials are set)
23
+ # =============================================================
24
+
25
+ name: Build & Push MegaLinter Custom Flavor
26
+
27
+ on:
28
+ push:
29
+ branches-ignore: [main]
30
+ release:
31
+ types: [edited, published]
32
+ workflow_dispatch:
33
+
34
+ concurrency:
35
+ group: ${{ github.workflow }}-${{ github.ref }}
36
+ cancel-in-progress: true
37
+
38
+ jobs:
39
+ build-custom-flavor:
40
+ name: Build Custom MegaLinter Flavor
41
+ runs-on: ubuntu-latest
42
+ permissions:
43
+ contents: read
44
+ packages: write
45
+
46
+ steps:
47
+ - name: Checkout Code
48
+ uses: actions/checkout@v4
49
+ with:
50
+ fetch-depth: 0
51
+
52
+ - name: Log in to GitHub Container Registry
53
+ uses: docker/login-action@v3
54
+ with:
55
+ registry: ghcr.io
56
+ username: ${{ github.actor }}
57
+ password: ${{ secrets.GITHUB_TOKEN }}
58
+
59
+ # Log in to Docker Hub only if credentials are provided
60
+ - name: Log in to Docker Hub
61
+ uses: docker/login-action@v3
62
+ with:
63
+ registry: docker.io
64
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
65
+ password: ${{ secrets.DOCKERHUB_PASSWORD }}
66
+ continue-on-error: true
67
+
68
+ - name: Build MegaLinter Custom Flavor
69
+ uses: oxsecurity/megalinter/flavors/custom-builder@main
70
+ with:
71
+ megalinter-custom-flavor-builder-tag: ${{ github.event_name == 'release' && github.event.release.tag_name || 'beta' }}
72
+ is-latest: ${{ github.event_name == 'release' && 'true' || 'false' }}
73
+ upload-to-ghcr: "true"
74
+ upload-to-dockerhub: ${{ secrets.DOCKERHUB_USERNAME != '' && secrets.DOCKERHUB_PASSWORD != '' && 'true' || 'false' }}
75
+ dockerhub-repo: ${{ vars.DOCKERHUB_REPO }}
76
+ env:
77
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
78
+ CUSTOM_FLAVOR_BUILD_REPO: ${{ github.repository }}
79
+ CUSTOM_FLAVOR_BUILD_REPO_URL: ${{ github.repositoryUrl }}
80
+ CUSTOM_FLAVOR_BUILD_USER: ${{ github.actor }}
@@ -0,0 +1,6 @@
1
+ # MegaLinter Custom Flavor configuration
2
+ # If you update it manually, run `npx mega-linter-runner --custom-flavor-setup` to propagate updates.
3
+
4
+ label: <%= CUSTOM_FLAVOR_LABEL %>
5
+ linters:
6
+ <%= CUSTOM_FLAVOR_LINTERS %>
package/lib/options.js CHANGED
@@ -122,6 +122,17 @@ export const optionsDefinition = optionator.default({
122
122
  type: "Boolean",
123
123
  description: "Generate MegaLinter configuration in your project",
124
124
  },
125
+ {
126
+ option: "custom-flavor-setup",
127
+ alias: "cfs",
128
+ type: "Boolean",
129
+ description: "Generate files to create a custom flavor",
130
+ },
131
+ {
132
+ option: "custom-flavor-linters",
133
+ type: "String",
134
+ description: "comma-separated list of linters to include in custom flavor",
135
+ },
125
136
  {
126
137
  option: "upgrade",
127
138
  alias: "u",
package/lib/runner.js CHANGED
@@ -54,6 +54,21 @@ export class MegaLinterRunner {
54
54
  return { status: 0 };
55
55
  }
56
56
 
57
+ // Run custom flavor generator
58
+ if (options.customFlavorSetup) {
59
+ if (options.customFlavorLinters) {
60
+ globalThis.customFlavorLinters = options.customFlavorLinters.split(",").map((linter) => linter.trim());
61
+ }
62
+ const env = createEnv();
63
+ const __dirname = dirname(fileURLToPath(import.meta.url));
64
+ const generatorPath = path.resolve(
65
+ path.join(__dirname, "..", "generators", "mega-linter-custom-flavor")
66
+ );
67
+ console.log("Yeoman generator used: " + generatorPath);
68
+ env.run(generatorPath);
69
+ return { status: 0 };
70
+ }
71
+
57
72
  // Run upgrader from v4 to v5
58
73
  if (options.upgrade) {
59
74
  const megaLinterUpgrader = new MegaLinterUpgrader();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mega-linter-runner",
3
- "version": "8.8.1-beta202507270753.0",
3
+ "version": "8.8.1-beta202507270946.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/oxsecurity/megalinter.git"
@@ -82,14 +82,16 @@
82
82
  "author": "Nicolas Vuillamy",
83
83
  "license": "MIT",
84
84
  "dependencies": {
85
- "chalk": "^5.3.0",
85
+ "chalk": "^5.4.1",
86
86
  "find-package-json": "^1.2.0",
87
87
  "fs-extra": "^11.1.1",
88
88
  "glob": "^11.0.0",
89
+ "js-yaml": "^4.1.0",
89
90
  "mem-fs": "^4.0.0",
90
91
  "open": "^10.0.2",
91
92
  "optionator": "^0.9.3",
92
93
  "prompts": "^2.4.2",
94
+ "simple-git": "^3.28.0",
93
95
  "uuid": "^11.0.0",
94
96
  "which": "^5.0.0",
95
97
  "yeoman-environment": "^4.0.0",