In YAML, block scalars (`|` and `>`) silently add a trailing newline by default
("clip" chomping). This can cause subtle bugs when the newline is unintentional.
This PR adds a warning when clip chomping is used in fields where trailing
newlines commonly cause issues:
- Environment variables (workflow, job, step, container, service levels)
- Action inputs (`with:`)
- Reusable workflow inputs and secrets
- Job outputs
- Matrix values (including `include` and `exclude`)
- Concurrency groups
The warning suggests using `|-` (strip) or `|+` (keep) to be explicit.
Intentionally does NOT warn for:
- `run:` scripts (trailing newlines are normal)
- Fields trimmed server-side (`if:`, `name:`, `runs-on:`, etc.)
The feature is gated behind the `blockScalarChompingWarning` feature flag.
Related #286 - When hovering over a cron expression, show the human-readable
description instead of empty content. Users who have inlay hints disabled
can now still see the cron description.
Follow-up to https://github.com/actions/languageservices/pull/289
## What this fixes
**Autocomplete was broken inside composite action steps.** When you typed inside a step and triggered autocomplete, nothing showed up. Now you correctly get suggestions like run, uses, shell, etc.
**Duplicate error messages for missing required fields.** When a required field was missing (like main for Node.js actions), users saw two error messages - one generic schema validation error, and one custom error with a clear explanation. Now they only see the custom one.
For example, with using: node24 but no main:
- Before: Two errors shown
- Schema: "There's not enough info to determine what you meant. Add one of these properties: args, entrypoint, image, main, ..."
- Custom: "'main' is required for Node.js actions (using: node24)"
- After: Only the custom error is shown
- Set main as required in node-runs-strict schema definition
- Add validation for invalid key combinations based on using value
- Add validation for missing required keys (main for node, steps for composite, image for docker)
- Filter autocomplete suggestions based on using value
- Prioritize 'using' in completions when not set yet
Fixes context-aware autocomplete for action.yml files where different
action types (node, composite, docker) have different valid keys under runs:
* Add experimentalFeatures to initialization options
Introduce a feature flagging system for opt-in experimental features.
Clients can enable features via initializationOptions.experimentalFeatures
with granular per-feature control or an 'all' flag to enable everything.
First experimental feature: missingInputsQuickfix (for upcoming code actions)
* Fix false positive for literal text in `if` conditions
Use token.value (parsed string without YAML quotes) instead of token.source
(raw YAML text) for expression parsing in single-line strings. This fixes a
false positive where `if: "${{ expr }}"` incorrectly triggered the
"literal text in condition" error because the outer quotes were treated as
literal text.
Follow-up to PR #216
Related issue: https://github.com/github/vscode-github-actions/issues/542
* Move issue reference to comment
Escape hatch completions now use a two-part edit strategy for VS Code compatibility:
- Main textEdit: Inserts newline and indented content at cursor position
(empty range so VS Code won't filter based on key text)
- additionalTextEdits: Replaces 'key: ' with 'key:' to remove trailing space
This prevents VS Code from filtering out escape hatches while still
producing the correct final YAML structure.
Escape hatch completions like '(switch to list)' and '(switch to mapping)'
were being filtered out in VS Code because filterText was set to the key
name (e.g., 'runs-on'), which doesn't match the empty string at the cursor
position when completing a value.
Since escape hatches only appear when the value is empty anyway, there's no
need for filterText. Without it, VS Code uses the label for filtering,
which properly shows them when no text is typed.
* Use labelDetails for completion item qualifiers
Use labelDetails.description instead of detail for qualifier text like
'full syntax' and 'list'. This renders the text inline after the label
in the completion menu, making variants immediately distinguishable
without hovering.
* Fix formatting
Provides runner label completions (ubuntu-latest, macos-latest, etc.)
when using the runs-on mapping syntax with the labels property:
jobs:
build:
runs-on:
labels: |
jobs:
build:
runs-on:
labels:
- |
Previously, completions only worked for the simple runs-on syntax:
jobs:
build:
runs-on: |
The fix registers the same value provider for both 'runs-on' and
'runs-on-labels' definition keys in the schema.
- Remove DiagnosticSeverity.Information for valid cron expressions
- Add new inlay-hints.ts module with getInlayHints() function
- Register inlayHintProvider capability in language server
- Display human-readable cron descriptions as inline hints
Related #269
When completing an empty value position (e.g., `runs-on: |`), add special
completions that let users switch to alternative structural forms:
- "(switch to list)" - restructures to `key:\n - `
- "(switch to mapping)" - restructures to `key:\n `
These help users escape "dead end" situations where the current form has
no valid completions but alternative forms are available in the schema.
- Move qualifiers (list, full syntax) from label to detail field
- Remove filterText since labels are now clean
- Update distinctValues to preserve variants with different details
- Standard LSP pattern: detail shown after label in completion UI
Follow-up to #265
When completing an empty value (e.g., `permissions: |`), mapping keys were
incorrectly shown alongside scalar values. This made completions confusing.
Before:
- `permissions: |` showed read-all, write-all, AND actions, contents, etc.
- `on: |` showed check_run AND check_run (full syntax), etc.
After:
- `permissions: |` shows only read-all and write-all
- `on: |` shows only event names like push, check_run
- `concurrency: |` shows no completions (user types their own group name)
Users who want the mapping form choose (full syntax) completions at the
parent level.
Recent autocomplete improvements (typing activation, completion chaining, schema
variant surfacing) now guide users to discover the full schema naturally. This
change removes the legacy behavior that showed invalid options and silently
transformed YAML upon insertion.
Key changes:
- Filter one-of completion options based on the token's actual structural type
- When user commits to scalar (non-empty string), only show scalar options
- When user commits to mapping/sequence, only show those options
- Skip null-only scalars in Key mode to prevent clobbering string constants
- Scalar event completions (e.g., check_run at 'on: |') now insert inline
This ensures that when a user explicitly chooses a simplified form, they only
see values valid for that form, creating a cleaner and more predictable
autocomplete experience.
* Expand one-of keys to multiple completion items
Some workflow fields accept multiple YAML structures (scalar, sequence, or
mapping), but completions previously only showed a single option—leaving users
unaware of the full schema flexibility. This change surfaces structural options
and inserts the correct YAML scaffolding so users land in the right place to
keep typing.
Example: runs-on
Completing runs-on now shows three options:
- runs-on → Ready for a string like ubuntu-latest
- runs-on (list) → Ready to add runner labels
- runs-on (full syntax) → Ready for labels:, group:, etc.
Notes:
- Qualifiers (list) and (full syntax) only appear when multiple structural types exist
- Scalar completions use the plain key name
- Qualified variants use filterText matching the base key
* Sort expanded one-of completions: scalar, list, full syntax
When completing a one-of typed property in key mode (e.g., 'check_run: ty|'),
insert newline and indentation to produce valid YAML structure instead of
inserting just the key name which creates invalid YAML.
Migrate expressions, workflow-parser, and languageservice packages to use
proper ESM imports with .js extensions that work with node16 moduleResolution.
Changes:
- Update tsconfig.build.json in each package to use module: node16 and
moduleResolution: node16
- Add .js extensions to all relative import paths (Option B approach)
- Fix yaml internal type imports in workflow-parser by defining local types
- Add skipLibCheck to handle @types/node compatibility issues
- Add TypeScript 5.8.3 override in root package.json
- Add ESM migration plan documentation
The languageserver package is deferred due to test hang issues that need
further investigation.
Related #154 - Upgrade moduleResolution from node to node16 or nodenext
Related #110 - Published ESM code has imports without file extensions
Related #64 - expressions: ERR_MODULE_NOT_FOUND attempting to run example
Related #146 - Can not import @actions/workflow-parser
Test results:
- expressions: 1068 tests passed
- workflow-parser: 292 tests passed
- languageservice: 452 tests passed
* docs: update ESM migration plan with findings
- Update languageserver blocker: vscode-languageserver v8.0.2 lacks ESM
exports (not a test hang issue)
- Document that Option B (manual .js extensions) was chosen over Option A
due to ts-jest compatibility issues
- Add workaround for yaml package internal types (LinePos, NodeBase)
- Update migration status table with accurate reason for deferral
- Add skipLibCheck note for @types/node compatibility
* Add ubuntu-slim and update runner labels
- Add ubuntu-slim runner (new 1-vCPU Linux runner)
- Add ubuntu-24.04 (current LTS)
- Update macOS runners to current versions (15, 14, 13)
- Remove deprecated runners (ubuntu-18.04, macos-12, macos-11, macos-10.15)
- Update tests to reflect new runner count
Fixes#255
* Remove macos-13 runner label
Per internal confirmation, macos-13 should not be included in the
suggested runner labels.
Fixes#51
Added the following activity types to pull_request and pull_request_target:
- milestoned
- demilestoned
- enqueued
- dequeued
These types were missing from workflow-v1.0.json but are valid workflow
triggers per GitHub docs.
Also added schema-sync.test.ts to ensure activity types in workflow-v1.0.json
stay in sync with webhooks.json. The test:
- Checks both directions (webhooks→schema and schema→webhooks)
- Has WEBHOOK_ONLY for types not valid as workflow triggers:
- check_suite: requested, rerequested
- registry_package: default
- Has SCHEMA_ONLY for types valid in workflows but not in webhooks:
- registry_package: updated
- Has NAME_MAPPINGS for naming differences:
- project_column: edited (webhook) ↔ updated (schema)
- Provides actionable error messages when mismatches are found
Fixes vscode#395 - Empty value for choice option shows 'Unexpected value' error
Empty strings are valid options for workflow_dispatch inputs with type: choice.
They allow users to make a choice 'optional' or force explicit selection.
Changes:
- Add sequence-of-string type that allows empty strings (unlike sequence-of-non-empty-string)
- Use sequence-of-string for workflow_dispatch options field
- Add test to verify empty string in choice options doesn't produce validation errors