Files
awesome-copilot/.github/workflows/skill-check.yml
T
Aaron Powell 28c3a14af4 Switch skill CI validation workflows to vally lint (#2030)
* Switch skill CI checks to vally lint

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Adding Vally to allowed words

* case sensitivity

* Migrate external plugin quality gates from skill-validator to vally lint

Replace the downloaded skill-validator binary with
px @microsoft/vally-cli lint
in the external plugin quality gates pipeline:

- Remove downloadSkillValidator() and SKILL_VALIDATOR_ARCHIVE_URL constant
- Replace uildSkillValidatorArgs() + 
unSkillValidatorGate() with
  uildVallyLintArgs() + 
unVallyLintGate() that run
px vally-cli lint
  per resolved skill directory (falling back to the full plugin root when no
  specific skill paths can be resolved from plugin.json)
- Rename result keys skill_validator_status / skill_validator_output
  to ally_lint_status / ally_lint_output throughout both
  ng/external-plugin-quality-gates.mjs and ng/external-plugin-intake.mjs
- Update PR comment markdown to show 'vally lint' instead of 'skill-validator'
- Update CONTRIBUTING.md prose references accordingly

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Use @microsoft/vally library directly instead of vally-cli subprocess

Replace the npx-spawned vally-cli process with a direct call to the
@microsoft/vally core library in the external plugin quality gates scripts:

- Add @microsoft/vally as a devDependency in package.json
- Import runLint and LintConsoleReporter from @microsoft/vally
- Replace runVallyLintGate() process spawn with async API call:
  - runLint({ rootPath }) returns structured LintResults
  - LintConsoleReporter with a Writable capture stream collects
    text output without printing to stdout
- Make runExternalPluginQualityGates() async (propagated to
  runExternalPluginPrQualityGates() and both main entry points)
- Use Promise.all in runExternalPluginPrQualityGates() for parallel
  plugin checks
- Fix remaining skill_validator_status reference in pr-quality-gates
  summary string (now vally-lint=...) and YAML workflow table header
- Add 'npm install @microsoft/vally' step to both calling workflows

This removes a layer of indirection (Node -> npx -> CLI -> library)
and replaces it with a direct in-process library call, which is faster,
more reliable, and gives structured access to lint results.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-30 14:07:45 +10:00

167 lines
5.8 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Vally Lint — PR Gate
on:
pull_request:
branches: [main]
types: [opened, synchronize, reopened]
paths:
- "skills/**"
- "agents/**"
- "plugins/**/skills/**"
- "plugins/**/agents/**"
permissions:
contents: read
jobs:
skill-check:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@3235b876344febd2b5f2414c5edc3a01b7f10a06 # v4.2.0
with:
node-version: 20
# ── Detect changed skills & agents ────────────────────────────
- name: Detect changed skills and agents
id: detect
run: |
declare -A SEEN_SKILL_DIRS=()
declare -A SEEN_AGENT_FILES=()
SKILL_DIRS=()
AGENT_FILES=()
while IFS= read -r -d '' file; do
case "$file" in
skills/*)
skill_dir="${file#skills/}"
skill_dir="skills/${skill_dir%%/*}"
if [ -d "$skill_dir" ] && [ -z "${SEEN_SKILL_DIRS[$skill_dir]+x}" ]; then
SEEN_SKILL_DIRS["$skill_dir"]=1
SKILL_DIRS+=("$skill_dir")
fi
;;
plugins/*/skills/*)
IFS='/' read -r seg1 seg2 seg3 seg4 _ <<< "$file"
skill_dir="$seg1/$seg2/$seg3/$seg4"
if [ -d "$skill_dir" ] && [ -z "${SEEN_SKILL_DIRS[$skill_dir]+x}" ]; then
SEEN_SKILL_DIRS["$skill_dir"]=1
SKILL_DIRS+=("$skill_dir")
fi
;;
esac
case "$file" in
agents/*.agent.md|plugins/*/agents/*.agent.md)
if [ -f "$file" ] && [ -z "${SEEN_AGENT_FILES[$file]+x}" ]; then
SEEN_AGENT_FILES["$file"]=1
AGENT_FILES+=("$file")
fi
;;
esac
done < <(git diff --name-only -z "origin/${{ github.base_ref }}...HEAD")
SKILL_COUNT=${#SKILL_DIRS[@]}
AGENT_COUNT=${#AGENT_FILES[@]}
TOTAL=$((SKILL_COUNT + AGENT_COUNT))
{
echo "total=$TOTAL"
echo "skill_count=$SKILL_COUNT"
echo "agent_count=$AGENT_COUNT"
echo "skill_dirs<<EOF"
printf '%s\n' "${SKILL_DIRS[@]}"
echo "EOF"
echo "agent_files<<EOF"
printf '%s\n' "${AGENT_FILES[@]}"
echo "EOF"
} >> "$GITHUB_OUTPUT"
echo "Found $SKILL_COUNT skill dir(s) and $AGENT_COUNT agent file(s) to check."
# ── Run vally lint check ───────────────────────────────────────
- name: Run vally lint check
id: check
if: steps.detect.outputs.total != '0'
env:
SKILL_DIRS_RAW: ${{ steps.detect.outputs.skill_dirs }}
AGENT_FILES_RAW: ${{ steps.detect.outputs.agent_files }}
run: |
SKILL_DIRS=()
AGENT_FILES=()
if [ -n "$SKILL_DIRS_RAW" ]; then
while IFS= read -r dir; do
[ -n "$dir" ] && SKILL_DIRS+=("$dir")
done <<< "$SKILL_DIRS_RAW"
fi
if [ -n "$AGENT_FILES_RAW" ]; then
while IFS= read -r file; do
[ -n "$file" ] && AGENT_FILES+=("$file")
done <<< "$AGENT_FILES_RAW"
fi
EXIT_CODE=0
: > vally-output.txt
if [ ${#SKILL_DIRS[@]} -eq 0 ] && [ ${#AGENT_FILES[@]} -eq 0 ]; then
echo "No skills or agents to validate." | tee -a vally-output.txt
fi
for skill_dir in "${SKILL_DIRS[@]}"; do
echo "### Linting ${skill_dir}" | tee -a vally-output.txt
set +e
OUTPUT=$(npx --yes @microsoft/vally-cli lint "$skill_dir" --verbose 2>&1)
CMD_EXIT=$?
set -e
echo "$OUTPUT" | tee -a vally-output.txt
echo "" >> vally-output.txt
if [ "$CMD_EXIT" -ne 0 ]; then
EXIT_CODE=1
fi
done
if [ ${#AGENT_FILES[@]} -gt 0 ]; then
{
echo "### Agent files detected (not linted by vally)"
echo "️ Vally currently lints SKILL.md content. Agent files were detected but skipped:"
printf '%s\n' "${AGENT_FILES[@]}"
echo ""
} | tee -a vally-output.txt
fi
echo "exit_code=$EXIT_CODE" >> "$GITHUB_OUTPUT"
# ── Upload results for the commenting workflow ────────────────
- name: Save metadata
if: always()
run: |
mkdir -p vally-results
echo "${{ github.event.pull_request.number }}" > vally-results/pr-number.txt
echo "${{ steps.detect.outputs.total }}" > vally-results/total.txt
echo "${{ steps.detect.outputs.skill_count }}" > vally-results/skill-count.txt
echo "${{ steps.detect.outputs.agent_count }}" > vally-results/agent-count.txt
echo "${{ steps.check.outputs.exit_code }}" > vally-results/exit-code.txt
if [ -f vally-output.txt ]; then
cp vally-output.txt vally-results/vally-output.txt
fi
- name: Upload results
if: always()
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
with:
name: vally-lint-results
path: vally-results/
retention-days: 1
- name: Post skip notice if no skills changed
if: steps.detect.outputs.total == '0'
run: echo "No skill or agent files changed in this PR — skipping validation."