ghreview 2.0.3 → 3.0.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/CHANGELOG.md +17 -0
- package/bin/ghreview.js +9 -2
- package/lib/git.js +24 -5
- package/lib/index.js +19 -7
- package/package.json +1 -1
- package/test/ghreview.test.js +7 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
## [3.0.0](https://github.com/rvagg/ghreview/compare/v2.0.4...v3.0.0) (2026-02-07)
|
|
2
|
+
|
|
3
|
+
### ⚠ BREAKING CHANGES
|
|
4
|
+
|
|
5
|
+
* only include tracked files in review by default
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
* only include tracked files in review by default ([8e20211](https://github.com/rvagg/ghreview/commit/8e20211e48c12ab42e7e170f48478e881930f04d))
|
|
10
|
+
* preserve staging state across review cycle ([6fe2429](https://github.com/rvagg/ghreview/commit/6fe242947623fc4fef3f8e75b1bc7b6baaf60463))
|
|
11
|
+
|
|
12
|
+
## [2.0.4](https://github.com/rvagg/ghreview/compare/v2.0.3...v2.0.4) (2026-02-02)
|
|
13
|
+
|
|
14
|
+
### Trivial Changes
|
|
15
|
+
|
|
16
|
+
* **deps-dev:** bump vitest from 4.0.17 to 4.0.18 ([#27](https://github.com/rvagg/ghreview/issues/27)) ([116ab54](https://github.com/rvagg/ghreview/commit/116ab54f511e5f2089b643df9eb8b27150c9a977))
|
|
17
|
+
|
|
1
18
|
## [2.0.3](https://github.com/rvagg/ghreview/compare/v2.0.2...v2.0.3) (2026-01-27)
|
|
2
19
|
|
|
3
20
|
### Trivial Changes
|
package/bin/ghreview.js
CHANGED
|
@@ -18,9 +18,16 @@ process.on('SIGTERM', () => {
|
|
|
18
18
|
yargs(hideBin(process.argv))
|
|
19
19
|
.scriptName('ghreview')
|
|
20
20
|
.usage('$0 <command> [args]')
|
|
21
|
-
.command('init', 'Create a PR for review',
|
|
21
|
+
.command('init', 'Create a PR for review', (yargs) => {
|
|
22
|
+
return yargs.option('all', {
|
|
23
|
+
alias: 'a',
|
|
24
|
+
type: 'boolean',
|
|
25
|
+
default: false,
|
|
26
|
+
describe: 'Include untracked files (by default, only tracked and staged files are included)'
|
|
27
|
+
})
|
|
28
|
+
}, async (argv) => {
|
|
22
29
|
try {
|
|
23
|
-
await init()
|
|
30
|
+
await init({ all: argv.all })
|
|
24
31
|
} catch (error) {
|
|
25
32
|
console.error(chalk.red('Error:'), error.message)
|
|
26
33
|
process.exit(1)
|
package/lib/git.js
CHANGED
|
@@ -10,17 +10,25 @@ export async function getCurrentBranch () {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export async function
|
|
13
|
+
export async function hasReviewableChanges ({ all = false } = {}) {
|
|
14
14
|
const git = simpleGit()
|
|
15
15
|
const status = await git.status()
|
|
16
|
-
|
|
16
|
+
if (all) {
|
|
17
|
+
return status.files.length > 0
|
|
18
|
+
}
|
|
19
|
+
// Exclude untracked files — user must `git add` new files explicitly
|
|
20
|
+
return status.files.some(f => !(f.index === '?' && f.working_dir === '?'))
|
|
17
21
|
}
|
|
18
22
|
|
|
19
|
-
export async function createReviewCommit (message, authorConfig) {
|
|
23
|
+
export async function createReviewCommit (message, authorConfig, { all = false } = {}) {
|
|
20
24
|
const git = simpleGit()
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
if (all) {
|
|
27
|
+
await git.add('.')
|
|
28
|
+
} else {
|
|
29
|
+
// Only stage tracked file modifications; new files require explicit `git add`
|
|
30
|
+
await git.add(['-u'])
|
|
31
|
+
}
|
|
24
32
|
|
|
25
33
|
// Set up environment for custom author if provided
|
|
26
34
|
const env = {}
|
|
@@ -44,6 +52,17 @@ export async function pushBranch (remote, branch) {
|
|
|
44
52
|
}
|
|
45
53
|
}
|
|
46
54
|
|
|
55
|
+
export async function saveIndex () {
|
|
56
|
+
const git = simpleGit()
|
|
57
|
+
const treeHash = await git.raw(['write-tree'])
|
|
58
|
+
return treeHash.trim()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function restoreIndex (treeHash) {
|
|
62
|
+
const git = simpleGit()
|
|
63
|
+
await git.raw(['read-tree', treeHash])
|
|
64
|
+
}
|
|
65
|
+
|
|
47
66
|
export async function resetLastCommit () {
|
|
48
67
|
const git = simpleGit()
|
|
49
68
|
await git.reset(['HEAD~1'])
|
package/lib/index.js
CHANGED
|
@@ -3,7 +3,9 @@ import ora from 'ora'
|
|
|
3
3
|
import { loadConfig } from './config.js'
|
|
4
4
|
import {
|
|
5
5
|
getCurrentBranch,
|
|
6
|
-
|
|
6
|
+
hasReviewableChanges,
|
|
7
|
+
saveIndex,
|
|
8
|
+
restoreIndex,
|
|
7
9
|
createReviewCommit,
|
|
8
10
|
pushBranch,
|
|
9
11
|
resetLastCommit,
|
|
@@ -16,9 +18,10 @@ import {
|
|
|
16
18
|
formatFeedback
|
|
17
19
|
} from './github.js'
|
|
18
20
|
|
|
19
|
-
export async function init () {
|
|
21
|
+
export async function init ({ all = false } = {}) {
|
|
20
22
|
const spinner = ora('Initializing review').start()
|
|
21
23
|
let commitCreated = false
|
|
24
|
+
let savedTree = null
|
|
22
25
|
|
|
23
26
|
try {
|
|
24
27
|
// Check if we're in a git repository
|
|
@@ -39,9 +42,11 @@ export async function init () {
|
|
|
39
42
|
const config = await loadConfig()
|
|
40
43
|
const [owner, repo] = config.reviewRepo.split('/')
|
|
41
44
|
|
|
42
|
-
// Check for
|
|
43
|
-
if (!await
|
|
44
|
-
spinner.fail(
|
|
45
|
+
// Check for reviewable changes
|
|
46
|
+
if (!await hasReviewableChanges({ all })) {
|
|
47
|
+
spinner.fail(all
|
|
48
|
+
? 'No changes to review'
|
|
49
|
+
: 'No tracked changes to review (use --all to include untracked files)')
|
|
45
50
|
return
|
|
46
51
|
}
|
|
47
52
|
|
|
@@ -63,11 +68,15 @@ export async function init () {
|
|
|
63
68
|
const currentBranch = await getCurrentBranch()
|
|
64
69
|
await pushBranch('review', `${currentBranch}:${baseBranch}`)
|
|
65
70
|
|
|
71
|
+
// Snapshot the current index so we can restore staging state after reset
|
|
72
|
+
savedTree = await saveIndex()
|
|
73
|
+
|
|
66
74
|
// Create temporary commit with changes
|
|
67
75
|
spinner.text = 'Creating review commit'
|
|
68
76
|
await createReviewCommit(
|
|
69
77
|
`Review checkpoint ${timestamp}`,
|
|
70
|
-
config.author
|
|
78
|
+
config.author,
|
|
79
|
+
{ all }
|
|
71
80
|
)
|
|
72
81
|
commitCreated = true
|
|
73
82
|
|
|
@@ -93,10 +102,13 @@ export async function init () {
|
|
|
93
102
|
spinner.fail('Failed to create review')
|
|
94
103
|
throw error
|
|
95
104
|
} finally {
|
|
96
|
-
// Always reset the commit if we created one
|
|
105
|
+
// Always reset the commit if we created one, then restore original staging
|
|
97
106
|
if (commitCreated) {
|
|
98
107
|
try {
|
|
99
108
|
await resetLastCommit()
|
|
109
|
+
if (savedTree) {
|
|
110
|
+
await restoreIndex(savedTree)
|
|
111
|
+
}
|
|
100
112
|
} catch (resetError) {
|
|
101
113
|
console.error(chalk.yellow('Warning: Failed to reset temporary commit'))
|
|
102
114
|
}
|
package/package.json
CHANGED
package/test/ghreview.test.js
CHANGED
|
@@ -23,9 +23,11 @@ describe('ghreview', () => {
|
|
|
23
23
|
})
|
|
24
24
|
|
|
25
25
|
// Mock git operations
|
|
26
|
-
vi.mocked(git.
|
|
26
|
+
vi.mocked(git.hasReviewableChanges).mockResolvedValue(true)
|
|
27
27
|
vi.mocked(git.getCurrentBranch).mockResolvedValue('main')
|
|
28
28
|
vi.mocked(git.ensureReviewRemote).mockResolvedValue('review')
|
|
29
|
+
vi.mocked(git.saveIndex).mockResolvedValue('abc123')
|
|
30
|
+
vi.mocked(git.restoreIndex).mockResolvedValue()
|
|
29
31
|
vi.mocked(git.createReviewCommit).mockResolvedValue()
|
|
30
32
|
vi.mocked(git.pushBranch).mockResolvedValue()
|
|
31
33
|
vi.mocked(git.resetLastCommit).mockResolvedValue()
|
|
@@ -41,10 +43,12 @@ describe('ghreview', () => {
|
|
|
41
43
|
await init()
|
|
42
44
|
|
|
43
45
|
// Verify calls
|
|
44
|
-
expect(git.
|
|
46
|
+
expect(git.hasReviewableChanges).toHaveBeenCalled()
|
|
47
|
+
expect(git.saveIndex).toHaveBeenCalled()
|
|
45
48
|
expect(git.createReviewCommit).toHaveBeenCalled()
|
|
46
49
|
expect(git.pushBranch).toHaveBeenCalledTimes(2) // base and review
|
|
47
50
|
expect(git.resetLastCommit).toHaveBeenCalled()
|
|
51
|
+
expect(git.restoreIndex).toHaveBeenCalledWith('abc123')
|
|
48
52
|
expect(github.createPullRequest).toHaveBeenCalled()
|
|
49
53
|
})
|
|
50
54
|
|
|
@@ -53,7 +57,7 @@ describe('ghreview', () => {
|
|
|
53
57
|
reviewRepo: 'owner/repo',
|
|
54
58
|
githubToken: 'test-token'
|
|
55
59
|
})
|
|
56
|
-
vi.mocked(git.
|
|
60
|
+
vi.mocked(git.hasReviewableChanges).mockResolvedValue(false)
|
|
57
61
|
|
|
58
62
|
await init()
|
|
59
63
|
|