mirror of
https://github.com/forcedotcom/afv-library.git
synced 2026-08-11 02:14:21 +08:00
chore: enhance skills validation and update workflows for npm publishing
This commit is contained in:
parent
a1ed6e21f2
commit
d2989fe74c
9
.github/workflows/release-skills.yml
vendored
9
.github/workflows/release-skills.yml
vendored
@ -6,6 +6,10 @@ on:
|
|||||||
paths: ['skills/**']
|
paths: ['skills/**']
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
packages: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -39,7 +43,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Create Github Release
|
- name: Create Github Release
|
||||||
id: release
|
id: release
|
||||||
uses: ncipollo/release-action@v2
|
uses: ncipollo/release-action@v1
|
||||||
if: ${{ steps.changelog.outputs.skipped == 'false' }}
|
if: ${{ steps.changelog.outputs.skipped == 'false' }}
|
||||||
with:
|
with:
|
||||||
name: "${{ steps.changelog.outputs.version }}"
|
name: "${{ steps.changelog.outputs.version }}"
|
||||||
@ -53,6 +57,7 @@ jobs:
|
|||||||
skipIfReleaseExists: true
|
skipIfReleaseExists: true
|
||||||
|
|
||||||
- name: Publish to npm
|
- name: Publish to npm
|
||||||
|
id: publish
|
||||||
if: ${{ steps.changelog.outputs.skipped == 'false' && steps.release.outputs.id != '' }}
|
if: ${{ steps.changelog.outputs.skipped == 'false' && steps.release.outputs.id != '' }}
|
||||||
run: |
|
run: |
|
||||||
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc
|
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc
|
||||||
@ -61,7 +66,7 @@ jobs:
|
|||||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
|
||||||
- name: Notify cline-fork
|
- name: Notify cline-fork
|
||||||
if: ${{ steps.changelog.outputs.skipped == 'false' }}
|
if: ${{ steps.changelog.outputs.skipped == 'false' && steps.release.outputs.id != '' && steps.publish.outcome == 'success' }}
|
||||||
uses: peter-evans/repository-dispatch@v3
|
uses: peter-evans/repository-dispatch@v3
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.IDEE_GH_TOKEN }}
|
token: ${{ secrets.IDEE_GH_TOKEN }}
|
||||||
|
|||||||
22
.github/workflows/validate-skills.yml
vendored
22
.github/workflows/validate-skills.yml
vendored
@ -9,8 +9,28 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
|
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm run validate
|
|
||||||
|
- name: Detect changed skill directories
|
||||||
|
id: changed-skills
|
||||||
|
run: |
|
||||||
|
# Collect top-level skill dirs touched by this PR (relative to skills/).
|
||||||
|
# Passing explicit dirs means pre-existing nested skill categories
|
||||||
|
# (to be flattened in a separate PR) don't block unrelated skill PRs.
|
||||||
|
DIRS=$(git diff --name-only origin/${{ github.base_ref }}...HEAD \
|
||||||
|
| grep '^skills/' \
|
||||||
|
| cut -d'/' -f2 \
|
||||||
|
| sort -u \
|
||||||
|
| tr '\n' ' ')
|
||||||
|
echo "dirs=$DIRS" >> $GITHUB_OUTPUT
|
||||||
|
echo "Validating skill dirs: $DIRS"
|
||||||
|
|
||||||
|
- name: Validate changed skills
|
||||||
|
run: npx tsx scripts/validate-skills.ts ${{ steps.changed-skills.outputs.dirs }}
|
||||||
|
|||||||
@ -6,13 +6,17 @@
|
|||||||
"files": [
|
"files": [
|
||||||
"skills/"
|
"skills/"
|
||||||
],
|
],
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public",
|
||||||
|
"registry": "https://registry.npmjs.org"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"tsx": "^4.21.0",
|
"tsx": "^4.21.0",
|
||||||
"@salesforce/webapp-template-app-react-sample-b2e-experimental": "*",
|
"@salesforce/webapp-template-app-react-sample-b2e-experimental": "*",
|
||||||
"@salesforce/webapp-template-app-react-sample-b2x-experimental": "*"
|
"@salesforce/webapp-template-app-react-sample-b2x-experimental": "*"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"validate": "tsx scripts/validate-skills.ts",
|
"validate:skills": "tsx scripts/validate-skills.ts",
|
||||||
"sync-react-b2e-sample": "node scripts/sync-react-b2e-sample.js",
|
"sync-react-b2e-sample": "node scripts/sync-react-b2e-sample.js",
|
||||||
"sync-react-b2x-sample": "node scripts/sync-react-b2x-sample.js"
|
"sync-react-b2x-sample": "node scripts/sync-react-b2x-sample.js"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
#!/usr/bin/env tsx
|
#!/usr/bin/env tsx
|
||||||
// Validates the skills/ directory structure and SKILL.md format.
|
// Validates the skills/ directory structure and SKILL.md format.
|
||||||
// Exits with code 1 if any violations are found.
|
// Exits with code 1 if any violations are found.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// tsx scripts/validate-skills.ts # validate all skills
|
||||||
|
// tsx scripts/validate-skills.ts apex-class # validate specific skill dirs
|
||||||
|
|
||||||
import fs from "fs"
|
import fs from "fs"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
@ -143,7 +147,10 @@ function parseFrontmatter(content: string): Record<string, string> | null {
|
|||||||
for (const line of match[1].split(/\r?\n/)) {
|
for (const line of match[1].split(/\r?\n/)) {
|
||||||
const colonIdx = line.indexOf(":")
|
const colonIdx = line.indexOf(":")
|
||||||
if (colonIdx === -1) continue
|
if (colonIdx === -1) continue
|
||||||
result[line.slice(0, colonIdx).trim()] = line.slice(colonIdx + 1).trim()
|
const key = line.slice(0, colonIdx).trim()
|
||||||
|
// Strip wrapping single or double quotes to match how consumers read values
|
||||||
|
const raw = line.slice(colonIdx + 1).trim()
|
||||||
|
result[key] = raw.replace(/^(['"])([\s\S]*)\1$/, "$2")
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -158,6 +165,10 @@ function getFrontmatterEnd(content: string): number {
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
function validateSkill(dirName: string, dirPath: string): string[] {
|
function validateSkill(dirName: string, dirPath: string): string[] {
|
||||||
|
if (!fs.existsSync(dirPath)) {
|
||||||
|
return [`skills/${dirName}: directory not found`]
|
||||||
|
}
|
||||||
|
|
||||||
const errors: string[] = []
|
const errors: string[] = []
|
||||||
|
|
||||||
for (const check of STRUCTURE_CHECKS) {
|
for (const check of STRUCTURE_CHECKS) {
|
||||||
@ -182,13 +193,18 @@ function validateSkill(dirName: string, dirPath: string): string[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function main(): void {
|
function main(): void {
|
||||||
const allErrors: string[] = []
|
// If skill dir names are passed as arguments, validate only those.
|
||||||
let checked = 0
|
// Otherwise validate all entries in skills/.
|
||||||
|
const targets = process.argv.slice(2)
|
||||||
|
const entries = targets.length > 0 ? targets : fs.readdirSync(SKILLS_DIR)
|
||||||
|
|
||||||
for (const entry of fs.readdirSync(SKILLS_DIR)) {
|
const allErrors: string[] = []
|
||||||
|
let passed = 0
|
||||||
|
|
||||||
|
for (const entry of entries) {
|
||||||
const entryErrors = validateSkill(entry, path.join(SKILLS_DIR, entry))
|
const entryErrors = validateSkill(entry, path.join(SKILLS_DIR, entry))
|
||||||
allErrors.push(...entryErrors)
|
allErrors.push(...entryErrors)
|
||||||
if (entryErrors.length === 0) checked++
|
if (entryErrors.length === 0) passed++
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allErrors.length > 0) {
|
if (allErrors.length > 0) {
|
||||||
@ -199,7 +215,7 @@ function main(): void {
|
|||||||
console.error("")
|
console.error("")
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
} else {
|
} else {
|
||||||
console.log(`Skill validation passed: ${checked} skill(s) checked.`)
|
console.log(`Skill validation passed: ${passed} of ${entries.length} skill(s) checked.`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user