Initial commit
This commit is contained in:
15
.claude-plugin/plugin.json
Normal file
15
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "deployment",
|
||||
"description": "v1.0.0 - Safe deployment automation with CICD integration. Manages branch-based deployments to dev/uat/prod environments with safety checks and build validation.",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "AutomateWith.Us",
|
||||
"email": "team@automatewith.us"
|
||||
},
|
||||
"commands": [
|
||||
"./commands"
|
||||
],
|
||||
"hooks": [
|
||||
"./hooks"
|
||||
]
|
||||
}
|
||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# deployment
|
||||
|
||||
v1.0.0 - Safe deployment automation with CICD integration. Manages branch-based deployments to dev/uat/prod environments with safety checks and build validation.
|
||||
244
commands/deploy.md
Normal file
244
commands/deploy.md
Normal file
@@ -0,0 +1,244 @@
|
||||
You are managing a deployment system. The user wants to deploy to an environment.
|
||||
|
||||
## Task: Deploy Application
|
||||
|
||||
Parse the environment from arguments: $ARGUMENTS
|
||||
Expected format: /deploy [environment]
|
||||
Valid environments: dev, uat, prod
|
||||
|
||||
### Step 1: Parse and Validate Environment
|
||||
|
||||
Extract the environment name from $ARGUMENTS.
|
||||
|
||||
If no environment provided, show error and STOP:
|
||||
```
|
||||
❌ Error: No environment specified
|
||||
|
||||
Usage: /deploy [environment]
|
||||
|
||||
Available environments:
|
||||
• dev - Development environment (deploy_dev branch)
|
||||
• uat - User Acceptance Testing (deploy_uat branch)
|
||||
• prod - Production environment (deploy_prod branch)
|
||||
|
||||
Example: /deploy dev
|
||||
```
|
||||
|
||||
### Step 2: Load Configuration
|
||||
|
||||
Run CLI to get configuration:
|
||||
|
||||
```bash
|
||||
node deployment/cli/deploy-cli.js config
|
||||
```
|
||||
|
||||
If configuration not found (error in output), show error and STOP:
|
||||
```
|
||||
❌ Error: Deployment not configured
|
||||
|
||||
💡 Run /deploy:init to set up deployment
|
||||
```
|
||||
|
||||
Parse the JSON output and extract:
|
||||
- mainBranch
|
||||
- buildCommand
|
||||
- environments.{env} configuration
|
||||
|
||||
If the requested environment doesn't exist in config, show available environments and STOP:
|
||||
```
|
||||
❌ Error: Unknown environment "{env}"
|
||||
|
||||
Available environments: {list from config}
|
||||
|
||||
💡 Edit .claude/deployment.config.json to add custom environments
|
||||
```
|
||||
|
||||
### Step 3: Run Pre-Deployment Validation
|
||||
|
||||
Run CLI validation for the target environment:
|
||||
|
||||
```bash
|
||||
node deployment/cli/deploy-cli.js validate --check-git --env {environment}
|
||||
```
|
||||
|
||||
Parse the JSON output.
|
||||
|
||||
If `success: false`, show all errors and STOP:
|
||||
```
|
||||
🚫 Deployment blocked by safety checks:
|
||||
|
||||
{for each error:}
|
||||
❌ {error.message}
|
||||
💡 Fix: {error.fix}
|
||||
|
||||
Please resolve these issues before deploying.
|
||||
```
|
||||
|
||||
If warnings exist (success: true but warnings present), show warnings but continue:
|
||||
```
|
||||
⚠️ Warnings detected:
|
||||
{for each warning:}
|
||||
• {warning.message}
|
||||
💡 {warning.fix}
|
||||
|
||||
Continuing with deployment...
|
||||
```
|
||||
|
||||
### Step 4: Determine Source Branch
|
||||
|
||||
Based on environment configuration:
|
||||
- If environment has `sourceBranch`: Use that branch
|
||||
- If environment has `sourceEnvironment`: Use that environment's deployment branch
|
||||
|
||||
Example:
|
||||
- dev: source is "main" (sourceBranch)
|
||||
- uat: source is "deploy_dev" (from sourceEnvironment: "dev")
|
||||
- prod: source is "deploy_uat" (from sourceEnvironment: "uat")
|
||||
|
||||
Store the source branch and deployment branch for later steps.
|
||||
|
||||
### Step 5: Run Build Validation
|
||||
|
||||
Show progress:
|
||||
```
|
||||
🔨 Running build validation...
|
||||
Command: {buildCommand}
|
||||
```
|
||||
|
||||
Execute the build command:
|
||||
|
||||
```bash
|
||||
{buildCommand}
|
||||
```
|
||||
|
||||
Monitor the output.
|
||||
|
||||
**If build succeeds:**
|
||||
```
|
||||
✓ Build completed successfully
|
||||
```
|
||||
Proceed to Step 6.
|
||||
|
||||
**If build fails:**
|
||||
|
||||
Show the build errors:
|
||||
```
|
||||
❌ Build failed with errors:
|
||||
|
||||
{build_error_output}
|
||||
|
||||
What would you like to do?
|
||||
```
|
||||
|
||||
Use AskUserQuestion:
|
||||
```json
|
||||
{
|
||||
"questions": [{
|
||||
"question": "Build failed. How should we proceed?",
|
||||
"header": "Action",
|
||||
"multiSelect": false,
|
||||
"options": [
|
||||
{"label": "Show me the errors, I'll fix them", "description": "Stop deployment, let me fix manually"},
|
||||
{"label": "Try to auto-fix", "description": "Let Claude attempt to fix the errors"},
|
||||
{"label": "Cancel deployment", "description": "Stop the deployment process"}
|
||||
]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
- If "Show me" or "Cancel": STOP with guidance
|
||||
- If "Try to auto-fix": Attempt to fix, then re-run build
|
||||
- If second build fails: STOP and ask user to fix manually
|
||||
|
||||
### Step 6: Checkout and Update Source Branch
|
||||
|
||||
Ensure we're on the correct source branch and it's up-to-date:
|
||||
|
||||
```bash
|
||||
git fetch origin && git checkout {source_branch} && git pull origin {source_branch}
|
||||
```
|
||||
|
||||
Verify the branch is clean and up-to-date.
|
||||
|
||||
### Step 7: Merge to Deployment Branch
|
||||
|
||||
Get the deployment branch from config: `environments.{env}.branch`
|
||||
|
||||
```bash
|
||||
git checkout {deployment_branch} && git pull origin {deployment_branch} && git merge {source_branch} --no-ff -m "Deploy {source_branch} to {environment} environment"
|
||||
```
|
||||
|
||||
**If merge conflicts occur:**
|
||||
|
||||
```
|
||||
❌ Merge conflict detected
|
||||
|
||||
Conflicting files:
|
||||
{list files from git status}
|
||||
|
||||
You need to resolve these conflicts manually:
|
||||
1. The merge is in progress with conflicts
|
||||
2. Resolve conflicts in the files listed above
|
||||
3. Run: git add . && git commit
|
||||
4. Then retry: /deploy {environment}
|
||||
|
||||
Aborting deployment.
|
||||
```
|
||||
|
||||
Run: `git merge --abort`
|
||||
STOP execution.
|
||||
|
||||
**If merge succeeds:**
|
||||
```
|
||||
✓ Merged {source_branch} → {deployment_branch}
|
||||
```
|
||||
|
||||
### Step 8: Push to Trigger Deployment
|
||||
|
||||
Push the deployment branch to trigger Netlify auto-deploy:
|
||||
|
||||
```bash
|
||||
git push origin {deployment_branch}
|
||||
```
|
||||
|
||||
If push fails, show error:
|
||||
```
|
||||
❌ Push failed
|
||||
|
||||
{error output}
|
||||
|
||||
💡 Check your remote connection and permissions
|
||||
```
|
||||
|
||||
STOP execution.
|
||||
|
||||
### Step 9: Display Success Message
|
||||
|
||||
Show deployment confirmation:
|
||||
|
||||
```
|
||||
✓ Deployment initiated successfully
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
🚀 Environment: {environment}
|
||||
📦 Branch: {deployment_branch}
|
||||
🔗 Source: {source_branch}
|
||||
|
||||
📊 Netlify will now build and deploy automatically
|
||||
Check your Netlify dashboard for deployment status
|
||||
|
||||
💡 Next steps:
|
||||
{if dev} → After testing, deploy to UAT: /deploy uat
|
||||
{if uat} → After approval, deploy to prod: /deploy prod
|
||||
{if prod} → Monitor production for any issues
|
||||
|
||||
🔍 To check status: Visit your Netlify dashboard
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**IMPORTANT:**
|
||||
- Always validate before executing
|
||||
- Show clear progress updates
|
||||
- Handle errors gracefully with recovery options
|
||||
- Enforce environment progression (dev → uat → prod)
|
||||
- Never skip safety checks
|
||||
176
commands/init.md
Normal file
176
commands/init.md
Normal file
@@ -0,0 +1,176 @@
|
||||
You are managing a deployment configuration system. The user wants to initialize deployment settings for their project.
|
||||
|
||||
## Task: Initialize Deployment Configuration
|
||||
|
||||
This command sets up deployment configuration for the project. This is a one-time setup.
|
||||
|
||||
### Step 1: Check for Existing Configuration
|
||||
|
||||
Run the CLI to check if configuration already exists:
|
||||
|
||||
```bash
|
||||
node deployment/cli/deploy-cli.js config 2>&1
|
||||
```
|
||||
|
||||
If the output contains "Configuration not found", proceed to Step 2.
|
||||
|
||||
If configuration exists, show this error and STOP:
|
||||
```
|
||||
❌ Error: Deployment configuration already exists
|
||||
📁 Location: .claude/deployment.config.json
|
||||
|
||||
💡 To view current config: Run node deployment/cli/deploy-cli.js config
|
||||
💡 To modify: Edit .claude/deployment.config.json directly
|
||||
```
|
||||
|
||||
### Step 2: Gather Configuration Details
|
||||
|
||||
Ask the user the following questions using AskUserQuestion tool:
|
||||
|
||||
```json
|
||||
{
|
||||
"questions": [
|
||||
{
|
||||
"question": "What is your main development branch?",
|
||||
"header": "Main Branch",
|
||||
"multiSelect": false,
|
||||
"options": [
|
||||
{"label": "main", "description": "Default branch named 'main'"},
|
||||
{"label": "master", "description": "Legacy default branch 'master'"},
|
||||
{"label": "develop", "description": "Use 'develop' as main branch"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "What command should run to build your project?",
|
||||
"header": "Build Command",
|
||||
"multiSelect": false,
|
||||
"options": [
|
||||
{"label": "npm run build", "description": "Node.js project with npm"},
|
||||
{"label": "yarn build", "description": "Node.js project with yarn"},
|
||||
{"label": "pnpm build", "description": "Node.js project with pnpm"},
|
||||
{"label": "make build", "description": "Project with Makefile"}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Store the user's answers for Step 3.
|
||||
|
||||
### Step 3: Create Configuration
|
||||
|
||||
Use the CLI to initialize the configuration with user's choices:
|
||||
|
||||
```bash
|
||||
node deployment/cli/deploy-cli.js init --main-branch {user_main_branch} --build-command "{user_build_command}"
|
||||
```
|
||||
|
||||
**Expected output**: JSON with success: true
|
||||
|
||||
If the command fails, show error and STOP:
|
||||
```
|
||||
❌ Error: Failed to initialize configuration
|
||||
{error_message}
|
||||
|
||||
💡 Check that .claude/ directory is writable
|
||||
```
|
||||
|
||||
### Step 4: Verify Configuration Created
|
||||
|
||||
Read the created configuration to verify:
|
||||
|
||||
```bash
|
||||
node deployment/cli/deploy-cli.js config
|
||||
```
|
||||
|
||||
Parse the JSON output and extract the environments.
|
||||
|
||||
### Step 5: Display Configuration Summary
|
||||
|
||||
Show the user what was configured:
|
||||
|
||||
```
|
||||
✓ Deployment configuration initialized
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
📁 Location: .claude/deployment.config.json
|
||||
|
||||
📋 Configuration:
|
||||
Main Branch: {main_branch}
|
||||
Build Command: {build_command}
|
||||
|
||||
🌍 Environments configured:
|
||||
• dev (deploy_dev) ← {main_branch}
|
||||
• uat (deploy_uat) ← deploy_dev
|
||||
• prod (deploy_prod) ← deploy_uat
|
||||
|
||||
🔒 Safety Features:
|
||||
✓ Uncommitted files check
|
||||
✓ Branch validation
|
||||
✓ Clean build requirement
|
||||
|
||||
💡 Next Steps:
|
||||
1. Review config: Edit .claude/deployment.config.json if needed
|
||||
2. Create deployment branches (see below)
|
||||
3. Deploy to dev: /deploy dev
|
||||
```
|
||||
|
||||
### Step 6: Offer to Create Deployment Branches
|
||||
|
||||
Ask the user:
|
||||
|
||||
```
|
||||
The following deployment branches need to exist in your repository:
|
||||
- deploy_dev
|
||||
- deploy_uat
|
||||
- deploy_prod
|
||||
|
||||
Would you like me to create these branches now?
|
||||
```
|
||||
|
||||
Use AskUserQuestion:
|
||||
```json
|
||||
{
|
||||
"questions": [{
|
||||
"question": "Create deployment branches?",
|
||||
"header": "Setup",
|
||||
"multiSelect": false,
|
||||
"options": [
|
||||
{"label": "Yes", "description": "Create all deployment branches from main"},
|
||||
{"label": "No", "description": "I'll create them manually later"}
|
||||
]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
If user selects "Yes":
|
||||
```bash
|
||||
git checkout {main_branch} && git pull origin {main_branch} && git checkout -b deploy_dev && git push -u origin deploy_dev && git checkout -b deploy_uat && git push -u origin deploy_uat && git checkout -b deploy_prod && git push -u origin deploy_prod && git checkout {main_branch}
|
||||
```
|
||||
|
||||
Show success message:
|
||||
```
|
||||
✓ Deployment branches created successfully
|
||||
• deploy_dev
|
||||
• deploy_uat
|
||||
• deploy_prod
|
||||
|
||||
All branches have been pushed to origin.
|
||||
You're ready to deploy!
|
||||
```
|
||||
|
||||
If user selects "No":
|
||||
```
|
||||
💡 Remember to create these branches manually:
|
||||
git checkout {main_branch}
|
||||
git checkout -b deploy_dev && git push -u origin deploy_dev
|
||||
git checkout -b deploy_uat && git push -u origin deploy_uat
|
||||
git checkout -b deploy_prod && git push -u origin deploy_prod
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**IMPORTANT:**
|
||||
- Use CLI for all config operations (plan mode support)
|
||||
- Validate user input before proceeding
|
||||
- Provide clear next steps
|
||||
- Make it interactive and user-friendly
|
||||
312
hooks/pre-deploy-check.js
Executable file
312
hooks/pre-deploy-check.js
Executable file
@@ -0,0 +1,312 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
/**
|
||||
* PreToolUse Hook: Pre-deployment Safety Checks
|
||||
*
|
||||
* Validates deployment operations before execution:
|
||||
* - Detects deployment-related commands
|
||||
* - Checks for uncommitted files
|
||||
* - Validates current branch
|
||||
* - Blocks execution if unsafe
|
||||
*/
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
// Read input from stdin
|
||||
const input = fs.readFileSync(0, 'utf8').trim();
|
||||
|
||||
if (!input) {
|
||||
process.exit(0); // No input, exit silently
|
||||
}
|
||||
|
||||
const eventData = JSON.parse(input);
|
||||
|
||||
// Extract tool input
|
||||
const toolInput = eventData.tool_input || {};
|
||||
const cwd = eventData.cwd || process.cwd();
|
||||
|
||||
// Change to correct directory
|
||||
process.chdir(cwd);
|
||||
|
||||
// Check if this is a deployment-related command
|
||||
if (!isDeploymentCommand(toolInput)) {
|
||||
process.exit(0); // Not a deployment, allow execution
|
||||
}
|
||||
|
||||
// Run safety checks
|
||||
const issues = await runSafetyChecks(toolInput);
|
||||
|
||||
if (issues.length === 0) {
|
||||
process.exit(0); // All checks passed, allow execution
|
||||
}
|
||||
|
||||
// Checks failed - block execution
|
||||
const output = {
|
||||
hookSpecificOutput: {
|
||||
blockExecution: true,
|
||||
additionalContext: formatIssues(issues, toolInput)
|
||||
}
|
||||
};
|
||||
|
||||
console.log(JSON.stringify(output));
|
||||
process.exit(0);
|
||||
|
||||
} catch (error) {
|
||||
// Silent failure - never block Claude Code
|
||||
// Log error to stderr for debugging (optional)
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if command is deployment-related
|
||||
*/
|
||||
function isDeploymentCommand(toolInput) {
|
||||
const command = toolInput.command || '';
|
||||
const description = toolInput.description || '';
|
||||
|
||||
// Check for deployment-related keywords
|
||||
const deploymentKeywords = [
|
||||
'deploy_dev',
|
||||
'deploy_uat',
|
||||
'deploy_prod',
|
||||
'/deploy',
|
||||
'deployment'
|
||||
];
|
||||
|
||||
const commandLower = command.toLowerCase();
|
||||
const descriptionLower = description.toLowerCase();
|
||||
|
||||
// Check if command or description contains deployment keywords
|
||||
for (const keyword of deploymentKeywords) {
|
||||
if (commandLower.includes(keyword) || descriptionLower.includes(keyword)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for git operations on deployment branches
|
||||
if (command.includes('git merge') || command.includes('git push')) {
|
||||
// Check if targeting a deployment branch
|
||||
const deployBranchPattern = /deploy_(dev|uat|prod)/;
|
||||
if (deployBranchPattern.test(command)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract environment from command if present
|
||||
*/
|
||||
function extractEnvironment(toolInput) {
|
||||
const command = toolInput.command || '';
|
||||
const description = toolInput.description || '';
|
||||
|
||||
const envPattern = /(dev|uat|prod)/i;
|
||||
|
||||
// Try to find environment in command
|
||||
const commandMatch = command.match(envPattern);
|
||||
if (commandMatch) {
|
||||
return commandMatch[1].toLowerCase();
|
||||
}
|
||||
|
||||
// Try to find in description
|
||||
const descMatch = description.match(envPattern);
|
||||
if (descMatch) {
|
||||
return descMatch[1].toLowerCase();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all safety checks
|
||||
* Returns array of issues found
|
||||
*/
|
||||
async function runSafetyChecks(toolInput) {
|
||||
const issues = [];
|
||||
|
||||
// Load configuration
|
||||
const configPath = path.join(process.cwd(), '.claude/deployment.config.json');
|
||||
|
||||
if (!fs.existsSync(configPath)) {
|
||||
// No config = not a configured deployment project
|
||||
// Don't block, user might be doing manual git operations
|
||||
return [];
|
||||
}
|
||||
|
||||
let config;
|
||||
try {
|
||||
config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||
} catch (error) {
|
||||
// Malformed config - warn but don't block
|
||||
return [{
|
||||
type: 'warning',
|
||||
message: 'Deployment config malformed',
|
||||
fix: 'Check .claude/deployment.config.json syntax'
|
||||
}];
|
||||
}
|
||||
|
||||
// Extract environment from command
|
||||
const environment = extractEnvironment(toolInput);
|
||||
|
||||
// Check 1: Uncommitted files
|
||||
if (config.safeguards?.checkUncommittedFiles) {
|
||||
const uncommitted = checkUncommittedFiles();
|
||||
if (uncommitted.count > 0) {
|
||||
issues.push({
|
||||
type: 'error',
|
||||
message: `${uncommitted.count} uncommitted file(s) detected`,
|
||||
details: uncommitted.files.slice(0, 5), // Show first 5 files
|
||||
fix: 'Commit or stash changes: git add . && git commit -m "..."',
|
||||
count: uncommitted.count
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Check 2: Branch validation
|
||||
if (config.safeguards?.checkBranch && environment) {
|
||||
const branchIssue = checkBranchValidity(config, environment);
|
||||
if (branchIssue) {
|
||||
issues.push(branchIssue);
|
||||
}
|
||||
}
|
||||
|
||||
// Check 3: Environment exists
|
||||
if (environment && !config.environments[environment]) {
|
||||
issues.push({
|
||||
type: 'error',
|
||||
message: `Unknown environment: ${environment}`,
|
||||
fix: `Valid environments: ${Object.keys(config.environments).join(', ')}`
|
||||
});
|
||||
}
|
||||
|
||||
return issues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for uncommitted files
|
||||
*/
|
||||
function checkUncommittedFiles() {
|
||||
try {
|
||||
const output = execSync('git status --porcelain', {
|
||||
encoding: 'utf8',
|
||||
stdio: ['pipe', 'pipe', 'pipe']
|
||||
}).trim();
|
||||
|
||||
if (!output) {
|
||||
return { count: 0, files: [] };
|
||||
}
|
||||
|
||||
const files = output.split('\n').map(line => {
|
||||
const status = line.substring(0, 2);
|
||||
const file = line.substring(3);
|
||||
return { status, file };
|
||||
});
|
||||
|
||||
return { count: files.length, files };
|
||||
|
||||
} catch (error) {
|
||||
// Not a git repo or git command failed
|
||||
return { count: 0, files: [] };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if on correct branch for deployment
|
||||
*/
|
||||
function checkBranchValidity(config, environment) {
|
||||
try {
|
||||
const currentBranch = execSync('git rev-parse --abbrev-ref HEAD', {
|
||||
encoding: 'utf8',
|
||||
stdio: ['pipe', 'pipe', 'pipe']
|
||||
}).trim();
|
||||
|
||||
const envConfig = config.environments[environment];
|
||||
if (!envConfig) {
|
||||
return null; // Environment doesn't exist
|
||||
}
|
||||
|
||||
// Determine expected source branch
|
||||
let expectedBranch;
|
||||
if (envConfig.sourceBranch) {
|
||||
expectedBranch = envConfig.sourceBranch;
|
||||
} else if (envConfig.sourceEnvironment) {
|
||||
const sourceEnv = config.environments[envConfig.sourceEnvironment];
|
||||
expectedBranch = sourceEnv?.branch;
|
||||
}
|
||||
|
||||
if (!expectedBranch) {
|
||||
return null; // Can't determine expected branch
|
||||
}
|
||||
|
||||
if (currentBranch !== expectedBranch) {
|
||||
return {
|
||||
type: 'warning',
|
||||
message: `On branch "${currentBranch}", expected "${expectedBranch}"`,
|
||||
fix: `Switch to correct branch: git checkout ${expectedBranch}`
|
||||
};
|
||||
}
|
||||
|
||||
return null; // Branch is correct
|
||||
|
||||
} catch (error) {
|
||||
return null; // Git command failed, don't block
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format issues into user-friendly message
|
||||
*/
|
||||
function formatIssues(issues, toolInput) {
|
||||
const errors = issues.filter(i => i.type === 'error');
|
||||
const warnings = issues.filter(i => i.type === 'warning');
|
||||
|
||||
let message = '🚫 Deployment blocked by safety checks:\n\n';
|
||||
|
||||
// Show errors
|
||||
if (errors.length > 0) {
|
||||
message += '**Errors** (must fix):\n';
|
||||
for (const error of errors) {
|
||||
message += `\n❌ ${error.message}\n`;
|
||||
|
||||
if (error.details && error.details.length > 0) {
|
||||
message += ' Files:\n';
|
||||
for (const detail of error.details) {
|
||||
message += ` - ${detail.file} (${detail.status})\n`;
|
||||
}
|
||||
if (error.count && error.details.length < error.count) {
|
||||
message += ` ... and ${error.count - error.details.length} more\n`;
|
||||
}
|
||||
}
|
||||
|
||||
if (error.fix) {
|
||||
message += ` 💡 Fix: ${error.fix}\n`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Show warnings
|
||||
if (warnings.length > 0) {
|
||||
message += '\n**Warnings** (recommended to fix):\n';
|
||||
for (const warning of warnings) {
|
||||
message += `\n⚠️ ${warning.message}\n`;
|
||||
if (warning.fix) {
|
||||
message += ` 💡 Suggestion: ${warning.fix}\n`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
message += '\n---\n\n';
|
||||
message += 'Fix the issues above before deploying.\n';
|
||||
message += 'Once fixed, retry the deployment command.\n';
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
main();
|
||||
53
plugin.lock.json
Normal file
53
plugin.lock.json
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"$schema": "internal://schemas/plugin.lock.v1.json",
|
||||
"pluginId": "gh:awudevelop/claude-plugins:deployment",
|
||||
"normalized": {
|
||||
"repo": null,
|
||||
"ref": "refs/tags/v20251128.0",
|
||||
"commit": "824a49ec5abf11b0d811fda9c8861515015582ba",
|
||||
"treeHash": "d715bf800868f8068f8a160d47f09a378e934fae7a013e7f41d5aa4dc6855b50",
|
||||
"generatedAt": "2025-11-28T10:14:05.577412Z",
|
||||
"toolVersion": "publish_plugins.py@0.2.0"
|
||||
},
|
||||
"origin": {
|
||||
"remote": "git@github.com:zhongweili/42plugin-data.git",
|
||||
"branch": "master",
|
||||
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
|
||||
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
|
||||
},
|
||||
"manifest": {
|
||||
"name": "deployment",
|
||||
"description": "v1.0.0 - Safe deployment automation with CICD integration. Manages branch-based deployments to dev/uat/prod environments with safety checks and build validation.",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"content": {
|
||||
"files": [
|
||||
{
|
||||
"path": "README.md",
|
||||
"sha256": "8150f9ee2d32f94c14c5ca28064341b078e6c021b10a88952ab1169a41be5385"
|
||||
},
|
||||
{
|
||||
"path": "hooks/pre-deploy-check.js",
|
||||
"sha256": "a716ecb7bd8d4bc154f1fe9565bafaf48b83a70c71f5fc7bea0c42b23ff54c58"
|
||||
},
|
||||
{
|
||||
"path": ".claude-plugin/plugin.json",
|
||||
"sha256": "d1e6223a482459eb57e397cdd73dc4e72aebe884cd8977630f3c75e91b42cc85"
|
||||
},
|
||||
{
|
||||
"path": "commands/init.md",
|
||||
"sha256": "0b9b55305d20b47f46bcbcd83f9d50a60df8f1d8cd7b22cf9b77b933ab3f108f"
|
||||
},
|
||||
{
|
||||
"path": "commands/deploy.md",
|
||||
"sha256": "e504114e294c4d4600d753f940d1e8f7bd9e3f7ec515c7828b978355d5d1f52a"
|
||||
}
|
||||
],
|
||||
"dirSha256": "d715bf800868f8068f8a160d47f09a378e934fae7a013e7f41d5aa4dc6855b50"
|
||||
},
|
||||
"security": {
|
||||
"scannedAt": null,
|
||||
"scannerVersion": null,
|
||||
"flags": []
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user