Implement GitHub Copilot repository instructions support
Co-authored-by: AstroSteveo <34114851+AstroSteveo@users.noreply.github.com>
This commit is contained in:
parent
36bc6de2a9
commit
920c966ed9
1
.github/copilot-instructions.md
vendored
1
.github/copilot-instructions.md
vendored
@ -39,3 +39,4 @@ The following instructions are only to be applied when performing a code review.
|
||||
* [ ] The file name is lower case, with words separated by hyphens.
|
||||
* [ ] Encourage the use of `tools`, but it's not required.
|
||||
* [ ] Strongly encourage the use of `model` to specify the model that the chat mode is optimised for.
|
||||
|
||||
|
||||
58
CONFIG.md
58
CONFIG.md
@ -183,6 +183,64 @@ The `node awesome-copilot.js init` command automatically configures VS Code to d
|
||||
|
||||
No manual VS Code configuration needed!
|
||||
|
||||
## GitHub Copilot Repository Instructions
|
||||
|
||||
Awesome Copilot can generate a `.github/copilot-instructions.md` file that provides repository-level instructions to GitHub Copilot. This feature supports GitHub's native repository instructions capability, which automatically applies instructions to all Copilot interactions within your repository.
|
||||
|
||||
### Generating Repository Instructions
|
||||
|
||||
```bash
|
||||
# Generate basic repository instructions file
|
||||
node /path/to/awesome-copilot/awesome-copilot.js generate-repo-instructions
|
||||
|
||||
# Generate with full instruction content included
|
||||
node /path/to/awesome-copilot/awesome-copilot.js generate-repo-instructions --consolidated
|
||||
|
||||
# Custom output location
|
||||
node /path/to/awesome-copilot/awesome-copilot.js generate-repo-instructions --output=.copilot/instructions.md
|
||||
|
||||
# Generate without header
|
||||
node /path/to/awesome-copilot/awesome-copilot.js generate-repo-instructions --no-header
|
||||
```
|
||||
|
||||
### Template Options
|
||||
|
||||
- **`repository` (default)**: Lists enabled instructions with references to individual files
|
||||
- **`consolidated`**: Includes full content from all enabled instruction files
|
||||
- **`basic`**: Simple list without detailed formatting
|
||||
|
||||
### Benefits of Repository Instructions
|
||||
|
||||
- **Automatic Application**: Instructions apply to all team members without manual configuration
|
||||
- **Version Control**: Instructions are tracked with your code and evolve with your project
|
||||
- **IDE Agnostic**: Works across VS Code, Visual Studio, GitHub Copilot CLI, and web interfaces
|
||||
- **Consistency**: Ensures all team members get the same Copilot behavior
|
||||
- **No Setup Required**: New team members automatically get proper instructions
|
||||
|
||||
### Integration with Configuration
|
||||
|
||||
The repository instructions are generated based on your enabled instructions in the configuration file:
|
||||
|
||||
```yaml
|
||||
instructions:
|
||||
csharp: true # Included in repository instructions
|
||||
python: true # Included in repository instructions
|
||||
java: false # Excluded from repository instructions
|
||||
|
||||
collections:
|
||||
testing-automation: true # All instructions in this collection included
|
||||
```
|
||||
|
||||
### Workflow Integration
|
||||
|
||||
Repository instructions work seamlessly with the existing workflow:
|
||||
|
||||
1. **Configure**: Enable instructions in your config file
|
||||
2. **Apply**: Run `awesome-copilot apply` to copy files to your project
|
||||
3. **Generate**: Run `generate-repo-instructions` to create the repository instructions file
|
||||
4. **Commit**: Add the generated file to version control
|
||||
5. **Collaborate**: Team members automatically get consistent Copilot behavior
|
||||
|
||||
## Examples
|
||||
|
||||
### Frontend React Project
|
||||
|
||||
25
README.md
25
README.md
@ -85,8 +85,33 @@ Use our configuration system to manage all customizations in one place:
|
||||
node /path/to/awesome-copilot/awesome-copilot.js apply
|
||||
```
|
||||
|
||||
6. **Generate repository instructions** (optional, for GitHub Copilot repository-level instructions):
|
||||
```bash
|
||||
# Generate .github/copilot-instructions.md from enabled instructions
|
||||
node /path/to/awesome-copilot/awesome-copilot.js generate-repo-instructions
|
||||
|
||||
# Or generate with full instruction content included
|
||||
node /path/to/awesome-copilot/awesome-copilot.js generate-repo-instructions --consolidated
|
||||
```
|
||||
|
||||
See [CONFIG.md](CONFIG.md) for detailed configuration documentation.
|
||||
|
||||
#### 🤖 GitHub Copilot Repository Instructions
|
||||
|
||||
Awesome Copilot can generate a `.github/copilot-instructions.md` file that provides repository-level instructions to GitHub Copilot. This file is automatically recognized by GitHub Copilot and applies to all code generation within your repository.
|
||||
|
||||
**Benefits:**
|
||||
- Instructions automatically apply to all Copilot interactions in your repository
|
||||
- No need to manually configure VS Code settings for each team member
|
||||
- Instructions are version-controlled with your code
|
||||
- Works across all supported IDEs and GitHub Copilot interfaces
|
||||
|
||||
**Templates:**
|
||||
- `--basic`: Simple list of enabled instructions (default)
|
||||
- `--consolidated`: Includes full content of all enabled instruction files
|
||||
- Custom templates can be created by modifying the `repository-instructions.js` file
|
||||
|
||||
|
||||
#### ⚖️ Configuration Precedence Rules
|
||||
|
||||
Awesome Copilot uses an **effective state system** that respects explicit overrides while allowing collections to provide convenient defaults. The effective state computation follows these precise rules:
|
||||
|
||||
@ -196,6 +196,11 @@ async function applyConfig(configPath = "awesome-copilot.config.yml") {
|
||||
console.log("2. Use prompts with /awesome-copilot command in GitHub Copilot Chat");
|
||||
console.log("3. Instructions will automatically apply to your coding");
|
||||
console.log("4. Import chat modes in VS Code settings");
|
||||
|
||||
// Suggest generating repository instructions if instructions are enabled
|
||||
if (summary.instructions > 0) {
|
||||
console.log("5. Consider running 'awesome-copilot generate-repo-instructions' to create .github/copilot-instructions.md");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -68,6 +68,15 @@ const commands = {
|
||||
}
|
||||
},
|
||||
|
||||
"generate-repo-instructions": {
|
||||
description: "Generate .github/copilot-instructions.md from enabled instructions",
|
||||
usage: "awesome-copilot generate-repo-instructions [config-file] [--consolidated|--basic] [--output=<file>] [--no-header]",
|
||||
action: async (args) => {
|
||||
const { handleGenerateRepoInstructions } = require("./repository-instructions");
|
||||
await handleGenerateRepoInstructions(args);
|
||||
}
|
||||
},
|
||||
|
||||
help: {
|
||||
description: "Show help information",
|
||||
usage: "awesome-copilot help",
|
||||
@ -101,11 +110,14 @@ function showHelp() {
|
||||
console.log(" awesome-copilot toggle instructions all off --config team.yml # Disable all instructions");
|
||||
console.log(" awesome-copilot toggle prompts all on --all # Force enable ALL prompts (override explicit settings)");
|
||||
console.log(" awesome-copilot toggle collections testing-automation on --apply # Enable collection and apply");
|
||||
console.log(" awesome-copilot generate-repo-instructions # Generate .github/copilot-instructions.md");
|
||||
console.log(" awesome-copilot generate-repo-instructions --consolidated # Include full instruction content");
|
||||
console.log("");
|
||||
console.log("Workflow:");
|
||||
console.log(" 1. Run 'awesome-copilot init' to create a configuration file");
|
||||
console.log(" 2. Use 'awesome-copilot list' and 'awesome-copilot toggle' to manage enabled items");
|
||||
console.log(" 3. Run 'awesome-copilot apply' to copy files to your project");
|
||||
console.log(" 4. Run 'awesome-copilot generate-repo-instructions' for GitHub Copilot repository instructions");
|
||||
}
|
||||
|
||||
function showError(message) {
|
||||
|
||||
344
repository-instructions.js
Normal file
344
repository-instructions.js
Normal file
@ -0,0 +1,344 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { parseConfigYamlContent } = require("./apply-config");
|
||||
const { computeEffectiveItemStates } = require("./config-manager");
|
||||
|
||||
/**
|
||||
* Generate or update .github/copilot-instructions.md based on enabled instructions
|
||||
*/
|
||||
async function generateRepositoryInstructions(configPath = "awesome-copilot.config.yml", options = {}) {
|
||||
const {
|
||||
outputFile = ".github/copilot-instructions.md",
|
||||
template = "repository",
|
||||
includeHeader = true,
|
||||
rootDir = __dirname
|
||||
} = options;
|
||||
|
||||
console.log("🤖 Generating GitHub Copilot repository instructions...");
|
||||
|
||||
// Load configuration
|
||||
if (!fs.existsSync(configPath)) {
|
||||
throw new Error(`Configuration file not found: ${configPath}`);
|
||||
}
|
||||
|
||||
const rawContent = fs.readFileSync(configPath, "utf8");
|
||||
const config = parseConfigYamlContent(rawContent) || {};
|
||||
|
||||
// Compute effective states to determine which instructions are enabled
|
||||
const effectiveStates = computeEffectiveItemStates(config);
|
||||
|
||||
// Get enabled instructions
|
||||
const enabledInstructions = [];
|
||||
for (const [instructionName, state] of Object.entries(effectiveStates.instructions)) {
|
||||
if (state.enabled) {
|
||||
const instructionPath = path.join(rootDir, "instructions", `${instructionName}.instructions.md`);
|
||||
if (fs.existsSync(instructionPath)) {
|
||||
enabledInstructions.push({
|
||||
name: instructionName,
|
||||
path: instructionPath,
|
||||
reason: state.reason
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`📋 Found ${enabledInstructions.length} enabled instructions`);
|
||||
|
||||
// Generate the repository instructions content
|
||||
const content = await generateInstructionsContent(enabledInstructions, template, includeHeader);
|
||||
|
||||
// Ensure output directory exists
|
||||
const outputDir = path.dirname(outputFile);
|
||||
if (!fs.existsSync(outputDir)) {
|
||||
fs.mkdirSync(outputDir, { recursive: true });
|
||||
console.log(`📁 Created directory: ${outputDir}`);
|
||||
}
|
||||
|
||||
// Write the file
|
||||
fs.writeFileSync(outputFile, content);
|
||||
console.log(`✅ Generated repository instructions: ${outputFile}`);
|
||||
|
||||
return {
|
||||
file: outputFile,
|
||||
instructionsCount: enabledInstructions.length,
|
||||
instructions: enabledInstructions.map(i => i.name)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the content for the repository instructions file
|
||||
*/
|
||||
async function generateInstructionsContent(enabledInstructions, template, includeHeader) {
|
||||
let content = "";
|
||||
|
||||
if (includeHeader) {
|
||||
content += generateHeader();
|
||||
}
|
||||
|
||||
if (enabledInstructions.length === 0) {
|
||||
content += generateEmptyInstructions();
|
||||
return content;
|
||||
}
|
||||
|
||||
// Add instructions based on template
|
||||
if (template === "repository") {
|
||||
content += generateRepositoryTemplate(enabledInstructions);
|
||||
} else if (template === "consolidated") {
|
||||
content += await generateConsolidatedTemplate(enabledInstructions);
|
||||
} else {
|
||||
content += await generateBasicTemplate(enabledInstructions);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate header for the repository instructions
|
||||
*/
|
||||
function generateHeader() {
|
||||
return `# GitHub Copilot Repository Instructions
|
||||
|
||||
This file contains custom instructions for GitHub Copilot when working in this repository.
|
||||
These instructions are automatically generated from the enabled instruction files in the awesome-copilot configuration.
|
||||
|
||||
## How This Works
|
||||
|
||||
GitHub Copilot will automatically use these instructions when:
|
||||
- You're working in this repository
|
||||
- Copilot is generating code, explanations, or suggestions
|
||||
- You're using Copilot Chat within this repository context
|
||||
|
||||
## Instructions Source
|
||||
|
||||
These instructions are compiled from the following sources:
|
||||
- Enabled instruction files from the awesome-copilot configuration
|
||||
- Repository-specific coding standards and best practices
|
||||
- Technology-specific guidelines relevant to this project
|
||||
|
||||
---
|
||||
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content when no instructions are enabled
|
||||
*/
|
||||
function generateEmptyInstructions() {
|
||||
return `## No Instructions Enabled
|
||||
|
||||
Currently, no instruction files are enabled in the awesome-copilot configuration.
|
||||
|
||||
To add instructions:
|
||||
1. Edit your \`awesome-copilot.config.yml\` file
|
||||
2. Enable the desired instruction files
|
||||
3. Run \`awesome-copilot generate-repo-instructions\` to update this file
|
||||
|
||||
Available instructions can be found in the \`instructions/\` directory.
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate repository-style template with references to instruction files
|
||||
*/
|
||||
function generateRepositoryTemplate(enabledInstructions) {
|
||||
let content = `## Active Instructions
|
||||
|
||||
The following ${enabledInstructions.length} instruction set${enabledInstructions.length !== 1 ? 's are' : ' is'} currently active for this repository:
|
||||
|
||||
`;
|
||||
|
||||
// Group instructions by reason
|
||||
const groupedByReason = {};
|
||||
enabledInstructions.forEach(instruction => {
|
||||
const reason = instruction.reason || 'explicit';
|
||||
if (!groupedByReason[reason]) {
|
||||
groupedByReason[reason] = [];
|
||||
}
|
||||
groupedByReason[reason].push(instruction);
|
||||
});
|
||||
|
||||
// Add instructions grouped by reason
|
||||
for (const [reason, instructions] of Object.entries(groupedByReason)) {
|
||||
content += `### ${reason === 'explicit' ? 'Explicitly Enabled' :
|
||||
reason === 'collection' ? 'Enabled via Collections' :
|
||||
reason.charAt(0).toUpperCase() + reason.slice(1)}\n\n`;
|
||||
|
||||
instructions.forEach(instruction => {
|
||||
const title = extractTitleFromInstruction(instruction.path) || instruction.name;
|
||||
content += `- **${title}** (\`${instruction.name}\`)\n`;
|
||||
});
|
||||
content += '\n';
|
||||
}
|
||||
|
||||
content += `## Instruction Details
|
||||
|
||||
For detailed information about each instruction set, refer to the individual instruction files in the \`instructions/\` directory.
|
||||
|
||||
`;
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate consolidated template with full instruction content
|
||||
*/
|
||||
async function generateConsolidatedTemplate(enabledInstructions) {
|
||||
let content = `## Consolidated Instructions
|
||||
|
||||
The following instructions combine all enabled instruction sets:
|
||||
|
||||
`;
|
||||
|
||||
for (const instruction of enabledInstructions) {
|
||||
const title = extractTitleFromInstruction(instruction.path) || instruction.name;
|
||||
const instructionContent = fs.readFileSync(instruction.path, 'utf8');
|
||||
|
||||
// Extract the main content (skip frontmatter)
|
||||
const cleanContent = extractInstructionContent(instructionContent);
|
||||
|
||||
content += `### ${title}
|
||||
|
||||
${cleanContent}
|
||||
|
||||
---
|
||||
|
||||
`;
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate basic template with simple list
|
||||
*/
|
||||
async function generateBasicTemplate(enabledInstructions) {
|
||||
let content = `## Enabled Instructions
|
||||
|
||||
`;
|
||||
|
||||
enabledInstructions.forEach(instruction => {
|
||||
const title = extractTitleFromInstruction(instruction.path) || instruction.name;
|
||||
content += `- ${title}\n`;
|
||||
});
|
||||
|
||||
content += `\nFor detailed instruction content, see the individual files in the \`instructions/\` directory.
|
||||
|
||||
`;
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract title from instruction file
|
||||
*/
|
||||
function extractTitleFromInstruction(filePath) {
|
||||
try {
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
const lines = content.split('\n');
|
||||
|
||||
// Look for title in frontmatter first
|
||||
let inFrontmatter = false;
|
||||
for (const line of lines) {
|
||||
if (line.trim() === '---') {
|
||||
inFrontmatter = !inFrontmatter;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inFrontmatter && line.includes('title:')) {
|
||||
const title = line.substring(line.indexOf('title:') + 6).trim();
|
||||
return title.replace(/^['"]|['"]$/g, '');
|
||||
}
|
||||
}
|
||||
|
||||
// Look for first heading
|
||||
for (const line of lines) {
|
||||
if (line.startsWith('# ')) {
|
||||
return line.substring(2).trim();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract main content from instruction file (skip frontmatter)
|
||||
*/
|
||||
function extractInstructionContent(content) {
|
||||
const lines = content.split('\n');
|
||||
let inFrontmatter = false;
|
||||
let frontmatterEnded = false;
|
||||
const contentLines = [];
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.trim() === '---') {
|
||||
if (!inFrontmatter) {
|
||||
inFrontmatter = true;
|
||||
continue;
|
||||
} else if (inFrontmatter && !frontmatterEnded) {
|
||||
frontmatterEnded = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inFrontmatter || frontmatterEnded) {
|
||||
contentLines.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
return contentLines.join('\n').trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* CLI handler for generate-repo-instructions command
|
||||
*/
|
||||
async function handleGenerateRepoInstructions(args) {
|
||||
const configFile = args.find(arg => !arg.startsWith('--')) || "awesome-copilot.config.yml";
|
||||
|
||||
// Parse flags
|
||||
const template = args.includes('--consolidated') ? 'consolidated' :
|
||||
args.includes('--basic') ? 'basic' : 'repository';
|
||||
const outputFile = args.find(arg => arg.startsWith('--output='))?.split('=')[1] ||
|
||||
".github/copilot-instructions.md";
|
||||
const noHeader = args.includes('--no-header');
|
||||
|
||||
try {
|
||||
const result = await generateRepositoryInstructions(configFile, {
|
||||
outputFile,
|
||||
template,
|
||||
includeHeader: !noHeader
|
||||
});
|
||||
|
||||
console.log(`\n📋 Repository instructions generated successfully!`);
|
||||
console.log(`📁 File: ${result.file}`);
|
||||
console.log(`📊 Instructions: ${result.instructionsCount}`);
|
||||
|
||||
if (result.instructions.length > 0) {
|
||||
console.log(`📝 Included: ${result.instructions.join(', ')}`);
|
||||
}
|
||||
|
||||
console.log(`\n💡 Next steps:`);
|
||||
console.log(` • Commit the generated file to enable repository-wide Copilot instructions`);
|
||||
console.log(` • GitHub Copilot will automatically use these instructions in this repository`);
|
||||
console.log(` • Update instructions by modifying your config and re-running this command`);
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ Error generating repository instructions: ${error.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generateRepositoryInstructions,
|
||||
handleGenerateRepoInstructions
|
||||
};
|
||||
|
||||
// CLI usage
|
||||
if (require.main === module) {
|
||||
const args = process.argv.slice(2);
|
||||
handleGenerateRepoInstructions(args);
|
||||
}
|
||||
12
test-all.js
12
test-all.js
@ -52,6 +52,15 @@ async function runAllTests() {
|
||||
console.error('Apply tests failed with error:', error.message);
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('\n🤖 Repository Instructions Tests');
|
||||
console.log('-' * 33);
|
||||
const { runTests: runRepoInstructionsTests } = require('./test-repository-instructions');
|
||||
results.repoInstructions = await runRepoInstructionsTests();
|
||||
} catch (error) {
|
||||
console.error('Repository instructions tests failed with error:', error.message);
|
||||
}
|
||||
|
||||
// Summary
|
||||
console.log('\n' + '=' * 60);
|
||||
console.log('📋 Test Suite Summary');
|
||||
@ -61,7 +70,8 @@ async function runAllTests() {
|
||||
{ name: 'Unit Tests', result: results.unit, emoji: '📊' },
|
||||
{ name: 'Integration Tests', result: results.integration, emoji: '🔄' },
|
||||
{ name: 'CLI Tests', result: results.cli, emoji: '⌨️' },
|
||||
{ name: 'Apply Tests', result: results.apply, emoji: '🎯' }
|
||||
{ name: 'Apply Tests', result: results.apply, emoji: '🎯' },
|
||||
{ name: 'Repo Instructions', result: results.repoInstructions, emoji: '🤖' }
|
||||
];
|
||||
|
||||
testTypes.forEach(test => {
|
||||
|
||||
198
test-repository-instructions.js
Normal file
198
test-repository-instructions.js
Normal file
@ -0,0 +1,198 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { generateRepositoryInstructions } = require("./repository-instructions");
|
||||
|
||||
console.log("🧪 Testing Repository Instructions Generation");
|
||||
console.log("=".repeat(50));
|
||||
|
||||
/**
|
||||
* Test repository instructions generation
|
||||
*/
|
||||
async function testRepositoryInstructions() {
|
||||
const testConfigPath = "test-repo-instructions.yml";
|
||||
const testOutputPath = ".github/test-copilot-instructions.md";
|
||||
|
||||
// Create a test configuration with some enabled instructions
|
||||
const testConfig = `# Test configuration for repository instructions
|
||||
instructions:
|
||||
javascript: true
|
||||
python: false
|
||||
csharp: true
|
||||
|
||||
collections:
|
||||
frontend-web-dev: true
|
||||
`;
|
||||
|
||||
try {
|
||||
// Write test config
|
||||
fs.writeFileSync(testConfigPath, testConfig);
|
||||
console.log("✅ Created test configuration");
|
||||
|
||||
// Test basic generation
|
||||
console.log("\n📋 Testing basic repository instructions generation...");
|
||||
const result = await generateRepositoryInstructions(testConfigPath, {
|
||||
outputFile: testOutputPath,
|
||||
template: "repository"
|
||||
});
|
||||
|
||||
console.log(`✅ Generated file: ${result.file}`);
|
||||
console.log(`📊 Instructions count: ${result.instructionsCount}`);
|
||||
console.log(`📝 Instructions: ${result.instructions.join(', ')}`);
|
||||
|
||||
// Verify the file was created
|
||||
if (fs.existsSync(testOutputPath)) {
|
||||
const content = fs.readFileSync(testOutputPath, 'utf8');
|
||||
console.log(`📄 File size: ${content.length} characters`);
|
||||
|
||||
// Check for expected content
|
||||
const hasHeader = content.includes("GitHub Copilot Repository Instructions");
|
||||
const hasInstructions = content.includes("Active Instructions");
|
||||
|
||||
console.log(`✅ Has header: ${hasHeader}`);
|
||||
console.log(`✅ Has instructions section: ${hasInstructions}`);
|
||||
|
||||
if (hasHeader && hasInstructions) {
|
||||
console.log("✅ Content validation passed");
|
||||
} else {
|
||||
console.log("❌ Content validation failed");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
console.log("❌ Output file was not created");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test consolidated template
|
||||
console.log("\n📋 Testing consolidated template...");
|
||||
const consolidatedPath = ".github/test-consolidated-instructions.md";
|
||||
await generateRepositoryInstructions(testConfigPath, {
|
||||
outputFile: consolidatedPath,
|
||||
template: "consolidated"
|
||||
});
|
||||
|
||||
if (fs.existsSync(consolidatedPath)) {
|
||||
const consolidatedContent = fs.readFileSync(consolidatedPath, 'utf8');
|
||||
console.log(`✅ Consolidated file created (${consolidatedContent.length} characters)`);
|
||||
fs.unlinkSync(consolidatedPath);
|
||||
}
|
||||
|
||||
// Test empty config
|
||||
console.log("\n📋 Testing empty configuration...");
|
||||
const emptyConfig = `# Empty configuration
|
||||
instructions: {}
|
||||
`;
|
||||
const emptyConfigPath = "test-empty-repo-instructions.yml";
|
||||
const emptyOutputPath = ".github/test-empty-instructions.md";
|
||||
|
||||
fs.writeFileSync(emptyConfigPath, emptyConfig);
|
||||
|
||||
await generateRepositoryInstructions(emptyConfigPath, {
|
||||
outputFile: emptyOutputPath,
|
||||
template: "repository"
|
||||
});
|
||||
|
||||
if (fs.existsSync(emptyOutputPath)) {
|
||||
const emptyContent = fs.readFileSync(emptyOutputPath, 'utf8');
|
||||
const hasEmptyMessage = emptyContent.includes("No Instructions Enabled");
|
||||
console.log(`✅ Empty config handled correctly: ${hasEmptyMessage}`);
|
||||
fs.unlinkSync(emptyOutputPath);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
fs.unlinkSync(testConfigPath);
|
||||
fs.unlinkSync(emptyConfigPath);
|
||||
fs.unlinkSync(testOutputPath);
|
||||
|
||||
console.log("\n🎉 All repository instructions tests passed!");
|
||||
return true;
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ Test failed: ${error.message}`);
|
||||
|
||||
// Cleanup on error
|
||||
[testConfigPath, testOutputPath, "test-empty-repo-instructions.yml", ".github/test-empty-instructions.md", ".github/test-consolidated-instructions.md"].forEach(file => {
|
||||
if (fs.existsSync(file)) {
|
||||
fs.unlinkSync(file);
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test CLI integration
|
||||
*/
|
||||
async function testCLIIntegration() {
|
||||
console.log("\n🖥️ Testing CLI Integration");
|
||||
console.log("-".repeat(30));
|
||||
|
||||
try {
|
||||
// Test the awesome-copilot command includes the new command
|
||||
const { main } = require("./awesome-copilot");
|
||||
|
||||
// Check if the command is registered
|
||||
const originalArgv = process.argv;
|
||||
process.argv = ["node", "awesome-copilot.js", "help"];
|
||||
|
||||
// Capture help output
|
||||
const originalLog = console.log;
|
||||
let helpOutput = "";
|
||||
console.log = (...args) => {
|
||||
helpOutput += args.join(" ") + "\n";
|
||||
};
|
||||
|
||||
try {
|
||||
main();
|
||||
} catch (error) {
|
||||
// Expected for help command
|
||||
}
|
||||
|
||||
console.log = originalLog;
|
||||
process.argv = originalArgv;
|
||||
|
||||
// Check if our command is in the help output
|
||||
const hasRepoInstructionsCommand = helpOutput.includes("generate-repo-instructions");
|
||||
console.log(`✅ Command registered in CLI: ${hasRepoInstructionsCommand}`);
|
||||
|
||||
return hasRepoInstructionsCommand;
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ CLI integration test failed: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main test runner
|
||||
*/
|
||||
async function runTests() {
|
||||
const test1 = await testRepositoryInstructions();
|
||||
const test2 = await testCLIIntegration();
|
||||
|
||||
console.log("\n" + "=".repeat(50));
|
||||
console.log("📊 Test Results Summary");
|
||||
console.log("=".repeat(50));
|
||||
console.log(`Repository Instructions Generation: ${test1 ? "✅ PASS" : "❌ FAIL"}`);
|
||||
console.log(`CLI Integration: ${test2 ? "✅ PASS" : "❌ FAIL"}`);
|
||||
|
||||
const allPassed = test1 && test2;
|
||||
console.log(`\nOverall Result: ${allPassed ? "✅ ALL TESTS PASSED" : "❌ SOME TESTS FAILED"}`);
|
||||
|
||||
if (allPassed) {
|
||||
console.log("\n🎉 Repository instructions feature is working correctly!");
|
||||
}
|
||||
|
||||
return allPassed;
|
||||
}
|
||||
|
||||
// Run tests
|
||||
if (require.main === module) {
|
||||
runTests().then(success => {
|
||||
process.exit(success ? 0 : 1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { runTests };
|
||||
Loading…
x
Reference in New Issue
Block a user