UNPKG

qraft

Version:

A powerful CLI tool to qraft structured project setups from GitHub template repositories

260 lines 10.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PullRequestCreator = void 0; class PullRequestCreator { constructor(githubToken) { this.githubToken = githubToken; } async createPullRequest(owner, repo, boxMetadata, options = {}) { try { if (!this.githubToken) { throw new Error('GitHub token required for creating pull requests'); } const title = options.title || this.generateTitle(boxMetadata); const description = options.description || this.generateDescription(boxMetadata); const baseBranch = options.baseBranch || 'main'; const headBranch = options.headBranch || `add-${boxMetadata.name}-box`; const prData = { title, body: description, head: headBranch, base: baseBranch, draft: options.draft || false, maintainer_can_modify: true }; const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/pulls`, { method: 'POST', headers: { 'Authorization': `token ${this.githubToken}`, 'Accept': 'application/vnd.github.v3+json', 'User-Agent': 'qraft-cli', 'Content-Type': 'application/json' }, body: JSON.stringify(prData) }); if (!response.ok) { const errorData = await response.json(); throw new Error(`GitHub API error: ${errorData.message || response.statusText}`); } const data = await response.json(); // Add labels if specified if (options.labels && options.labels.length > 0) { await this.addLabels(owner, repo, data.number, options.labels); } // Add assignees if specified if (options.assignees && options.assignees.length > 0) { await this.addAssignees(owner, repo, data.number, options.assignees); } // Request reviewers if specified if (options.reviewers && options.reviewers.length > 0) { await this.requestReviewers(owner, repo, data.number, options.reviewers); } return { success: true, prUrl: data.html_url, prNumber: data.number, title: data.title, description: data.body, message: 'Pull request created successfully', nextSteps: [ 'Review the pull request description', 'Wait for maintainer review and feedback', 'Address any requested changes', 'Monitor the PR for approval and merge' ] }; } catch (error) { return { success: false, prUrl: '', prNumber: 0, title: '', description: '', message: `Failed to create pull request: ${error}`, nextSteps: [ 'Check your GitHub token permissions', 'Verify the repository exists and you have access', 'Ensure the branch exists and has commits', 'Try creating the PR manually through GitHub web interface' ] }; } } generateTitle(boxMetadata) { const { name } = boxMetadata; return `Add ${name} box`; } generateDescription(boxMetadata) { const { name, description, tags, fileCount, size } = boxMetadata; let desc = `## 📦 New Box: ${name}\n\n`; if (description) { desc += `${description}\n\n`; } desc += `### 📊 Box Details\n\n`; desc += `- **Files**: ${fileCount} files\n`; desc += `- **Size**: ${size}\n`; if (tags.length > 0) { desc += `- **Tags**: ${tags.join(', ')}\n`; } desc += `\n### 🎯 Purpose\n\n`; desc += `This box provides a template that can be used to quickly bootstrap new projects.\n\n`; desc += `### 🔍 What's Included\n\n`; desc += `- Complete project structure\n`; desc += `- Configuration files\n`; desc += `- Example code and documentation\n`; desc += `- Ready-to-use setup\n\n`; desc += `### 🚀 Usage\n\n`; desc += `Once merged, users can create new projects using:\n`; desc += `\`\`\`bash\n`; desc += `qraft create my-project ${name}\n`; desc += `\`\`\`\n\n`; desc += `---\n\n`; desc += `*This pull request was automatically generated by qraft CLI*`; return desc; } async addLabels(owner, repo, prNumber, labels) { try { await fetch(`https://api.github.com/repos/${owner}/${repo}/issues/${prNumber}/labels`, { method: 'POST', headers: { 'Authorization': `token ${this.githubToken}`, 'Accept': 'application/vnd.github.v3+json', 'User-Agent': 'qraft-cli', 'Content-Type': 'application/json' }, body: JSON.stringify({ labels }) }); } catch { // Ignore label errors - not critical } } async addAssignees(owner, repo, prNumber, assignees) { try { await fetch(`https://api.github.com/repos/${owner}/${repo}/issues/${prNumber}/assignees`, { method: 'POST', headers: { 'Authorization': `token ${this.githubToken}`, 'Accept': 'application/vnd.github.v3+json', 'User-Agent': 'qraft-cli', 'Content-Type': 'application/json' }, body: JSON.stringify({ assignees }) }); } catch { // Ignore assignee errors - not critical } } async requestReviewers(owner, repo, prNumber, reviewers) { try { await fetch(`https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}/requested_reviewers`, { method: 'POST', headers: { 'Authorization': `token ${this.githubToken}`, 'Accept': 'application/vnd.github.v3+json', 'User-Agent': 'qraft-cli', 'Content-Type': 'application/json' }, body: JSON.stringify({ reviewers }) }); } catch { // Ignore reviewer errors - not critical } } // Generate PR description for dry run generatePRPreview(boxMetadata, options = {}) { const title = options.title || this.generateTitle(boxMetadata); const description = options.description || this.generateDescription(boxMetadata); const baseBranch = options.baseBranch || 'main'; const headBranch = options.headBranch || `add-${boxMetadata.name}-box`; return { title, description, baseBranch, headBranch }; } // Check if a PR already exists for the box async checkExistingPR(owner, repo, boxName, headBranch) { try { if (!this.githubToken) { return { exists: false }; } const branch = headBranch || `add-${boxName}-box`; const response = await fetch(`https://api.github.com/repos/${owner}/${repo}/pulls?head=${branch}&state=open`, { headers: { 'Authorization': `token ${this.githubToken}`, 'Accept': 'application/vnd.github.v3+json', 'User-Agent': 'qraft-cli' } }); if (response.ok) { const data = await response.json(); if (data.length > 0) { return { exists: true, prUrl: data[0].html_url, prNumber: data[0].number }; } } return { exists: false }; } catch { return { exists: false }; } } // Dry run method for testing async createPullRequestDryRun(owner, repo, boxMetadata, options = {}) { const preview = this.generatePRPreview(boxMetadata, options); return { success: true, prUrl: `https://github.com/${owner}/${repo}/pull/123`, prNumber: 123, title: preview.title, description: preview.description, message: '[DRY RUN] Pull request would be created successfully', nextSteps: [ '[DRY RUN] Review the pull request description', '[DRY RUN] Wait for maintainer review and feedback', '[DRY RUN] Address any requested changes', '[DRY RUN] Monitor the PR for approval and merge' ] }; } // Validate PR options validatePROptions(options) { const errors = []; if (options.title && options.title.length > 256) { errors.push('Title must be 256 characters or less'); } if (options.description && options.description.length > 65536) { errors.push('Description must be 65536 characters or less'); } if (options.labels) { if (options.labels.length > 100) { errors.push('Maximum 100 labels allowed'); } for (const label of options.labels) { if (label.length > 50) { errors.push(`Label "${label}" must be 50 characters or less`); } } } if (options.assignees && options.assignees.length > 10) { errors.push('Maximum 10 assignees allowed'); } if (options.reviewers && options.reviewers.length > 15) { errors.push('Maximum 15 reviewers allowed'); } return { valid: errors.length === 0, errors }; } } exports.PullRequestCreator = PullRequestCreator; //# sourceMappingURL=pullRequestCreator.js.map