@lansisdev/gh-createpr 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +457 -0
- package/dist/github.d.ts +2 -0
- package/dist/github.d.ts.map +1 -0
- package/dist/github.js +185 -0
- package/dist/github.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +393 -0
- package/dist/index.js.map +1 -0
- package/dist/jira.d.ts +2 -0
- package/dist/jira.d.ts.map +1 -0
- package/dist/jira.js +145 -0
- package/dist/jira.js.map +1 -0
- package/package.json +36 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 lansisDev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
# gh-createpr
|
|
2
|
+
|
|
3
|
+
[](https://opensource.org/licenses/ISC)
|
|
4
|
+
[](https://cli.github.com/)
|
|
5
|
+
|
|
6
|
+
A powerful GitHub CLI extension that streamlines the process of creating GitHub Pull Requests directly from Jira tickets. This extension automates the entire workflow from ticket information extraction to PR creation, making development workflows more efficient and consistent.
|
|
7
|
+
|
|
8
|
+
## 🚀 Features
|
|
9
|
+
|
|
10
|
+
- **🎫 Jira Integration**: Automatically fetches ticket information including title, description, and team details
|
|
11
|
+
- **🌿 Branch Management**: Creates appropriately named feature branches based on ticket information
|
|
12
|
+
- **📝 Smart PR Creation**: Generates well-formatted Pull Requests with proper titles and descriptions
|
|
13
|
+
- **⚡ Workflow Automation**: Handles git operations including branch creation, commits, and pushes
|
|
14
|
+
- **🏷️ Team Detection**: Automatically detects and includes team information in PR titles
|
|
15
|
+
- **🔗 Cross-linking**: Links PRs back to their corresponding Jira tickets
|
|
16
|
+
|
|
17
|
+
## 📋 Prerequisites
|
|
18
|
+
|
|
19
|
+
Before using this extension, make sure you have:
|
|
20
|
+
|
|
21
|
+
- **GitHub CLI** (v2.0.0 or higher) - [Install here](https://cli.github.com/)
|
|
22
|
+
- **GitHub CLI authenticated** - Run `gh auth login` if not already done
|
|
23
|
+
- **Node.js** (v16 or higher) - Required for the extension runtime
|
|
24
|
+
- **Git** configured with your credentials
|
|
25
|
+
- **Jira API access** with appropriate permissions
|
|
26
|
+
- A repository with a `develop` branch (default base branch for PRs)
|
|
27
|
+
|
|
28
|
+
### Quick Setup Check
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Verify GitHub CLI is installed and authenticated
|
|
32
|
+
gh --version
|
|
33
|
+
gh auth status
|
|
34
|
+
|
|
35
|
+
# Verify Git is configured
|
|
36
|
+
git config --global user.name
|
|
37
|
+
git config --global user.email
|
|
38
|
+
|
|
39
|
+
# Verify Node.js version
|
|
40
|
+
node --version
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Prerequisites
|
|
44
|
+
|
|
45
|
+
- GitHub CLI (`gh`) installed and authenticated
|
|
46
|
+
- **Node.js 18 or higher** (required for native fetch support)
|
|
47
|
+
- Access to Jira REST API with appropriate permissions
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
### Quick Install (Recommended)
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Install the extension directly from GitHub
|
|
55
|
+
gh extension install lansisDev/gh-createpr
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
That's it! The extension is now available as `gh createpr`.
|
|
59
|
+
|
|
60
|
+
### Verify Installation
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Check if the extension is installed
|
|
64
|
+
gh extension list
|
|
65
|
+
|
|
66
|
+
# Test the extension
|
|
67
|
+
gh createpr --help
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Prerequisites for GitHub CLI Extensions
|
|
71
|
+
|
|
72
|
+
Before installing, ensure you have:
|
|
73
|
+
|
|
74
|
+
1. **GitHub CLI installed**: [Download here](https://cli.github.com/) or install via:
|
|
75
|
+
```bash
|
|
76
|
+
# macOS
|
|
77
|
+
brew install gh
|
|
78
|
+
|
|
79
|
+
# Windows
|
|
80
|
+
winget install --id GitHub.cli
|
|
81
|
+
|
|
82
|
+
# Linux (Ubuntu/Debian)
|
|
83
|
+
sudo apt install gh
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
2. **GitHub CLI authenticated**:
|
|
87
|
+
```bash
|
|
88
|
+
gh auth login
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Manual Installation (for Development)
|
|
92
|
+
|
|
93
|
+
If you want to contribute or modify the extension:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Clone the repository
|
|
97
|
+
git clone https://github.com/lansisDev/gh-createpr.git
|
|
98
|
+
cd gh-createpr
|
|
99
|
+
|
|
100
|
+
# Install dependencies
|
|
101
|
+
npm install
|
|
102
|
+
|
|
103
|
+
# Build the project
|
|
104
|
+
npm run build
|
|
105
|
+
|
|
106
|
+
# Install as local GitHub CLI extension
|
|
107
|
+
gh extension install .
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Troubleshooting Installation
|
|
111
|
+
|
|
112
|
+
If you encounter issues:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Uninstall and reinstall
|
|
116
|
+
gh extension remove createpr
|
|
117
|
+
gh extension install lansisDev/gh-createpr
|
|
118
|
+
|
|
119
|
+
# Check GitHub CLI version (requires v2.0.0+)
|
|
120
|
+
gh --version
|
|
121
|
+
|
|
122
|
+
# Verify GitHub CLI authentication
|
|
123
|
+
gh auth status
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## 🚀 Quick Start
|
|
127
|
+
|
|
128
|
+
1. **Install the extension**:
|
|
129
|
+
```bash
|
|
130
|
+
gh extension install lansisDev/gh-createpr
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
2. **Set up Jira credentials** (see [Configuration](#%EF%B8%8F-configuration) section below):
|
|
134
|
+
```bash
|
|
135
|
+
export JIRA_BASE_URL="https://your-company.atlassian.net"
|
|
136
|
+
export JIRA_EMAIL="your-email@company.com"
|
|
137
|
+
export JIRA_API_TOKEN="your-jira-api-token"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
3. **Navigate to your git repository** and run:
|
|
141
|
+
```bash
|
|
142
|
+
gh createpr LAN-123
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
That's it! The extension will create a branch, commit, and pull request automatically.
|
|
146
|
+
|
|
147
|
+
## ⚙️ Configuration
|
|
148
|
+
|
|
149
|
+
### Required Environment Variables
|
|
150
|
+
|
|
151
|
+
The extension requires these Jira credentials to fetch ticket information:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
export JIRA_BASE_URL="https://your-company.atlassian.net"
|
|
155
|
+
export JIRA_EMAIL="your-email@company.com"
|
|
156
|
+
export JIRA_API_TOKEN="your-jira-api-token"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Step-by-Step Configuration
|
|
160
|
+
|
|
161
|
+
#### 1. Get Your Jira API Token
|
|
162
|
+
|
|
163
|
+
1. Go to [Atlassian Account Settings](https://id.atlassian.com/manage-profile/security/api-tokens)
|
|
164
|
+
2. Click "Create API token"
|
|
165
|
+
3. Give it a descriptive name (e.g., "gh-createpr-extension")
|
|
166
|
+
4. Copy the generated token (save it securely!)
|
|
167
|
+
|
|
168
|
+
#### 2. Find Your Jira Details
|
|
169
|
+
|
|
170
|
+
- **JIRA_BASE_URL**: Your company's Jira URL (e.g., `https://mycompany.atlassian.net`)
|
|
171
|
+
- **JIRA_EMAIL**: The email address associated with your Jira account
|
|
172
|
+
|
|
173
|
+
#### 3. Set Environment Variables
|
|
174
|
+
|
|
175
|
+
**Option A: Temporary (current session only)**
|
|
176
|
+
```bash
|
|
177
|
+
export JIRA_BASE_URL="https://your-company.atlassian.net"
|
|
178
|
+
export JIRA_EMAIL="your-email@company.com"
|
|
179
|
+
export JIRA_API_TOKEN="your-jira-api-token"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Option B: Permanent (recommended)**
|
|
183
|
+
|
|
184
|
+
Add to your shell profile file (`~/.zshrc`, `~/.bashrc`, or `~/.bash_profile`):
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
# GitHub CLI createpr extension - Jira Configuration
|
|
188
|
+
export JIRA_BASE_URL="https://your-company.atlassian.net"
|
|
189
|
+
export JIRA_EMAIL="your-email@company.com"
|
|
190
|
+
export JIRA_API_TOKEN="your-jira-api-token"
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Then reload your shell:
|
|
194
|
+
```bash
|
|
195
|
+
source ~/.zshrc # or ~/.bashrc
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
#### 4. Verify Configuration
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# Test that environment variables are set
|
|
202
|
+
echo $JIRA_BASE_URL
|
|
203
|
+
echo $JIRA_EMAIL
|
|
204
|
+
echo $JIRA_API_TOKEN
|
|
205
|
+
|
|
206
|
+
# Test the extension with a real ticket
|
|
207
|
+
gh createpr YOUR-TICKET-123
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## 🎯 Usage
|
|
211
|
+
|
|
212
|
+
### Basic Usage
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
gh createpr <JIRA_TICKET>
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Examples
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
# Create PR for ticket LAN-123
|
|
222
|
+
gh createpr LAN-123
|
|
223
|
+
|
|
224
|
+
# Create PR for ticket PROJ-456
|
|
225
|
+
gh createpr PROJ-456
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### What the tool does:
|
|
229
|
+
|
|
230
|
+
1. **Fetches Jira ticket data** including title, description, and team information
|
|
231
|
+
2. **Switches to develop branch** and pulls latest changes
|
|
232
|
+
3. **Creates a new feature branch** with format: `{ticket-id}-{slugified-title}`
|
|
233
|
+
4. **Makes an initial commit** with a conventional commit message
|
|
234
|
+
5. **Pushes the branch** to the remote repository
|
|
235
|
+
6. **Creates a Pull Request** with proper title and description linking back to Jira
|
|
236
|
+
|
|
237
|
+
### Example Output
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
🔍 Fetching data for LAN-123 from Jira...
|
|
241
|
+
🔍 Validating data obtained from Jira...
|
|
242
|
+
✅ Title: Add user authentication feature
|
|
243
|
+
📝 Description: Implement OAuth2 authentication for user login
|
|
244
|
+
👥 Team: Frontend
|
|
245
|
+
🌿 New branch: lan-123-add-user-authentication-feature
|
|
246
|
+
🔄 Switching to develop and updating...
|
|
247
|
+
🚧 Creating new branch: lan-123-add-user-authentication-feature
|
|
248
|
+
📝 Creating initial commit...
|
|
249
|
+
⬆️ Pushing branch to origin...
|
|
250
|
+
🚀 Creating Pull Request from lan-123-add-user-authentication-feature to develop...
|
|
251
|
+
🎉 Pull Request created from 'lan-123-add-user-authentication-feature' to 'develop'
|
|
252
|
+
✅ You are now on branch 'lan-123-add-user-authentication-feature' with initial commit pushed
|
|
253
|
+
🔗 The PR is ready on GitHub
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## 📁 Project Structure
|
|
257
|
+
|
|
258
|
+
```
|
|
259
|
+
gh-createpr/
|
|
260
|
+
├── src/
|
|
261
|
+
│ └── index.ts # Main CLI application
|
|
262
|
+
├── dist/ # Compiled JavaScript output
|
|
263
|
+
├── manifest.yml # GitHub CLI extension manifest
|
|
264
|
+
├── package.json # Project configuration
|
|
265
|
+
├── tsconfig.json # TypeScript configuration
|
|
266
|
+
├── LICENSE # ISC License
|
|
267
|
+
└── README.md # This file
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## 🛠️ Development
|
|
271
|
+
|
|
272
|
+
### Available Scripts
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
# Build the project
|
|
276
|
+
npm run build
|
|
277
|
+
|
|
278
|
+
# Run in development mode
|
|
279
|
+
npm run dev
|
|
280
|
+
|
|
281
|
+
# Start the built version
|
|
282
|
+
npm start
|
|
283
|
+
|
|
284
|
+
# Prepare for publishing
|
|
285
|
+
npm run prepare
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Building from Source
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
# Clone and setup
|
|
292
|
+
git clone https://github.com/lansisDev/gh-createpr.git
|
|
293
|
+
cd gh-createpr
|
|
294
|
+
npm install
|
|
295
|
+
|
|
296
|
+
# Build
|
|
297
|
+
npm run build
|
|
298
|
+
|
|
299
|
+
# Test the extension locally
|
|
300
|
+
gh createpr LAN-123
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## 🏗️ Architecture
|
|
304
|
+
|
|
305
|
+
This GitHub CLI extension is built with:
|
|
306
|
+
|
|
307
|
+
- **TypeScript** for type safety and modern JavaScript features
|
|
308
|
+
- **Commander.js** for CLI argument parsing and command structure
|
|
309
|
+
- **Node-fetch** for HTTP requests to Jira API
|
|
310
|
+
- **Node.js Child Process** for Git operations
|
|
311
|
+
- **GitHub CLI** as the platform for the extension
|
|
312
|
+
|
|
313
|
+
### Key Components
|
|
314
|
+
|
|
315
|
+
- **Jira API Integration**: Fetches ticket data using REST API
|
|
316
|
+
- **Git Operations**: Automated branch management and commits
|
|
317
|
+
- **GitHub CLI Integration**: Leverages `gh pr create` for PR creation
|
|
318
|
+
- **Data Processing**: Intelligent parsing of ticket information and team detection
|
|
319
|
+
|
|
320
|
+
## 🔧 Configuration Options
|
|
321
|
+
|
|
322
|
+
### Branch Naming
|
|
323
|
+
|
|
324
|
+
Branches are automatically named using the format:
|
|
325
|
+
```
|
|
326
|
+
{ticket-id-lowercase}-{slugified-title}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Example: `lan-123-add-user-authentication-feature`
|
|
330
|
+
|
|
331
|
+
### PR Title Format
|
|
332
|
+
|
|
333
|
+
```
|
|
334
|
+
[{JIRA_TICKET}][{TEAM}] {TITLE}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Example: `[LAN-123][Frontend] Add user authentication feature`
|
|
338
|
+
|
|
339
|
+
### Commit Message Format
|
|
340
|
+
|
|
341
|
+
```
|
|
342
|
+
feat({JIRA_TICKET}): initial commit for {TITLE}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Example: `feat(LAN-123): initial commit for Add user authentication feature`
|
|
346
|
+
|
|
347
|
+
## 🚨 Error Handling
|
|
348
|
+
|
|
349
|
+
The extension includes comprehensive error handling for:
|
|
350
|
+
|
|
351
|
+
- **Missing environment variables**
|
|
352
|
+
- **Invalid Jira tickets**
|
|
353
|
+
- **Network connectivity issues**
|
|
354
|
+
- **Git operation failures**
|
|
355
|
+
- **GitHub CLI authentication problems**
|
|
356
|
+
|
|
357
|
+
## 📦 Extension Management
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
# List installed extensions
|
|
361
|
+
gh extension list
|
|
362
|
+
|
|
363
|
+
# Upgrade the extension
|
|
364
|
+
gh extension upgrade createpr
|
|
365
|
+
|
|
366
|
+
# Uninstall the extension
|
|
367
|
+
gh extension remove createpr
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## 🚀 Publishing the Extension
|
|
371
|
+
|
|
372
|
+
To make the extension available for installation via `gh extension install lansisDev/gh-createpr`:
|
|
373
|
+
|
|
374
|
+
### 1. Build and Prepare
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
# Build the project
|
|
378
|
+
npm run build
|
|
379
|
+
|
|
380
|
+
# Make the binary executable
|
|
381
|
+
chmod +x dist/index.js
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### 2. Create a Release
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
# Create and push a tag
|
|
388
|
+
git tag v1.1.0
|
|
389
|
+
git push origin v1.1.0
|
|
390
|
+
|
|
391
|
+
# Create a GitHub release
|
|
392
|
+
gh release create v1.1.0 --title "v1.1.0" --notes "English translation release"
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### 3. Update Manifest
|
|
396
|
+
|
|
397
|
+
Ensure `manifest.yml` has the correct tag version:
|
|
398
|
+
|
|
399
|
+
```yaml
|
|
400
|
+
name: createpr
|
|
401
|
+
owner: lansisDev
|
|
402
|
+
host: github.com
|
|
403
|
+
tag: v1.1.0
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### 4. Test Installation
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
# Test the installation
|
|
410
|
+
gh extension install lansisDev/gh-createpr
|
|
411
|
+
|
|
412
|
+
# Verify it works
|
|
413
|
+
gh createpr --help
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
## 🤝 Contributing
|
|
417
|
+
|
|
418
|
+
1. Fork the repository
|
|
419
|
+
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
420
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
421
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
422
|
+
5. Open a Pull Request
|
|
423
|
+
|
|
424
|
+
## 📄 License
|
|
425
|
+
|
|
426
|
+
This project is licensed under the ISC License - see the [LICENSE](LICENSE) file for details.
|
|
427
|
+
|
|
428
|
+
## 👤 Author
|
|
429
|
+
|
|
430
|
+
**Gonzalo Buasso**
|
|
431
|
+
|
|
432
|
+
## 🆘 Support
|
|
433
|
+
|
|
434
|
+
If you encounter any issues or have questions:
|
|
435
|
+
|
|
436
|
+
1. Check the [Issues](https://github.com/lansisDev/gh-createpr/issues) page
|
|
437
|
+
2. Create a new issue with detailed information about your problem
|
|
438
|
+
3. Include relevant error messages and environment details
|
|
439
|
+
|
|
440
|
+
## 🔄 Changelog
|
|
441
|
+
|
|
442
|
+
### Version 1.1.0
|
|
443
|
+
- **English Translation**: Translated all Spanish text to English for international accessibility
|
|
444
|
+
- **Improved User Interface**: All console messages, error messages, and help text now in English
|
|
445
|
+
- **Better Documentation**: Example output updated to reflect English interface
|
|
446
|
+
- **Enhanced Usability**: More professional appearance for global developer community
|
|
447
|
+
|
|
448
|
+
### Version 1.0.0
|
|
449
|
+
- Initial release
|
|
450
|
+
- Jira integration for ticket data fetching
|
|
451
|
+
- Automated branch creation and PR generation
|
|
452
|
+
- Team detection and proper PR formatting
|
|
453
|
+
- Comprehensive error handling
|
|
454
|
+
|
|
455
|
+
---
|
|
456
|
+
|
|
457
|
+
Made with ❤️ by [lansisDev](https://github.com/lansisDev)
|
package/dist/github.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"AAsCA,eAAO,MAAM,uBAAuB,GAAU,UAAU,MAAM,kBA8M7D,CAAC"}
|
package/dist/github.js
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import * as p from "@clack/prompts";
|
|
3
|
+
import pc from "picocolors";
|
|
4
|
+
// Use native fetch (available in Node.js 18+)
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
const fetch = globalThis.fetch;
|
|
7
|
+
const GITHUB_GRAPHQL_URL = "https://api.github.com/graphql";
|
|
8
|
+
export const createPrFromGithubIssue = async (issueArg) => {
|
|
9
|
+
const issueRegex = /^(?:([a-zA-Z0-9-]+)\/([a-zA-Z0-9._-]+)#(\d+)|#(\d+)|(\d+))$/;
|
|
10
|
+
const match = issueArg.match(issueRegex);
|
|
11
|
+
let owner;
|
|
12
|
+
let repo;
|
|
13
|
+
let issueNumber;
|
|
14
|
+
if (match) {
|
|
15
|
+
// owner/repo#number format
|
|
16
|
+
if (match[1] && match[2] && match[3]) {
|
|
17
|
+
owner = match[1];
|
|
18
|
+
repo = match[2];
|
|
19
|
+
issueNumber = parseInt(match[3], 10);
|
|
20
|
+
}
|
|
21
|
+
else if (match[4] || match[5]) {
|
|
22
|
+
// #number or just number format - use current repo from git
|
|
23
|
+
try {
|
|
24
|
+
const currentRemote = execSync("git remote get-url origin", { encoding: "utf-8" }).trim();
|
|
25
|
+
const remoteRegex = /github\.com[:/](?:[^/]+)\/([^/.]+)|github\.com[:/]([^/]+)\/([^/.]+)/;
|
|
26
|
+
const remoteMatch = currentRemote.match(remoteRegex);
|
|
27
|
+
if (!remoteMatch) {
|
|
28
|
+
throw new Error("No se pudo determinar el repositorio actual desde el remote de git");
|
|
29
|
+
}
|
|
30
|
+
owner = remoteMatch[1] || remoteMatch[2];
|
|
31
|
+
repo = remoteMatch[3] || remoteMatch[1];
|
|
32
|
+
const numStr = match[4] || match[5];
|
|
33
|
+
issueNumber = parseInt(numStr, 10);
|
|
34
|
+
// Strip out .git from repo name if it exists
|
|
35
|
+
repo = repo.replace(/\.git$/, '');
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
p.cancel(pc.red("Error obteniendo el repo actual. Asegurate de estar en un repo de git con un remote origin."));
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
p.cancel(pc.red("Formato de issue inválido. Usá owner/repo#number o #number o simplemente el número."));
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
p.cancel(pc.red("Formato de issue inválido. Usá owner/repo#number o #number o simplemente el número."));
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
const GITHUB_TOKEN = process.env.GITHUB_TOKEN || "";
|
|
52
|
+
if (!GITHUB_TOKEN) {
|
|
53
|
+
p.cancel(pc.red("Falta la variable de entorno GITHUB_TOKEN"));
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
const s = p.spinner();
|
|
57
|
+
s.start(`Buscando issue #${issueNumber} en ${owner}/${repo}...`);
|
|
58
|
+
try {
|
|
59
|
+
const query = `
|
|
60
|
+
query GetIssue($owner: String!, $repo: String!, $number: Int!) {
|
|
61
|
+
repository(owner: $owner, name: $repo) {
|
|
62
|
+
issue(number: $number) {
|
|
63
|
+
number
|
|
64
|
+
title
|
|
65
|
+
body
|
|
66
|
+
labels(first: 10) {
|
|
67
|
+
nodes {
|
|
68
|
+
name
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
assignees(first: 5) {
|
|
72
|
+
nodes {
|
|
73
|
+
login
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
`;
|
|
80
|
+
const res = await fetch(GITHUB_GRAPHQL_URL, {
|
|
81
|
+
method: "POST",
|
|
82
|
+
headers: {
|
|
83
|
+
"Authorization": `Bearer ${GITHUB_TOKEN}`,
|
|
84
|
+
"Content-Type": "application/json",
|
|
85
|
+
},
|
|
86
|
+
body: JSON.stringify({
|
|
87
|
+
query,
|
|
88
|
+
variables: { owner, repo, number: issueNumber },
|
|
89
|
+
}),
|
|
90
|
+
});
|
|
91
|
+
if (!res.ok) {
|
|
92
|
+
throw new Error(`Error en la API de GitHub: ${res.status} ${res.statusText}`);
|
|
93
|
+
}
|
|
94
|
+
const response = (await res.json());
|
|
95
|
+
if (response.errors && response.errors.length > 0) {
|
|
96
|
+
throw new Error(`Error de GraphQL: ${response.errors.map((e) => e.message).join(", ")}`);
|
|
97
|
+
}
|
|
98
|
+
const issue = response.repository?.issue;
|
|
99
|
+
if (!issue) {
|
|
100
|
+
throw new Error(`No se encontró la issue #${issueNumber} en ${owner}/${repo}`);
|
|
101
|
+
}
|
|
102
|
+
const title = issue.title || "";
|
|
103
|
+
const description = issue.body || "";
|
|
104
|
+
const label = issue.labels?.nodes?.[0]?.name;
|
|
105
|
+
if (!title) {
|
|
106
|
+
throw new Error(`No se pudo obtener el título para la issue #${issueNumber}`);
|
|
107
|
+
}
|
|
108
|
+
s.stop(`Datos de la issue obtenidos correctamente`);
|
|
109
|
+
// Create slug for branch
|
|
110
|
+
const slugTitle = title
|
|
111
|
+
.normalize("NFD").replace(/[\u0300-\u036f]/g, "")
|
|
112
|
+
.toLowerCase()
|
|
113
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
114
|
+
.replace(/^-+|-+$/g, "");
|
|
115
|
+
const ticketRef = `${owner}-${repo}-${issueNumber}`;
|
|
116
|
+
const branchName = `${ticketRef}-${slugTitle}`.substring(0, 100);
|
|
117
|
+
let summaryText = `${pc.bold("Issue:")} #${issueNumber}\n` +
|
|
118
|
+
`${pc.bold("Título:")} ${title}\n`;
|
|
119
|
+
if (label)
|
|
120
|
+
summaryText += `${pc.bold("Label:")} ${label}\n`;
|
|
121
|
+
summaryText += `${pc.bold("Rama:")} ${pc.cyan(branchName)}`;
|
|
122
|
+
p.note(summaryText, "Resumen del PR");
|
|
123
|
+
const shouldContinue = await p.confirm({
|
|
124
|
+
message: '¿Continuar con la creación de la rama y PR?',
|
|
125
|
+
initialValue: true,
|
|
126
|
+
});
|
|
127
|
+
if (p.isCancel(shouldContinue) || !shouldContinue) {
|
|
128
|
+
p.cancel('Operación cancelada por el usuario.');
|
|
129
|
+
process.exit(0);
|
|
130
|
+
}
|
|
131
|
+
s.start('Validando estado de git...');
|
|
132
|
+
// Validate: Check for uncommitted changes
|
|
133
|
+
const statusOutput = execSync("git status --porcelain", { encoding: "utf-8" }).trim();
|
|
134
|
+
if (statusOutput) {
|
|
135
|
+
throw new Error("Tenés cambios sin commitear. Por favor hacé commit o stash antes de correr esto.");
|
|
136
|
+
}
|
|
137
|
+
// Validate: Check for unpushed commits on current branch
|
|
138
|
+
const currentBranch = execSync("git branch --show-current", { encoding: "utf-8" }).trim();
|
|
139
|
+
if (currentBranch) {
|
|
140
|
+
// Allow it to fail gracefully if there is no upstream
|
|
141
|
+
try {
|
|
142
|
+
const unpushedOutput = execSync(`git log @{u}..HEAD --oneline`, { encoding: "utf-8", stdio: ["pipe", "pipe", "ignore"] }).toString().trim();
|
|
143
|
+
if (unpushedOutput) {
|
|
144
|
+
throw new Error(`Tenés commits sin pushear en la rama '${currentBranch}'.\nPor favor hacé push antes de correr este script.`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch (e) {
|
|
148
|
+
// No upstream branch, ignore
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
s.stop('Estado de git validado');
|
|
152
|
+
s.start('Cambiando a develop y actualizando...');
|
|
153
|
+
execSync(`git checkout develop`, { stdio: "ignore" });
|
|
154
|
+
execSync(`git pull origin develop`, { stdio: "ignore" });
|
|
155
|
+
s.stop('Rama develop actualizada');
|
|
156
|
+
s.start(`Creando nueva rama: ${branchName}`);
|
|
157
|
+
execSync(`git checkout -b ${branchName}`, { stdio: "ignore" });
|
|
158
|
+
s.stop(`Rama ${pc.cyan(branchName)} creada`);
|
|
159
|
+
s.start('Creando commit inicial...');
|
|
160
|
+
execSync(`git add .`, { stdio: "ignore" });
|
|
161
|
+
execSync(`git commit -m "feat(${ticketRef}): initial commit for ${title}" --allow-empty --no-verify`, { stdio: "ignore" });
|
|
162
|
+
s.stop('Commit inicial creado');
|
|
163
|
+
s.start('Pusheando rama al remoto...');
|
|
164
|
+
execSync(`git push origin ${branchName}`, { stdio: "ignore" });
|
|
165
|
+
s.stop('Rama pusheada');
|
|
166
|
+
s.start('Creando Pull Request en GitHub...');
|
|
167
|
+
const prTitle = label
|
|
168
|
+
? `[${ticketRef}][${label}] ${title}`
|
|
169
|
+
: `[${ticketRef}] ${title}`;
|
|
170
|
+
const issueUrl = `https://github.com/${owner}/${repo}/issues/${issueNumber}`;
|
|
171
|
+
const prBody = description
|
|
172
|
+
? `**Relates to GitHub issue [${issueNumber}](${issueUrl})**\n\n${description}`
|
|
173
|
+
: `**Relates to GitHub issue [${issueNumber}](${issueUrl})**`;
|
|
174
|
+
execSync(`gh pr create --title "${prTitle}" --body "${prBody}" --base develop --head "${branchName}"`, { stdio: "ignore" });
|
|
175
|
+
s.stop('Pull Request creado');
|
|
176
|
+
execSync(`git push --set-upstream origin "${branchName}"`, { stdio: "ignore" });
|
|
177
|
+
p.outro(`¡Todo listo! Estás en la rama ${pc.cyan(branchName)} y la PR ya está subida.`);
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
s.stop('Ocurrió un error');
|
|
181
|
+
p.cancel(pc.red(`Error: ${err.message}`));
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import * as p3 from "@clack/prompts";
|
|
6
|
+
import pc3 from "picocolors";
|
|
7
|
+
|
|
8
|
+
// src/jira.ts
|
|
9
|
+
import { execSync } from "child_process";
|
|
10
|
+
import * as p from "@clack/prompts";
|
|
11
|
+
import pc from "picocolors";
|
|
12
|
+
var fetch = globalThis.fetch;
|
|
13
|
+
var createPrFromJira = async (jiraTicket) => {
|
|
14
|
+
const JIRA_BASE_URL = process.env.JIRA_BASE_URL || "";
|
|
15
|
+
const JIRA_EMAIL = process.env.JIRA_EMAIL || "";
|
|
16
|
+
const JIRA_API_TOKEN = process.env.JIRA_API_TOKEN || "";
|
|
17
|
+
if (!JIRA_BASE_URL || !JIRA_EMAIL || !JIRA_API_TOKEN) {
|
|
18
|
+
p.cancel(pc.red("Faltan variables de entorno (JIRA_BASE_URL, JIRA_EMAIL, JIRA_API_TOKEN)"));
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
const s = p.spinner();
|
|
22
|
+
s.start(`Buscando datos del ticket ${pc.cyan(jiraTicket)} en Jira...`);
|
|
23
|
+
try {
|
|
24
|
+
const res = await fetch(`${JIRA_BASE_URL}/rest/api/3/issue/${jiraTicket}`, {
|
|
25
|
+
headers: {
|
|
26
|
+
"Authorization": "Basic " + Buffer.from(`${JIRA_EMAIL}:${JIRA_API_TOKEN}`).toString("base64"),
|
|
27
|
+
"Accept": "application/json"
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
if (!res.ok) {
|
|
31
|
+
throw new Error(`Error de Jira: ${res.status} ${res.statusText}`);
|
|
32
|
+
}
|
|
33
|
+
const response = await res.json();
|
|
34
|
+
if (response.errorMessages && response.errorMessages.length > 0) {
|
|
35
|
+
throw new Error(`Error de Jira: ${response.errorMessages.join(", ")}`);
|
|
36
|
+
}
|
|
37
|
+
const title = response.fields?.summary || "";
|
|
38
|
+
const description = response.fields?.description?.content?.[0]?.content?.[0]?.text || "";
|
|
39
|
+
const teamFields = [
|
|
40
|
+
response.fields?.customfield_10001?.name,
|
|
41
|
+
response.fields?.customfield_10001,
|
|
42
|
+
response.fields?.customfield_10037?.value,
|
|
43
|
+
response.fields?.customfield_10038?.value,
|
|
44
|
+
response.fields?.components?.[0]?.name,
|
|
45
|
+
response.fields?.labels?.[0]
|
|
46
|
+
].filter(Boolean);
|
|
47
|
+
let team = teamFields.length > 0 ? teamFields[0] : response.fields?.project?.key || "";
|
|
48
|
+
if (!title) {
|
|
49
|
+
throw new Error(`No se pudo obtener el t\xEDtulo para el ticket ${jiraTicket}`);
|
|
50
|
+
}
|
|
51
|
+
if (!team) {
|
|
52
|
+
throw new Error(`No se pudo obtener el equipo para el ticket ${jiraTicket}`);
|
|
53
|
+
}
|
|
54
|
+
s.stop(`Datos de Jira obtenidos correctamente`);
|
|
55
|
+
const slugTitle = title.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
56
|
+
const ticketLower = jiraTicket.toLowerCase();
|
|
57
|
+
const branchName = `${ticketLower}-${slugTitle}`;
|
|
58
|
+
p.note(
|
|
59
|
+
`${pc.bold("Ticket:")} ${jiraTicket}
|
|
60
|
+
${pc.bold("T\xEDtulo:")} ${title}
|
|
61
|
+
${pc.bold("Equipo:")} ${team}
|
|
62
|
+
${pc.bold("Rama:")} ${pc.cyan(branchName)}`,
|
|
63
|
+
"Resumen del PR"
|
|
64
|
+
);
|
|
65
|
+
const shouldContinue = await p.confirm({
|
|
66
|
+
message: "\xBFContinuar con la creaci\xF3n de la rama y PR?",
|
|
67
|
+
initialValue: true
|
|
68
|
+
});
|
|
69
|
+
if (p.isCancel(shouldContinue) || !shouldContinue) {
|
|
70
|
+
p.cancel("Operaci\xF3n cancelada por el usuario.");
|
|
71
|
+
process.exit(0);
|
|
72
|
+
}
|
|
73
|
+
s.start("Validando estado de git...");
|
|
74
|
+
const statusOutput = execSync("git status --porcelain", { encoding: "utf-8" }).trim();
|
|
75
|
+
if (statusOutput) {
|
|
76
|
+
throw new Error("Ten\xE9s cambios sin commitear. Por favor hac\xE9 commit o stash antes de correr esto.");
|
|
77
|
+
}
|
|
78
|
+
s.stop("Estado de git validado");
|
|
79
|
+
s.start("Cambiando a develop y actualizando...");
|
|
80
|
+
execSync(`git checkout develop`, { stdio: "ignore" });
|
|
81
|
+
execSync(`git pull origin develop`, { stdio: "ignore" });
|
|
82
|
+
s.stop("Rama develop actualizada");
|
|
83
|
+
s.start(`Creando nueva rama: ${branchName}`);
|
|
84
|
+
execSync(`git checkout -b ${branchName}`, { stdio: "ignore" });
|
|
85
|
+
s.stop(`Rama ${pc.cyan(branchName)} creada`);
|
|
86
|
+
s.start("Creando commit inicial...");
|
|
87
|
+
execSync(`git add .`, { stdio: "ignore" });
|
|
88
|
+
execSync(`git commit -m "feat(${jiraTicket}): initial commit for ${title}" --allow-empty --no-verify`, { stdio: "ignore" });
|
|
89
|
+
s.stop("Commit inicial creado");
|
|
90
|
+
s.start("Pusheando rama al remoto...");
|
|
91
|
+
execSync(`git push origin ${branchName}`, { stdio: "ignore" });
|
|
92
|
+
s.stop("Rama pusheada");
|
|
93
|
+
s.start("Creando Pull Request en GitHub...");
|
|
94
|
+
const prTitle = team ? `[${jiraTicket}][${team}] ${title}` : `[${jiraTicket}] ${title}`;
|
|
95
|
+
const prBody = `**Relates to Jira ticket [${jiraTicket}](${JIRA_BASE_URL}/browse/${jiraTicket})**
|
|
96
|
+
|
|
97
|
+
${description}`;
|
|
98
|
+
execSync(`gh pr create --title "${prTitle}" --body "${prBody}" --base develop --head "${branchName}"`, { stdio: "ignore" });
|
|
99
|
+
s.stop("Pull Request creado");
|
|
100
|
+
s.start(`Moviendo ticket ${jiraTicket} a 'In Progress'...`);
|
|
101
|
+
try {
|
|
102
|
+
const transitionsRes = await fetch(`${JIRA_BASE_URL}/rest/api/3/issue/${jiraTicket}/transitions`, {
|
|
103
|
+
method: "GET",
|
|
104
|
+
headers: {
|
|
105
|
+
"Authorization": "Basic " + Buffer.from(`${JIRA_EMAIL}:${JIRA_API_TOKEN}`).toString("base64"),
|
|
106
|
+
"Accept": "application/json"
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
if (transitionsRes.ok) {
|
|
110
|
+
const transitionsData = await transitionsRes.json();
|
|
111
|
+
const transitions = transitionsData.transitions || [];
|
|
112
|
+
const inProgress = transitions.find((t) => t.name.toLowerCase() === "in progress");
|
|
113
|
+
if (inProgress) {
|
|
114
|
+
const doTransitionRes = await fetch(`${JIRA_BASE_URL}/rest/api/3/issue/${jiraTicket}/transitions`, {
|
|
115
|
+
method: "POST",
|
|
116
|
+
headers: {
|
|
117
|
+
"Authorization": "Basic " + Buffer.from(`${JIRA_EMAIL}:${JIRA_API_TOKEN}`).toString("base64"),
|
|
118
|
+
"Accept": "application/json",
|
|
119
|
+
"Content-Type": "application/json"
|
|
120
|
+
},
|
|
121
|
+
body: JSON.stringify({ transition: { id: inProgress.id } })
|
|
122
|
+
});
|
|
123
|
+
if (!doTransitionRes.ok) {
|
|
124
|
+
p.log.warn(`No se pudo mover a In Progress: ${doTransitionRes.statusText}`);
|
|
125
|
+
} else {
|
|
126
|
+
p.log.success(`Ticket ${jiraTicket} movido a 'In Progress' en Jira`);
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
p.log.warn("No se encontr\xF3 el estado 'In Progress' para este ticket.");
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
} catch (jiraTransitionError) {
|
|
133
|
+
p.log.warn(`Error al intentar mover en Jira: ${jiraTransitionError.message}`);
|
|
134
|
+
}
|
|
135
|
+
s.stop("Transici\xF3n de Jira procesada");
|
|
136
|
+
execSync(`git push --set-upstream origin "${branchName}"`, { stdio: "ignore" });
|
|
137
|
+
p.outro(`\xA1Todo listo! Est\xE1s en la rama ${pc.cyan(branchName)} y la PR ya est\xE1 subida.`);
|
|
138
|
+
} catch (err) {
|
|
139
|
+
s.stop("Ocurri\xF3 un error");
|
|
140
|
+
p.cancel(pc.red(`Error: ${err.message}`));
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// src/github.ts
|
|
146
|
+
import { execSync as execSync2 } from "child_process";
|
|
147
|
+
import * as p2 from "@clack/prompts";
|
|
148
|
+
import pc2 from "picocolors";
|
|
149
|
+
var fetch2 = globalThis.fetch;
|
|
150
|
+
var GITHUB_GRAPHQL_URL = "https://api.github.com/graphql";
|
|
151
|
+
var createPrFromGithubIssue = async (issueArg) => {
|
|
152
|
+
const issueRegex = /^(?:([a-zA-Z0-9-]+)\/([a-zA-Z0-9._-]+)#(\d+)|#(\d+)|(\d+))$/;
|
|
153
|
+
const match = issueArg.match(issueRegex);
|
|
154
|
+
let owner;
|
|
155
|
+
let repo;
|
|
156
|
+
let issueNumber;
|
|
157
|
+
if (match) {
|
|
158
|
+
if (match[1] && match[2] && match[3]) {
|
|
159
|
+
owner = match[1];
|
|
160
|
+
repo = match[2];
|
|
161
|
+
issueNumber = parseInt(match[3], 10);
|
|
162
|
+
} else if (match[4] || match[5]) {
|
|
163
|
+
try {
|
|
164
|
+
const currentRemote = execSync2("git remote get-url origin", { encoding: "utf-8" }).trim();
|
|
165
|
+
const remoteRegex = /github\.com[:/](?:[^/]+)\/([^/.]+)|github\.com[:/]([^/]+)\/([^/.]+)/;
|
|
166
|
+
const remoteMatch = currentRemote.match(remoteRegex);
|
|
167
|
+
if (!remoteMatch) {
|
|
168
|
+
throw new Error("No se pudo determinar el repositorio actual desde el remote de git");
|
|
169
|
+
}
|
|
170
|
+
owner = remoteMatch[1] || remoteMatch[2];
|
|
171
|
+
repo = remoteMatch[3] || remoteMatch[1];
|
|
172
|
+
const numStr = match[4] || match[5];
|
|
173
|
+
issueNumber = parseInt(numStr, 10);
|
|
174
|
+
repo = repo.replace(/\.git$/, "");
|
|
175
|
+
} catch (e) {
|
|
176
|
+
p2.cancel(pc2.red("Error obteniendo el repo actual. Asegurate de estar en un repo de git con un remote origin."));
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
} else {
|
|
180
|
+
p2.cancel(pc2.red("Formato de issue inv\xE1lido. Us\xE1 owner/repo#number o #number o simplemente el n\xFAmero."));
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
} else {
|
|
184
|
+
p2.cancel(pc2.red("Formato de issue inv\xE1lido. Us\xE1 owner/repo#number o #number o simplemente el n\xFAmero."));
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
const GITHUB_TOKEN = process.env.GITHUB_TOKEN || "";
|
|
188
|
+
if (!GITHUB_TOKEN) {
|
|
189
|
+
p2.cancel(pc2.red("Falta la variable de entorno GITHUB_TOKEN"));
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
const s = p2.spinner();
|
|
193
|
+
s.start(`Buscando issue #${issueNumber} en ${owner}/${repo}...`);
|
|
194
|
+
try {
|
|
195
|
+
const query = `
|
|
196
|
+
query GetIssue($owner: String!, $repo: String!, $number: Int!) {
|
|
197
|
+
repository(owner: $owner, name: $repo) {
|
|
198
|
+
issue(number: $number) {
|
|
199
|
+
number
|
|
200
|
+
title
|
|
201
|
+
body
|
|
202
|
+
labels(first: 10) {
|
|
203
|
+
nodes {
|
|
204
|
+
name
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
assignees(first: 5) {
|
|
208
|
+
nodes {
|
|
209
|
+
login
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
`;
|
|
216
|
+
const res = await fetch2(GITHUB_GRAPHQL_URL, {
|
|
217
|
+
method: "POST",
|
|
218
|
+
headers: {
|
|
219
|
+
"Authorization": `Bearer ${GITHUB_TOKEN}`,
|
|
220
|
+
"Content-Type": "application/json"
|
|
221
|
+
},
|
|
222
|
+
body: JSON.stringify({
|
|
223
|
+
query,
|
|
224
|
+
variables: { owner, repo, number: issueNumber }
|
|
225
|
+
})
|
|
226
|
+
});
|
|
227
|
+
if (!res.ok) {
|
|
228
|
+
throw new Error(`Error en la API de GitHub: ${res.status} ${res.statusText}`);
|
|
229
|
+
}
|
|
230
|
+
const response = await res.json();
|
|
231
|
+
if (response.errors && response.errors.length > 0) {
|
|
232
|
+
throw new Error(`Error de GraphQL: ${response.errors.map((e) => e.message).join(", ")}`);
|
|
233
|
+
}
|
|
234
|
+
const issue = response.repository?.issue;
|
|
235
|
+
if (!issue) {
|
|
236
|
+
throw new Error(`No se encontr\xF3 la issue #${issueNumber} en ${owner}/${repo}`);
|
|
237
|
+
}
|
|
238
|
+
const title = issue.title || "";
|
|
239
|
+
const description = issue.body || "";
|
|
240
|
+
const label = issue.labels?.nodes?.[0]?.name;
|
|
241
|
+
if (!title) {
|
|
242
|
+
throw new Error(`No se pudo obtener el t\xEDtulo para la issue #${issueNumber}`);
|
|
243
|
+
}
|
|
244
|
+
s.stop(`Datos de la issue obtenidos correctamente`);
|
|
245
|
+
const slugTitle = title.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
246
|
+
const ticketRef = `${owner}-${repo}-${issueNumber}`;
|
|
247
|
+
const branchName = `${ticketRef}-${slugTitle}`.substring(0, 100);
|
|
248
|
+
let summaryText = `${pc2.bold("Issue:")} #${issueNumber}
|
|
249
|
+
${pc2.bold("T\xEDtulo:")} ${title}
|
|
250
|
+
`;
|
|
251
|
+
if (label) summaryText += `${pc2.bold("Label:")} ${label}
|
|
252
|
+
`;
|
|
253
|
+
summaryText += `${pc2.bold("Rama:")} ${pc2.cyan(branchName)}`;
|
|
254
|
+
p2.note(summaryText, "Resumen del PR");
|
|
255
|
+
const shouldContinue = await p2.confirm({
|
|
256
|
+
message: "\xBFContinuar con la creaci\xF3n de la rama y PR?",
|
|
257
|
+
initialValue: true
|
|
258
|
+
});
|
|
259
|
+
if (p2.isCancel(shouldContinue) || !shouldContinue) {
|
|
260
|
+
p2.cancel("Operaci\xF3n cancelada por el usuario.");
|
|
261
|
+
process.exit(0);
|
|
262
|
+
}
|
|
263
|
+
s.start("Validando estado de git...");
|
|
264
|
+
const statusOutput = execSync2("git status --porcelain", { encoding: "utf-8" }).trim();
|
|
265
|
+
if (statusOutput) {
|
|
266
|
+
throw new Error("Ten\xE9s cambios sin commitear. Por favor hac\xE9 commit o stash antes de correr esto.");
|
|
267
|
+
}
|
|
268
|
+
const currentBranch = execSync2("git branch --show-current", { encoding: "utf-8" }).trim();
|
|
269
|
+
if (currentBranch) {
|
|
270
|
+
try {
|
|
271
|
+
const unpushedOutput = execSync2(`git log @{u}..HEAD --oneline`, { encoding: "utf-8", stdio: ["pipe", "pipe", "ignore"] }).toString().trim();
|
|
272
|
+
if (unpushedOutput) {
|
|
273
|
+
throw new Error(`Ten\xE9s commits sin pushear en la rama '${currentBranch}'.
|
|
274
|
+
Por favor hac\xE9 push antes de correr este script.`);
|
|
275
|
+
}
|
|
276
|
+
} catch (e) {
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
s.stop("Estado de git validado");
|
|
280
|
+
s.start("Cambiando a develop y actualizando...");
|
|
281
|
+
execSync2(`git checkout develop`, { stdio: "ignore" });
|
|
282
|
+
execSync2(`git pull origin develop`, { stdio: "ignore" });
|
|
283
|
+
s.stop("Rama develop actualizada");
|
|
284
|
+
s.start(`Creando nueva rama: ${branchName}`);
|
|
285
|
+
execSync2(`git checkout -b ${branchName}`, { stdio: "ignore" });
|
|
286
|
+
s.stop(`Rama ${pc2.cyan(branchName)} creada`);
|
|
287
|
+
s.start("Creando commit inicial...");
|
|
288
|
+
execSync2(`git add .`, { stdio: "ignore" });
|
|
289
|
+
execSync2(`git commit -m "feat(${ticketRef}): initial commit for ${title}" --allow-empty --no-verify`, { stdio: "ignore" });
|
|
290
|
+
s.stop("Commit inicial creado");
|
|
291
|
+
s.start("Pusheando rama al remoto...");
|
|
292
|
+
execSync2(`git push origin ${branchName}`, { stdio: "ignore" });
|
|
293
|
+
s.stop("Rama pusheada");
|
|
294
|
+
s.start("Creando Pull Request en GitHub...");
|
|
295
|
+
const prTitle = label ? `[${ticketRef}][${label}] ${title}` : `[${ticketRef}] ${title}`;
|
|
296
|
+
const issueUrl = `https://github.com/${owner}/${repo}/issues/${issueNumber}`;
|
|
297
|
+
const prBody = description ? `**Relates to GitHub issue [${issueNumber}](${issueUrl})**
|
|
298
|
+
|
|
299
|
+
${description}` : `**Relates to GitHub issue [${issueNumber}](${issueUrl})**`;
|
|
300
|
+
execSync2(`gh pr create --title "${prTitle}" --body "${prBody}" --base develop --head "${branchName}"`, { stdio: "ignore" });
|
|
301
|
+
s.stop("Pull Request creado");
|
|
302
|
+
execSync2(`git push --set-upstream origin "${branchName}"`, { stdio: "ignore" });
|
|
303
|
+
p2.outro(`\xA1Todo listo! Est\xE1s en la rama ${pc2.cyan(branchName)} y la PR ya est\xE1 subida.`);
|
|
304
|
+
} catch (err) {
|
|
305
|
+
s.stop("Ocurri\xF3 un error");
|
|
306
|
+
p2.cancel(pc2.red(`Error: ${err.message}`));
|
|
307
|
+
process.exit(1);
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
// src/index.ts
|
|
312
|
+
var program = new Command();
|
|
313
|
+
program.name("gh-createpr").description("CLI interactiva para crear GitHub Pull Requests desde Jira o GitHub Issues").version("1.3.2");
|
|
314
|
+
program.command("jira").description("Crear PR desde un ticket de Jira").argument("[ticket]", "ID del ticket de Jira (ej: LAN-3)").action(async (ticket) => {
|
|
315
|
+
let finalTicket = ticket;
|
|
316
|
+
if (!finalTicket) {
|
|
317
|
+
p3.intro(pc3.bgBlue(pc3.white(" gh-createpr: Jira ")));
|
|
318
|
+
const result = await p3.text({
|
|
319
|
+
message: "Ingres\xE1 el ID del ticket de Jira (ej: LAN-3):",
|
|
320
|
+
placeholder: "LAN-3",
|
|
321
|
+
validate(value) {
|
|
322
|
+
if (!value) return "Por favor ingres\xE1 un ticket.";
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
if (p3.isCancel(result)) {
|
|
326
|
+
p3.cancel("Operaci\xF3n cancelada.");
|
|
327
|
+
process.exit(0);
|
|
328
|
+
}
|
|
329
|
+
finalTicket = result;
|
|
330
|
+
}
|
|
331
|
+
await createPrFromJira(finalTicket);
|
|
332
|
+
});
|
|
333
|
+
program.command("github").description("Crear PR desde una GitHub Issue").argument("[issue]", "ID de la Issue (ej: owner/repo#123 o #123)").action(async (issue) => {
|
|
334
|
+
let finalIssue = issue;
|
|
335
|
+
if (!finalIssue) {
|
|
336
|
+
p3.intro(pc3.bgMagenta(pc3.white(" gh-createpr: GitHub Issue ")));
|
|
337
|
+
const result = await p3.text({
|
|
338
|
+
message: "Ingres\xE1 el ID de la Issue (ej: owner/repo#123 o #123):",
|
|
339
|
+
placeholder: "#123",
|
|
340
|
+
validate(value) {
|
|
341
|
+
if (!value) return "Por favor ingres\xE1 un identificador.";
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
if (p3.isCancel(result)) {
|
|
345
|
+
p3.cancel("Operaci\xF3n cancelada.");
|
|
346
|
+
process.exit(0);
|
|
347
|
+
}
|
|
348
|
+
finalIssue = result;
|
|
349
|
+
}
|
|
350
|
+
await createPrFromGithubIssue(finalIssue);
|
|
351
|
+
});
|
|
352
|
+
program.action(async () => {
|
|
353
|
+
p3.intro(pc3.bgCyan(pc3.black(" gh-createpr: CLI Interactiva ")));
|
|
354
|
+
const sourceType = await p3.select({
|
|
355
|
+
message: "\xBFDesde d\xF3nde quer\xE9s crear tu Pull Request?",
|
|
356
|
+
options: [
|
|
357
|
+
{ value: "jira", label: "Jira Ticket", hint: "Ej: LAN-3" },
|
|
358
|
+
{ value: "github", label: "GitHub Issue", hint: "Ej: #123 o owner/repo#123" }
|
|
359
|
+
]
|
|
360
|
+
});
|
|
361
|
+
if (p3.isCancel(sourceType)) {
|
|
362
|
+
p3.cancel("Operaci\xF3n cancelada por el usuario.");
|
|
363
|
+
process.exit(0);
|
|
364
|
+
}
|
|
365
|
+
if (sourceType === "jira") {
|
|
366
|
+
const ticketId = await p3.text({
|
|
367
|
+
message: "Ingres\xE1 el ID del ticket de Jira:",
|
|
368
|
+
placeholder: "LAN-3",
|
|
369
|
+
validate: (value) => {
|
|
370
|
+
if (!value) return "Por favor ingres\xE1 un ticket v\xE1lido.";
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
if (p3.isCancel(ticketId)) {
|
|
374
|
+
p3.cancel("Operaci\xF3n cancelada.");
|
|
375
|
+
process.exit(0);
|
|
376
|
+
}
|
|
377
|
+
await createPrFromJira(ticketId);
|
|
378
|
+
} else if (sourceType === "github") {
|
|
379
|
+
const issueId = await p3.text({
|
|
380
|
+
message: "Ingres\xE1 el ID de la Issue:",
|
|
381
|
+
placeholder: "#123",
|
|
382
|
+
validate: (value) => {
|
|
383
|
+
if (!value) return "Por favor ingres\xE1 un ID v\xE1lido.";
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
if (p3.isCancel(issueId)) {
|
|
387
|
+
p3.cancel("Operaci\xF3n cancelada.");
|
|
388
|
+
process.exit(0);
|
|
389
|
+
}
|
|
390
|
+
await createPrFromGithubIssue(issueId);
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
program.parse(process.argv);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/jira.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jira.d.ts","sourceRoot":"","sources":["../src/jira.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,gBAAgB,GAAU,YAAY,MAAM,kBAkKxD,CAAC"}
|
package/dist/jira.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import * as p from "@clack/prompts";
|
|
3
|
+
import pc from "picocolors";
|
|
4
|
+
// Use native fetch (available in Node.js 18+)
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
const fetch = globalThis.fetch;
|
|
7
|
+
export const createPrFromJira = async (jiraTicket) => {
|
|
8
|
+
const JIRA_BASE_URL = process.env.JIRA_BASE_URL || "";
|
|
9
|
+
const JIRA_EMAIL = process.env.JIRA_EMAIL || "";
|
|
10
|
+
const JIRA_API_TOKEN = process.env.JIRA_API_TOKEN || "";
|
|
11
|
+
if (!JIRA_BASE_URL || !JIRA_EMAIL || !JIRA_API_TOKEN) {
|
|
12
|
+
p.cancel(pc.red("Faltan variables de entorno (JIRA_BASE_URL, JIRA_EMAIL, JIRA_API_TOKEN)"));
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
const s = p.spinner();
|
|
16
|
+
s.start(`Buscando datos del ticket ${pc.cyan(jiraTicket)} en Jira...`);
|
|
17
|
+
try {
|
|
18
|
+
const res = await fetch(`${JIRA_BASE_URL}/rest/api/3/issue/${jiraTicket}`, {
|
|
19
|
+
headers: {
|
|
20
|
+
"Authorization": "Basic " + Buffer.from(`${JIRA_EMAIL}:${JIRA_API_TOKEN}`).toString("base64"),
|
|
21
|
+
"Accept": "application/json"
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
if (!res.ok) {
|
|
25
|
+
throw new Error(`Error de Jira: ${res.status} ${res.statusText}`);
|
|
26
|
+
}
|
|
27
|
+
const response = await res.json();
|
|
28
|
+
if (response.errorMessages && response.errorMessages.length > 0) {
|
|
29
|
+
throw new Error(`Error de Jira: ${response.errorMessages.join(", ")}`);
|
|
30
|
+
}
|
|
31
|
+
const title = response.fields?.summary || "";
|
|
32
|
+
const description = response.fields?.description?.content?.[0]?.content?.[0]?.text || "";
|
|
33
|
+
// Get team
|
|
34
|
+
const teamFields = [
|
|
35
|
+
response.fields?.customfield_10001?.name,
|
|
36
|
+
response.fields?.customfield_10001,
|
|
37
|
+
response.fields?.customfield_10037?.value,
|
|
38
|
+
response.fields?.customfield_10038?.value,
|
|
39
|
+
response.fields?.components?.[0]?.name,
|
|
40
|
+
response.fields?.labels?.[0],
|
|
41
|
+
].filter(Boolean);
|
|
42
|
+
let team = teamFields.length > 0 ? teamFields[0] : response.fields?.project?.key || "";
|
|
43
|
+
if (!title) {
|
|
44
|
+
throw new Error(`No se pudo obtener el título para el ticket ${jiraTicket}`);
|
|
45
|
+
}
|
|
46
|
+
if (!team) {
|
|
47
|
+
throw new Error(`No se pudo obtener el equipo para el ticket ${jiraTicket}`);
|
|
48
|
+
}
|
|
49
|
+
s.stop(`Datos de Jira obtenidos correctamente`);
|
|
50
|
+
// Create slug for branch
|
|
51
|
+
const slugTitle = title
|
|
52
|
+
.normalize("NFD").replace(/[\u0300-\u036f]/g, "")
|
|
53
|
+
.toLowerCase()
|
|
54
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
55
|
+
.replace(/^-+|-+$/g, "");
|
|
56
|
+
const ticketLower = jiraTicket.toLowerCase();
|
|
57
|
+
const branchName = `${ticketLower}-${slugTitle}`;
|
|
58
|
+
p.note(`${pc.bold("Ticket:")} ${jiraTicket}\n` +
|
|
59
|
+
`${pc.bold("Título:")} ${title}\n` +
|
|
60
|
+
`${pc.bold("Equipo:")} ${team}\n` +
|
|
61
|
+
`${pc.bold("Rama:")} ${pc.cyan(branchName)}`, "Resumen del PR");
|
|
62
|
+
const shouldContinue = await p.confirm({
|
|
63
|
+
message: '¿Continuar con la creación de la rama y PR?',
|
|
64
|
+
initialValue: true,
|
|
65
|
+
});
|
|
66
|
+
if (p.isCancel(shouldContinue) || !shouldContinue) {
|
|
67
|
+
p.cancel('Operación cancelada por el usuario.');
|
|
68
|
+
process.exit(0);
|
|
69
|
+
}
|
|
70
|
+
s.start('Validando estado de git...');
|
|
71
|
+
// Validate: Check for uncommitted changes
|
|
72
|
+
const statusOutput = execSync("git status --porcelain", { encoding: "utf-8" }).trim();
|
|
73
|
+
if (statusOutput) {
|
|
74
|
+
throw new Error("Tenés cambios sin commitear. Por favor hacé commit o stash antes de correr esto.");
|
|
75
|
+
}
|
|
76
|
+
s.stop('Estado de git validado');
|
|
77
|
+
s.start('Cambiando a develop y actualizando...');
|
|
78
|
+
execSync(`git checkout develop`, { stdio: "ignore" });
|
|
79
|
+
execSync(`git pull origin develop`, { stdio: "ignore" });
|
|
80
|
+
s.stop('Rama develop actualizada');
|
|
81
|
+
s.start(`Creando nueva rama: ${branchName}`);
|
|
82
|
+
execSync(`git checkout -b ${branchName}`, { stdio: "ignore" });
|
|
83
|
+
s.stop(`Rama ${pc.cyan(branchName)} creada`);
|
|
84
|
+
s.start('Creando commit inicial...');
|
|
85
|
+
execSync(`git add .`, { stdio: "ignore" });
|
|
86
|
+
execSync(`git commit -m "feat(${jiraTicket}): initial commit for ${title}" --allow-empty --no-verify`, { stdio: "ignore" });
|
|
87
|
+
s.stop('Commit inicial creado');
|
|
88
|
+
s.start('Pusheando rama al remoto...');
|
|
89
|
+
execSync(`git push origin ${branchName}`, { stdio: "ignore" });
|
|
90
|
+
s.stop('Rama pusheada');
|
|
91
|
+
s.start('Creando Pull Request en GitHub...');
|
|
92
|
+
const prTitle = team ? `[${jiraTicket}][${team}] ${title}` : `[${jiraTicket}] ${title}`;
|
|
93
|
+
const prBody = `**Relates to Jira ticket [${jiraTicket}](${JIRA_BASE_URL}/browse/${jiraTicket})**\n\n${description}`;
|
|
94
|
+
execSync(`gh pr create --title "${prTitle}" --body "${prBody}" --base develop --head "${branchName}"`, { stdio: "ignore" });
|
|
95
|
+
s.stop('Pull Request creado');
|
|
96
|
+
// JIRA TRANSITION TO IN PROGRESS
|
|
97
|
+
s.start(`Moviendo ticket ${jiraTicket} a 'In Progress'...`);
|
|
98
|
+
try {
|
|
99
|
+
const transitionsRes = await fetch(`${JIRA_BASE_URL}/rest/api/3/issue/${jiraTicket}/transitions`, {
|
|
100
|
+
method: "GET",
|
|
101
|
+
headers: {
|
|
102
|
+
"Authorization": "Basic " + Buffer.from(`${JIRA_EMAIL}:${JIRA_API_TOKEN}`).toString("base64"),
|
|
103
|
+
"Accept": "application/json"
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
if (transitionsRes.ok) {
|
|
107
|
+
const transitionsData = await transitionsRes.json();
|
|
108
|
+
const transitions = transitionsData.transitions || [];
|
|
109
|
+
const inProgress = transitions.find((t) => t.name.toLowerCase() === "in progress");
|
|
110
|
+
if (inProgress) {
|
|
111
|
+
const doTransitionRes = await fetch(`${JIRA_BASE_URL}/rest/api/3/issue/${jiraTicket}/transitions`, {
|
|
112
|
+
method: "POST",
|
|
113
|
+
headers: {
|
|
114
|
+
"Authorization": "Basic " + Buffer.from(`${JIRA_EMAIL}:${JIRA_API_TOKEN}`).toString("base64"),
|
|
115
|
+
"Accept": "application/json",
|
|
116
|
+
"Content-Type": "application/json"
|
|
117
|
+
},
|
|
118
|
+
body: JSON.stringify({ transition: { id: inProgress.id } })
|
|
119
|
+
});
|
|
120
|
+
if (!doTransitionRes.ok) {
|
|
121
|
+
p.log.warn(`No se pudo mover a In Progress: ${doTransitionRes.statusText}`);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
p.log.success(`Ticket ${jiraTicket} movido a 'In Progress' en Jira`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
p.log.warn("No se encontró el estado 'In Progress' para este ticket.");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch (jiraTransitionError) {
|
|
133
|
+
p.log.warn(`Error al intentar mover en Jira: ${jiraTransitionError.message}`);
|
|
134
|
+
}
|
|
135
|
+
s.stop('Transición de Jira procesada');
|
|
136
|
+
execSync(`git push --set-upstream origin "${branchName}"`, { stdio: "ignore" });
|
|
137
|
+
p.outro(`¡Todo listo! Estás en la rama ${pc.cyan(branchName)} y la PR ya está subida.`);
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
s.stop('Ocurrió un error');
|
|
141
|
+
p.cancel(pc.red(`Error: ${err.message}`));
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
//# sourceMappingURL=jira.js.map
|
package/dist/jira.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jira.js","sourceRoot":"","sources":["../src/jira.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lansisdev/gh-createpr",
|
|
3
|
+
"version": "1.3.2",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"bin": {
|
|
6
|
+
"gh-createpr": "./dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "rm -rf dist && tsc && npm run bundle",
|
|
10
|
+
"bundle": "esbuild src/index.ts --bundle --platform=node --target=node18 --outfile=dist/index.js --format=esm --packages=external --allow-overwrite",
|
|
11
|
+
"start": "node dist/index.js",
|
|
12
|
+
"dev": "ts-node --esm src/index.ts",
|
|
13
|
+
"prepare": "npm run build && chmod +x dist/index.js",
|
|
14
|
+
"build:bin": "rm -rf dist/bin && mkdir -p dist/bin && bun build src/index.ts --compile --target=bun-darwin-x64 --outfile dist/bin/gh-createpr-darwin-amd64 && bun build src/index.ts --compile --target=bun-darwin-arm64 --outfile dist/bin/gh-createpr-darwin-arm64",
|
|
15
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [],
|
|
18
|
+
"author": "Gonzalo Buasso",
|
|
19
|
+
"license": "ISC",
|
|
20
|
+
"description": "CLI tool to create GitHub PRs from Jira tickets",
|
|
21
|
+
"type": "module",
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@clack/prompts": "^1.1.0",
|
|
27
|
+
"@types/node": "^24.2.1",
|
|
28
|
+
"commander": "^14.0.0",
|
|
29
|
+
"picocolors": "^1.1.1",
|
|
30
|
+
"ts-node": "^10.9.2",
|
|
31
|
+
"typescript": "^5.9.2"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"esbuild": "^0.25.8"
|
|
35
|
+
}
|
|
36
|
+
}
|