Add more tests
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import {CodeAction, TextEdit} from "vscode-languageserver-types";
|
||||
import {CodeActionContext, CodeActionProvider} from "../types";
|
||||
import {DiagnosticCode, MissingInputsDiagnosticData} from "../../validate-action";
|
||||
import { CodeAction, TextEdit } from "vscode-languageserver-types";
|
||||
import { CodeActionContext, CodeActionProvider } from "../types";
|
||||
import { DiagnosticCode, MissingInputsDiagnosticData } from "../../validate-action";
|
||||
|
||||
export const addMissingInputsProvider: CodeActionProvider = {
|
||||
diagnosticCodes: [DiagnosticCode.MissingRequiredInputs],
|
||||
@@ -22,11 +22,11 @@ export const addMissingInputsProvider: CodeActionProvider = {
|
||||
title: `Add missing input${data.missingInputs.length > 1 ? "s" : ""}: ${inputNames}`,
|
||||
edit: {
|
||||
changes: {
|
||||
[context.uri]: edits
|
||||
}
|
||||
}
|
||||
[context.uri]: edits,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
function createInputEdits(data: MissingInputsDiagnosticData): TextEdit[] | undefined {
|
||||
@@ -42,13 +42,13 @@ function createInputEdits(data: MissingInputsDiagnosticData): TextEdit[] | undef
|
||||
});
|
||||
|
||||
edits.push({
|
||||
range: {start: data.insertPosition, end: data.insertPosition},
|
||||
newText: inputLines.map(line => line + "\n").join("")
|
||||
range: { start: data.insertPosition, end: data.insertPosition },
|
||||
newText: inputLines.map(line => line + "\n").join(""),
|
||||
});
|
||||
} else {
|
||||
// No `with:` key - use step indentation for `with:`, +2 for inputs
|
||||
const withIndent = " ".repeat(data.stepIndent + 2);
|
||||
const inputIndent = " ".repeat(data.stepIndent + 4);
|
||||
// No `with:` key - `with:` at step indentation, inputs at step indentation + 2
|
||||
const withIndent = " ".repeat(data.stepIndent);
|
||||
const inputIndent = " ".repeat(data.stepIndent + 2);
|
||||
|
||||
const inputLines = data.missingInputs.map(input => {
|
||||
const value = input.default !== undefined ? input.default : '""';
|
||||
@@ -58,8 +58,8 @@ function createInputEdits(data: MissingInputsDiagnosticData): TextEdit[] | undef
|
||||
const newText = [`${withIndent}with:\n`, ...inputLines.map(line => `${line}\n`)].join("");
|
||||
|
||||
edits.push({
|
||||
range: {start: data.insertPosition, end: data.insertPosition},
|
||||
newText
|
||||
range: { start: data.insertPosition, end: data.insertPosition },
|
||||
newText,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import {TextEdit} from "vscode-languageserver-types";
|
||||
import {TextDocument} from "vscode-languageserver-textdocument";
|
||||
import {validate, ValidationConfig} from "../../validate";
|
||||
import {getCodeActions, CodeActionParams} from "../index";
|
||||
import { TextEdit } from "vscode-languageserver-types";
|
||||
import { TextDocument } from "vscode-languageserver-textdocument";
|
||||
import { validate, ValidationConfig } from "../../validate";
|
||||
import { getCodeActions, CodeActionParams } from "../index";
|
||||
|
||||
// Marker pattern: # want "diagnostic message" fix="code-action-name"
|
||||
const MARKER_PATTERN = /#\s*want\s+"([^"]+)"(?:\s+fix="([^"]+)")?/;
|
||||
@@ -69,7 +69,7 @@ export function loadTestCases(testdataDir: string): TestCase[] {
|
||||
const testCases: TestCase[] = [];
|
||||
|
||||
function walkDir(dir: string) {
|
||||
const entries = fs.readdirSync(dir, {withFileTypes: true});
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
@@ -147,6 +147,7 @@ export async function runTestCase(testCase: TestCase, validationConfig: Validati
|
||||
const missingDiagnostics: string[] = [];
|
||||
for (const marker of testCase.markers) {
|
||||
const found = diagnostics.find(d => d.range.start.line === marker.line && d.message.includes(marker.message));
|
||||
console.log(found);
|
||||
if (!found) {
|
||||
missingDiagnostics.push(`line ${marker.line}: "${marker.message}"`);
|
||||
}
|
||||
@@ -188,9 +189,8 @@ export async function runTestCase(testCase: TestCase, validationConfig: Validati
|
||||
return {
|
||||
name: testCase.name,
|
||||
passed: false,
|
||||
error: `Code action "${marker.fix}" not found for diagnostic on line ${marker.line}.\nAvailable actions: ${
|
||||
actions.map(a => a.title).join(", ") || "(none)"
|
||||
}`
|
||||
error: `Code action "${marker.fix}" not found for diagnostic on line ${marker.line}.\nAvailable actions: ${actions.map(a => a.title).join(", ") || "(none)"
|
||||
}`
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
languageservice/src/code-actions/tests/testdata/quickfix/existing-with-key-without-inputs.golden.yml
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
on: push
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: ""
|
||||
key: ""
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
on: push
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/cache@v1
|
||||
with: # want "Missing required inputs: `path`, `key`" fix="Add missing inputs: path, key"
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
on: push
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: ""
|
||||
key: ""
|
||||
@@ -0,0 +1,6 @@
|
||||
on: push
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/cache@v1 # want "Missing required inputs: `path`, `key`" fix="Add missing inputs: path, key"
|
||||
@@ -1,12 +1,12 @@
|
||||
import {isMapping} from "@actions/workflow-parser";
|
||||
import {isActionStep} from "@actions/workflow-parser/model/type-guards";
|
||||
import {Step} from "@actions/workflow-parser/model/workflow-template";
|
||||
import {ScalarToken} from "@actions/workflow-parser/templates/tokens/scalar-token";
|
||||
import {TemplateToken} from "@actions/workflow-parser/templates/tokens/template-token";
|
||||
import {Diagnostic, DiagnosticSeverity} from "vscode-languageserver-types";
|
||||
import {ActionReference, parseActionReference} from "./action";
|
||||
import {mapRange} from "./utils/range";
|
||||
import {ValidationConfig} from "./validate";
|
||||
import { isMapping } from "@actions/workflow-parser";
|
||||
import { isActionStep } from "@actions/workflow-parser/model/type-guards";
|
||||
import { Step } from "@actions/workflow-parser/model/workflow-template";
|
||||
import { ScalarToken } from "@actions/workflow-parser/templates/tokens/scalar-token";
|
||||
import { TemplateToken } from "@actions/workflow-parser/templates/tokens/template-token";
|
||||
import { Diagnostic, DiagnosticSeverity } from "vscode-languageserver-types";
|
||||
import { ActionReference, parseActionReference } from "./action";
|
||||
import { mapRange } from "./utils/range";
|
||||
import { ValidationConfig } from "./validate";
|
||||
|
||||
export const DiagnosticCode = {
|
||||
MissingRequiredInputs: "missing-required-inputs"
|
||||
@@ -23,7 +23,7 @@ export interface MissingInputsDiagnosticData {
|
||||
withIndent?: number;
|
||||
stepIndent: number;
|
||||
// Position where new content should be inserted
|
||||
insertPosition: {line: number; character: number};
|
||||
insertPosition: { line: number; character: number };
|
||||
}
|
||||
|
||||
export async function validateAction(
|
||||
@@ -53,7 +53,7 @@ export async function validateAction(
|
||||
|
||||
let withKey: ScalarToken | undefined;
|
||||
let withToken: TemplateToken | undefined;
|
||||
for (const {key, value} of stepToken) {
|
||||
for (const { key, value } of stepToken) {
|
||||
if (key.toString() === "with") {
|
||||
withKey = key;
|
||||
withToken = value;
|
||||
@@ -63,7 +63,7 @@ export async function validateAction(
|
||||
|
||||
const stepInputs = new Map<string, ScalarToken>();
|
||||
if (withToken && isMapping(withToken)) {
|
||||
for (const {key} of withToken) {
|
||||
for (const { key } of withToken) {
|
||||
stepInputs.set(key.toString(), key);
|
||||
}
|
||||
}
|
||||
@@ -105,6 +105,25 @@ export async function validateAction(
|
||||
const stepIndent = stepToken.range ? stepToken.range.start.column - 1 : 0; // 0-indexed
|
||||
const withIndent = withKey?.range ? withKey.range.start.column - 1 : undefined;
|
||||
|
||||
// Calculate insert position
|
||||
// For withToken, we need to handle empty mappings specially - insert after the with: line
|
||||
let insertPosition: { line: number; character: number };
|
||||
if (withToken?.range) {
|
||||
// Check if with: has any children by comparing start and end lines
|
||||
const hasChildren = stepInputs.size > 0;
|
||||
if (hasChildren) {
|
||||
// Insert after the last child
|
||||
insertPosition = { line: withToken.range.end.line - 1, character: 0 };
|
||||
} else {
|
||||
// Empty with: block - insert on the next line after with:
|
||||
insertPosition = { line: withKey!.range!.end.line, character: 0 };
|
||||
}
|
||||
} else if (stepToken.range) {
|
||||
insertPosition = { line: stepToken.range.end.line - 1, character: 0 };
|
||||
} else {
|
||||
insertPosition = { line: 0, character: 0 };
|
||||
}
|
||||
|
||||
const diagnosticData: MissingInputsDiagnosticData = {
|
||||
action,
|
||||
missingInputs: missingRequiredInputs.map(([name, input]) => ({
|
||||
@@ -114,11 +133,7 @@ export async function validateAction(
|
||||
hasWithKey: withKey !== undefined,
|
||||
withIndent,
|
||||
stepIndent,
|
||||
insertPosition: withToken?.range
|
||||
? {line: withToken.range.end.line - 1, character: 0}
|
||||
: stepToken.range
|
||||
? {line: stepToken.range.end.line - 1, character: 0}
|
||||
: {line: 0, character: 0}
|
||||
insertPosition
|
||||
};
|
||||
|
||||
diagnostics.push({
|
||||
|
||||
Reference in New Issue
Block a user