ghreview 1.0.1 → 2.0.1
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/.github/dependabot.yml +6 -2
- package/.github/workflows/test-and-release.yml +7 -6
- package/CHANGELOG.md +30 -0
- package/lib/config.js +72 -25
- package/lib/github.js +71 -9
- package/package.json +7 -6
package/.github/dependabot.yml
CHANGED
|
@@ -3,14 +3,18 @@ updates:
|
|
|
3
3
|
- package-ecosystem: "github-actions"
|
|
4
4
|
directory: "/"
|
|
5
5
|
schedule:
|
|
6
|
-
interval: "
|
|
6
|
+
interval: "weekly"
|
|
7
7
|
commit-message:
|
|
8
8
|
prefix: "chore"
|
|
9
9
|
include: "scope"
|
|
10
|
+
cooldown:
|
|
11
|
+
default-days: 5
|
|
10
12
|
- package-ecosystem: "npm"
|
|
11
13
|
directory: "/"
|
|
12
14
|
schedule:
|
|
13
|
-
interval: "
|
|
15
|
+
interval: "weekly"
|
|
14
16
|
commit-message:
|
|
15
17
|
prefix: "chore"
|
|
16
18
|
include: "scope"
|
|
19
|
+
cooldown:
|
|
20
|
+
default-days: 5
|
|
@@ -5,14 +5,14 @@ jobs:
|
|
|
5
5
|
strategy:
|
|
6
6
|
fail-fast: false
|
|
7
7
|
matrix:
|
|
8
|
-
node: [
|
|
8
|
+
node: [lts/*, current]
|
|
9
9
|
os: [macos-latest, ubuntu-latest, windows-latest]
|
|
10
10
|
runs-on: ${{ matrix.os }}
|
|
11
11
|
steps:
|
|
12
12
|
- name: Checkout Repository
|
|
13
|
-
uses: actions/checkout@
|
|
13
|
+
uses: actions/checkout@v6.0.1
|
|
14
14
|
- name: Use Node.js ${{ matrix.node }}
|
|
15
|
-
uses: actions/setup-node@
|
|
15
|
+
uses: actions/setup-node@v6.1.0
|
|
16
16
|
with:
|
|
17
17
|
node-version: ${{ matrix.node }}
|
|
18
18
|
- name: Install Dependencies
|
|
@@ -31,13 +31,14 @@ jobs:
|
|
|
31
31
|
contents: write
|
|
32
32
|
issues: write
|
|
33
33
|
pull-requests: write
|
|
34
|
+
id-token: write
|
|
34
35
|
steps:
|
|
35
36
|
- name: Checkout
|
|
36
|
-
uses: actions/checkout@
|
|
37
|
+
uses: actions/checkout@v6.0.1
|
|
37
38
|
with:
|
|
38
39
|
fetch-depth: 0
|
|
39
40
|
- name: Setup Node.js
|
|
40
|
-
uses: actions/setup-node@
|
|
41
|
+
uses: actions/setup-node@v6.1.0
|
|
41
42
|
with:
|
|
42
43
|
node-version: lts/*
|
|
43
44
|
- name: Install dependencies
|
|
@@ -46,6 +47,6 @@ jobs:
|
|
|
46
47
|
- name: Release
|
|
47
48
|
env:
|
|
48
49
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
49
|
-
|
|
50
|
+
NPM_CONFIG_PROVENANCE: true
|
|
50
51
|
run: npx semantic-release
|
|
51
52
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
## [2.0.1](https://github.com/rvagg/ghreview/compare/v2.0.0...v2.0.1) (2026-01-24)
|
|
2
|
+
|
|
3
|
+
### Trivial Changes
|
|
4
|
+
|
|
5
|
+
* **deps-dev:** bump nock from 14.0.7 to 14.0.10 ([#5](https://github.com/rvagg/ghreview/issues/5)) ([b979aba](https://github.com/rvagg/ghreview/commit/b979abaad70a259a0d01eb6d8b89eeb0a7707dc6))
|
|
6
|
+
|
|
7
|
+
## [2.0.0](https://github.com/rvagg/ghreview/compare/v1.0.1...v2.0.0) (2026-01-24)
|
|
8
|
+
|
|
9
|
+
### ⚠ BREAKING CHANGES
|
|
10
|
+
|
|
11
|
+
* Config location changed from ~/.ghreview/config.json
|
|
12
|
+
to XDG paths (~/.config/ghreview/config.json on Linux). Move your
|
|
13
|
+
existing config to the new location.
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* add interactive auth and filter resolved comments ([29a8196](https://github.com/rvagg/ghreview/commit/29a81961b5c9ee636552d048f96cc9d59c7ace81))
|
|
18
|
+
|
|
19
|
+
### Trivial Changes
|
|
20
|
+
|
|
21
|
+
* **ci:** oidc publishing ([4cef06b](https://github.com/rvagg/ghreview/commit/4cef06b9f64ec067b0363fc230babca74e224395))
|
|
22
|
+
* **deps-dev:** bump @semantic-release/github from 11.0.6 to 12.0.0 ([cef9450](https://github.com/rvagg/ghreview/commit/cef94502b1d00ced4c653b67b0af7b6ff350948b))
|
|
23
|
+
* **deps-dev:** bump @semantic-release/npm from 12.0.2 to 13.1.1 ([c63e419](https://github.com/rvagg/ghreview/commit/c63e419188b913ed866ddf48b7bbbe4c2d2b8f00))
|
|
24
|
+
* **deps-dev:** bump nock from 14.0.7 to 14.0.10 ([a7c98df](https://github.com/rvagg/ghreview/commit/a7c98dfe7840fbd26a5c9c81ed21acd5bfcf7240))
|
|
25
|
+
* **deps:** bump actions/checkout from 4.2.2 to 6.0.1 ([170b48c](https://github.com/rvagg/ghreview/commit/170b48c47bfd6a601037d362b9c3b4e084a83d05))
|
|
26
|
+
* **deps:** bump actions/setup-node from 4.4.0 to 6.1.0 ([61ce2d9](https://github.com/rvagg/ghreview/commit/61ce2d9f083b83562d139de8bcfba985c9017a4a))
|
|
27
|
+
* **deps:** bump chalk from 5.4.1 to 5.6.2 ([948fa9d](https://github.com/rvagg/ghreview/commit/948fa9d78c11b527c4483276e7426b6207084751))
|
|
28
|
+
* **deps:** bump ora from 8.2.0 to 9.0.0 ([8dff5ca](https://github.com/rvagg/ghreview/commit/8dff5ca3d61eb056739422b647d8e7c260967924))
|
|
29
|
+
* fix dependabot config ([4d2b670](https://github.com/rvagg/ghreview/commit/4d2b670cda6b6c975d760ec822f0ce2ca1b337cd))
|
|
30
|
+
|
|
1
31
|
## [1.0.1](https://github.com/rvagg/ghreview/compare/v1.0.0...v1.0.1) (2025-07-28)
|
|
2
32
|
|
|
3
33
|
### Trivial Changes
|
package/lib/config.js
CHANGED
|
@@ -1,42 +1,89 @@
|
|
|
1
1
|
import fs from 'fs/promises'
|
|
2
2
|
import path from 'path'
|
|
3
3
|
import os from 'os'
|
|
4
|
+
import ghauth from 'ghauth'
|
|
5
|
+
import { read } from 'read'
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
+
function getConfigPath () {
|
|
8
|
+
const home = os.homedir()
|
|
9
|
+
switch (os.platform()) {
|
|
10
|
+
case 'darwin':
|
|
11
|
+
return path.join(home, 'Library', 'Application Support', 'ghreview', 'config.json')
|
|
12
|
+
case 'win32':
|
|
13
|
+
return path.join(process.env.APPDATA || path.join(home, 'AppData', 'Roaming'), 'ghreview', 'config.json')
|
|
14
|
+
default:
|
|
15
|
+
return path.join(process.env.XDG_CONFIG_HOME || path.join(home, '.config'), 'ghreview', 'config.json')
|
|
16
|
+
}
|
|
17
|
+
}
|
|
7
18
|
|
|
8
|
-
|
|
19
|
+
const CONFIG_FILE = getConfigPath()
|
|
20
|
+
const CONFIG_DIR = path.dirname(CONFIG_FILE)
|
|
21
|
+
|
|
22
|
+
async function readConfig () {
|
|
9
23
|
try {
|
|
10
24
|
const configData = await fs.readFile(CONFIG_FILE, 'utf8')
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
throw new Error('Missing required config field: reviewRepo')
|
|
25
|
+
return JSON.parse(configData)
|
|
26
|
+
} catch (error) {
|
|
27
|
+
if (error.code === 'ENOENT') {
|
|
28
|
+
return {}
|
|
16
29
|
}
|
|
30
|
+
throw error
|
|
31
|
+
}
|
|
32
|
+
}
|
|
17
33
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
34
|
+
async function writeConfig (config) {
|
|
35
|
+
await fs.mkdir(CONFIG_DIR, { recursive: true, mode: 0o700 })
|
|
36
|
+
await fs.writeFile(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 })
|
|
37
|
+
}
|
|
21
38
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
39
|
+
export async function loadConfig () {
|
|
40
|
+
const config = await readConfig()
|
|
41
|
+
let configChanged = false
|
|
26
42
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
43
|
+
// Check if we need to acquire a token
|
|
44
|
+
if (!config.githubToken) {
|
|
45
|
+
console.log('GitHub authentication required.\n')
|
|
46
|
+
const authData = await ghauth({
|
|
47
|
+
configName: 'ghreview',
|
|
48
|
+
scopes: ['repo'],
|
|
49
|
+
noSave: true,
|
|
50
|
+
noDeviceFlow: true
|
|
51
|
+
})
|
|
52
|
+
config.githubToken = authData.token
|
|
53
|
+
config.user = authData.user
|
|
54
|
+
configChanged = true
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Check if we need a reviewRepo
|
|
58
|
+
if (!config.reviewRepo) {
|
|
59
|
+
const defaultRepo = config.user ? `${config.user}/reviews` : null
|
|
60
|
+
const prompt = defaultRepo
|
|
61
|
+
? `Review repository (owner/repo) [${defaultRepo}]: `
|
|
62
|
+
: 'Review repository (owner/repo): '
|
|
63
|
+
|
|
64
|
+
const input = await read({ prompt })
|
|
65
|
+
config.reviewRepo = input || defaultRepo
|
|
66
|
+
|
|
67
|
+
if (!config.reviewRepo) {
|
|
68
|
+
throw new Error('Review repository is required')
|
|
31
69
|
}
|
|
32
|
-
|
|
70
|
+
configChanged = true
|
|
33
71
|
}
|
|
72
|
+
|
|
73
|
+
// Validate repo format
|
|
74
|
+
if (!config.reviewRepo.includes('/')) {
|
|
75
|
+
throw new Error('Invalid reviewRepo format. Expected: owner/repo')
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Save config if anything changed
|
|
79
|
+
if (configChanged) {
|
|
80
|
+
await writeConfig(config)
|
|
81
|
+
console.log(`\nConfig saved to ${CONFIG_FILE}\n`)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return config
|
|
34
85
|
}
|
|
35
86
|
|
|
36
87
|
export async function ensureConfigDir () {
|
|
37
|
-
|
|
38
|
-
await fs.mkdir(CONFIG_DIR, { recursive: true })
|
|
39
|
-
} catch (error) {
|
|
40
|
-
// Directory might already exist, that's fine
|
|
41
|
-
}
|
|
88
|
+
await fs.mkdir(CONFIG_DIR, { recursive: true })
|
|
42
89
|
}
|
package/lib/github.js
CHANGED
|
@@ -60,12 +60,73 @@ All comments will be collected with line numbers and context for AI consumption.
|
|
|
60
60
|
export async function fetchReviewComments (owner, repo, prNumber, token) {
|
|
61
61
|
const octokit = createOctokit(token)
|
|
62
62
|
|
|
63
|
-
//
|
|
64
|
-
const
|
|
65
|
-
owner
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
// Use GraphQL to fetch review threads with resolution status
|
|
64
|
+
const query = `
|
|
65
|
+
query($owner: String!, $repo: String!, $prNumber: Int!, $cursor: String) {
|
|
66
|
+
repository(owner: $owner, name: $repo) {
|
|
67
|
+
pullRequest(number: $prNumber) {
|
|
68
|
+
reviewThreads(first: 100, after: $cursor) {
|
|
69
|
+
pageInfo {
|
|
70
|
+
hasNextPage
|
|
71
|
+
endCursor
|
|
72
|
+
}
|
|
73
|
+
nodes {
|
|
74
|
+
isResolved
|
|
75
|
+
isOutdated
|
|
76
|
+
path
|
|
77
|
+
line
|
|
78
|
+
startLine
|
|
79
|
+
comments(first: 100) {
|
|
80
|
+
nodes {
|
|
81
|
+
id
|
|
82
|
+
body
|
|
83
|
+
path
|
|
84
|
+
line: originalLine
|
|
85
|
+
startLine: originalStartLine
|
|
86
|
+
position: originalPosition
|
|
87
|
+
user: author {
|
|
88
|
+
login
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
`
|
|
98
|
+
|
|
99
|
+
// Fetch all review threads with pagination
|
|
100
|
+
const allThreads = []
|
|
101
|
+
let cursor = null
|
|
102
|
+
let hasNextPage = true
|
|
103
|
+
|
|
104
|
+
while (hasNextPage) {
|
|
105
|
+
const result = await octokit.graphql(query, {
|
|
106
|
+
owner,
|
|
107
|
+
repo,
|
|
108
|
+
prNumber,
|
|
109
|
+
cursor
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
const threads = result.repository.pullRequest.reviewThreads
|
|
113
|
+
allThreads.push(...threads.nodes)
|
|
114
|
+
hasNextPage = threads.pageInfo.hasNextPage
|
|
115
|
+
cursor = threads.pageInfo.endCursor
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Filter to only unresolved threads and flatten comments
|
|
119
|
+
const unresolvedComments = allThreads
|
|
120
|
+
.filter(thread => !thread.isResolved)
|
|
121
|
+
.flatMap(thread => thread.comments.nodes.map(comment => ({
|
|
122
|
+
...comment,
|
|
123
|
+
path: thread.path,
|
|
124
|
+
line: comment.line || thread.line,
|
|
125
|
+
start_line: comment.startLine || thread.startLine,
|
|
126
|
+
original_line: comment.line || thread.line,
|
|
127
|
+
original_start_line: comment.startLine || thread.startLine,
|
|
128
|
+
position: comment.position
|
|
129
|
+
})))
|
|
69
130
|
|
|
70
131
|
// Fetch PR reviews (general comments)
|
|
71
132
|
const { data: reviews } = await octokit.rest.pulls.listReviews({
|
|
@@ -82,7 +143,7 @@ export async function fetchReviewComments (owner, repo, prNumber, token) {
|
|
|
82
143
|
})
|
|
83
144
|
|
|
84
145
|
return {
|
|
85
|
-
inline:
|
|
146
|
+
inline: unresolvedComments,
|
|
86
147
|
reviews: reviews.filter(r => r.body), // Only reviews with comments
|
|
87
148
|
discussion: issueComments
|
|
88
149
|
}
|
|
@@ -93,10 +154,11 @@ export function formatFeedback (comments, filterBots = true) {
|
|
|
93
154
|
|
|
94
155
|
// Filter out bot comments if requested
|
|
95
156
|
const isBot = (comment) => {
|
|
157
|
+
const login = comment.user?.login || comment.author?.login
|
|
96
158
|
return filterBots && (
|
|
97
159
|
comment.user?.type === 'Bot' ||
|
|
98
|
-
|
|
99
|
-
|
|
160
|
+
login?.includes('[bot]') ||
|
|
161
|
+
login?.includes('-bot')
|
|
100
162
|
)
|
|
101
163
|
}
|
|
102
164
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ghreview",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "GitHub PR-based code review workflow for AI-assisted development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -25,8 +25,9 @@
|
|
|
25
25
|
"license": "Apache-2.0",
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@octokit/rest": "^22.0.0",
|
|
28
|
-
"chalk": "^5.
|
|
29
|
-
"
|
|
28
|
+
"chalk": "^5.6.2",
|
|
29
|
+
"ghauth": "^7.0.0",
|
|
30
|
+
"ora": "^9.0.0",
|
|
30
31
|
"simple-git": "^3.28.0",
|
|
31
32
|
"yargs": "^18.0.0"
|
|
32
33
|
},
|
|
@@ -34,11 +35,11 @@
|
|
|
34
35
|
"@semantic-release/changelog": "^6.0.3",
|
|
35
36
|
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
36
37
|
"@semantic-release/git": "^10.0.1",
|
|
37
|
-
"@semantic-release/github": "^
|
|
38
|
-
"@semantic-release/npm": "^
|
|
38
|
+
"@semantic-release/github": "^12.0.0",
|
|
39
|
+
"@semantic-release/npm": "^13.1.1",
|
|
39
40
|
"@semantic-release/release-notes-generator": "^14.0.3",
|
|
40
41
|
"conventional-changelog-conventionalcommits": "^9.0.0",
|
|
41
|
-
"nock": "^14.0.
|
|
42
|
+
"nock": "^14.0.10",
|
|
42
43
|
"standard": "^17.1.2",
|
|
43
44
|
"vitest": "^3.2.4"
|
|
44
45
|
},
|