mega-linter-runner 9.4.0 → 9.6.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.
- package/README.md +160 -144
- package/generators/mega-linter/index.js +9 -0
- package/generators/mega-linter/templates/bitbucket-pipelines.yml +20 -19
- package/generators/mega-linter/templates/mega-linter.yml +22 -3
- package/generators/mega-linter-custom-flavor/templates/README.md +8 -2
- package/generators/mega-linter-custom-flavor/templates/action.yml +0 -3
- package/generators/mega-linter-custom-flavor/templates/check-new-megalinter-version.yml +27 -38
- package/generators/mega-linter-custom-flavor/templates/megalinter-custom-flavor-builder.yml +19 -8
- package/lib/cli.js +0 -1
- package/lib/env-parser.js +28 -0
- package/lib/index.js +0 -0
- package/lib/list-vars.js +100 -0
- package/lib/megalinter-vars.json +29873 -0
- package/lib/options.js +115 -32
- package/lib/runner.js +33 -6
- package/lib/upgrade.js +22 -15
- package/package.json +10 -7
|
@@ -191,6 +191,14 @@ When you don't know what option to select, please use default values`
|
|
|
191
191
|
this.validateAllCodeBaseGha += " github.ref == 'refs/heads/main'"
|
|
192
192
|
this.validateAllCodeBaseGha += " }}";
|
|
193
193
|
}
|
|
194
|
+
// persist-credentials
|
|
195
|
+
if (this.props.applyFixes === true) {
|
|
196
|
+
this.persistCredentials =
|
|
197
|
+
"# persist-credentials: false # Comment this line and uncomment the next one if you use APPLY_FIXES\n persist-credentials: true # zizmor: ignore[artipacked]";
|
|
198
|
+
} else {
|
|
199
|
+
this.persistCredentials =
|
|
200
|
+
"persist-credentials: false # Comment this line and uncomment the next one if you use APPLY_FIXES\n # persist-credentials: true # zizmor: ignore[artipacked]";
|
|
201
|
+
}
|
|
194
202
|
this.disable = false;
|
|
195
203
|
// COPY PASTES
|
|
196
204
|
if (this.props.copyPaste === true) {
|
|
@@ -224,6 +232,7 @@ When you don't know what option to select, please use default values`
|
|
|
224
232
|
DEFAULT_BRANCH: this.props.defaultBranch,
|
|
225
233
|
GITHUB_ACTION_NAME: this.gitHubActionName,
|
|
226
234
|
GITHUB_ACTION_VERSION: this.gitHubActionVersion,
|
|
235
|
+
PERSIST_CREDENTIALS: this.persistCredentials,
|
|
227
236
|
VALIDATE_ALL_CODE_BASE_GHA: this.validateAllCodeBaseGha,
|
|
228
237
|
}
|
|
229
238
|
);
|
|
@@ -4,22 +4,23 @@
|
|
|
4
4
|
image: atlassian/default-image:5
|
|
5
5
|
|
|
6
6
|
pipelines:
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
7
|
+
pull-requests: # Note: Bitbucket PR comment reporting requires pull request context
|
|
8
|
+
"**": # Run on PRs for any branch (the source branch of the pull request)
|
|
9
|
+
- parallel:
|
|
10
|
+
- step:
|
|
11
|
+
name: Run MegaLinter
|
|
12
|
+
image: <%= DOCKER_IMAGE_NAME %>:<%= DOCKER_IMAGE_VERSION %>
|
|
13
|
+
script:
|
|
14
|
+
# Disable LLM Advisor for bot PRs (dependabot, renovate, etc.)
|
|
15
|
+
# Note: Bitbucket has limited access to PR metadata, this is a basic check
|
|
16
|
+
- |
|
|
17
|
+
if [[ "$BITBUCKET_BRANCH" =~ ^(dependabot|renovate)/ ]] ||
|
|
18
|
+
[[ "$BITBUCKET_PR_TITLE" =~ ^(chore|fix|deps?|bump)(\(.*\))?: ]] ||
|
|
19
|
+
[[ "$BITBUCKET_STEP_TRIGGERER_UUID" =~ dependabot|renovate ]]; then
|
|
20
|
+
export LLM_ADVISOR_ENABLED=false
|
|
21
|
+
else
|
|
22
|
+
export LLM_ADVISOR_ENABLED=true
|
|
23
|
+
fi
|
|
24
|
+
- export DEFAULT_WORKSPACE=$BITBUCKET_CLONE_DIR && bash /entrypoint.sh
|
|
25
|
+
artifacts:
|
|
26
|
+
- megalinter-reports/**
|
|
@@ -35,6 +35,8 @@ concurrency:
|
|
|
35
35
|
group: ${{ github.ref }}-${{ github.workflow }}
|
|
36
36
|
cancel-in-progress: true
|
|
37
37
|
|
|
38
|
+
permissions: {}
|
|
39
|
+
|
|
38
40
|
jobs:
|
|
39
41
|
megalinter:
|
|
40
42
|
name: MegaLinter
|
|
@@ -52,7 +54,17 @@ jobs:
|
|
|
52
54
|
- name: Checkout Code
|
|
53
55
|
uses: actions/checkout@v6
|
|
54
56
|
with:
|
|
57
|
+
# SECURITY NOTE: Using a Personal Access Token (PAT) is NOT
|
|
58
|
+
# recommended. Open-source projects have been heavily targeted by
|
|
59
|
+
# supply-chain attacks in recent months, and a leaked PAT can give
|
|
60
|
+
# attackers broad write access to your repository — better safe
|
|
61
|
+
# than sorry! If you only need workflows to re-trigger after
|
|
62
|
+
# MegaLinter applies fixes, prefer one of these safer alternatives:
|
|
63
|
+
# - Manually re-run the workflow from the GitHub Actions tab, or
|
|
64
|
+
# - Push another commit on the branch to trigger workflows again.
|
|
65
|
+
# Only define `secrets.PAT` if you fully understand the trade-off.
|
|
55
66
|
token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }}
|
|
67
|
+
<%- PERSIST_CREDENTIALS %>
|
|
56
68
|
|
|
57
69
|
# If you use VALIDATE_ALL_CODEBASE = true, you can remove this line to
|
|
58
70
|
# improve performance
|
|
@@ -124,7 +136,7 @@ jobs:
|
|
|
124
136
|
# Create pull request if applicable
|
|
125
137
|
# (for now works only on PR from same repository, not from forks)
|
|
126
138
|
- name: Create Pull Request with applied fixes
|
|
127
|
-
uses: peter-evans/create-pull-request@
|
|
139
|
+
uses: peter-evans/create-pull-request@v8
|
|
128
140
|
id: cpr
|
|
129
141
|
if: >-
|
|
130
142
|
steps.ml.outputs.has_updated_sources == 1 &&
|
|
@@ -139,6 +151,10 @@ jobs:
|
|
|
139
151
|
) &&
|
|
140
152
|
!contains(github.event.head_commit.message, 'skip fix')
|
|
141
153
|
with:
|
|
154
|
+
# SECURITY NOTE: see the warning on the checkout step above —
|
|
155
|
+
# using `secrets.PAT` is NOT recommended for security reasons.
|
|
156
|
+
# Prefer manually re-running the workflow or pushing another
|
|
157
|
+
# commit on the branch to trigger workflows again.
|
|
142
158
|
token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }}
|
|
143
159
|
commit-message: "[MegaLinter] Apply linters automatic fixes"
|
|
144
160
|
title: "[MegaLinter] Apply linters automatic fixes"
|
|
@@ -157,9 +173,12 @@ jobs:
|
|
|
157
173
|
github.event.pull_request.head.repo.full_name == github.repository
|
|
158
174
|
) &&
|
|
159
175
|
!contains(github.event.head_commit.message, 'skip fix')
|
|
176
|
+
env:
|
|
177
|
+
PR_NUMBER: ${{ steps.cpr.outputs.pull-request-number }}
|
|
178
|
+
PR_URL: ${{ steps.cpr.outputs.pull-request-url }}
|
|
160
179
|
run: |
|
|
161
|
-
echo "PR Number - ${
|
|
162
|
-
echo "PR URL - ${
|
|
180
|
+
echo "PR Number - ${PR_NUMBER}"
|
|
181
|
+
echo "PR URL - ${PR_URL}"
|
|
163
182
|
|
|
164
183
|
# Push new commit if applicable
|
|
165
184
|
# (for now works only on PR from same repository, not from forks)
|
|
@@ -33,14 +33,20 @@ This custom flavor is automatically kept up to date with MegaLinter releases:
|
|
|
33
33
|
|
|
34
34
|
## Configuration requirements
|
|
35
35
|
|
|
36
|
-
###
|
|
36
|
+
### Optional: Personal Access Token (use with care)
|
|
37
|
+
|
|
38
|
+
> **Security warning**: Using a Personal Access Token (PAT) is **not recommended**. Open-source projects have been heavily targeted by supply-chain attacks in recent months, and a leaked or compromised PAT can give attackers broad write access to your repository — better safe than sorry!
|
|
39
|
+
> If you do not need fully automatic daily version sync, you can skip the PAT entirely and trigger the `check-new-megalinter-version` workflow manually whenever you want to upgrade.
|
|
40
|
+
|
|
41
|
+
If you decide automatic daily releases are worth the trade-off, configure a `PAT_TOKEN` secret as a **repository-scoped fine-grained token** with:
|
|
37
42
|
|
|
38
|
-
For automatic version checking to work, a `PAT_TOKEN` secret must be configured as a **repository-scoped fine-grained token** with:
|
|
39
43
|
- **Repository access**: Only select repositories (select this repository)
|
|
40
44
|
- **Repository permissions**:
|
|
41
45
|
- Contents: Read and write
|
|
42
46
|
- Actions: Read and write
|
|
43
47
|
|
|
48
|
+
Rotate the token regularly.
|
|
49
|
+
|
|
44
50
|
See the [Custom Flavors documentation](https://megalinter.io/beta/custom-flavors/) for detailed setup instructions.
|
|
45
51
|
|
|
46
52
|
### Optional: Docker Hub publishing
|
|
@@ -9,9 +9,6 @@ runs:
|
|
|
9
9
|
using: "docker"
|
|
10
10
|
# You can manually update the Docker image version here, or use the latest tag
|
|
11
11
|
image: "docker://<%= DOCKER_IMAGE_VERSION %>"
|
|
12
|
-
args:
|
|
13
|
-
- "-v"
|
|
14
|
-
- "/var/run/docker.sock:/var/run/docker.sock:rw"
|
|
15
12
|
branding:
|
|
16
13
|
icon: "check"
|
|
17
14
|
color: "green"
|
|
@@ -26,7 +26,17 @@
|
|
|
26
26
|
# This is required to trigger the builder workflow. Without it, the workflow
|
|
27
27
|
# will fail and the release will be deleted (to be recreated once the token is set).
|
|
28
28
|
#
|
|
29
|
-
#
|
|
29
|
+
# SECURITY WARNING: Using a PAT comes with risk. Open-source projects have been
|
|
30
|
+
# heavily targeted by supply-chain attacks in recent months, and a leaked or
|
|
31
|
+
# compromised PAT can give attackers broad write access to your repository —
|
|
32
|
+
# better safe than sorry! If you do not need fully automatic daily version
|
|
33
|
+
# sync, you can skip the PAT entirely and trigger this workflow manually
|
|
34
|
+
# (Actions tab → "Check for New MegaLinter Version" → "Run workflow") whenever
|
|
35
|
+
# you want to bump to a new MegaLinter release. Only configure PAT_TOKEN if
|
|
36
|
+
# the daily automation is worth the trade-off, and always scope it to this
|
|
37
|
+
# single repository with the minimum required permissions.
|
|
38
|
+
#
|
|
39
|
+
# To create a Fine-grained PAT (still discouraged unless you need automation):
|
|
30
40
|
# 1. Go to GitHub Settings > Developer settings > Personal access tokens > Fine-grained tokens
|
|
31
41
|
# 2. Click "Generate new token"
|
|
32
42
|
# 3. Give it a descriptive name (e.g., "MegaLinter Auto-Release")
|
|
@@ -62,6 +72,7 @@ jobs:
|
|
|
62
72
|
uses: actions/checkout@v6
|
|
63
73
|
with:
|
|
64
74
|
fetch-depth: 0
|
|
75
|
+
persist-credentials: false
|
|
65
76
|
|
|
66
77
|
- name: Fetch MegaLinter Repository Tags
|
|
67
78
|
id: fetch-megalinter-tags
|
|
@@ -109,12 +120,12 @@ jobs:
|
|
|
109
120
|
|
|
110
121
|
- name: Find New Version
|
|
111
122
|
id: find-new-version
|
|
123
|
+
env:
|
|
124
|
+
LATEST_MEGALINTER_TAG: ${{ steps.fetch-megalinter-tags.outputs.latest_tag }}
|
|
125
|
+
LATEST_REPO_TAG: ${{ steps.fetch-repo-tags.outputs.latest_repo_tag }}
|
|
112
126
|
run: |
|
|
113
127
|
echo "Comparing versions..."
|
|
114
128
|
|
|
115
|
-
LATEST_MEGALINTER_TAG="${{ steps.fetch-megalinter-tags.outputs.latest_tag }}"
|
|
116
|
-
LATEST_REPO_TAG="${{ steps.fetch-repo-tags.outputs.latest_repo_tag }}"
|
|
117
|
-
|
|
118
129
|
echo "Latest MegaLinter tag: $LATEST_MEGALINTER_TAG"
|
|
119
130
|
echo "Latest repository tag: $LATEST_REPO_TAG"
|
|
120
131
|
|
|
@@ -170,11 +181,10 @@ jobs:
|
|
|
170
181
|
# Use PAT_TOKEN if available, otherwise fall back to GITHUB_TOKEN
|
|
171
182
|
# Note: GITHUB_TOKEN doesn't have permission to trigger workflows
|
|
172
183
|
GITHUB_TOKEN: ${{ secrets.PAT_TOKEN || secrets.GITHUB_TOKEN }}
|
|
184
|
+
NEW_VERSION: ${{ steps.find-new-version.outputs.new_version }}
|
|
173
185
|
run: |
|
|
174
186
|
echo "Triggering megalinter-custom-flavor-builder workflow..."
|
|
175
187
|
|
|
176
|
-
NEW_VERSION="${{ steps.find-new-version.outputs.new_version }}"
|
|
177
|
-
|
|
178
188
|
# Trigger the workflow using GitHub CLI and capture output
|
|
179
189
|
set +e # Don't exit immediately on error
|
|
180
190
|
gh workflow run megalinter-custom-flavor-builder.yml \
|
|
@@ -212,12 +222,12 @@ jobs:
|
|
|
212
222
|
echo "::error::2. Token name: 'MegaLinter Auto-Release'"
|
|
213
223
|
echo "::error::3. Expiration: Choose 90 days or 1 year"
|
|
214
224
|
echo "::error::4. Repository access: Select 'Only select repositories'"
|
|
215
|
-
echo "::error::5. Choose repository: ${
|
|
225
|
+
echo "::error::5. Choose repository: ${GITHUB_REPOSITORY}"
|
|
216
226
|
echo "::error::6. Repository permissions:"
|
|
217
227
|
echo "::error:: - Contents: Read and write"
|
|
218
228
|
echo "::error:: - Actions: Read and write"
|
|
219
229
|
echo "::error::7. Click 'Generate token' and copy it"
|
|
220
|
-
echo "::error::8. Go to: https://github.com/${
|
|
230
|
+
echo "::error::8. Go to: https://github.com/${GITHUB_REPOSITORY}/settings/secrets/actions"
|
|
221
231
|
echo "::error::9. Click 'New repository secret'"
|
|
222
232
|
echo "::error::10. Name: 'PAT_TOKEN', Value: paste your token"
|
|
223
233
|
echo "::error::"
|
|
@@ -231,43 +241,22 @@ jobs:
|
|
|
231
241
|
|
|
232
242
|
- name: Summary
|
|
233
243
|
if: always()
|
|
244
|
+
env:
|
|
245
|
+
LATEST_MEGALINTER_TAG: ${{ steps.fetch-megalinter-tags.outputs.latest_tag }}
|
|
246
|
+
LATEST_REPO_TAG: ${{ steps.fetch-repo-tags.outputs.latest_repo_tag }}
|
|
247
|
+
NEW_VERSION_FOUND: ${{ steps.find-new-version.outputs.new_version_found }}
|
|
248
|
+
NEW_VERSION: ${{ steps.find-new-version.outputs.new_version }}
|
|
249
|
+
GH_REPO: ${GITHUB_REPOSITORY}
|
|
234
250
|
run: |
|
|
235
251
|
echo "## Check for New MegaLinter Version Summary" >> $GITHUB_STEP_SUMMARY
|
|
236
252
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
237
253
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
if [ "${{ steps.find-new-version.outputs.new_version_found }}" == "true" ]; then
|
|
242
|
-
echo "✅ New version found: **${{ steps.find-new-version.outputs.new_version }}**" >> $GITHUB_STEP_SUMMARY
|
|
254
|
+
if [ "${NEW_VERSION_FOUND}" == "true" ]; then
|
|
255
|
+
echo "New version found: **${NEW_VERSION}**" >> $GITHUB_STEP_SUMMARY
|
|
243
256
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
244
257
|
echo "A new release has been created, which will trigger the custom flavor builder workflow." >> $GITHUB_STEP_SUMMARY
|
|
245
|
-
|
|
246
|
-
# Check if PAT_TOKEN is configured
|
|
247
|
-
if [ -z "${{ secrets.PAT_TOKEN }}" ]; then
|
|
248
|
-
echo "" >> $GITHUB_STEP_SUMMARY
|
|
249
|
-
echo "### ⚠️ REQUIRED: Configure PAT_TOKEN" >> $GITHUB_STEP_SUMMARY
|
|
250
|
-
echo "" >> $GITHUB_STEP_SUMMARY
|
|
251
|
-
echo "**PAT_TOKEN is required to trigger the builder workflow and create releases.**" >> $GITHUB_STEP_SUMMARY
|
|
252
|
-
echo "" >> $GITHUB_STEP_SUMMARY
|
|
253
|
-
echo "Without it, releases will be automatically deleted and the workflow will fail." >> $GITHUB_STEP_SUMMARY
|
|
254
|
-
echo "" >> $GITHUB_STEP_SUMMARY
|
|
255
|
-
echo "**To create a Fine-grained Personal Access Token (recommended - more secure):**" >> $GITHUB_STEP_SUMMARY
|
|
256
|
-
echo "1. Go to [GitHub Settings > Personal access tokens > Fine-grained tokens](https://github.com/settings/personal-access-tokens/new)" >> $GITHUB_STEP_SUMMARY
|
|
257
|
-
echo "2. Token name: \`MegaLinter Auto-Release\`" >> $GITHUB_STEP_SUMMARY
|
|
258
|
-
echo "3. Expiration: Choose 90 days or 1 year" >> $GITHUB_STEP_SUMMARY
|
|
259
|
-
echo "4. Repository access: **Only select repositories**" >> $GITHUB_STEP_SUMMARY
|
|
260
|
-
echo "5. Choose repository: \`${{ github.repository }}\`" >> $GITHUB_STEP_SUMMARY
|
|
261
|
-
echo "6. Repository permissions:" >> $GITHUB_STEP_SUMMARY
|
|
262
|
-
echo " - **Contents**: Read and write" >> $GITHUB_STEP_SUMMARY
|
|
263
|
-
echo " - **Actions**: Read and write" >> $GITHUB_STEP_SUMMARY
|
|
264
|
-
echo "7. Click **Generate token** and copy it" >> $GITHUB_STEP_SUMMARY
|
|
265
|
-
echo "8. Go to [Repository Settings > Secrets](https://github.com/${{ github.repository }}/settings/secrets/actions)" >> $GITHUB_STEP_SUMMARY
|
|
266
|
-
echo "9. Click **New repository secret**" >> $GITHUB_STEP_SUMMARY
|
|
267
|
-
echo "10. Name: \`PAT_TOKEN\`, Value: paste your token" >> $GITHUB_STEP_SUMMARY
|
|
268
|
-
fi
|
|
269
258
|
else
|
|
270
|
-
echo "
|
|
259
|
+
echo "No new versions found. Repository is up to date with MegaLinter." >> $GITHUB_STEP_SUMMARY
|
|
271
260
|
fi
|
|
272
261
|
|
|
273
262
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
@@ -45,6 +45,8 @@ concurrency:
|
|
|
45
45
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
46
46
|
cancel-in-progress: true
|
|
47
47
|
|
|
48
|
+
permissions: {}
|
|
49
|
+
|
|
48
50
|
jobs:
|
|
49
51
|
build-custom-flavor:
|
|
50
52
|
name: Build Custom MegaLinter Flavor
|
|
@@ -61,12 +63,17 @@ jobs:
|
|
|
61
63
|
|
|
62
64
|
- name: Determine MegaLinter Version Tag
|
|
63
65
|
id: determine-tag
|
|
66
|
+
env:
|
|
67
|
+
INPUT_MEGALINTER_VERSION: ${{ inputs.megalinter-version }}
|
|
68
|
+
INPUT_IS_LATEST: ${{ inputs.is-latest }}
|
|
69
|
+
EVENT_NAME: ${{ github.event_name }}
|
|
70
|
+
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
|
64
71
|
run: |
|
|
65
|
-
if [ -n "${
|
|
66
|
-
TAG="${
|
|
72
|
+
if [ -n "${INPUT_MEGALINTER_VERSION}" ]; then
|
|
73
|
+
TAG="${INPUT_MEGALINTER_VERSION}"
|
|
67
74
|
echo "Using workflow input version: $TAG"
|
|
68
|
-
elif [ "${
|
|
69
|
-
TAG="${
|
|
75
|
+
elif [ "${EVENT_NAME}" == "release" ]; then
|
|
76
|
+
TAG="${RELEASE_TAG}"
|
|
70
77
|
echo "Using release tag: $TAG"
|
|
71
78
|
else
|
|
72
79
|
TAG="beta"
|
|
@@ -75,10 +82,10 @@ jobs:
|
|
|
75
82
|
echo "tag=$TAG" >> $GITHUB_OUTPUT
|
|
76
83
|
|
|
77
84
|
# Determine is-latest flag
|
|
78
|
-
if [ "${
|
|
79
|
-
IS_LATEST="${
|
|
85
|
+
if [ "${EVENT_NAME}" == "workflow_dispatch" ]; then
|
|
86
|
+
IS_LATEST="${INPUT_IS_LATEST}"
|
|
80
87
|
echo "Using workflow input is-latest: $IS_LATEST"
|
|
81
|
-
elif [ "${
|
|
88
|
+
elif [ "${EVENT_NAME}" == "release" ]; then
|
|
82
89
|
IS_LATEST="true"
|
|
83
90
|
echo "Release event - is-latest: true"
|
|
84
91
|
else
|
|
@@ -103,6 +110,10 @@ jobs:
|
|
|
103
110
|
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
|
104
111
|
continue-on-error: true
|
|
105
112
|
|
|
113
|
+
- name: Set Lowercase Repository Name
|
|
114
|
+
id: lowercase-repo
|
|
115
|
+
run: echo "repo=$(echo "${GITHUB_REPOSITORY}" | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
|
|
116
|
+
|
|
106
117
|
- name: Build MegaLinter Custom Flavor
|
|
107
118
|
uses: oxsecurity/megalinter/flavors/custom-builder@main
|
|
108
119
|
with:
|
|
@@ -114,6 +125,6 @@ jobs:
|
|
|
114
125
|
dockerhub-repo: ${{ vars.DOCKERHUB_REPO }}
|
|
115
126
|
env:
|
|
116
127
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
117
|
-
CUSTOM_FLAVOR_BUILD_REPO: ${{
|
|
128
|
+
CUSTOM_FLAVOR_BUILD_REPO: ${{ steps.lowercase-repo.outputs.repo }}
|
|
118
129
|
CUSTOM_FLAVOR_BUILD_REPO_URL: ${{ github.repositoryUrl }}
|
|
119
130
|
CUSTOM_FLAVOR_BUILD_USER: ${{ github.actor }}
|
package/lib/cli.js
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const ENV_KEY_VALUE_RE = /^[A-Za-z_][A-Za-z0-9_]*=/;
|
|
2
|
+
|
|
3
|
+
// Expand a list of -e values, splitting the legacy comma-separated KEY=VAL,KEY=VAL form
|
|
4
|
+
// into multiple entries while preserving values that simply contain a comma
|
|
5
|
+
// (e.g. ENABLE_LINTERS=YAML_PRETTIER,YAML_YAMLLINT).
|
|
6
|
+
//
|
|
7
|
+
// Heuristic: split on `,` only when every comma-separated part looks like KEY=...
|
|
8
|
+
// Otherwise the comma belongs to the value of a single env var.
|
|
9
|
+
export function expandEnvEntries(envList) {
|
|
10
|
+
if (!Array.isArray(envList)) {
|
|
11
|
+
return envList;
|
|
12
|
+
}
|
|
13
|
+
const result = [];
|
|
14
|
+
for (const entry of envList) {
|
|
15
|
+
if (typeof entry !== "string" || !entry.includes(",")) {
|
|
16
|
+
result.push(entry);
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
const parts = entry.split(",");
|
|
20
|
+
const allLookLikeKv = parts.every((p) => ENV_KEY_VALUE_RE.test(p));
|
|
21
|
+
if (allLookLikeKv && parts.length > 1) {
|
|
22
|
+
result.push(...parts);
|
|
23
|
+
} else {
|
|
24
|
+
result.push(entry);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
package/lib/index.js
CHANGED
|
File without changes
|
package/lib/list-vars.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { default as fs } from "fs-extra";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { dirname } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
|
|
6
|
+
const VARS_FILE = path.join(
|
|
7
|
+
dirname(fileURLToPath(import.meta.url)),
|
|
8
|
+
"megalinter-vars.json",
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
function loadVars() {
|
|
12
|
+
if (!fs.existsSync(VARS_FILE)) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
`Bundled variables file not found at ${VARS_FILE}. Re-run \`make megalinter-build\` to regenerate it.`,
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
return fs.readJsonSync(VARS_FILE);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function matches(variable, pattern) {
|
|
21
|
+
if (!pattern) return true;
|
|
22
|
+
const p = pattern.toLowerCase();
|
|
23
|
+
return (
|
|
24
|
+
variable.name.toLowerCase().includes(p) ||
|
|
25
|
+
(variable.category || "").toLowerCase().includes(p) ||
|
|
26
|
+
(variable.section || "").toLowerCase().includes(p) ||
|
|
27
|
+
(variable.title || "").toLowerCase().includes(p)
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function formatType(variable) {
|
|
32
|
+
const t = variable.type;
|
|
33
|
+
if (Array.isArray(t)) return t.join(" | ");
|
|
34
|
+
return t || "string";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function renderHuman(variables, pattern, meta) {
|
|
38
|
+
const lines = [];
|
|
39
|
+
if (pattern) {
|
|
40
|
+
lines.push(
|
|
41
|
+
`MegaLinter variables matching "${pattern}" (${variables.length}/${meta.variable_count}):`,
|
|
42
|
+
);
|
|
43
|
+
} else {
|
|
44
|
+
lines.push(`MegaLinter variables (${variables.length} total):`);
|
|
45
|
+
}
|
|
46
|
+
lines.push("");
|
|
47
|
+
for (const v of variables) {
|
|
48
|
+
lines.push(` ${v.name} [${formatType(v)}] (${v.category || "GENERAL"})`);
|
|
49
|
+
if (v.title) {
|
|
50
|
+
lines.push(` ${v.title}`);
|
|
51
|
+
}
|
|
52
|
+
if (v.description && v.description !== v.title) {
|
|
53
|
+
lines.push(` ${v.description}`);
|
|
54
|
+
}
|
|
55
|
+
if (v.default !== undefined) {
|
|
56
|
+
lines.push(` default: ${JSON.stringify(v.default)}`);
|
|
57
|
+
}
|
|
58
|
+
if (Array.isArray(v.enum) && v.enum.length > 0) {
|
|
59
|
+
lines.push(` allowed: ${v.enum.join(", ")}`);
|
|
60
|
+
}
|
|
61
|
+
if (Array.isArray(v.items_enum) && v.items_enum.length > 0) {
|
|
62
|
+
const preview = v.items_enum.slice(0, 6).join(", ");
|
|
63
|
+
const suffix =
|
|
64
|
+
v.items_enum.length > 6
|
|
65
|
+
? `, … (${v.items_enum.length} values)`
|
|
66
|
+
: "";
|
|
67
|
+
lines.push(` item values: ${preview}${suffix}`);
|
|
68
|
+
}
|
|
69
|
+
if (Array.isArray(v.examples) && v.examples.length > 0) {
|
|
70
|
+
lines.push(` examples: ${v.examples.map((e) => JSON.stringify(e)).join(", ")}`);
|
|
71
|
+
}
|
|
72
|
+
lines.push("");
|
|
73
|
+
}
|
|
74
|
+
lines.push(`Reference: ${meta.doc_url}`);
|
|
75
|
+
lines.push(
|
|
76
|
+
pattern
|
|
77
|
+
? "Pass variables with: mega-linter-runner -e KEY=VALUE"
|
|
78
|
+
: "Filter results: mega-linter-runner --list-vars <pattern>",
|
|
79
|
+
);
|
|
80
|
+
return lines.join("\n");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function listVars({ pattern, asJson } = {}) {
|
|
84
|
+
const data = loadVars();
|
|
85
|
+
const all = Object.values(data.variables);
|
|
86
|
+
const filtered = all.filter((v) => matches(v, pattern));
|
|
87
|
+
if (asJson) {
|
|
88
|
+
return {
|
|
89
|
+
stdout: JSON.stringify(
|
|
90
|
+
{
|
|
91
|
+
_meta: { ...data._meta, pattern: pattern || null, returned: filtered.length },
|
|
92
|
+
variables: filtered,
|
|
93
|
+
},
|
|
94
|
+
null,
|
|
95
|
+
2,
|
|
96
|
+
),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return { stdout: renderHuman(filtered, pattern, data._meta) };
|
|
100
|
+
}
|