prwatcher 2.0.0 → 2.1.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # prwatcher
2
2
 
3
- CLI tool that watches GitHub PRs and sends Slack notifications when CI passes, fails, or the PR is ready to merge.
3
+ CLI tool that watches GitHub PRs and sends Slack notifications when CI passes, fails, or the PR is ready to merge. Optionally auto-merges when all checks pass.
4
4
 
5
5
  **Zero setup for developers** — just run one command. No Slack app creation, no servers, no ngrok.
6
6
 
@@ -29,17 +29,39 @@ Or use directly with npx:
29
29
  npx prwatcher https://github.com/owner/repo/pull/123
30
30
  ```
31
31
 
32
+ ### GitHub Token Setup
33
+
34
+ On first run you'll be prompted for a GitHub personal access token. Here's what permissions it needs depending on how you use the tool:
35
+
36
+ #### Watching only (no auto-merge)
37
+
38
+ **Classic token** — check `repo` scope
39
+
40
+ **Fine-grained token** — enable:
41
+ - `Metadata` → Read-only (required)
42
+ - `Pull requests` → Read-only
43
+
44
+ #### Watching + Auto-merge (`--auto-merge`)
45
+
46
+ **Classic token** — check `repo` scope
47
+
48
+ **Fine-grained token** — enable:
49
+ - `Metadata` → Read-only (required)
50
+ - `Pull requests` → Read and write
51
+ - `Contents` → Read and write ← required for merging
52
+
53
+ > Your token is saved to `~/.watch-pr` on your machine with owner-only permissions (0600). It is never sent anywhere except the GitHub API.
54
+
32
55
  ### Usage
33
56
 
34
57
  ```bash
35
58
  prwatcher https://github.com/owner/repo/pull/123
36
59
  ```
37
60
 
38
- On first run, you'll be prompted for:
39
- 1. **GitHub token** — [create one here](https://github.com/settings/tokens) with `repo` scope
40
- 2. **Slack webhook URL** — your team's [Incoming Webhook](https://api.slack.com/messaging/webhooks)
61
+ On first run, you'll also be prompted for:
62
+ - **Slack webhook URL** — your team's [Incoming Webhook](https://api.slack.com/messaging/webhooks)
41
63
 
42
- These are saved to `~/.prwatcher` so you only enter them once.
64
+ Both are saved to `~/.watch-pr` so you only enter them once.
43
65
 
44
66
  ### Options
45
67
 
@@ -48,6 +70,7 @@ prwatcher <pr-url> [options]
48
70
 
49
71
  Options:
50
72
  --interval <minutes> Polling interval in minutes (default: 1)
73
+ --auto-merge Automatically merge PR once all required checks pass
51
74
  --reset-config Re-enter GitHub token and Slack webhook URL
52
75
  -V, --version Output version number
53
76
  -h, --help Display help
@@ -59,6 +82,9 @@ Options:
59
82
  # Watch a PR with default 1-minute polling
60
83
  prwatcher https://github.com/org/repo/pull/42
61
84
 
85
+ # Watch and auto-merge when ready
86
+ prwatcher https://github.com/org/repo/pull/42 --auto-merge
87
+
62
88
  # Poll every 30 seconds
63
89
  prwatcher https://github.com/org/repo/pull/42 --interval 0.5
64
90
 
@@ -78,8 +104,10 @@ You'll get Slack messages when:
78
104
  | Required CI checks fail | ⚠️ CI checks failed (lists which ones) |
79
105
  | PR needs rebase | 🔄 PR needs rebase |
80
106
  | PR is ready to merge | ✅ PR is ready to merge! |
107
+ | PR is auto-merged | 🎉 PR was auto-merged! |
81
108
  | PR is merged | 🎉 PR was merged! |
82
109
  | PR is closed | ❌ PR was closed without merging |
110
+ | Auto-merge failed | ⚠️ Auto-merge failed (with reason) |
83
111
 
84
112
  Notifications only fire on **state changes** — no spam.
85
113
 
@@ -113,6 +141,7 @@ Detect state change (CI failed, ready, merged, etc.)
113
141
 
114
142
  POST to Slack webhook
115
143
 
144
+ --auto-merge? → merge via GitHub API → exit
116
145
  PR merged/closed? → exit
117
146
  ```
118
147
 
package/bin/watch-pr.js CHANGED
@@ -6,9 +6,10 @@ const { run } = require('../src/cli');
6
6
  program
7
7
  .name('prwatcher')
8
8
  .description('Watch a GitHub PR and get Slack notifications on state changes')
9
- .version('2.0.0')
9
+ .version('2.1.0')
10
10
  .argument('<pr-url>', 'GitHub PR URL (e.g., https://github.com/owner/repo/pull/123)')
11
11
  .option('--interval <minutes>', 'polling interval in minutes', '1')
12
+ .option('--auto-merge', 'automatically merge PR once all required checks pass')
12
13
  .option('--reset-config', 're-enter GitHub token and Slack webhook URL')
13
14
  .action((prUrl, options) => {
14
15
  run(prUrl, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prwatcher",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "CLI tool that watches GitHub PRs and sends Slack notifications when CI passes, fails, or PR is ready to merge",
5
5
  "main": "src/cli.js",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  const { parsePRUrl, buildPRKey } = require('./utils');
2
2
  const { ensureConfig } = require('./config');
3
- const { createClient, fetchRequiredChecks, fetchPRState } = require('./github');
3
+ const { createClient, fetchRequiredChecks, fetchPRState, mergePR } = require('./github');
4
4
  const { sendNotification, formatMerged, formatClosed, formatCIFailed, formatRebaseNeeded, formatReady } = require('./slack');
5
5
 
6
6
  async function run(prUrl, options = {}) {
@@ -70,6 +70,9 @@ async function run(prUrl, options = {}) {
70
70
  const intervalMs = intervalMinutes * 60 * 1000;
71
71
 
72
72
  console.log(` Polling every ${intervalMinutes >= 1 ? `${intervalMinutes} minute(s)` : `${intervalMinutes * 60} seconds`}`);
73
+ if (options.autoMerge) {
74
+ console.log(' ⚠ Auto-merge is ON — PR will be merged automatically when ready');
75
+ }
73
76
  console.log(' Press Ctrl+C to stop\n');
74
77
 
75
78
  // 6. Poll function
@@ -127,6 +130,24 @@ async function run(prUrl, options = {}) {
127
130
  console.log(` ✅ ${timestamp} — Ready to merge!`);
128
131
  await sendNotification(config.slackWebhookUrl, formatReady(state.htmlUrl, state.title));
129
132
  lastState = 'ready';
133
+
134
+ if (options.autoMerge) {
135
+ try {
136
+ console.log(` 🔀 ${timestamp} — Auto-merging...`);
137
+ await mergePR(octokit, { owner, repo, prNumber });
138
+ console.log(` 🎉 ${timestamp} — Auto-merged!`);
139
+ await sendNotification(config.slackWebhookUrl, `🎉 *PR was auto-merged!*\n<${state.htmlUrl}|${state.title}>`);
140
+ cleanup();
141
+ process.exit(0);
142
+ } catch (mergeError) {
143
+ const mergeMsg = mergeError.response?.data?.message || mergeError.message;
144
+ const hint = mergeError.status === 403
145
+ ? ' (GitHub token needs "repo" scope or "Pull requests: write" permission)'
146
+ : '';
147
+ console.error(` ⚠ ${timestamp} — Auto-merge failed: ${mergeMsg}${hint}`);
148
+ await sendNotification(config.slackWebhookUrl, `⚠️ *Auto-merge failed*\n<${state.htmlUrl}|${state.title}>\nReason: ${mergeMsg}${hint}`);
149
+ }
150
+ }
130
151
  } else {
131
152
  console.log(` ✅ ${timestamp} — Still ready (already notified)`);
132
153
  }
package/src/github.js CHANGED
@@ -115,8 +115,23 @@ async function fetchPRState(octokit, { owner, repo, prNumber, requiredCheckNames
115
115
  };
116
116
  }
117
117
 
118
+ /**
119
+ * Merge a PR via GitHub API.
120
+ * Returns { merged: true } on success, or throws on failure.
121
+ */
122
+ async function mergePR(octokit, { owner, repo, prNumber }) {
123
+ const { data } = await octokit.pulls.merge({
124
+ owner,
125
+ repo,
126
+ pull_number: prNumber,
127
+ merge_method: 'merge'
128
+ });
129
+ return data;
130
+ }
131
+
118
132
  module.exports = {
119
133
  createClient,
120
134
  fetchRequiredChecks,
121
- fetchPRState
135
+ fetchPRState,
136
+ mergePR
122
137
  };