Skip to content
Merged
Show file tree
Hide file tree
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
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ inputs:
working-directory:
description: 'Working directory for running vlt query (defaults to repository root)'
required: false
show-results:
description: 'Show query output in logs and summary when queries fail. Set to "always" to show for all queries, "never" to hide, or "failed" (default) to show only for failed queries.'
required: false
default: 'failed'

outputs:
results:
Expand Down
61 changes: 32 additions & 29 deletions dist/index.js

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ async function run(): Promise<void> {
const scope = core.getInput('scope');
const target = core.getInput('target');
const workingDirectory = core.getInput('working-directory');
const showResults = core.getInput('show-results') || 'failed';

// Validate inputs
if (!query && !queries) {
Expand Down Expand Up @@ -55,10 +56,10 @@ async function run(): Promise<void> {
core.info(`Executing ${parsedQueries.length} vlt queries...`);

// Execute queries
const results = await executeQueries(parsedQueries, workingDirectory);
const results = await executeQueries(parsedQueries, workingDirectory, showResults);

// Generate summary
const summary = generateSummaryTable(results);
const summary = generateSummaryTable(results, showResults);
await core.summary.addRaw(summary).write();

// Set outputs
Expand Down
37 changes: 34 additions & 3 deletions src/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,23 @@ export async function executeQuery(
return queryResult;
}

/**
* Check whether output should be shown based on the show-results setting
*/
function shouldShowOutput(passed: boolean, showResults: string): boolean {
if (showResults === 'always') return true;
if (showResults === 'never') return false;
// 'failed' (default) — show only for failed queries
return !passed;
}

/**
* Execute multiple queries
*/
export async function executeQueries(
queries: ParsedQuery[],
workingDirectory?: string
workingDirectory?: string,
showResults: string = 'failed'
): Promise<QueryResult[]> {
const results: QueryResult[] = [];

Expand All @@ -100,8 +111,21 @@ export async function executeQueries(
// Log result
if (result.passed) {
core.info(`✅ ${result.query}`);
if (shouldShowOutput(true, showResults) && result.output && result.output.trim()) {
core.info(`Query output:\n${result.output}`);
}
} else {
core.error(`❌ ${result.query}: ${result.error}`);
if (shouldShowOutput(false, showResults)) {
// Show stdout so users can see what matched (e.g. expect-results failures)
if (result.output && result.output.trim()) {
core.info(`Query output:\n${result.output}`);
}
// Show stderr so users can see CLI errors (e.g. unsupported selector)
if (result.stderr && result.stderr.trim()) {
core.info(`Query stderr:\n${result.stderr}`);
}
}
}
}

Expand All @@ -111,7 +135,7 @@ export async function executeQueries(
/**
* Generate summary table for GitHub Actions step summary
*/
export function generateSummaryTable(results: QueryResult[]): string {
export function generateSummaryTable(results: QueryResult[], showResults: string = 'failed'): string {
const lines: string[] = [];

lines.push('## Query Deps Results');
Expand Down Expand Up @@ -147,12 +171,19 @@ export function generateSummaryTable(results: QueryResult[]): string {
if (result.stderr) {
lines.push(`- stderr: \`${escapeMarkdown(result.stderr)}\``);
}
if (shouldShowOutput(false, showResults) && result.output && result.output.trim()) {
lines.push('');
lines.push('Output:');
lines.push('```');
lines.push(result.output);
lines.push('```');
}
lines.push('');
}
}

// Add output for successful queries with actual output
const successfulWithOutput = results.filter(r => r.passed && r.output.trim());
const successfulWithOutput = results.filter(r => r.passed && r.output.trim() && shouldShowOutput(true, showResults));
if (successfulWithOutput.length > 0) {
lines.push('### Query Outputs');
lines.push('');
Expand Down
155 changes: 152 additions & 3 deletions tests/query.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,111 @@ describe('generateSummaryTable', () => {
expect(summary).toContain('Expected 0 results, but got 1');
});

it('should include query outputs for successful queries', () => {
it('should include query output in failed queries section (default show-results=failed)', () => {
const results: QueryResult[] = [
{
query: '*:license(copyleft) --expect-results=0',
selector: '*:license(copyleft)',
flags: ['--expect-results=0'],
output: 'gpl-pkg@1.0.0\nlgpl-lib@2.3.4\nagpl-service@0.1.0',
stderr: '',
exitCode: 0,
success: true,
passed: false,
error: 'Expected 0 results, but got 3',
expectedResults: '0',
actualResultCount: 3,
duration: 120,
},
];

const summary = generateSummaryTable(results);

expect(summary).toContain('### Failed Queries');
expect(summary).toContain('Expected 0 results, but got 3');
// The actual matched packages should be shown
expect(summary).toContain('Output:');
expect(summary).toContain('gpl-pkg@1.0.0');
expect(summary).toContain('lgpl-lib@2.3.4');
expect(summary).toContain('agpl-service@0.1.0');
});

it('should show stderr in failed queries section for CLI errors', () => {
const results: QueryResult[] = [
{
query: ':diff() --expect-results=0',
selector: ':diff()',
flags: ['--expect-results=0'],
output: '',
stderr: 'Error: unsupported selector :diff()',
exitCode: 1,
success: false,
passed: false,
error: 'Error: unsupported selector :diff()',
duration: 50,
},
];

const summary = generateSummaryTable(results);

expect(summary).toContain('### Failed Queries');
expect(summary).toContain('unsupported selector');
expect(summary).toContain('stderr');
});

it('should show both stdout and stderr for CLI errors with partial output', () => {
const results: QueryResult[] = [
{
query: ':some-selector',
selector: ':some-selector',
flags: [],
output: 'partial-result@1.0.0',
stderr: 'Warning: query terminated early\nError: connection reset',
exitCode: 1,
success: false,
passed: false,
error: 'Warning: query terminated early\nError: connection reset',
duration: 300,
},
];

const summary = generateSummaryTable(results);

expect(summary).toContain('### Failed Queries');
expect(summary).toContain('connection reset');
// stdout should also be shown
expect(summary).toContain('Output:');
expect(summary).toContain('partial-result@1.0.0');
});

it('should not show output for failed queries when show-results=never', () => {
const results: QueryResult[] = [
{
query: '*:license(copyleft) --expect-results=0',
selector: '*:license(copyleft)',
flags: ['--expect-results=0'],
output: 'gpl-pkg@1.0.0\nlgpl-lib@2.3.4',
stderr: '',
exitCode: 0,
success: true,
passed: false,
error: 'Expected 0 results, but got 2',
expectedResults: '0',
actualResultCount: 2,
duration: 120,
},
];

const summary = generateSummaryTable(results, 'never');

expect(summary).toContain('### Failed Queries');
expect(summary).toContain('Expected 0 results, but got 2');
// Output should NOT be shown
expect(summary).not.toContain('gpl-pkg@1.0.0');
expect(summary).not.toContain('Output:');
});

it('should show output for successful queries when show-results=always', () => {
const results: QueryResult[] = [
{
query: ':outdated --view=json',
Expand All @@ -95,7 +199,52 @@ describe('generateSummaryTable', () => {
},
];

const summary = generateSummaryTable(results);
const summary = generateSummaryTable(results, 'always');

expect(summary).toContain('### Query Outputs');
expect(summary).toContain('```');
expect(summary).toContain('"name": "lodash"');
});

it('should not show successful query outputs with default show-results=failed', () => {
const results: QueryResult[] = [
{
query: ':outdated --view=json',
selector: ':outdated',
flags: ['--view=json'],
output: '[\n {\n "name": "lodash",\n "current": "4.17.20",\n "wanted": "4.17.21"\n }\n]',
stderr: '',
exitCode: 0,
success: true,
passed: true,
duration: 200,
},
];

const summary = generateSummaryTable(results, 'failed');

// With 'failed' mode, successful query output should NOT be shown
expect(summary).not.toContain('### Query Outputs');
expect(summary).not.toContain('"name": "lodash"');
});

it('should include query outputs for successful queries (legacy default behavior)', () => {
// When show-results is 'always', successful query outputs are shown
const results: QueryResult[] = [
{
query: ':outdated --view=json',
selector: ':outdated',
flags: ['--view=json'],
output: '[\n {\n "name": "lodash",\n "current": "4.17.20",\n "wanted": "4.17.21"\n }\n]',
stderr: '',
exitCode: 0,
success: true,
passed: true,
duration: 200,
},
];

const summary = generateSummaryTable(results, 'always');

expect(summary).toContain('### Query Outputs');
expect(summary).toContain('```');
Expand Down Expand Up @@ -159,4 +308,4 @@ describe('setOutputs', () => {

expect(mockSetOutput).toHaveBeenCalledWith('passed', 'false');
});
});
});
Loading