mirror of
https://github.com/github/awesome-copilot.git
synced 2026-06-17 13:11:27 +00:00
chore: publish from staged
This commit is contained in:
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
- [ ] I have read and followed the [CONTRIBUTING.md](https://github.com/github/awesome-copilot/blob/main/CONTRIBUTING.md) guidelines.
|
- [ ] I have read and followed the [CONTRIBUTING.md](https://github.com/github/awesome-copilot/blob/main/CONTRIBUTING.md) guidelines.
|
||||||
- [ ] I have read and followed the [Guidance for submissions involving paid services](https://github.com/github/awesome-copilot/discussions/968).
|
- [ ] I have read and followed the [Guidance for submissions involving paid services](https://github.com/github/awesome-copilot/discussions/968).
|
||||||
- [ ] My contribution adds a new instruction, prompt, agent, skill, or workflow file in the correct directory.
|
- [ ] My contribution adds a new instruction, prompt, agent, skill, workflow, or canvas extension file in the correct directory.
|
||||||
- [ ] The file follows the required naming convention.
|
- [ ] The file follows the required naming convention.
|
||||||
- [ ] The content is clearly structured and follows the example format.
|
- [ ] The content is clearly structured and follows the example format.
|
||||||
- [ ] I have tested my instructions, prompt, agent, skill, or workflow with GitHub Copilot.
|
- [ ] I have tested my instructions, prompt, agent, skill, workflow, or canvas extension with GitHub Copilot.
|
||||||
- [ ] I have run `npm start` and verified that `README.md` is up to date.
|
- [ ] I have run `npm start` and verified that `README.md` is up to date.
|
||||||
- [ ] I am targeting the `staged` branch for this pull request.
|
- [ ] I am targeting the `staged` branch for this pull request.
|
||||||
|
|
||||||
@@ -25,7 +25,8 @@
|
|||||||
- [ ] New plugin.
|
- [ ] New plugin.
|
||||||
- [ ] New skill file.
|
- [ ] New skill file.
|
||||||
- [ ] New agentic workflow.
|
- [ ] New agentic workflow.
|
||||||
- [ ] Update to existing instruction, prompt, agent, plugin, skill, or workflow.
|
- [ ] New canvas extension.
|
||||||
|
- [ ] Update to existing instruction, prompt, agent, plugin, skill, workflow, or canvas extension.
|
||||||
- [ ] Other (please specify):
|
- [ ] Other (please specify):
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -63,6 +63,10 @@ jobs:
|
|||||||
'workflow': {
|
'workflow': {
|
||||||
color: 'BFD4F2',
|
color: 'BFD4F2',
|
||||||
description: 'PR touches workflow automation'
|
description: 'PR touches workflow automation'
|
||||||
|
},
|
||||||
|
'canvas-extension': {
|
||||||
|
color: 'E4B9FF',
|
||||||
|
description: 'PR touches canvas extensions'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -139,12 +143,16 @@ jobs:
|
|||||||
/^workflows\/.+\.md$/,
|
/^workflows\/.+\.md$/,
|
||||||
/^\.github\/workflows\/.+\.(?:ya?ml|md)$/
|
/^\.github\/workflows\/.+\.(?:ya?ml|md)$/
|
||||||
],
|
],
|
||||||
|
canvasExtension: [
|
||||||
|
/^extensions\/[^/]+\//
|
||||||
|
],
|
||||||
newSubmission: [
|
newSubmission: [
|
||||||
/^agents\/.+\.agent\.md$/,
|
/^agents\/.+\.agent\.md$/,
|
||||||
/^instructions\/.+\.instructions\.md$/,
|
/^instructions\/.+\.instructions\.md$/,
|
||||||
/^skills\/[^/]+\/SKILL\.md$/,
|
/^skills\/[^/]+\/SKILL\.md$/,
|
||||||
/^hooks\/[^/]+\/(?:README\.md|hooks\.json)$/,
|
/^hooks\/[^/]+\/(?:README\.md|hooks\.json)$/,
|
||||||
/^plugins\/[^/]+\/\.github\/plugin\/plugin\.json$/,
|
/^plugins\/[^/]+\/\.github\/plugin\/plugin\.json$/,
|
||||||
|
/^extensions\/[^/]+\/extension\.mjs$/,
|
||||||
/^workflows\/.+\.md$/,
|
/^workflows\/.+\.md$/,
|
||||||
/^\.github\/workflows\/.+\.(?:ya?ml|md)$/,
|
/^\.github\/workflows\/.+\.(?:ya?ml|md)$/,
|
||||||
/^website\//
|
/^website\//
|
||||||
@@ -197,6 +205,10 @@ jobs:
|
|||||||
desiredLabels.add('workflow');
|
desiredLabels.add('workflow');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filenames.some((filename) => matchesAny(filename, patterns.canvasExtension))) {
|
||||||
|
desiredLabels.add('canvas-extension');
|
||||||
|
}
|
||||||
|
|
||||||
if (hasNewSubmission) {
|
if (hasNewSubmission) {
|
||||||
desiredLabels.add('new-submission');
|
desiredLabels.add('new-submission');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
name: Validate Canvas Extensions
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: [staged]
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
paths:
|
||||||
|
- "extensions/**"
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Validate changed canvas extensions
|
||||||
|
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
// Collect changed extension directories from the PR diff
|
||||||
|
const { execSync } = require('child_process');
|
||||||
|
const changedFiles = execSync(
|
||||||
|
`git diff --name-only origin/${{ github.base_ref }}...HEAD`
|
||||||
|
).toString().trim().split('\n').filter(Boolean);
|
||||||
|
|
||||||
|
const EXTENSIONS_DIR = 'extensions';
|
||||||
|
const EXTERNAL_ASSETS_DIR = 'external-assets';
|
||||||
|
|
||||||
|
const changedExtDirs = new Set();
|
||||||
|
for (const file of changedFiles) {
|
||||||
|
const parts = file.split('/');
|
||||||
|
if (parts[0] === EXTENSIONS_DIR && parts.length >= 2) {
|
||||||
|
const extName = parts[1];
|
||||||
|
// Skip the external-assets directory — it's not a canvas extension
|
||||||
|
if (extName !== EXTERNAL_ASSETS_DIR) {
|
||||||
|
changedExtDirs.add(path.join(EXTENSIONS_DIR, extName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changedExtDirs.size === 0) {
|
||||||
|
console.log('No canvas extension directories changed — skipping validation.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Validating ${changedExtDirs.size} extension(s): ${[...changedExtDirs].join(', ')}`);
|
||||||
|
|
||||||
|
const errors = [];
|
||||||
|
|
||||||
|
for (const extDir of changedExtDirs) {
|
||||||
|
if (!fs.existsSync(extDir)) {
|
||||||
|
// Directory was deleted — skip
|
||||||
|
console.log(`${extDir} no longer exists (deleted?), skipping.`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const extName = path.basename(extDir);
|
||||||
|
|
||||||
|
// Rule 1: must contain extension.mjs
|
||||||
|
const mainFile = path.join(extDir, 'extension.mjs');
|
||||||
|
if (!fs.existsSync(mainFile)) {
|
||||||
|
errors.push(
|
||||||
|
`**\`${extDir}\`**: missing required \`extension.mjs\`. ` +
|
||||||
|
`Canvas extensions must have their entry point named \`extension.mjs\`.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rule 2: must contain assets/preview.png
|
||||||
|
const previewFile = path.join(extDir, 'assets', 'preview.png');
|
||||||
|
if (!fs.existsSync(previewFile)) {
|
||||||
|
errors.push(
|
||||||
|
`**\`${extDir}\`**: missing required \`assets/preview.png\`. ` +
|
||||||
|
`Canvas extensions must include a screenshot at \`assets/preview.png\` ` +
|
||||||
|
`so reviewers and users can preview the extension before installing it.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errors.length === 0) {
|
||||||
|
console.log('✅ All changed canvas extensions pass validation.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isFork = context.payload.pull_request.head.repo.fork;
|
||||||
|
const body = [
|
||||||
|
'❌ **Canvas extension validation failed**',
|
||||||
|
'',
|
||||||
|
'The following issue(s) were found in changed canvas extension(s):',
|
||||||
|
'',
|
||||||
|
...errors.map(e => `- ${e}`),
|
||||||
|
'',
|
||||||
|
'---',
|
||||||
|
'',
|
||||||
|
'### Required structure for canvas extensions',
|
||||||
|
'',
|
||||||
|
'Each extension folder under `extensions/` must contain:',
|
||||||
|
'',
|
||||||
|
'| Path | Required | Description |',
|
||||||
|
'|------|----------|-------------|',
|
||||||
|
'| `extension.mjs` | ✅ | Entry point for the canvas extension |',
|
||||||
|
'| `assets/preview.png` | ✅ | Screenshot shown on the website and in the marketplace |',
|
||||||
|
'',
|
||||||
|
'Please add the missing file(s) and push an update to this PR.',
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
if (!isFork) {
|
||||||
|
try {
|
||||||
|
await github.rest.pulls.createReview({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
pull_number: context.issue.number,
|
||||||
|
event: 'REQUEST_CHANGES',
|
||||||
|
body
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
core.warning(`Could not post PR review: ${error.message}`);
|
||||||
|
core.warning(body);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
core.warning('PR is from a fork — skipping createReview to avoid permission errors.');
|
||||||
|
core.warning(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
core.setFailed(`Canvas extension validation failed with ${errors.length} error(s).`);
|
||||||
Reference in New Issue
Block a user