@pilatos/bitbucket-cli 1.0.0 → 1.2.0
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/README.md +50 -230
- package/dist/index.js +389 -48
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,56 +32,20 @@
|
|
|
32
32
|
|
|
33
33
|
If you've used GitHub's `gh` CLI and loved it, you've probably wished for something similar for Bitbucket. **Now you have it.**
|
|
34
34
|
|
|
35
|
-
`bb` brings the power of command-line workflows to Bitbucket Cloud, letting you:
|
|
36
|
-
|
|
37
35
|
- **Stay in your terminal** — No more context-switching to the browser
|
|
38
|
-
- **Automate your workflow** — Script common operations with
|
|
36
|
+
- **Automate your workflow** — Script common operations with JSON output
|
|
39
37
|
- **Work faster** — Clone repos, create PRs, and manage code reviews in seconds
|
|
40
|
-
- **
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## Table of Contents
|
|
45
|
-
|
|
46
|
-
- [Installation](#installation)
|
|
47
|
-
- [Quick Start](#quick-start)
|
|
48
|
-
- [Commands](#commands)
|
|
49
|
-
- [Authentication](#authentication)
|
|
50
|
-
- [Repositories](#repositories)
|
|
51
|
-
- [Pull Requests](#pull-requests)
|
|
52
|
-
- [Configuration](#configuration)
|
|
53
|
-
- [Shell Completion](#shell-completion)
|
|
54
|
-
- [Global Options](#global-options)
|
|
55
|
-
- [Authentication Setup](#authentication-setup)
|
|
56
|
-
- [Configuration](#configuration-1)
|
|
57
|
-
- [Examples](#examples)
|
|
58
|
-
- [Development](#development)
|
|
59
|
-
- [Contributing](#contributing)
|
|
60
|
-
- [License](#license)
|
|
38
|
+
- **Smart context detection** — Automatically detects workspace/repo from git directory
|
|
61
39
|
|
|
62
40
|
---
|
|
63
41
|
|
|
64
42
|
## Installation
|
|
65
43
|
|
|
66
|
-
### Using npm (Recommended)
|
|
67
|
-
|
|
68
44
|
```bash
|
|
69
45
|
npm install -g @pilatos/bitbucket-cli
|
|
70
46
|
```
|
|
71
47
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
```bash
|
|
75
|
-
bun install -g @pilatos/bitbucket-cli
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
### Using Yarn
|
|
79
|
-
|
|
80
|
-
```bash
|
|
81
|
-
yarn global add @pilatos/bitbucket-cli
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### Verify Installation
|
|
48
|
+
Verify installation:
|
|
85
49
|
|
|
86
50
|
```bash
|
|
87
51
|
bb --version
|
|
@@ -93,21 +57,19 @@ bb --version
|
|
|
93
57
|
|
|
94
58
|
## Quick Start
|
|
95
59
|
|
|
96
|
-
Get up and running in under a minute:
|
|
97
|
-
|
|
98
60
|
```bash
|
|
99
61
|
# 1. Authenticate with Bitbucket
|
|
100
62
|
bb auth login
|
|
101
63
|
|
|
102
64
|
# 2. Clone a repository
|
|
103
65
|
bb repo clone myworkspace/myrepo
|
|
66
|
+
cd myrepo
|
|
104
67
|
|
|
105
68
|
# 3. Create a feature branch and make changes
|
|
106
|
-
cd myrepo
|
|
107
69
|
git checkout -b feature/awesome-feature
|
|
108
70
|
|
|
109
71
|
# 4. Create a pull request
|
|
110
|
-
bb pr create --title "Add awesome feature"
|
|
72
|
+
bb pr create --title "Add awesome feature"
|
|
111
73
|
|
|
112
74
|
# 5. List open pull requests
|
|
113
75
|
bb pr list
|
|
@@ -115,156 +77,55 @@ bb pr list
|
|
|
115
77
|
|
|
116
78
|
---
|
|
117
79
|
|
|
118
|
-
##
|
|
119
|
-
|
|
120
|
-
### Authentication
|
|
121
|
-
|
|
122
|
-
Manage your Bitbucket authentication securely.
|
|
123
|
-
|
|
124
|
-
| Command | Description |
|
|
125
|
-
|---------|-------------|
|
|
126
|
-
| `bb auth login` | Authenticate with Bitbucket using an API Token |
|
|
127
|
-
| `bb auth logout` | Log out and remove stored credentials |
|
|
128
|
-
| `bb auth status` | Check your current authentication status |
|
|
129
|
-
| `bb auth token` | Print your current access token |
|
|
130
|
-
|
|
131
|
-
### Repositories
|
|
132
|
-
|
|
133
|
-
Clone, create, and manage your Bitbucket repositories.
|
|
134
|
-
|
|
135
|
-
| Command | Description |
|
|
136
|
-
|---------|-------------|
|
|
137
|
-
| `bb repo clone <repo>` | Clone a repository to your local machine |
|
|
138
|
-
| `bb repo create <name>` | Create a new repository |
|
|
139
|
-
| `bb repo list` | List repositories in a workspace |
|
|
140
|
-
| `bb repo view [repo]` | View repository details and metadata |
|
|
141
|
-
| `bb repo delete <repo>` | Delete a repository (use with caution!) |
|
|
142
|
-
|
|
143
|
-
### Pull Requests
|
|
144
|
-
|
|
145
|
-
Full pull request workflow management from your terminal.
|
|
146
|
-
|
|
147
|
-
| Command | Description |
|
|
148
|
-
|---------|-------------|
|
|
149
|
-
| `bb pr create` | Create a new pull request |
|
|
150
|
-
| `bb pr list` | List pull requests with filtering options |
|
|
151
|
-
| `bb pr view <id>` | View pull request details, diff, and comments |
|
|
152
|
-
| `bb pr merge <id>` | Merge a pull request |
|
|
153
|
-
| `bb pr approve <id>` | Approve a pull request |
|
|
154
|
-
| `bb pr decline <id>` | Decline a pull request |
|
|
155
|
-
| `bb pr checkout <id>` | Checkout a pull request branch locally |
|
|
156
|
-
|
|
157
|
-
### Configuration
|
|
158
|
-
|
|
159
|
-
Customize your CLI experience.
|
|
160
|
-
|
|
161
|
-
| Command | Description |
|
|
162
|
-
|---------|-------------|
|
|
163
|
-
| `bb config get <key>` | Get a configuration value |
|
|
164
|
-
| `bb config set <key> <value>` | Set a configuration value |
|
|
165
|
-
| `bb config list` | List all configuration values |
|
|
166
|
-
|
|
167
|
-
### Shell Completion
|
|
168
|
-
|
|
169
|
-
Enable intelligent tab completion for faster command entry.
|
|
170
|
-
|
|
171
|
-
| Command | Description |
|
|
172
|
-
|---------|-------------|
|
|
173
|
-
| `bb completion install` | Install shell completions (auto-detects shell) |
|
|
174
|
-
| `bb completion uninstall` | Remove shell completions |
|
|
175
|
-
|
|
176
|
-
**Setup:**
|
|
177
|
-
|
|
178
|
-
```bash
|
|
179
|
-
# Install completions
|
|
180
|
-
bb completion install
|
|
181
|
-
|
|
182
|
-
# Restart your shell or source your profile
|
|
183
|
-
source ~/.bashrc # Bash
|
|
184
|
-
source ~/.zshrc # Zsh
|
|
185
|
-
source ~/.config/fish/config.fish # Fish
|
|
186
|
-
```
|
|
80
|
+
## Features
|
|
187
81
|
|
|
188
|
-
|
|
82
|
+
| Category | Commands |
|
|
83
|
+
|----------|----------|
|
|
84
|
+
| **Authentication** | `login`, `logout`, `status`, `token` |
|
|
85
|
+
| **Repositories** | `clone`, `create`, `list`, `view`, `delete` |
|
|
86
|
+
| **Pull Requests** | `create`, `list`, `view`, `edit`, `merge`, `approve`, `decline`, `checkout`, `diff`, `comment`, `comments` |
|
|
87
|
+
| **Configuration** | `get`, `set`, `list` |
|
|
88
|
+
| **Shell Completion** | `install`, `uninstall` |
|
|
189
89
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
```
|
|
90
|
+
**Global Options:**
|
|
91
|
+
- `--json` — Output results as JSON for scripting
|
|
92
|
+
- `-w, --workspace` — Specify workspace
|
|
93
|
+
- `-r, --repo` — Specify repository
|
|
195
94
|
|
|
196
95
|
---
|
|
197
96
|
|
|
198
|
-
##
|
|
97
|
+
## Documentation
|
|
199
98
|
|
|
200
|
-
|
|
99
|
+
Full documentation is available at **[bitbucket-cli.paulvanderlei.com](https://bitbucket-cli.paulvanderlei.com)**
|
|
201
100
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
| `-v, --version` | Show version number |
|
|
101
|
+
- [Quick Start Guide](https://bitbucket-cli.paulvanderlei.com/getting-started/quickstart/)
|
|
102
|
+
- [Command Reference](https://bitbucket-cli.paulvanderlei.com/commands/auth/)
|
|
103
|
+
- [Scripting & Automation](https://bitbucket-cli.paulvanderlei.com/guides/scripting/)
|
|
104
|
+
- [CI/CD Integration](https://bitbucket-cli.paulvanderlei.com/guides/cicd/)
|
|
105
|
+
- [Troubleshooting](https://bitbucket-cli.paulvanderlei.com/help/troubleshooting/)
|
|
106
|
+
- [FAQ](https://bitbucket-cli.paulvanderlei.com/help/faq/)
|
|
209
107
|
|
|
210
108
|
---
|
|
211
109
|
|
|
212
|
-
## Authentication
|
|
110
|
+
## Authentication
|
|
213
111
|
|
|
214
|
-
The CLI uses **Bitbucket API Tokens** for secure authentication.
|
|
112
|
+
The CLI uses **Bitbucket API Tokens** for secure authentication.
|
|
215
113
|
|
|
216
|
-
> **Note**: As of September 9, 2025, Bitbucket app passwords are deprecated
|
|
114
|
+
> **Note**: As of September 9, 2025, Bitbucket app passwords are deprecated. Use API tokens instead.
|
|
217
115
|
|
|
218
|
-
###
|
|
116
|
+
### Create an API Token
|
|
219
117
|
|
|
220
118
|
1. Go to [Bitbucket API Tokens](https://bitbucket.org/account/settings/api-tokens/)
|
|
221
119
|
2. Click **"Create API token"**
|
|
222
|
-
3.
|
|
223
|
-
4.
|
|
224
|
-
- **Account:** Read
|
|
225
|
-
- **Repositories:** Read, Write, Admin (as needed)
|
|
226
|
-
- **Pull requests:** Read, Write
|
|
227
|
-
5. Click **"Create"**
|
|
228
|
-
6. **Copy the generated token** (you won't see it again!)
|
|
120
|
+
3. Select required scopes (Account, Repositories, Pull requests)
|
|
121
|
+
4. Copy the token
|
|
229
122
|
|
|
230
|
-
###
|
|
123
|
+
### Authenticate
|
|
231
124
|
|
|
232
125
|
```bash
|
|
233
126
|
bb auth login
|
|
234
127
|
```
|
|
235
128
|
|
|
236
|
-
Enter your Bitbucket username and the API Token when prompted.
|
|
237
|
-
|
|
238
|
-
### Step 3: Verify
|
|
239
|
-
|
|
240
|
-
```bash
|
|
241
|
-
bb auth status
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
---
|
|
245
|
-
|
|
246
|
-
## Configuration
|
|
247
|
-
|
|
248
|
-
Configuration files are stored in platform-specific locations:
|
|
249
|
-
|
|
250
|
-
| Platform | Location |
|
|
251
|
-
|----------|----------|
|
|
252
|
-
| **macOS / Linux** | `~/.config/bb/config.json` |
|
|
253
|
-
| **Windows** | `%APPDATA%\bb\config.json` |
|
|
254
|
-
|
|
255
|
-
### Available Settings
|
|
256
|
-
|
|
257
|
-
```bash
|
|
258
|
-
# Set your default workspace
|
|
259
|
-
bb config set workspace myworkspace
|
|
260
|
-
|
|
261
|
-
# Set your default repository
|
|
262
|
-
bb config set repo myrepo
|
|
263
|
-
|
|
264
|
-
# View all settings
|
|
265
|
-
bb config list
|
|
266
|
-
```
|
|
267
|
-
|
|
268
129
|
---
|
|
269
130
|
|
|
270
131
|
## Examples
|
|
@@ -272,53 +133,38 @@ bb config list
|
|
|
272
133
|
### Daily Workflow
|
|
273
134
|
|
|
274
135
|
```bash
|
|
275
|
-
#
|
|
276
|
-
bb pr list
|
|
136
|
+
# Check open PRs
|
|
137
|
+
bb pr list
|
|
277
138
|
|
|
278
|
-
# Review
|
|
139
|
+
# Review and merge
|
|
279
140
|
bb pr view 42
|
|
280
|
-
|
|
281
|
-
# Approve and merge
|
|
282
141
|
bb pr approve 42
|
|
283
142
|
bb pr merge 42
|
|
284
143
|
```
|
|
285
144
|
|
|
286
|
-
###
|
|
145
|
+
### Scripting with JSON
|
|
287
146
|
|
|
288
147
|
```bash
|
|
289
|
-
#
|
|
290
|
-
bb pr
|
|
291
|
-
--title "feat: Add user notifications" \
|
|
292
|
-
--description "Implements real-time notifications using WebSockets" \
|
|
293
|
-
--source feature/notifications \
|
|
294
|
-
--destination main
|
|
295
|
-
```
|
|
148
|
+
# Get all open PR titles
|
|
149
|
+
bb pr list --json | jq '.[].title'
|
|
296
150
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
```bash
|
|
300
|
-
# Get all open PRs as JSON for processing
|
|
301
|
-
bb pr list --state OPEN --json | jq '.[] | .title'
|
|
302
|
-
|
|
303
|
-
# List repos and filter by name
|
|
151
|
+
# Filter repos by name
|
|
304
152
|
bb repo list --json | jq '.[] | select(.name | contains("api"))'
|
|
305
153
|
```
|
|
306
154
|
|
|
307
|
-
###
|
|
155
|
+
### CI/CD Usage
|
|
308
156
|
|
|
309
157
|
```bash
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
bb
|
|
313
|
-
|
|
158
|
+
export BB_USERNAME=myuser
|
|
159
|
+
export BB_API_TOKEN=my-token
|
|
160
|
+
bb auth login
|
|
161
|
+
bb pr list -w workspace -r repo --json
|
|
314
162
|
```
|
|
315
163
|
|
|
316
164
|
---
|
|
317
165
|
|
|
318
166
|
## Development
|
|
319
167
|
|
|
320
|
-
Want to contribute or run locally? Here's how:
|
|
321
|
-
|
|
322
168
|
```bash
|
|
323
169
|
# Clone the repository
|
|
324
170
|
git clone https://github.com/0pilatos0/bitbucket-cli.git
|
|
@@ -335,59 +181,33 @@ bun test
|
|
|
335
181
|
|
|
336
182
|
# Build for production
|
|
337
183
|
bun run build
|
|
338
|
-
|
|
339
|
-
# Generate API client from OpenAPI spec
|
|
340
|
-
bun run generate:api
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
### Project Structure
|
|
344
|
-
|
|
345
|
-
```
|
|
346
|
-
bitbucket-cli/
|
|
347
|
-
├── src/
|
|
348
|
-
│ ├── commands/ # Command implementations
|
|
349
|
-
│ ├── core/ # Core utilities and base classes
|
|
350
|
-
│ └── index.ts # Entry point
|
|
351
|
-
├── tests/ # Test files
|
|
352
|
-
├── docs/ # Documentation site (Astro)
|
|
353
|
-
└── specs/ # OpenAPI specifications
|
|
354
184
|
```
|
|
355
185
|
|
|
356
186
|
---
|
|
357
187
|
|
|
358
188
|
## Contributing
|
|
359
189
|
|
|
360
|
-
We welcome contributions
|
|
361
|
-
|
|
362
|
-
- Reporting bugs
|
|
363
|
-
- Suggesting new features
|
|
364
|
-
- Improving documentation
|
|
365
|
-
- Submitting pull requests
|
|
366
|
-
|
|
367
|
-
Please read our [Contributing Guide](CONTRIBUTING.md) to get started.
|
|
368
|
-
|
|
369
|
-
### Quick Contribution Steps
|
|
190
|
+
We welcome contributions! Please read our [Contributing Guide](CONTRIBUTING.md) to get started.
|
|
370
191
|
|
|
371
192
|
1. Fork the repository
|
|
372
|
-
2. Create a feature branch
|
|
193
|
+
2. Create a feature branch
|
|
373
194
|
3. Make your changes
|
|
374
195
|
4. Run tests (`bun test`)
|
|
375
|
-
5.
|
|
376
|
-
6. Push and open a Pull Request
|
|
196
|
+
5. Submit a Pull Request
|
|
377
197
|
|
|
378
198
|
---
|
|
379
199
|
|
|
380
200
|
## Acknowledgments
|
|
381
201
|
|
|
382
|
-
- Inspired by [GitHub CLI (`gh`)](https://cli.github.com/)
|
|
383
|
-
- Built with [Commander.js](https://github.com/tj/commander.js)
|
|
202
|
+
- Inspired by [GitHub CLI (`gh`)](https://cli.github.com/)
|
|
203
|
+
- Built with [Commander.js](https://github.com/tj/commander.js)
|
|
384
204
|
- Uses the [Bitbucket Cloud REST API](https://developer.atlassian.com/cloud/bitbucket/rest/)
|
|
385
205
|
|
|
386
206
|
---
|
|
387
207
|
|
|
388
208
|
## License
|
|
389
209
|
|
|
390
|
-
|
|
210
|
+
MIT License — see [LICENSE](LICENSE) for details.
|
|
391
211
|
|
|
392
212
|
---
|
|
393
213
|
|
package/dist/index.js
CHANGED
|
@@ -27629,7 +27629,7 @@ var require_iso2022 = __commonJS((exports, module) => {
|
|
|
27629
27629
|
|
|
27630
27630
|
// node_modules/external-editor/node_modules/chardet/index.js
|
|
27631
27631
|
var require_chardet = __commonJS((exports, module) => {
|
|
27632
|
-
var
|
|
27632
|
+
var fs2 = __require("fs");
|
|
27633
27633
|
var utf8 = require_utf8();
|
|
27634
27634
|
var unicode = require_unicode();
|
|
27635
27635
|
var mbcs = require_mbcs();
|
|
@@ -27703,29 +27703,29 @@ var require_chardet = __commonJS((exports, module) => {
|
|
|
27703
27703
|
var fd;
|
|
27704
27704
|
var handler = function(err, buffer) {
|
|
27705
27705
|
if (fd) {
|
|
27706
|
-
|
|
27706
|
+
fs2.closeSync(fd);
|
|
27707
27707
|
}
|
|
27708
27708
|
if (err)
|
|
27709
27709
|
return cb(err, null);
|
|
27710
27710
|
cb(null, self2.detect(buffer, opts));
|
|
27711
27711
|
};
|
|
27712
27712
|
if (opts && opts.sampleSize) {
|
|
27713
|
-
fd =
|
|
27714
|
-
|
|
27713
|
+
fd = fs2.openSync(filepath, "r"), sample = Buffer.allocUnsafe(opts.sampleSize);
|
|
27714
|
+
fs2.read(fd, sample, 0, opts.sampleSize, null, function(err) {
|
|
27715
27715
|
handler(err, sample);
|
|
27716
27716
|
});
|
|
27717
27717
|
return;
|
|
27718
27718
|
}
|
|
27719
|
-
|
|
27719
|
+
fs2.readFile(filepath, handler);
|
|
27720
27720
|
};
|
|
27721
27721
|
module.exports.detectFileSync = function(filepath, opts) {
|
|
27722
27722
|
if (opts && opts.sampleSize) {
|
|
27723
|
-
var fd =
|
|
27724
|
-
|
|
27725
|
-
|
|
27723
|
+
var fd = fs2.openSync(filepath, "r"), sample2 = Buffer.allocUnsafe(opts.sampleSize);
|
|
27724
|
+
fs2.readSync(fd, sample2, 0, opts.sampleSize);
|
|
27725
|
+
fs2.closeSync(fd);
|
|
27726
27726
|
return self2.detect(sample2, opts);
|
|
27727
27727
|
}
|
|
27728
|
-
return self2.detect(
|
|
27728
|
+
return self2.detect(fs2.readFileSync(filepath), opts);
|
|
27729
27729
|
};
|
|
27730
27730
|
module.exports.detectAll = function(buffer, opts) {
|
|
27731
27731
|
if (typeof opts !== "object") {
|
|
@@ -31087,7 +31087,7 @@ var require_tmp = __commonJS((exports, module) => {
|
|
|
31087
31087
|
*
|
|
31088
31088
|
* MIT Licensed
|
|
31089
31089
|
*/
|
|
31090
|
-
var
|
|
31090
|
+
var fs2 = __require("fs");
|
|
31091
31091
|
var path = __require("path");
|
|
31092
31092
|
var crypto = __require("crypto");
|
|
31093
31093
|
var osTmpDir = require_os_tmpdir();
|
|
@@ -31151,7 +31151,7 @@ var require_tmp = __commonJS((exports, module) => {
|
|
|
31151
31151
|
return cb(new Error("Invalid template provided"));
|
|
31152
31152
|
(function _getUniqueName() {
|
|
31153
31153
|
const name = _generateTmpName(opts);
|
|
31154
|
-
|
|
31154
|
+
fs2.stat(name, function(err) {
|
|
31155
31155
|
if (!err) {
|
|
31156
31156
|
if (tries-- > 0)
|
|
31157
31157
|
return _getUniqueName();
|
|
@@ -31170,7 +31170,7 @@ var require_tmp = __commonJS((exports, module) => {
|
|
|
31170
31170
|
do {
|
|
31171
31171
|
const name = _generateTmpName(opts);
|
|
31172
31172
|
try {
|
|
31173
|
-
|
|
31173
|
+
fs2.statSync(name);
|
|
31174
31174
|
} catch (e) {
|
|
31175
31175
|
return name;
|
|
31176
31176
|
}
|
|
@@ -31183,14 +31183,14 @@ var require_tmp = __commonJS((exports, module) => {
|
|
|
31183
31183
|
tmpName(opts, function _tmpNameCreated(err, name) {
|
|
31184
31184
|
if (err)
|
|
31185
31185
|
return cb(err);
|
|
31186
|
-
|
|
31186
|
+
fs2.open(name, CREATE_FLAGS, opts.mode || FILE_MODE, function _fileCreated(err2, fd) {
|
|
31187
31187
|
if (err2)
|
|
31188
31188
|
return cb(err2);
|
|
31189
31189
|
if (opts.discardDescriptor) {
|
|
31190
|
-
return
|
|
31190
|
+
return fs2.close(fd, function _discardCallback(err3) {
|
|
31191
31191
|
if (err3) {
|
|
31192
31192
|
try {
|
|
31193
|
-
|
|
31193
|
+
fs2.unlinkSync(name);
|
|
31194
31194
|
} catch (e) {
|
|
31195
31195
|
if (!isENOENT(e)) {
|
|
31196
31196
|
err3 = e;
|
|
@@ -31213,9 +31213,9 @@ var require_tmp = __commonJS((exports, module) => {
|
|
|
31213
31213
|
opts.postfix = opts.postfix || ".tmp";
|
|
31214
31214
|
const discardOrDetachDescriptor = opts.discardDescriptor || opts.detachDescriptor;
|
|
31215
31215
|
const name = tmpNameSync(opts);
|
|
31216
|
-
var fd =
|
|
31216
|
+
var fd = fs2.openSync(name, CREATE_FLAGS, opts.mode || FILE_MODE);
|
|
31217
31217
|
if (opts.discardDescriptor) {
|
|
31218
|
-
|
|
31218
|
+
fs2.closeSync(fd);
|
|
31219
31219
|
fd = undefined;
|
|
31220
31220
|
}
|
|
31221
31221
|
return {
|
|
@@ -31227,9 +31227,9 @@ var require_tmp = __commonJS((exports, module) => {
|
|
|
31227
31227
|
function _rmdirRecursiveSync(root) {
|
|
31228
31228
|
const dirs = [root];
|
|
31229
31229
|
do {
|
|
31230
|
-
var dir2 = dirs.pop(), deferred = false, files =
|
|
31230
|
+
var dir2 = dirs.pop(), deferred = false, files = fs2.readdirSync(dir2);
|
|
31231
31231
|
for (var i = 0, length = files.length;i < length; i++) {
|
|
31232
|
-
var file2 = path.join(dir2, files[i]), stat =
|
|
31232
|
+
var file2 = path.join(dir2, files[i]), stat = fs2.lstatSync(file2);
|
|
31233
31233
|
if (stat.isDirectory()) {
|
|
31234
31234
|
if (!deferred) {
|
|
31235
31235
|
deferred = true;
|
|
@@ -31237,11 +31237,11 @@ var require_tmp = __commonJS((exports, module) => {
|
|
|
31237
31237
|
}
|
|
31238
31238
|
dirs.push(file2);
|
|
31239
31239
|
} else {
|
|
31240
|
-
|
|
31240
|
+
fs2.unlinkSync(file2);
|
|
31241
31241
|
}
|
|
31242
31242
|
}
|
|
31243
31243
|
if (!deferred) {
|
|
31244
|
-
|
|
31244
|
+
fs2.rmdirSync(dir2);
|
|
31245
31245
|
}
|
|
31246
31246
|
} while (dirs.length !== 0);
|
|
31247
31247
|
}
|
|
@@ -31250,7 +31250,7 @@ var require_tmp = __commonJS((exports, module) => {
|
|
|
31250
31250
|
tmpName(opts, function _tmpNameCreated(err, name) {
|
|
31251
31251
|
if (err)
|
|
31252
31252
|
return cb(err);
|
|
31253
|
-
|
|
31253
|
+
fs2.mkdir(name, opts.mode || DIR_MODE, function _dirCreated(err2) {
|
|
31254
31254
|
if (err2)
|
|
31255
31255
|
return cb(err2);
|
|
31256
31256
|
cb(null, name, _prepareTmpDirRemoveCallback(name, opts));
|
|
@@ -31260,7 +31260,7 @@ var require_tmp = __commonJS((exports, module) => {
|
|
|
31260
31260
|
function dirSync(options) {
|
|
31261
31261
|
var args = _parseArguments(options), opts = args[0];
|
|
31262
31262
|
const name = tmpNameSync(opts);
|
|
31263
|
-
|
|
31263
|
+
fs2.mkdirSync(name, opts.mode || DIR_MODE);
|
|
31264
31264
|
return {
|
|
31265
31265
|
name,
|
|
31266
31266
|
removeCallback: _prepareTmpDirRemoveCallback(name, opts)
|
|
@@ -31270,7 +31270,7 @@ var require_tmp = __commonJS((exports, module) => {
|
|
|
31270
31270
|
const removeCallback = _prepareRemoveCallback(function _removeCallback(fdPath) {
|
|
31271
31271
|
try {
|
|
31272
31272
|
if (0 <= fdPath[0]) {
|
|
31273
|
-
|
|
31273
|
+
fs2.closeSync(fdPath[0]);
|
|
31274
31274
|
}
|
|
31275
31275
|
} catch (e) {
|
|
31276
31276
|
if (!isEBADF(e) && !isENOENT(e)) {
|
|
@@ -31278,7 +31278,7 @@ var require_tmp = __commonJS((exports, module) => {
|
|
|
31278
31278
|
}
|
|
31279
31279
|
}
|
|
31280
31280
|
try {
|
|
31281
|
-
|
|
31281
|
+
fs2.unlinkSync(fdPath[1]);
|
|
31282
31282
|
} catch (e) {
|
|
31283
31283
|
if (!isENOENT(e)) {
|
|
31284
31284
|
throw e;
|
|
@@ -31291,7 +31291,7 @@ var require_tmp = __commonJS((exports, module) => {
|
|
|
31291
31291
|
return removeCallback;
|
|
31292
31292
|
}
|
|
31293
31293
|
function _prepareTmpDirRemoveCallback(name, opts) {
|
|
31294
|
-
const removeFunction = opts.unsafeCleanup ? _rmdirRecursiveSync :
|
|
31294
|
+
const removeFunction = opts.unsafeCleanup ? _rmdirRecursiveSync : fs2.rmdirSync.bind(fs2);
|
|
31295
31295
|
const removeCallback = _prepareRemoveCallback(removeFunction, name);
|
|
31296
31296
|
if (!opts.keep) {
|
|
31297
31297
|
_removeObjects.unshift(removeCallback);
|
|
@@ -32550,13 +32550,13 @@ var require_src = __commonJS((exports, module) => {
|
|
|
32550
32550
|
|
|
32551
32551
|
// node_modules/tabtab/lib/utils/tabtabDebug.js
|
|
32552
32552
|
var require_tabtabDebug = __commonJS((exports, module) => {
|
|
32553
|
-
var
|
|
32553
|
+
var fs2 = __require("fs");
|
|
32554
32554
|
var util = __require("util");
|
|
32555
32555
|
var tabtabDebug = (name) => {
|
|
32556
32556
|
let debug = require_src()(name);
|
|
32557
32557
|
if (process.env.TABTAB_DEBUG) {
|
|
32558
32558
|
const file = process.env.TABTAB_DEBUG;
|
|
32559
|
-
const stream =
|
|
32559
|
+
const stream = fs2.createWriteStream(file, {
|
|
32560
32560
|
flags: "a+"
|
|
32561
32561
|
});
|
|
32562
32562
|
const log = (...args) => {
|
|
@@ -32700,7 +32700,7 @@ var require_promisify = __commonJS((exports) => {
|
|
|
32700
32700
|
// node_modules/mkdirp/index.js
|
|
32701
32701
|
var require_mkdirp = __commonJS((exports, module) => {
|
|
32702
32702
|
var path = __require("path");
|
|
32703
|
-
var
|
|
32703
|
+
var fs2 = __require("fs");
|
|
32704
32704
|
var _0777 = parseInt("0777", 8);
|
|
32705
32705
|
module.exports = mkdirP.mkdirp = mkdirP.mkdirP = mkdirP;
|
|
32706
32706
|
function mkdirP(p, opts, f, made) {
|
|
@@ -32711,7 +32711,7 @@ var require_mkdirp = __commonJS((exports, module) => {
|
|
|
32711
32711
|
opts = { mode: opts };
|
|
32712
32712
|
}
|
|
32713
32713
|
var mode = opts.mode;
|
|
32714
|
-
var xfs = opts.fs ||
|
|
32714
|
+
var xfs = opts.fs || fs2;
|
|
32715
32715
|
if (mode === undefined) {
|
|
32716
32716
|
mode = _0777;
|
|
32717
32717
|
}
|
|
@@ -32751,7 +32751,7 @@ var require_mkdirp = __commonJS((exports, module) => {
|
|
|
32751
32751
|
opts = { mode: opts };
|
|
32752
32752
|
}
|
|
32753
32753
|
var mode = opts.mode;
|
|
32754
|
-
var xfs = opts.fs ||
|
|
32754
|
+
var xfs = opts.fs || fs2;
|
|
32755
32755
|
if (mode === undefined) {
|
|
32756
32756
|
mode = _0777;
|
|
32757
32757
|
}
|
|
@@ -32791,10 +32791,10 @@ var require_systemShell = __commonJS((exports, module) => {
|
|
|
32791
32791
|
|
|
32792
32792
|
// node_modules/tabtab/lib/utils/exists.js
|
|
32793
32793
|
var require_exists = __commonJS((exports, module) => {
|
|
32794
|
-
var
|
|
32794
|
+
var fs2 = __require("fs");
|
|
32795
32795
|
var untildify = require_untildify();
|
|
32796
32796
|
var { promisify: promisify2 } = require_promisify();
|
|
32797
|
-
var readFile = promisify2(
|
|
32797
|
+
var readFile = promisify2(fs2.readFile);
|
|
32798
32798
|
module.exports = async (file) => {
|
|
32799
32799
|
let fileExists;
|
|
32800
32800
|
try {
|
|
@@ -32838,16 +32838,16 @@ var require_constants = __commonJS((exports, module) => {
|
|
|
32838
32838
|
// node_modules/tabtab/lib/installer.js
|
|
32839
32839
|
var require_installer = __commonJS((exports, module) => {
|
|
32840
32840
|
var __dirname = "/home/runner/work/bitbucket-cli/bitbucket-cli/node_modules/tabtab/lib";
|
|
32841
|
-
var
|
|
32841
|
+
var fs2 = __require("fs");
|
|
32842
32842
|
var path = __require("path");
|
|
32843
32843
|
var untildify = require_untildify();
|
|
32844
32844
|
var { promisify: promisify2 } = require_promisify();
|
|
32845
32845
|
var mkdirp = promisify2(require_mkdirp());
|
|
32846
32846
|
var { tabtabDebug, systemShell, exists } = require_utils2();
|
|
32847
32847
|
var debug = tabtabDebug("tabtab:installer");
|
|
32848
|
-
var readFile = promisify2(
|
|
32849
|
-
var writeFile = promisify2(
|
|
32850
|
-
var unlink = promisify2(
|
|
32848
|
+
var readFile = promisify2(fs2.readFile);
|
|
32849
|
+
var writeFile = promisify2(fs2.writeFile);
|
|
32850
|
+
var unlink = promisify2(fs2.unlink);
|
|
32851
32851
|
var {
|
|
32852
32852
|
BASH_LOCATION,
|
|
32853
32853
|
FISH_LOCATION,
|
|
@@ -32907,7 +32907,7 @@ var require_installer = __commonJS((exports, module) => {
|
|
|
32907
32907
|
const filepath = untildify(filename);
|
|
32908
32908
|
debug("Creating directory for %s file", filepath);
|
|
32909
32909
|
mkdirp(path.dirname(filepath)).then(() => {
|
|
32910
|
-
const stream =
|
|
32910
|
+
const stream = fs2.createWriteStream(filepath, { flags: "a" });
|
|
32911
32911
|
stream.on("error", reject);
|
|
32912
32912
|
stream.on("finish", () => resolve());
|
|
32913
32913
|
debug("Writing to shell configuration file (%s)", filename);
|
|
@@ -33258,11 +33258,16 @@ var ServiceTokens = {
|
|
|
33258
33258
|
CreatePRCommand: "CreatePRCommand",
|
|
33259
33259
|
ListPRsCommand: "ListPRsCommand",
|
|
33260
33260
|
ViewPRCommand: "ViewPRCommand",
|
|
33261
|
+
EditPRCommand: "EditPRCommand",
|
|
33261
33262
|
MergePRCommand: "MergePRCommand",
|
|
33262
33263
|
ApprovePRCommand: "ApprovePRCommand",
|
|
33263
33264
|
DeclinePRCommand: "DeclinePRCommand",
|
|
33264
33265
|
CheckoutPRCommand: "CheckoutPRCommand",
|
|
33265
33266
|
DiffPRCommand: "DiffPRCommand",
|
|
33267
|
+
CommentPRCommand: "CommentPRCommand",
|
|
33268
|
+
ListCommentsPRCommand: "ListCommentsPRCommand",
|
|
33269
|
+
EditCommentPRCommand: "EditCommentPRCommand",
|
|
33270
|
+
DeleteCommentPRCommand: "DeleteCommentPRCommand",
|
|
33266
33271
|
GetConfigCommand: "GetConfigCommand",
|
|
33267
33272
|
SetConfigCommand: "SetConfigCommand",
|
|
33268
33273
|
ListConfigCommand: "ListConfigCommand",
|
|
@@ -34278,6 +34283,11 @@ class HttpClient {
|
|
|
34278
34283
|
body: body ? JSON.stringify(body) : undefined,
|
|
34279
34284
|
signal: controller.signal
|
|
34280
34285
|
});
|
|
34286
|
+
if (process.env.DEBUG === "true") {
|
|
34287
|
+
console.debug(`[HTTP] ${method} ${url} - ${response.status}`);
|
|
34288
|
+
console.debug(`[HTTP] Response Headers:`, Object.fromEntries(response.headers.entries()));
|
|
34289
|
+
console.debug(`[HTTP] Response Body:`, await response.clone().text());
|
|
34290
|
+
}
|
|
34281
34291
|
clearTimeout(timeoutId);
|
|
34282
34292
|
return acceptText ? this.handleTextResponse(response) : this.handleResponse(response);
|
|
34283
34293
|
} catch (error) {
|
|
@@ -34298,11 +34308,12 @@ class HttpClient {
|
|
|
34298
34308
|
}
|
|
34299
34309
|
async handleResponse(response) {
|
|
34300
34310
|
if (!response.ok) {
|
|
34311
|
+
const textBody = await response.text();
|
|
34301
34312
|
let errorBody;
|
|
34302
34313
|
try {
|
|
34303
|
-
errorBody =
|
|
34314
|
+
errorBody = JSON.parse(textBody);
|
|
34304
34315
|
} catch {
|
|
34305
|
-
errorBody =
|
|
34316
|
+
errorBody = textBody;
|
|
34306
34317
|
}
|
|
34307
34318
|
const message = this.extractErrorMessage(errorBody, response.statusText);
|
|
34308
34319
|
return Result.err(new APIError(message, response.status, errorBody, {
|
|
@@ -34325,11 +34336,12 @@ class HttpClient {
|
|
|
34325
34336
|
}
|
|
34326
34337
|
async handleTextResponse(response) {
|
|
34327
34338
|
if (!response.ok) {
|
|
34339
|
+
const textBody = await response.text();
|
|
34328
34340
|
let errorBody;
|
|
34329
34341
|
try {
|
|
34330
|
-
errorBody =
|
|
34342
|
+
errorBody = JSON.parse(textBody);
|
|
34331
34343
|
} catch {
|
|
34332
|
-
errorBody =
|
|
34344
|
+
errorBody = textBody;
|
|
34333
34345
|
}
|
|
34334
34346
|
const message = this.extractErrorMessage(errorBody, response.statusText);
|
|
34335
34347
|
return Result.err(new APIError(message, response.status, errorBody, {
|
|
@@ -34391,6 +34403,16 @@ class UserRepository {
|
|
|
34391
34403
|
return this.httpClient.get("/user");
|
|
34392
34404
|
}
|
|
34393
34405
|
}
|
|
34406
|
+
// src/constants.ts
|
|
34407
|
+
var API_PAGELEN_LIMITS = {
|
|
34408
|
+
PULL_REQUESTS: 50,
|
|
34409
|
+
REPOSITORIES: 100
|
|
34410
|
+
};
|
|
34411
|
+
var DEFAULT_PAGELEN = {
|
|
34412
|
+
PULL_REQUESTS: 25,
|
|
34413
|
+
REPOSITORIES: 25
|
|
34414
|
+
};
|
|
34415
|
+
|
|
34394
34416
|
// src/repositories/repo.repository.ts
|
|
34395
34417
|
class RepoRepository {
|
|
34396
34418
|
httpClient;
|
|
@@ -34401,7 +34423,8 @@ class RepoRepository {
|
|
|
34401
34423
|
return this.httpClient.get(`/repositories/${encodeURIComponent(workspace)}/${encodeURIComponent(repoSlug)}`);
|
|
34402
34424
|
}
|
|
34403
34425
|
async list(workspace, limit = 25) {
|
|
34404
|
-
|
|
34426
|
+
const safeLimit = Math.min(limit, API_PAGELEN_LIMITS.REPOSITORIES);
|
|
34427
|
+
return this.httpClient.get(`/repositories/${encodeURIComponent(workspace)}?pagelen=${safeLimit}`);
|
|
34405
34428
|
}
|
|
34406
34429
|
async create(workspace, request) {
|
|
34407
34430
|
const repoSlug = request.name.toLowerCase().replace(/\s+/g, "-");
|
|
@@ -34425,19 +34448,23 @@ class PullRequestRepository {
|
|
|
34425
34448
|
return this.httpClient.get(this.buildPath(workspace, repoSlug, `/${id}`));
|
|
34426
34449
|
}
|
|
34427
34450
|
async list(workspace, repoSlug, state = "OPEN", limit = 25) {
|
|
34428
|
-
|
|
34451
|
+
const safeLimit = Math.min(limit, API_PAGELEN_LIMITS.PULL_REQUESTS);
|
|
34452
|
+
return this.httpClient.get(this.buildPath(workspace, repoSlug, `?state=${state}&pagelen=${safeLimit}`));
|
|
34429
34453
|
}
|
|
34430
34454
|
async create(workspace, repoSlug, request) {
|
|
34431
34455
|
return this.httpClient.post(this.buildPath(workspace, repoSlug), request);
|
|
34432
34456
|
}
|
|
34457
|
+
async update(workspace, repoSlug, id, request) {
|
|
34458
|
+
return this.httpClient.put(this.buildPath(workspace, repoSlug, `/${id}`), request);
|
|
34459
|
+
}
|
|
34433
34460
|
async merge(workspace, repoSlug, id, request) {
|
|
34434
34461
|
return this.httpClient.post(this.buildPath(workspace, repoSlug, `/${id}/merge`), request);
|
|
34435
34462
|
}
|
|
34436
34463
|
async approve(workspace, repoSlug, id) {
|
|
34437
|
-
return this.httpClient.post(this.buildPath(workspace, repoSlug, `/${id}/approve`));
|
|
34464
|
+
return this.httpClient.post(this.buildPath(workspace, repoSlug, `/${id}/approve`), {});
|
|
34438
34465
|
}
|
|
34439
34466
|
async decline(workspace, repoSlug, id) {
|
|
34440
|
-
return this.httpClient.post(this.buildPath(workspace, repoSlug, `/${id}/decline`));
|
|
34467
|
+
return this.httpClient.post(this.buildPath(workspace, repoSlug, `/${id}/decline`), {});
|
|
34441
34468
|
}
|
|
34442
34469
|
async getDiff(workspace, repoSlug, id) {
|
|
34443
34470
|
return this.httpClient.getText(this.buildPath(workspace, repoSlug, `/${id}/diff`));
|
|
@@ -34445,6 +34472,22 @@ class PullRequestRepository {
|
|
|
34445
34472
|
async getDiffstat(workspace, repoSlug, id) {
|
|
34446
34473
|
return this.httpClient.get(this.buildPath(workspace, repoSlug, `/${id}/diffstat`));
|
|
34447
34474
|
}
|
|
34475
|
+
async listComments(workspace, repoSlug, prId, limit = 25) {
|
|
34476
|
+
const safeLimit = Math.min(limit, API_PAGELEN_LIMITS.PULL_REQUESTS);
|
|
34477
|
+
return this.httpClient.get(`/repositories/${encodeURIComponent(workspace)}/${encodeURIComponent(repoSlug)}/pullrequests/${prId}/comments?pagelen=${safeLimit}`);
|
|
34478
|
+
}
|
|
34479
|
+
async getComment(workspace, repoSlug, prId, commentId) {
|
|
34480
|
+
return this.httpClient.get(`/repositories/${encodeURIComponent(workspace)}/${encodeURIComponent(repoSlug)}/pullrequests/${prId}/comments/${commentId}`);
|
|
34481
|
+
}
|
|
34482
|
+
async createComment(workspace, repoSlug, prId, content) {
|
|
34483
|
+
return this.httpClient.post(`/repositories/${encodeURIComponent(workspace)}/${encodeURIComponent(repoSlug)}/pullrequests/${prId}/comments`, { content: { raw: content } });
|
|
34484
|
+
}
|
|
34485
|
+
async updateComment(workspace, repoSlug, prId, commentId, content) {
|
|
34486
|
+
return this.httpClient.put(`/repositories/${encodeURIComponent(workspace)}/${encodeURIComponent(repoSlug)}/pullrequests/${prId}/comments/${commentId}`, { content: { raw: content } });
|
|
34487
|
+
}
|
|
34488
|
+
async deleteComment(workspace, repoSlug, prId, commentId) {
|
|
34489
|
+
return this.httpClient.delete(`/repositories/${encodeURIComponent(workspace)}/${encodeURIComponent(repoSlug)}/pullrequests/${prId}/comments/${commentId}`);
|
|
34490
|
+
}
|
|
34448
34491
|
}
|
|
34449
34492
|
// src/core/base-command.ts
|
|
34450
34493
|
class BaseCommand {
|
|
@@ -35069,6 +35112,98 @@ class ViewPRCommand extends BaseCommand {
|
|
|
35069
35112
|
}
|
|
35070
35113
|
}
|
|
35071
35114
|
|
|
35115
|
+
// src/commands/pr/edit.command.ts
|
|
35116
|
+
import * as fs from "fs";
|
|
35117
|
+
class EditPRCommand extends BaseCommand {
|
|
35118
|
+
prRepository;
|
|
35119
|
+
contextService;
|
|
35120
|
+
gitService;
|
|
35121
|
+
name = "edit";
|
|
35122
|
+
description = "Edit a pull request";
|
|
35123
|
+
constructor(prRepository, contextService, gitService, output) {
|
|
35124
|
+
super(output);
|
|
35125
|
+
this.prRepository = prRepository;
|
|
35126
|
+
this.contextService = contextService;
|
|
35127
|
+
this.gitService = gitService;
|
|
35128
|
+
}
|
|
35129
|
+
async execute(options, context) {
|
|
35130
|
+
const repoContextResult = await this.contextService.requireRepoContext({
|
|
35131
|
+
...context.globalOptions,
|
|
35132
|
+
...options
|
|
35133
|
+
});
|
|
35134
|
+
if (!repoContextResult.success) {
|
|
35135
|
+
this.handleResult(repoContextResult, context);
|
|
35136
|
+
return repoContextResult;
|
|
35137
|
+
}
|
|
35138
|
+
const { workspace, repoSlug } = repoContextResult.value;
|
|
35139
|
+
let prId;
|
|
35140
|
+
if (options.id) {
|
|
35141
|
+
prId = parseInt(options.id, 10);
|
|
35142
|
+
} else {
|
|
35143
|
+
const branchResult = await this.gitService.getCurrentBranch();
|
|
35144
|
+
if (!branchResult.success) {
|
|
35145
|
+
this.handleResult(branchResult, context);
|
|
35146
|
+
return branchResult;
|
|
35147
|
+
}
|
|
35148
|
+
const currentBranch = branchResult.value;
|
|
35149
|
+
const prsResult = await this.prRepository.list(workspace, repoSlug, "OPEN", DEFAULT_PAGELEN.PULL_REQUESTS);
|
|
35150
|
+
if (!prsResult.success) {
|
|
35151
|
+
this.handleResult(prsResult, context);
|
|
35152
|
+
return prsResult;
|
|
35153
|
+
}
|
|
35154
|
+
const matchingPR = prsResult.value.values.find((pr) => pr.source.branch.name === currentBranch);
|
|
35155
|
+
if (!matchingPR) {
|
|
35156
|
+
const error = new ValidationError("id", `No open pull request found for current branch '${currentBranch}'. Specify a PR ID explicitly.`);
|
|
35157
|
+
this.output.error(error.message);
|
|
35158
|
+
if (true) {
|
|
35159
|
+
process.exitCode = 1;
|
|
35160
|
+
}
|
|
35161
|
+
return Result.err(error);
|
|
35162
|
+
}
|
|
35163
|
+
prId = matchingPR.id;
|
|
35164
|
+
}
|
|
35165
|
+
let body = options.body;
|
|
35166
|
+
if (options.bodyFile) {
|
|
35167
|
+
try {
|
|
35168
|
+
body = fs.readFileSync(options.bodyFile, "utf-8");
|
|
35169
|
+
} catch (err) {
|
|
35170
|
+
const error = new ValidationError("bodyFile", `Failed to read file '${options.bodyFile}': ${err instanceof Error ? err.message : "Unknown error"}`);
|
|
35171
|
+
this.output.error(error.message);
|
|
35172
|
+
if (true) {
|
|
35173
|
+
process.exitCode = 1;
|
|
35174
|
+
}
|
|
35175
|
+
return Result.err(error);
|
|
35176
|
+
}
|
|
35177
|
+
}
|
|
35178
|
+
if (!options.title && !body) {
|
|
35179
|
+
const error = new ValidationError("title", "At least one of --title or --body (or --body-file) is required.");
|
|
35180
|
+
this.output.error(error.message);
|
|
35181
|
+
if (true) {
|
|
35182
|
+
process.exitCode = 1;
|
|
35183
|
+
}
|
|
35184
|
+
return Result.err(error);
|
|
35185
|
+
}
|
|
35186
|
+
const request = {};
|
|
35187
|
+
if (options.title) {
|
|
35188
|
+
request.title = options.title;
|
|
35189
|
+
}
|
|
35190
|
+
if (body) {
|
|
35191
|
+
request.description = body;
|
|
35192
|
+
}
|
|
35193
|
+
const result = await this.prRepository.update(workspace, repoSlug, prId, request);
|
|
35194
|
+
this.handleResult(result, context, (pr) => {
|
|
35195
|
+
this.output.success(`Updated pull request #${pr.id}`);
|
|
35196
|
+
this.output.text(` ${source_default.dim("Title:")} ${pr.title}`);
|
|
35197
|
+
if (pr.description) {
|
|
35198
|
+
const truncatedDesc = pr.description.length > 100 ? pr.description.substring(0, 100) + "..." : pr.description;
|
|
35199
|
+
this.output.text(` ${source_default.dim("Description:")} ${truncatedDesc}`);
|
|
35200
|
+
}
|
|
35201
|
+
this.output.text(` ${source_default.dim("URL:")} ${pr.links.html.href}`);
|
|
35202
|
+
});
|
|
35203
|
+
return result;
|
|
35204
|
+
}
|
|
35205
|
+
}
|
|
35206
|
+
|
|
35072
35207
|
// src/commands/pr/merge.command.ts
|
|
35073
35208
|
class MergePRCommand extends BaseCommand {
|
|
35074
35209
|
prRepository;
|
|
@@ -35279,7 +35414,7 @@ class DiffPRCommand extends BaseCommand {
|
|
|
35279
35414
|
return Result.err(error);
|
|
35280
35415
|
}
|
|
35281
35416
|
const currentBranch = currentBranchResult.value;
|
|
35282
|
-
const prsResult = await this.prRepository.list(workspace, repoSlug, "OPEN",
|
|
35417
|
+
const prsResult = await this.prRepository.list(workspace, repoSlug, "OPEN", DEFAULT_PAGELEN.PULL_REQUESTS);
|
|
35283
35418
|
if (!prsResult.success) {
|
|
35284
35419
|
this.handleResult(prsResult, context);
|
|
35285
35420
|
return prsResult;
|
|
@@ -35445,6 +35580,139 @@ class DiffPRCommand extends BaseCommand {
|
|
|
35445
35580
|
}
|
|
35446
35581
|
}
|
|
35447
35582
|
|
|
35583
|
+
// src/commands/pr/comment.command.ts
|
|
35584
|
+
class CommentPRCommand extends BaseCommand {
|
|
35585
|
+
prRepository;
|
|
35586
|
+
contextService;
|
|
35587
|
+
name = "comment";
|
|
35588
|
+
description = "Add a comment to a pull request";
|
|
35589
|
+
constructor(prRepository, contextService, output) {
|
|
35590
|
+
super(output);
|
|
35591
|
+
this.prRepository = prRepository;
|
|
35592
|
+
this.contextService = contextService;
|
|
35593
|
+
}
|
|
35594
|
+
async execute(options, context) {
|
|
35595
|
+
const repoContextResult = await this.contextService.requireRepoContext({
|
|
35596
|
+
...context.globalOptions,
|
|
35597
|
+
...options
|
|
35598
|
+
});
|
|
35599
|
+
if (!repoContextResult.success) {
|
|
35600
|
+
this.handleResult(repoContextResult, context);
|
|
35601
|
+
return repoContextResult;
|
|
35602
|
+
}
|
|
35603
|
+
const { workspace, repoSlug } = repoContextResult.value;
|
|
35604
|
+
const prId = parseInt(options.id, 10);
|
|
35605
|
+
const result = await this.prRepository.createComment(workspace, repoSlug, prId, options.message);
|
|
35606
|
+
this.handleResult(result, context, () => {
|
|
35607
|
+
this.output.success(`Added comment to pull request #${prId}`);
|
|
35608
|
+
});
|
|
35609
|
+
return result;
|
|
35610
|
+
}
|
|
35611
|
+
}
|
|
35612
|
+
|
|
35613
|
+
// src/commands/pr/comments.list.command.ts
|
|
35614
|
+
class ListCommentsPRCommand extends BaseCommand {
|
|
35615
|
+
prRepository;
|
|
35616
|
+
contextService;
|
|
35617
|
+
name = "comments";
|
|
35618
|
+
description = "List comments on a pull request";
|
|
35619
|
+
constructor(prRepository, contextService, output) {
|
|
35620
|
+
super(output);
|
|
35621
|
+
this.prRepository = prRepository;
|
|
35622
|
+
this.contextService = contextService;
|
|
35623
|
+
}
|
|
35624
|
+
async execute(options, context) {
|
|
35625
|
+
const repoContextResult = await this.contextService.requireRepoContext({
|
|
35626
|
+
...context.globalOptions,
|
|
35627
|
+
...options
|
|
35628
|
+
});
|
|
35629
|
+
if (!repoContextResult.success) {
|
|
35630
|
+
this.handleResult(repoContextResult, context);
|
|
35631
|
+
return repoContextResult;
|
|
35632
|
+
}
|
|
35633
|
+
const { workspace, repoSlug } = repoContextResult.value;
|
|
35634
|
+
const prId = parseInt(options.id, 10);
|
|
35635
|
+
const limit = options.limit ? parseInt(options.limit, 10) : 25;
|
|
35636
|
+
const result = await this.prRepository.listComments(workspace, repoSlug, prId, limit);
|
|
35637
|
+
this.handleResult(result, context, (data) => {
|
|
35638
|
+
if (data.values.length === 0) {
|
|
35639
|
+
this.output.info("No comments found on this pull request");
|
|
35640
|
+
return;
|
|
35641
|
+
}
|
|
35642
|
+
const rows = data.values.map((comment) => [
|
|
35643
|
+
comment.id.toString(),
|
|
35644
|
+
comment.author?.username ?? comment.author?.display_name ?? "Unknown",
|
|
35645
|
+
comment.content.raw.slice(0, 60) + (comment.content.raw.length > 60 ? "..." : ""),
|
|
35646
|
+
this.output.formatDate(comment.created_on)
|
|
35647
|
+
]);
|
|
35648
|
+
this.output.table(["ID", "Author", "Content", "Date"], rows);
|
|
35649
|
+
});
|
|
35650
|
+
return result;
|
|
35651
|
+
}
|
|
35652
|
+
}
|
|
35653
|
+
|
|
35654
|
+
// src/commands/pr/comments.edit.command.ts
|
|
35655
|
+
class EditCommentPRCommand extends BaseCommand {
|
|
35656
|
+
prRepository;
|
|
35657
|
+
contextService;
|
|
35658
|
+
name = "edit";
|
|
35659
|
+
description = "Edit a comment on a pull request";
|
|
35660
|
+
constructor(prRepository, contextService, output) {
|
|
35661
|
+
super(output);
|
|
35662
|
+
this.prRepository = prRepository;
|
|
35663
|
+
this.contextService = contextService;
|
|
35664
|
+
}
|
|
35665
|
+
async execute(options, context) {
|
|
35666
|
+
const repoContextResult = await this.contextService.requireRepoContext({
|
|
35667
|
+
...context.globalOptions,
|
|
35668
|
+
...options
|
|
35669
|
+
});
|
|
35670
|
+
if (!repoContextResult.success) {
|
|
35671
|
+
this.handleResult(repoContextResult, context);
|
|
35672
|
+
return repoContextResult;
|
|
35673
|
+
}
|
|
35674
|
+
const { workspace, repoSlug } = repoContextResult.value;
|
|
35675
|
+
const prId = parseInt(options.prId, 10);
|
|
35676
|
+
const commentId = parseInt(options.commentId, 10);
|
|
35677
|
+
const result = await this.prRepository.updateComment(workspace, repoSlug, prId, commentId, options.message);
|
|
35678
|
+
this.handleResult(result, context, () => {
|
|
35679
|
+
this.output.success(`Updated comment #${commentId}`);
|
|
35680
|
+
});
|
|
35681
|
+
return result;
|
|
35682
|
+
}
|
|
35683
|
+
}
|
|
35684
|
+
|
|
35685
|
+
// src/commands/pr/comments.delete.command.ts
|
|
35686
|
+
class DeleteCommentPRCommand extends BaseCommand {
|
|
35687
|
+
prRepository;
|
|
35688
|
+
contextService;
|
|
35689
|
+
name = "delete";
|
|
35690
|
+
description = "Delete a comment on a pull request";
|
|
35691
|
+
constructor(prRepository, contextService, output) {
|
|
35692
|
+
super(output);
|
|
35693
|
+
this.prRepository = prRepository;
|
|
35694
|
+
this.contextService = contextService;
|
|
35695
|
+
}
|
|
35696
|
+
async execute(options, context) {
|
|
35697
|
+
const repoContextResult = await this.contextService.requireRepoContext({
|
|
35698
|
+
...context.globalOptions,
|
|
35699
|
+
...options
|
|
35700
|
+
});
|
|
35701
|
+
if (!repoContextResult.success) {
|
|
35702
|
+
this.handleResult(repoContextResult, context);
|
|
35703
|
+
return repoContextResult;
|
|
35704
|
+
}
|
|
35705
|
+
const { workspace, repoSlug } = repoContextResult.value;
|
|
35706
|
+
const prId = parseInt(options.prId, 10);
|
|
35707
|
+
const commentId = parseInt(options.commentId, 10);
|
|
35708
|
+
const result = await this.prRepository.deleteComment(workspace, repoSlug, prId, commentId);
|
|
35709
|
+
this.handleResult(result, context, () => {
|
|
35710
|
+
this.output.success(`Deleted comment #${commentId} from PR #${prId}`);
|
|
35711
|
+
});
|
|
35712
|
+
return result;
|
|
35713
|
+
}
|
|
35714
|
+
}
|
|
35715
|
+
|
|
35448
35716
|
// src/types/config.ts
|
|
35449
35717
|
var SETTABLE_CONFIG_KEYS = ["defaultWorkspace"];
|
|
35450
35718
|
var READABLE_CONFIG_KEYS = ["username", "defaultWorkspace"];
|
|
@@ -35722,6 +35990,13 @@ function bootstrap() {
|
|
|
35722
35990
|
const output = container.resolve(ServiceTokens.OutputService);
|
|
35723
35991
|
return new ViewPRCommand(prRepo, contextService, output);
|
|
35724
35992
|
});
|
|
35993
|
+
container.register(ServiceTokens.EditPRCommand, () => {
|
|
35994
|
+
const prRepo = container.resolve(ServiceTokens.PullRequestRepository);
|
|
35995
|
+
const contextService = container.resolve(ServiceTokens.ContextService);
|
|
35996
|
+
const gitService = container.resolve(ServiceTokens.GitService);
|
|
35997
|
+
const output = container.resolve(ServiceTokens.OutputService);
|
|
35998
|
+
return new EditPRCommand(prRepo, contextService, gitService, output);
|
|
35999
|
+
});
|
|
35725
36000
|
container.register(ServiceTokens.MergePRCommand, () => {
|
|
35726
36001
|
const prRepo = container.resolve(ServiceTokens.PullRequestRepository);
|
|
35727
36002
|
const contextService = container.resolve(ServiceTokens.ContextService);
|
|
@@ -35754,6 +36029,30 @@ function bootstrap() {
|
|
|
35754
36029
|
const output = container.resolve(ServiceTokens.OutputService);
|
|
35755
36030
|
return new DiffPRCommand(prRepo, contextService, gitService, output);
|
|
35756
36031
|
});
|
|
36032
|
+
container.register(ServiceTokens.CommentPRCommand, () => {
|
|
36033
|
+
const prRepo = container.resolve(ServiceTokens.PullRequestRepository);
|
|
36034
|
+
const contextService = container.resolve(ServiceTokens.ContextService);
|
|
36035
|
+
const output = container.resolve(ServiceTokens.OutputService);
|
|
36036
|
+
return new CommentPRCommand(prRepo, contextService, output);
|
|
36037
|
+
});
|
|
36038
|
+
container.register(ServiceTokens.ListCommentsPRCommand, () => {
|
|
36039
|
+
const prRepo = container.resolve(ServiceTokens.PullRequestRepository);
|
|
36040
|
+
const contextService = container.resolve(ServiceTokens.ContextService);
|
|
36041
|
+
const output = container.resolve(ServiceTokens.OutputService);
|
|
36042
|
+
return new ListCommentsPRCommand(prRepo, contextService, output);
|
|
36043
|
+
});
|
|
36044
|
+
container.register(ServiceTokens.EditCommentPRCommand, () => {
|
|
36045
|
+
const prRepo = container.resolve(ServiceTokens.PullRequestRepository);
|
|
36046
|
+
const contextService = container.resolve(ServiceTokens.ContextService);
|
|
36047
|
+
const output = container.resolve(ServiceTokens.OutputService);
|
|
36048
|
+
return new EditCommentPRCommand(prRepo, contextService, output);
|
|
36049
|
+
});
|
|
36050
|
+
container.register(ServiceTokens.DeleteCommentPRCommand, () => {
|
|
36051
|
+
const prRepo = container.resolve(ServiceTokens.PullRequestRepository);
|
|
36052
|
+
const contextService = container.resolve(ServiceTokens.ContextService);
|
|
36053
|
+
const output = container.resolve(ServiceTokens.OutputService);
|
|
36054
|
+
return new DeleteCommentPRCommand(prRepo, contextService, output);
|
|
36055
|
+
});
|
|
35757
36056
|
container.register(ServiceTokens.GetConfigCommand, () => {
|
|
35758
36057
|
const configService = container.resolve(ServiceTokens.ConfigService);
|
|
35759
36058
|
const output = container.resolve(ServiceTokens.OutputService);
|
|
@@ -35804,7 +36103,7 @@ if (process.argv.includes("--get-yargs-completions") || process.env.COMP_LINE) {
|
|
|
35804
36103
|
} else if (env2.prev === "repo") {
|
|
35805
36104
|
completions.push("clone", "create", "list", "view", "delete");
|
|
35806
36105
|
} else if (env2.prev === "pr") {
|
|
35807
|
-
completions.push("create", "list", "view", "merge", "approve", "decline", "checkout", "diff");
|
|
36106
|
+
completions.push("create", "list", "view", "edit", "merge", "approve", "decline", "checkout", "diff", "comments");
|
|
35808
36107
|
} else if (env2.prev === "config") {
|
|
35809
36108
|
completions.push("get", "set", "list");
|
|
35810
36109
|
} else if (env2.prev === "completion") {
|
|
@@ -35930,6 +36229,14 @@ prCmd.command("view <id>").description("View pull request details").action(async
|
|
|
35930
36229
|
process.exit(1);
|
|
35931
36230
|
}
|
|
35932
36231
|
});
|
|
36232
|
+
prCmd.command("edit [id]").description("Edit a pull request").option("-t, --title <title>", "New pull request title").option("-b, --body <body>", "New pull request description").option("-F, --body-file <file>", "Read description from file").action(async (id, options) => {
|
|
36233
|
+
const cmd = container.resolve(ServiceTokens.EditPRCommand);
|
|
36234
|
+
const context = createContext(cli);
|
|
36235
|
+
const result = await cmd.execute(withGlobalOptions({ id, ...options }, context), context);
|
|
36236
|
+
if (!result.success) {
|
|
36237
|
+
process.exit(1);
|
|
36238
|
+
}
|
|
36239
|
+
});
|
|
35933
36240
|
prCmd.command("merge <id>").description("Merge a pull request").option("-m, --message <message>", "Merge commit message").option("--close-source-branch", "Delete the source branch after merging").option("--strategy <strategy>", "Merge strategy (merge_commit, squash, fast_forward)").action(async (id, options) => {
|
|
35934
36241
|
const cmd = container.resolve(ServiceTokens.MergePRCommand);
|
|
35935
36242
|
const context = createContext(cli);
|
|
@@ -35970,7 +36277,41 @@ prCmd.command("diff [id]").description("View pull request diff").option("--color
|
|
|
35970
36277
|
process.exit(1);
|
|
35971
36278
|
}
|
|
35972
36279
|
});
|
|
36280
|
+
var prCommentsCmd = new Command("comments").description("Manage pull request comments");
|
|
36281
|
+
prCommentsCmd.command("list <id>").description("List comments on a pull request").option("--limit <number>", "Maximum number of comments (default: 25)").action(async (id, options) => {
|
|
36282
|
+
const cmd = container.resolve(ServiceTokens.ListCommentsPRCommand);
|
|
36283
|
+
const context = createContext(cli);
|
|
36284
|
+
const result = await cmd.execute(withGlobalOptions({ id, ...options }, context), context);
|
|
36285
|
+
if (!result.success) {
|
|
36286
|
+
process.exit(1);
|
|
36287
|
+
}
|
|
36288
|
+
});
|
|
36289
|
+
prCommentsCmd.command("add <id> <message>").description("Add a comment to a pull request").action(async (id, message, options) => {
|
|
36290
|
+
const cmd = container.resolve(ServiceTokens.CommentPRCommand);
|
|
36291
|
+
const context = createContext(cli);
|
|
36292
|
+
const result = await cmd.execute(withGlobalOptions({ id, message }, context), context);
|
|
36293
|
+
if (!result.success) {
|
|
36294
|
+
process.exit(1);
|
|
36295
|
+
}
|
|
36296
|
+
});
|
|
36297
|
+
prCommentsCmd.command("edit <pr-id> <comment-id> <message>").description("Edit a comment on a pull request").action(async (prId, commentId, message, options) => {
|
|
36298
|
+
const cmd = container.resolve(ServiceTokens.EditCommentPRCommand);
|
|
36299
|
+
const context = createContext(cli);
|
|
36300
|
+
const result = await cmd.execute(withGlobalOptions({ prId, commentId, message }, context), context);
|
|
36301
|
+
if (!result.success) {
|
|
36302
|
+
process.exit(1);
|
|
36303
|
+
}
|
|
36304
|
+
});
|
|
36305
|
+
prCommentsCmd.command("delete <pr-id> <comment-id>").description("Delete a comment on a pull request").action(async (prId, commentId, options) => {
|
|
36306
|
+
const cmd = container.resolve(ServiceTokens.DeleteCommentPRCommand);
|
|
36307
|
+
const context = createContext(cli);
|
|
36308
|
+
const result = await cmd.execute(withGlobalOptions({ prId, commentId }, context), context);
|
|
36309
|
+
if (!result.success) {
|
|
36310
|
+
process.exit(1);
|
|
36311
|
+
}
|
|
36312
|
+
});
|
|
35973
36313
|
cli.addCommand(prCmd);
|
|
36314
|
+
prCmd.addCommand(prCommentsCmd);
|
|
35974
36315
|
var configCmd = new Command("config").description("Manage configuration");
|
|
35975
36316
|
configCmd.command("get <key>").description("Get a configuration value").action(async (key) => {
|
|
35976
36317
|
const cmd = container.resolve(ServiceTokens.GetConfigCommand);
|