✨ feat(vscode): 审查视图也能隐藏测试文件,和未提交的更改共用一个开关
This commit is contained in:
1 parent
851be48c43
commit
78d5748b81
12 files changed
+139
-53
No files matched your search
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { CHANGE_STYLES, changeOf, reviewBaseFile } from './changedFiles'
|
||||
import { CHANGE_STYLES, changeOf, reviewBaseFile, reviewTree } from './changedFiles'
|
||||
|
||||
describe('改动状态', () => {
|
||||
it('新增 A、删除 D,别的(改名、复制、改了、没改)都算修改 M', () => {
|
||||
@@ -31,3 +31,39 @@ describe('审查时在 PR 目标分支上取哪个文件', () => {
|
||||
expect(reviewBaseFile(files, 'src/untouched.ts')).toEqual({ path: 'src/untouched.ts', added: false })
|
||||
})
|
||||
})
|
||||
|
||||
describe('审查时树上摆哪些文件', () => {
|
||||
const files = [
|
||||
{ path: 'backend/app.py', status: 'changed' },
|
||||
{ path: 'backend/test_app.py', status: 'added' },
|
||||
{ path: 'backend/tests/test_avatar.py', status: 'added' },
|
||||
{ path: 'backend/tests/fixtures/avatar.png', status: 'added' },
|
||||
{ path: 'web/src/__tests__/Avatar.tsx', status: 'changed' },
|
||||
{ path: 'web/src/Avatar.tsx', status: 'changed' },
|
||||
]
|
||||
const names = (tree: ReturnType<typeof reviewTree>['tree'], dir: string): string[] => (tree.get(dir) ?? []).map(entry => entry.name)
|
||||
|
||||
it('隐藏测试文件时剔掉 tests/、__tests__/ 下的和 test_*.py,只装着测试文件的目录不摆,数出剔了几个', () => {
|
||||
const { tree, hidden } = reviewTree(files, true)
|
||||
expect(hidden).toBe(4)
|
||||
expect(names(tree, '')).toEqual(['backend', 'web'])
|
||||
expect(names(tree, 'backend')).toEqual(['app.py'])
|
||||
expect(names(tree, 'web/src')).toEqual(['Avatar.tsx'])
|
||||
expect(tree.has('backend/tests')).toBe(false)
|
||||
expect(tree.has('backend/tests/fixtures')).toBe(false)
|
||||
expect(tree.has('web/src/__tests__')).toBe(false)
|
||||
})
|
||||
|
||||
it('不隐藏时 PR 改过的都在,剔了 0 个', () => {
|
||||
const { tree, hidden } = reviewTree(files, false)
|
||||
expect(hidden).toBe(0)
|
||||
expect(names(tree, 'backend')).toEqual(['tests', 'app.py', 'test_app.py'])
|
||||
expect(names(tree, 'backend/tests')).toEqual(['fixtures', 'test_avatar.py'])
|
||||
expect(names(tree, 'web/src')).toEqual(['__tests__', 'Avatar.tsx'])
|
||||
})
|
||||
|
||||
it('改动状态照 Gitea 的', () => {
|
||||
const { tree } = reviewTree(files, true)
|
||||
expect(tree.get('backend')?.[0]).toMatchObject({ path: 'backend/app.py', change: 'M' })
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,6 @@
|
||||
import type { FileChange } from '../explorer/changedTree'
|
||||
import type { ChangedTree, FileChange } from '../explorer/changedTree'
|
||||
import { buildChangedTree } from '../explorer/changedTree'
|
||||
import { isTestFile } from '../uncommitted/testFiles'
|
||||
|
||||
/**
|
||||
* Gitea 给的改动状态 → M / A / D。Gitea 的状态有 added、deleted、changed、renamed、copied、unchanged:
|
||||
@@ -8,6 +10,16 @@ export function changeOf(status: string): FileChange {
|
||||
return status === 'added' ? 'A' : status === 'deleted' ? 'D' : 'M'
|
||||
}
|
||||
|
||||
/**
|
||||
* 审查时树上摆的:PR 改过的文件和通往它们的目录。隐藏测试文件时先剔掉测试文件再摆,只装着测试文件的目录跟着不摆;
|
||||
* hidden 是剔了几个。
|
||||
*/
|
||||
export function reviewTree(files: readonly { path: string, status: string }[], hideTests: boolean): { tree: ChangedTree, hidden: number } {
|
||||
const changes = files.map(file => ({ path: file.path, change: changeOf(file.status) }))
|
||||
const shown = hideTests ? changes.filter(file => !isTestFile(file.path)) : changes
|
||||
return { tree: buildChangedTree(shown), hidden: changes.length - shown.length }
|
||||
}
|
||||
|
||||
/**
|
||||
* 审查时工作副本里的一个文件(path 相对工作副本的根)在 PR 目标分支上叫什么、有没有:
|
||||
* 改名的取改名前的路径,PR 里新加的(Gitea 的 added)目标分支上没有。PR 没改过的文件照原路径取。
|
||||
|
||||
@@ -10,10 +10,9 @@ import * as path from 'node:path'
|
||||
import { QuickPickItemKind, Uri, window, workspace } from 'vscode'
|
||||
import { fileAtRef } from '../../git/fileAt'
|
||||
import { logger } from '../../logging/logger'
|
||||
import { buildChangedTree } from '../explorer/changedTree'
|
||||
import { toPathKey } from '../pathMap'
|
||||
import { ChangeDecorations } from './changeDecorations'
|
||||
import { changeOf, reviewBaseFile } from './changedFiles'
|
||||
import { changeOf, reviewBaseFile, reviewTree } from './changedFiles'
|
||||
import { countingFiles, pickEntries, pickItemText, pickRows, withFileCount } from './pickList'
|
||||
import { columnLabel, REVIEW_COLUMNS_TEXT, reviewableIssue, reviewablePullRequest, reviewBaseLabel, reviewBaseMissing, reviewDescription, reviewMessage } from './reviewRules'
|
||||
import { loadIssue, loadPullRequest, loadPullRequestFiles, requireRepo, reviewCandidateIssues } from './reviewSource'
|
||||
@@ -189,6 +188,11 @@ export class ReviewMode implements TreeFilter, Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
/** 隐藏测试文件的开关换了:正审查着的文件按新开关重摆。 */
|
||||
testsToggled(): void {
|
||||
this.place()
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
for (const disposable of this.disposables)
|
||||
disposable.dispose()
|
||||
@@ -272,21 +276,29 @@ export class ReviewMode implements TreeFilter, Disposable {
|
||||
}
|
||||
|
||||
private async show(loaded: Loaded): Promise<void> {
|
||||
const { issue, pr, files, worktree } = loaded
|
||||
const root = Uri.file(worktree)
|
||||
// 工作副本当根,名字照写工作区文件夹的:看的还是这个仓库,只是 PR 最新的代码
|
||||
const folder: WorkspaceFolder = { uri: root, name: workspace.workspaceFolders?.[0]?.name ?? path.basename(worktree), index: 0 }
|
||||
const changes = files.map(file => ({ path: file.path, change: changeOf(file.status) }))
|
||||
const root = Uri.file(loaded.worktree)
|
||||
// 先记下再进:进的时候打开着的预览就来问对比基准
|
||||
this.loaded = loaded
|
||||
const entering = this.filters.enter(this, 'review')
|
||||
this.files.showChanges([{ roots: [{ folder, tree: buildChangedTree(changes) }] }])
|
||||
this.decorations.show(changes.map(file => ({ uri: Uri.joinPath(root, file.path), change: file.change })))
|
||||
this.view.description = reviewDescription(issue.number)
|
||||
this.view.message = reviewMessage(issue, pr, files.length)
|
||||
this.place()
|
||||
this.decorations.show(loaded.files.map(file => ({ uri: Uri.joinPath(root, file.path), change: changeOf(file.status) })))
|
||||
await Promise.all([
|
||||
entering,
|
||||
this.context.workspaceState.update(REVIEW_ISSUE_KEY, issue.number),
|
||||
this.context.workspaceState.update(REVIEW_ISSUE_KEY, loaded.issue.number),
|
||||
])
|
||||
}
|
||||
|
||||
/** 把正审查着的 PR 改过的文件摆上树(隐藏测试文件时剔掉),标题后面写上藏了几个。 */
|
||||
private place(): void {
|
||||
const loaded = this.loaded
|
||||
if (!loaded)
|
||||
return
|
||||
const { issue, pr, files, worktree } = loaded
|
||||
// 工作副本当根,名字照写工作区文件夹的:看的还是这个仓库,只是 PR 最新的代码
|
||||
const folder: WorkspaceFolder = { uri: Uri.file(worktree), name: workspace.workspaceFolders?.[0]?.name ?? path.basename(worktree), index: 0 }
|
||||
const { tree, hidden } = reviewTree(files, this.filters.testsHidden)
|
||||
this.files.showChanges([{ roots: [{ folder, tree }] }])
|
||||
this.view.description = reviewDescription(issue.number, hidden)
|
||||
this.view.message = reviewMessage(issue, pr, files.length)
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,13 @@ const issue = { number: 446, title: '用户资料:上传头像,收紧非管
|
||||
|
||||
describe('审查时的视图标题', () => {
|
||||
it('标题后面「审查 #446」,下面一行工单标题、PR、改了几个文件', () => {
|
||||
expect(reviewDescription(446)).toBe('审查 #446')
|
||||
expect(reviewDescription(446, 0)).toBe('审查 #446')
|
||||
expect(reviewMessage(issue, 447, 6)).toBe('#446 用户资料:上传头像,收紧非管理员改资料的权限 · PR #447 · 改了 6 个文件')
|
||||
})
|
||||
|
||||
it('隐藏了测试文件时标题后面接上藏了几个,和「未提交的更改」一个说法', () => {
|
||||
expect(reviewDescription(446, 3)).toBe('审查 #446 · 已隐藏 3 个测试文件')
|
||||
})
|
||||
})
|
||||
|
||||
describe('选工单弹框列哪些工单', () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Issue, IssueColumn } from '../../gitea/types'
|
||||
import { withHiddenTests } from '../uncommitted/testFiles'
|
||||
|
||||
/** 工单关联的 PR 号;state JSON 里没有、或不是正整数时没有。 */
|
||||
export function prNumberOf(issue: Pick<Issue, 'pr'>): number | undefined {
|
||||
@@ -67,9 +68,9 @@ export function reviewablePullRequest<T extends { state: string, merged: boolean
|
||||
return { pull }
|
||||
}
|
||||
|
||||
/** 审查时视图标题后面淡色的字(TreeView.description)。 */
|
||||
export function reviewDescription(issueNumber: number): string {
|
||||
return `审查 #${issueNumber}`
|
||||
/** 审查时视图标题后面淡色的字(TreeView.description):隐藏了测试文件时接上藏了几个。 */
|
||||
export function reviewDescription(issueNumber: number, hiddenTests: number): string {
|
||||
return withHiddenTests(`审查 #${issueNumber}`, hiddenTests)
|
||||
}
|
||||
|
||||
/** 审查时视图标题下面的一行(TreeView.message)。 */
|
||||
|
||||
Reference in new issue
Block a user