Skip to content

Conversation

@rentziass
Copy link
Member

This PR adds CodeAction capabilities to the language server and sets up the inner loop for them, using workflow files where to define expected diagnostics and golden files to specify expected results. This also adds a CodeActionKind.QuickFix for when an action is used but it's missing required inputs:

CleanShot 2025-12-16 at 13 40 17

Copilot AI review requested due to automatic review settings December 16, 2025 13:44
@rentziass rentziass requested a review from a team as a code owner December 16, 2025 13:44
@rentziass rentziass force-pushed the rentziass/codeactions2 branch from c66abfd to b6bd0ad Compare December 16, 2025 13:48
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces CodeAction capabilities to the GitHub Actions language server, specifically implementing a quickfix feature for automatically adding missing required action inputs. The implementation includes:

  • A new code action infrastructure with a provider-based architecture
  • A quickfix provider that generates edits to add missing required inputs
  • Test infrastructure using golden files to validate code action behavior
  • Enhanced diagnostic data to support code actions

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
languageservice/src/code-actions/index.ts Main entry point for code actions, implementing provider aggregation and filtering logic
languageservice/src/code-actions/types.ts Type definitions for code action context and provider interface
languageservice/src/code-actions/quickfix/index.ts Exports quickfix providers array
languageservice/src/code-actions/quickfix/add-missing-inputs.ts Implementation of the quickfix provider for adding missing required inputs
languageservice/src/code-actions/tests/runner.ts Test infrastructure for running golden file tests
languageservice/src/code-actions/tests/runner.test.ts Test suite using the golden file runner
languageservice/src/code-actions/tests/testdata/quickfix/*.yml Test input files with markers for expected diagnostics and fixes
languageservice/src/code-actions/tests/testdata/quickfix/*.golden.yml Expected output files after applying code actions
languageservice/src/validate-action.ts Enhanced validation to include diagnostic data needed for code actions
languageservice/src/validate.actions.test.ts Updated tests to verify new diagnostic data fields
languageservice/src/index.ts Exports the new getCodeActions function
languageserver/src/connection.ts Registers code action handler and declares CodeActionKind.QuickFix capability

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@rentziass rentziass force-pushed the rentziass/codeactions2 branch 3 times, most recently from 1b0264b to f35d847 Compare December 16, 2025 14:09

if (data.hasWithKey && data.withIndent !== undefined) {
// `with:` exists - use its indentation + 2 for inputs
const inputIndent = " ".repeat(data.withIndent + 2);
Copy link
Collaborator

@ericsciple ericsciple Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of assuming 2, have you considered matching the customer's indent? You could detect this based on the indent amount of the first job. For example:

function detectIndentSize(rootToken: MappingToken): number {
  const jobsValue = rootToken.find("jobs");
  if (jobsValue && isMapping(jobsValue) && jobsValue.count > 0) {
    const firstJob = jobsValue.get(0);
    if (firstJob?.key.range && jobsValue.range) {
      return firstJob.key.range.start.column - jobsValue.range.start.column;
    }
  }
  return 2; // fallback
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, thank you ❤️ I wonder if indent size is something we wanna carry around with WorkflowTemplate itself, I suspect it'll keep coming in use 🤔

Copy link
Collaborator

@ericsciple ericsciple Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or the WorkflowContext object might be more appropriate 🤷 (still kind of doesnt fit)

ericsciple
ericsciple previously approved these changes Dec 17, 2025
rentziass and others added 4 commits January 5, 2026 14:58
Co-authored-by: Salman Chishti <salmanmkc@GitHub.com>
- Add indentSize to MissingInputsDiagnosticData interface
- Pass indentSize parameter from validate.ts to validateActionReference
- Detect indentSize from workflow structure (jobs key to first child)
- Fall back to detecting from with: block children when available
@rentziass rentziass force-pushed the rentziass/codeactions2 branch from a1bd7e8 to fa9be15 Compare January 5, 2026 15:18
salmanmkc
salmanmkc previously approved these changes Jan 5, 2026
}
}
},
"actions/setup-node@v3": {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use the latest version?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are just static actions that are part of test data (also added in this PR):

const metadata: Record<string, ActionMetadata> = {
"actions/cache@v1": {
name: "Cache",
description: "Cache dependencies",
inputs: {
path: {
description: "A list of files to cache",
required: true
},
key: {
description: "Cache key",
required: true
},
"restore-keys": {
description: "Restore keys",
required: false
}
}
},
"actions/setup-node@v3": {
name: "Setup Node",
description: "Setup Node.js",
inputs: {
"node-version": {
description: "Node version",
required: true,
default: "16"
}
}
}

build:
runs-on: ubuntu-latest
steps:
- uses: actions/cache@v1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also use latest versions here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are just static actions that are part of test data (also added in this PR):

const metadata: Record<string, ActionMetadata> = {
"actions/cache@v1": {
name: "Cache",
description: "Cache dependencies",
inputs: {
path: {
description: "A list of files to cache",
required: true
},
key: {
description: "Cache key",
required: true
},
"restore-keys": {
description: "Restore keys",
required: false
}
}
},
"actions/setup-node@v3": {
name: "Setup Node",
description: "Setup Node.js",
inputs: {
"node-version": {
description: "Node version",
required: true,
default: "16"
}
}
}

@@ -0,0 +1,53 @@
import {FeatureFlags} from "@actions/expressions";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subdirectory index.ts files break repo pattern ⚠️

The existing repo pattern imports directly from specific files in the main index.ts:

export {complete} from "./complete.js";
export {hover} from "./hover.js";
export {validate, ValidationConfig, ActionsMetadataProvider} from "./validate.js";
export {ValueProviderConfig, ValueProviderKind} from "./value-providers/config.js";  // Direct file!

No subdirectory has its own index.ts - the main package-level index.ts imports directly from the implementation files (e.g., value-providers/config.js, not value-providers/index.js).

This PR introduces:

  • code-actions/index.ts (new subdirectory index with implementation code)
  • code-actions/quickfix/index.ts (another subdirectory index)
  • Main index.ts imports from "./code-actions/index.js" instead of a specific file

Questions:

  • Should subdirectory index.ts files contain implementation, or be exports-only like the main index.ts?

Recommendation: Follow existing pattern - use meaningful file names instead of index.ts:

  • code-actions/index.tscode-actions/code-actions.ts
  • code-actions/quickfix/index.tscode-actions/quickfix/quickfix-providers.ts

Then update the main index.ts:

export {getCodeActions, CodeActionParams} from "./code-actions/code-actions.js";

This avoids having many files named index.ts with implementation code, making the codebase easier to navigate.

This is a minor consistency issue, not a blocker.

missingRequiredInputs.length === 1
? `Missing required input \`${missingRequiredInputs[0][0]}\``
: `Missing required inputs: ${missingRequiredInputs.map(input => `\`${input[0]}\``).join(", ")}`;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Position calculation should live in the quickfix, not validation ⚠️

The pattern issue: Insert position and indentation are calculated in validate-action-reference.ts but consumed in add-missing-inputs.ts. This differs from how complete.ts works - it calls guessIndentation() at completion time rather than pre-computing during an earlier phase.

Why it matters: With the current approach, every new quickfix requires adding position logic to validation. "Fix deprecated action version"? Add position logic to validation. "Add missing runs-on"? More position logic. Validation accumulates code unrelated to detecting problems.

Specific issues in the current implementation:

Issue Code Problem
Dangerous fallback insertPosition = {line: 0, character: 0} Would insert at top of file on malformed YAML
Non-obvious offset withToken.range.end.line - 1 Comment says "after" but code inserts "before"
Scattered state stepIndent, withIndent, indentSize, insertPosition Four related values computed in validation, consumed in quickfix

Recommendation: Diagnostic carries only: missing inputs, action reference, step token range. Quickfix computes insertion point when generating the fix. Shared position utilities can emerge in the code-actions layer.

ericsciple
ericsciple previously approved these changes Jan 6, 2026
- Rename index.ts files to follow repo patterns:
  - code-actions/index.ts → code-actions/code-actions.ts
  - code-actions/quickfix/index.ts → quickfix/quickfix-providers.ts
- Move position calculation from validation to quickfix:
  - MissingInputsDiagnosticData now passes raw token ranges
  - Quickfix computes insertion position and indentation at code action time
  - detectIndentSize moved from validate.ts to validate-action-reference.ts
@rentziass rentziass force-pushed the rentziass/codeactions2 branch from cf63c84 to 1116f79 Compare January 7, 2026 17:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants