-
-
Notifications
You must be signed in to change notification settings - Fork 23
feat(dependabot): validator, tests and example config for issue #73 #87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| version: 2 | ||
| updates: | ||
| - package-ecosystem: "npm" | ||
| directory: "/" | ||
| schedule: | ||
| interval: weekly | ||
| multi-ecosystem-groups: | ||
| "all-deps": | ||
| patterns: | ||
| - "*" | ||
| - package-ecosystem: "pip" | ||
| directory: "/" | ||
| schedule: | ||
| interval: monthly | ||
|
|
||
| groups: | ||
| "frontend-backend": | ||
| patterns: | ||
| - "@myorg/frontend*" | ||
| - "@myorg/backend*" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -198,6 +198,10 @@ _minted* | |
| # nomencl | ||
| *.nlg | ||
| *.nlo | ||
|
|
||
| # Node dependencies | ||
| /node_modules | ||
|
|
||
| *.nls | ||
|
|
||
| # pax | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,14 @@ | ||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||
| "name": "template-repo", | ||||||||||||||||||||||||||||||||||||||||||
| "version": "0.1.0", | ||||||||||||||||||||||||||||||||||||||||||
| "private": true, | ||||||||||||||||||||||||||||||||||||||||||
| "scripts": { | ||||||||||||||||||||||||||||||||||||||||||
| "test": "vitest run", | ||||||||||||||||||||||||||||||||||||||||||
| "test:watch": "vitest", | ||||||||||||||||||||||||||||||||||||||||||
| "check": "echo \"No checks configured yet\"" | ||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||
| "devDependencies": { | ||||||||||||||||||||||||||||||||||||||||||
| "vitest": "^1.0.0", | ||||||||||||||||||||||||||||||||||||||||||
| "js-yaml": "^4.1.0" | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+10
to
+13
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "1) Confirm js-yaml is imported by runtime validator code:"
rg -n --type=js "require\\(['\"]js-yaml['\"]\\)|from ['\"]js-yaml['\"]" scripts
echo
echo "2) Confirm js-yaml is currently declared only in devDependencies:"
rg -n "\"dependencies\"|\"devDependencies\"|\"js-yaml\"" package.json -C2Repository: AOSSIE-Org/Template-Repo Length of output: 415 Move
Proposed fix {
"name": "template-repo",
"version": "0.1.0",
"private": true,
"scripts": {
"test": "vitest run",
"test:watch": "vitest",
"check": "echo \"No checks configured yet\""
},
- "devDependencies": {
- "vitest": "^1.0.0",
- "js-yaml": "^4.1.0"
- }
+ "dependencies": {
+ "js-yaml": "^4.1.0"
+ },
+ "devDependencies": {
+ "vitest": "^1.0.0"
+ }
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,61 @@ | ||||||||||||||||||||||||||||||||||||||||
| const fs = require('fs'); | ||||||||||||||||||||||||||||||||||||||||
| const yaml = require('js-yaml'); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||
| * Load dependabot configuration and check whether it contains | ||||||||||||||||||||||||||||||||||||||||
| * either (1) top-level "groups" definitions, or (2) multi-ecosystem groups | ||||||||||||||||||||||||||||||||||||||||
| * under "updates" entries. | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * Returns an object {ok: boolean, issues: string[]} where ok is true if | ||||||||||||||||||||||||||||||||||||||||
| * configuration satisfies the feature requirement (groups or multi-ecosystem groups). | ||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||
| function validateDependabot(path = '.github/dependabot.yml') { | ||||||||||||||||||||||||||||||||||||||||
| if (!fs.existsSync(path)) { | ||||||||||||||||||||||||||||||||||||||||
| return { ok: false, issues: [`file not found: ${path}`] }; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| const raw = fs.readFileSync(path, 'utf-8'); | ||||||||||||||||||||||||||||||||||||||||
| let doc; | ||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||
| doc = yaml.load(raw); | ||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||
| return { ok: false, issues: ['YAML parse error: ' + e.message] }; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| const issues = []; | ||||||||||||||||||||||||||||||||||||||||
| // if the document isn't an object, treat as parse error | ||||||||||||||||||||||||||||||||||||||||
| if (typeof doc !== 'object' || doc === null) { | ||||||||||||||||||||||||||||||||||||||||
| return { ok: false, issues: ['YAML parse error: document is not an object'] }; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // the structure: typically at root there's "updates" array. | ||||||||||||||||||||||||||||||||||||||||
| if (!doc || !Array.isArray(doc.updates)) { | ||||||||||||||||||||||||||||||||||||||||
| issues.push('missing updates array'); | ||||||||||||||||||||||||||||||||||||||||
| return { ok: false, issues }; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // check if any update has groups or if there's top-level groups | ||||||||||||||||||||||||||||||||||||||||
| let foundGroup = false; | ||||||||||||||||||||||||||||||||||||||||
| if (doc.groups && Object.keys(doc.groups).length > 0) { | ||||||||||||||||||||||||||||||||||||||||
| foundGroup = true; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| for (const upd of doc.updates) { | ||||||||||||||||||||||||||||||||||||||||
| if (upd.groups && Object.keys(upd.groups).length > 0) { | ||||||||||||||||||||||||||||||||||||||||
| foundGroup = true; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| if (upd['multi-ecosystem'] || upd['multi-ecosystem-groups']) { | ||||||||||||||||||||||||||||||||||||||||
| foundGroup = true; | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+42
to
+47
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# First, examine the specific lines mentioned in the review
echo "=== File content around lines 42-47 ==="
sed -n '35,55p' scripts/validate-dependabot.js
echo ""
echo "=== Full file content ==="
wc -l scripts/validate-dependabot.js
echo ""
echo "=== Complete file ==="
cat -n scripts/validate-dependabot.jsRepository: AOSSIE-Org/Template-Repo Length of output: 2983 Guard Line 31 validates Proposed fix for (const upd of doc.updates) {
+ if (!upd || typeof upd !== 'object') {
+ continue;
+ }
if (upd.groups && Object.keys(upd.groups).length > 0) {
foundGroup = true;
}
if (upd['multi-ecosystem'] || upd['multi-ecosystem-groups']) {
foundGroup = true;
}
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if (!foundGroup) { | ||||||||||||||||||||||||||||||||||||||||
| issues.push('no groups or multi-ecosystem groups defined'); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| return { ok: foundGroup, issues }; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // Export for tests | ||||||||||||||||||||||||||||||||||||||||
| module.exports = { | ||||||||||||||||||||||||||||||||||||||||
| validateDependabot, | ||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+58
to
+61
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Get current working directory and list files
echo "=== Repository structure ==="
git ls-files | head -20
echo -e "\n=== Content of scripts/validate-dependabot.js ==="
cat -n scripts/validate-dependabot.js
echo -e "\n=== Check README for documented CLI usage ==="
if [ -f "README.md" ]; then
rg -n "node scripts/validate-dependabot.js" README.md || echo "Pattern not found in README"
else
echo "README.md not found"
fiRepository: AOSSIE-Org/Template-Repo Length of output: 3085 🏁 Script executed: #!/bin/bash
# Let's see the context around line 129 in README to understand the documented usage
sed -n '120,140p' README.mdRepository: AOSSIE-Org/Template-Repo Length of output: 757 Add a CLI entrypoint for the documented The README documents running the validator with Proposed fix module.exports = {
validateDependabot,
};
+
+if (require.main === module) {
+ const result = validateDependabot(process.argv[2]);
+ if (!result.ok) {
+ for (const issue of result.issues) {
+ console.error(issue);
+ }
+ process.exit(1);
+ }
+ console.log('dependabot config is valid');
+}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| #!/usr/bin/env pwsh | ||
| Write-Host "Running setup (PowerShell)" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial 🧩 Analysis chain🏁 Script executed: find . -name "setup.ps1" -type fRepository: AOSSIE-Org/Template-Repo Length of output: 79 🏁 Script executed: cat -n setup.ps1Repository: AOSSIE-Org/Template-Repo Length of output: 512 Replace Lines 2, 7, and 10 use Proposed fix-Write-Host "Running setup (PowerShell)"
+Write-Output "Running setup (PowerShell)"
@@
-Write-Host "Installing npm dependencies..."
+Write-Output "Installing npm dependencies..."
@@
-Write-Host "Running tests..."
+Write-Output "Running tests..."🧰 Tools🪛 PSScriptAnalyzer (1.24.0)[warning] 2-2: File 'setup.ps1' uses Write-Host. Avoid using Write-Host because it might not work in all hosts, does not work when there is no host, and (prior to PS 5.0) cannot be suppressed, captured, or redirected. Instead, use Write-Output, Write-Verbose, or Write-Information. (PSAvoidUsingWriteHost) 🤖 Prompt for AI Agents |
||
| if (!(Test-Path package.json)) { | ||
| Write-Error "package.json not found. Aborting." | ||
| exit 1 | ||
| } | ||
| Write-Host "Installing npm dependencies..." | ||
| npm install | ||
| if ($LASTEXITCODE -ne 0) { Write-Error "npm install failed"; exit $LASTEXITCODE } | ||
| Write-Host "Running tests..." | ||
| npm test | ||
| exit $LASTEXITCODE | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
| echo "Running setup (bash)" | ||
| if [ ! -f package.json ]; then | ||
| echo "package.json not found. Aborting." >&2 | ||
| exit 1 | ||
| fi | ||
| echo "Installing npm dependencies..." | ||
| npm install | ||
| echo "Running tests..." | ||
| npm test |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| import { describe, it, expect, beforeAll, afterAll } from 'vitest'; | ||
| import fs from 'fs'; | ||
| import path from 'path'; | ||
| import { validateDependabot } from '../scripts/validate-dependabot.js'; | ||
|
|
||
| // Helper to write temporary config | ||
| function writeConfig(content) { | ||
| const file = path.join(process.cwd(), '.github', 'dependabot.yml'); | ||
| fs.mkdirSync(path.dirname(file), { recursive: true }); | ||
| fs.writeFileSync(file, content); | ||
| } | ||
|
|
||
| function removeConfig() { | ||
| const file = path.join(process.cwd(), '.github', 'dependabot.yml'); | ||
| if (fs.existsSync(file)) fs.unlinkSync(file); | ||
| } | ||
|
Comment on lines
+7
to
+16
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not mutate the real These tests currently overwrite and delete repository config files; use an isolated temporary file path and pass it to Proposed fix (isolate test fixture path) import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import fs from 'fs';
import path from 'path';
+import os from 'os';
import { validateDependabot } from '../scripts/validate-dependabot.js';
+const TEST_DIR = fs.mkdtempSync(path.join(os.tmpdir(), 'dependabot-validator-'));
+const TEST_CONFIG = path.join(TEST_DIR, 'dependabot.yml');
+
// Helper to write temporary config
function writeConfig(content) {
- const file = path.join(process.cwd(), '.github', 'dependabot.yml');
- fs.mkdirSync(path.dirname(file), { recursive: true });
- fs.writeFileSync(file, content);
+ fs.mkdirSync(path.dirname(TEST_CONFIG), { recursive: true });
+ fs.writeFileSync(TEST_CONFIG, content);
}
function removeConfig() {
- const file = path.join(process.cwd(), '.github', 'dependabot.yml');
- if (fs.existsSync(file)) fs.unlinkSync(file);
+ if (fs.existsSync(TEST_CONFIG)) fs.unlinkSync(TEST_CONFIG);
}
@@
- const result = validateDependabot();
+ const result = validateDependabot(TEST_CONFIG);Also applies to: 19-21, 23-103 🤖 Prompt for AI Agents |
||
|
|
||
| describe('dependabot configuration validation', () => { | ||
| afterAll(() => { | ||
| removeConfig(); | ||
| }); | ||
|
|
||
| it('fails when file is missing', () => { | ||
| removeConfig(); | ||
| const result = validateDependabot(); | ||
| expect(result.ok).toBe(false); | ||
| expect(result.issues).toContain('file not found: .github/dependabot.yml'); | ||
| }); | ||
|
|
||
| it('fails with malformed yaml', () => { | ||
| writeConfig('::notyaml'); | ||
| const result = validateDependabot(); | ||
| expect(result.ok).toBe(false); | ||
| expect(result.issues[0]).toMatch(/YAML parse error/); | ||
| }); | ||
|
|
||
| it('fails when no updates array', () => { | ||
| writeConfig('version: 2'); | ||
| const result = validateDependabot(); | ||
| expect(result.ok).toBe(false); | ||
| expect(result.issues).toContain('missing updates array'); | ||
| }); | ||
|
|
||
| it('fails when no groups or multi-ecosystem groups', () => { | ||
| writeConfig(`version: 2 | ||
| updates: | ||
| - package-ecosystem: npm | ||
| directory: "/" | ||
| schedule: | ||
| interval: daily | ||
| `); | ||
| const result = validateDependabot(); | ||
| expect(result.ok).toBe(false); | ||
| expect(result.issues).toContain('no groups or multi-ecosystem groups defined'); | ||
| }); | ||
|
|
||
| it('passes when top-level groups defined', () => { | ||
| writeConfig(`version: 2 | ||
| updates: | ||
| - package-ecosystem: npm | ||
| directory: "/" | ||
| schedule: | ||
| interval: weekly | ||
| groups: | ||
| "all": | ||
| patterns: | ||
| - "*" | ||
| `); | ||
| const result = validateDependabot(); | ||
| expect(result.ok).toBe(true); | ||
| }); | ||
|
|
||
| it('passes when an update has groups', () => { | ||
| writeConfig(`version: 2 | ||
| updates: | ||
| - package-ecosystem: maven | ||
| directory: "/" | ||
| schedule: | ||
| interval: monthly | ||
| groups: | ||
| "java": | ||
| patterns: | ||
| - "org.apache.*" | ||
| `); | ||
| const result = validateDependabot(); | ||
| expect(result.ok).toBe(true); | ||
| }); | ||
|
|
||
| it('passes when multi-ecosystem groups are used', () => { | ||
| writeConfig(`version: 2 | ||
| updates: | ||
| - package-ecosystem: "npm" | ||
| directory: "/" | ||
| schedule: | ||
| interval: weekly | ||
| multi-ecosystem-groups: | ||
| "base": | ||
| patterns: | ||
| - "*" | ||
| `); | ||
| const result = validateDependabot(); | ||
| expect(result.ok).toBe(true); | ||
| }); | ||
| }); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normalize file line endings to LF to satisfy YAMLlint.
Line 1 indicates CRLF newlines; YAMLlint expects
\nand will fail until this file is normalized.🧰 Tools
🪛 YAMLlint (1.38.0)
[error] 1-1: wrong new line character: expected \n
(new-lines)
🤖 Prompt for AI Agents