Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 62 additions & 4 deletions tools/spectral/ipa/scripts/filter-ipa-violations.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,47 @@
import fs from 'node:fs/promises';
import { execSync } from 'child_process';
import path from 'path';
import http from 'http';
import https from 'https';

async function filterIpaViolations() {
try {
// Check if rule ID is provided
const ruleId = process.argv[2];
if (!ruleId) {
console.error('Usage: node filter-ipa-violations.js <rule-id>');
console.error('Usage: node filter-ipa-violations.js <rule-id> [remote-openapi-url]');
console.error('Example: node filter-ipa-violations.js xgen-IPA-102-collection-identifier-camelCase');
console.error(
'Example with remote file: node filter-ipa-violations.js xgen-IPA-102-collection-identifier-camelCase https://raw.githubusercontent.com/mongodb/openapi/refs/heads/dev/openapi/.raw/v2.yaml'
);
process.exit(1);
}

// Check if a remote OpenAPI file URL is provided
const remoteUrl = process.argv[3];
const outputFile = path.join(process.cwd(), `${ruleId}-violations.md`);

console.log(`Filtering violations for rule ID: ${ruleId}`);
console.log('Running IPA validation...');

// If remote URL provided, download it to a temp file
let openapiFilePath = './openapi/.raw/v2.yaml'; // Default local file
let tempFile = null;

if (remoteUrl) {
console.log(`Using remote OpenAPI file: ${remoteUrl}`);
tempFile = path.join(process.cwd(), 'temp_openapi_file.yaml');
await downloadFile(remoteUrl, tempFile);
openapiFilePath = tempFile;
} else {
console.log('Using local OpenAPI file');
}

let validationOutput;
try {
// Run IPA validation and get output as JSON
execSync(
'spectral lint --format=json -o results.json ./openapi/.raw/v2.yaml --ruleset=./tools/spectral/ipa/ipa-spectral.yaml',
`spectral lint --format=json -o results.json ${openapiFilePath} --ruleset=./tools/spectral/ipa/ipa-spectral.yaml`,
{
encoding: 'utf-8',
timeout: 4000,
Expand All @@ -30,6 +50,15 @@ async function filterIpaViolations() {
);
} catch (error) {
console.error('Error (expected):', error.message);
} finally {
// Clean up temp file if it exists
if (tempFile) {
try {
await fs.unlink(tempFile);
} catch (err) {
console.error('Error removing temporary file:', err.message);
}
}
}

// Read the JSON output
Expand Down Expand Up @@ -59,12 +88,11 @@ async function filterIpaViolations() {
// Generate markdown content
let markdownContent = `# ${ruleId} Violations Checklist\n\n`;
markdownContent += `Generated on: ${new Date().toLocaleString()}\n\n`;

Object.keys(groupedBySource).forEach((source) => {
const violations = groupedBySource[source];

violations.forEach((violation) => {
markdownContent += `## ${violation.source}\n\n`;
markdownContent += `## ${violation.message}\n\n`;
markdownContent += `Path: \`${violation.path.join('/')}\`\n\n`;
markdownContent += `- [ ] Fixed\n\n`;
});
Expand All @@ -82,4 +110,34 @@ async function filterIpaViolations() {
}
}

// Function to download a file from a URL
function downloadFile(url, outputPath) {
return new Promise((resolve, reject) => {
const client = url.startsWith('https') ? https : http;

console.log(`Downloading OpenAPI file from ${url}...`);

const request = client.get(url, (response) => {
if (response.statusCode < 200 || response.statusCode >= 300) {
return reject(new Error(`Failed to download file, status code: ${response.statusCode}`));
}

const file = fs.open(outputPath, 'w').then((fileHandle) => fileHandle.createWriteStream());
file
.then((fileStream) => {
response.pipe(fileStream);
response.on('end', () => {
console.log('Download complete');
resolve();
});
})
.catch(reject);
});

request.on('error', (err) => {
reject(err);
});
});
}

filterIpaViolations();
Loading