Skip to content

Commit 07f849d

Browse files
authored
Fix missing commit messages in experiment branches (#3053)
1 parent 819a100 commit 07f849d

File tree

10 files changed

+112
-96
lines changed

10 files changed

+112
-96
lines changed

extension/src/cli/git/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,6 @@ export enum Commit {
4848

4949
export const DEFAULT_REMOTE = 'origin'
5050

51+
export const COMMITS_SEPARATOR = '\u0000'
52+
5153
export type Args = (Command | Flag | Commit | typeof DEFAULT_REMOTE | string)[]

extension/src/cli/git/reader.ts

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { trimAndSplit } from '../../util/stdout'
77
import { isDirectory } from '../../fileSystem'
88

99
export const autoRegisteredCommands = {
10-
GIT_GET_LAST_THREE_COMMIT_MESSAGES: 'getLastThreeCommitMessages',
10+
GIT_GET_COMMIT_MESSAGES: 'getCommitMessages',
1111
GIT_GET_REPOSITORY_ROOT: 'getGitRepositoryRoot',
1212
GIT_HAS_CHANGES: 'hasChanges',
1313
GIT_LIST_UNTRACKED: 'listUntracked'
@@ -31,26 +31,18 @@ export class GitReader extends GitCli {
3131
return !!output
3232
}
3333

34-
public async getLastThreeCommitMessages(cwd: string): Promise<{
35-
[sha: string]: string
36-
}> {
34+
public async getCommitMessages(cwd: string, sha: string): Promise<string> {
3735
const options = getOptions(
3836
cwd,
3937
Command.LOG,
38+
`${sha}^..HEAD`,
4039
Flag.PRETTY_FORMAT_COMMIT_MESSAGE,
41-
Flag.NUMBER,
42-
'6',
4340
Flag.SEPARATE_WITH_NULL
4441
)
4542
try {
46-
const output = await this.executeProcess(options)
47-
const commits = output.split('\u0000').map(commit => {
48-
const [sha, ...splitMessage] = commit.split(' ')
49-
return [sha, splitMessage.join(' ')]
50-
})
51-
return Object.fromEntries(commits)
43+
return await this.executeProcess(options)
5244
} catch {
53-
return {}
45+
return ''
5446
}
5547
}
5648

extension/src/experiments/index.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -173,15 +173,15 @@ export class Experiments extends BaseRepository<TableData> {
173173

174174
public async setState(data: ExperimentsOutput) {
175175
const dvcLiveOnly = await this.checkSignalFile()
176-
177-
const commitMessages: { [sha: string]: string } =
178-
await this.internalCommands.executeCommand(
179-
AvailableCommands.GIT_GET_LAST_THREE_COMMIT_MESSAGES,
180-
this.dvcRoot
181-
)
176+
const dataKeys = Object.keys(data)
177+
const commitsOutput = await this.internalCommands.executeCommand(
178+
AvailableCommands.GIT_GET_COMMIT_MESSAGES,
179+
this.dvcRoot,
180+
dataKeys[dataKeys.length - 1]
181+
)
182182
await Promise.all([
183183
this.columns.transformAndSet(data),
184-
this.experiments.transformAndSet(data, dvcLiveOnly, commitMessages)
184+
this.experiments.transformAndSet(data, dvcLiveOnly, commitsOutput)
185185
])
186186

187187
return this.notifyChanged(data)

extension/src/experiments/model/collect.test.ts

Lines changed: 52 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@ import {
55
ExperimentStatus,
66
EXPERIMENT_WORKSPACE_ID
77
} from '../../cli/dvc/contract'
8+
import { COMMITS_SEPARATOR } from '../../cli/git/constants'
89

910
describe('collectExperiments', () => {
10-
it('should return an empty array if no branches are present', async () => {
11-
const { branches } = await collectExperiments(
11+
it('should return an empty array if no branches are present', () => {
12+
const { branches } = collectExperiments(
1213
{
1314
[EXPERIMENT_WORKSPACE_ID]: {
1415
baseline: {}
1516
}
1617
},
1718
false,
18-
{}
19+
''
1920
)
2021
expect(branches).toStrictEqual([])
2122
})
@@ -39,56 +40,67 @@ describe('collectExperiments', () => {
3940
}
4041
}
4142

42-
it('should define a workspace', async () => {
43-
const { workspace } = await collectExperiments(
44-
repoWithTwoBranches,
45-
false,
46-
{}
47-
)
43+
it('should define a workspace', () => {
44+
const { workspace } = collectExperiments(repoWithTwoBranches, false, '')
4845

4946
expect(workspace).toBeDefined()
5047
})
5148

52-
it('should find two branches from a repo with two branches', async () => {
53-
const { branches } = await collectExperiments(
54-
repoWithTwoBranches,
55-
false,
56-
{}
57-
)
49+
it('should find two branches from a repo with two branches', () => {
50+
const { branches } = collectExperiments(repoWithTwoBranches, false, '')
5851

5952
expect(branches.length).toStrictEqual(2)
6053
})
6154

62-
it('should list branches in the same order as they are collected', async () => {
63-
const { branches } = await collectExperiments(
64-
repoWithTwoBranches,
65-
false,
66-
{}
67-
)
55+
it('should list branches in the same order as they are collected', () => {
56+
const { branches } = collectExperiments(repoWithTwoBranches, false, '')
6857
const [branchA, branchB] = branches
6958

7059
expect(branchA.id).toStrictEqual('branchA')
7160
expect(branchB.id).toStrictEqual('branchB')
7261
})
7362

74-
it('should find two experiments on branchA', async () => {
75-
const { experimentsByBranch } = await collectExperiments(
63+
it('should find two experiments on branchA', () => {
64+
const { experimentsByBranch } = collectExperiments(
7665
repoWithTwoBranches,
7766
false,
78-
{}
67+
''
7968
)
8069
expect(experimentsByBranch.get('branchA')?.length).toStrictEqual(2)
8170
})
8271

83-
it('should find no experiments on branchB', async () => {
84-
const { experimentsByBranch } = await collectExperiments(
72+
it('should find no experiments on branchB', () => {
73+
const { experimentsByBranch } = collectExperiments(
8574
repoWithTwoBranches,
8675
false,
87-
{}
76+
''
8877
)
8978
expect(experimentsByBranch.get('branchB')).toBeUndefined()
9079
})
9180

81+
it('should add git commit messages to branches if git log output is provided', () => {
82+
const { branches } = collectExperiments(
83+
{
84+
[EXPERIMENT_WORKSPACE_ID]: {
85+
baseline: {}
86+
},
87+
a123: {
88+
baseline: { data: {} }
89+
},
90+
b123: {
91+
baseline: { data: {} }
92+
}
93+
},
94+
false,
95+
`a123 add new feature${COMMITS_SEPARATOR}b123 update various dependencies\n* update dvc\n* update jest`
96+
)
97+
const [branch1, branch2] = branches
98+
expect(branch1.displayNameOrParent).toStrictEqual('add new feature')
99+
expect(branch2.displayNameOrParent).toStrictEqual(
100+
'update various dependencies ...'
101+
)
102+
})
103+
92104
const repoWithNestedCheckpoints = {
93105
[EXPERIMENT_WORKSPACE_ID]: { baseline: {} },
94106
branchA: {
@@ -108,31 +120,31 @@ describe('collectExperiments', () => {
108120
}
109121
}
110122

111-
it('should only list the tip as a top-level experiment', async () => {
112-
const { experimentsByBranch } = await collectExperiments(
123+
it('should only list the tip as a top-level experiment', () => {
124+
const { experimentsByBranch } = collectExperiments(
113125
repoWithNestedCheckpoints,
114126
false,
115-
{}
127+
''
116128
)
117129
expect(experimentsByBranch.size).toStrictEqual(1)
118130
})
119131

120-
it('should find three checkpoints on the tip', async () => {
121-
const { checkpointsByTip } = await collectExperiments(
132+
it('should find three checkpoints on the tip', () => {
133+
const { checkpointsByTip } = collectExperiments(
122134
repoWithNestedCheckpoints,
123135
false,
124-
{}
136+
''
125137
)
126138
const checkpoints = checkpointsByTip.get('tip1') as Experiment[]
127139

128140
expect(checkpoints?.length).toStrictEqual(3)
129141
})
130142

131-
it('should find checkpoints in the correct order', async () => {
132-
const { checkpointsByTip } = await collectExperiments(
143+
it('should find checkpoints in the correct order', () => {
144+
const { checkpointsByTip } = collectExperiments(
133145
repoWithNestedCheckpoints,
134146
false,
135-
{}
147+
''
136148
)
137149
const checkpoints = checkpointsByTip.get('tip1') as Experiment[]
138150
const [tip1cp1, tip1cp2, tip1cp3] = checkpoints
@@ -141,12 +153,8 @@ describe('collectExperiments', () => {
141153
expect(tip1cp3.id).toStrictEqual('tip1cp3')
142154
})
143155

144-
it('should handle the continuation of a modified checkpoint', async () => {
145-
const { checkpointsByTip } = await collectExperiments(
146-
modifiedFixture,
147-
false,
148-
{}
149-
)
156+
it('should handle the continuation of a modified checkpoint', () => {
157+
const { checkpointsByTip } = collectExperiments(modifiedFixture, false, '')
150158

151159
const modifiedCheckpointTip = checkpointsByTip
152160
.get('exp-01b3a')
@@ -181,7 +189,7 @@ describe('collectExperiments', () => {
181189
}
182190
})
183191

184-
it('should handle a checkpoint tip not having a name', async () => {
192+
it('should handle a checkpoint tip not having a name', () => {
185193
const checkpointTipWithoutAName = '3fceabdcef3c7b97c7779f8ae0c69a5542eefaf5'
186194

187195
const repoWithNestedCheckpoints = {
@@ -202,7 +210,7 @@ describe('collectExperiments', () => {
202210
}
203211
}
204212
}
205-
const acc = await collectExperiments(repoWithNestedCheckpoints, false, {})
213+
const acc = collectExperiments(repoWithNestedCheckpoints, false, '')
206214

207215
const { experimentsByBranch, checkpointsByTip } = acc
208216
const [experiment] = experimentsByBranch.get('branchA') || []

extension/src/experiments/model/collect.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { uniqueValues } from '../../util/array'
2222
import { RegisteredCommands } from '../../commands/external'
2323
import { Resource } from '../../resourceLocator'
2424
import { shortenForLabel } from '../../util/string'
25+
import { COMMITS_SEPARATOR } from '../../cli/git/constants'
2526

2627
export type ExperimentItem = {
2728
command?: {
@@ -316,22 +317,32 @@ const formatCommitMessage = (commit: string) => {
316317
return `${lines[0]}${lines.length > 1 ? ' ...' : ''}`
317318
}
318319

320+
const getCommitMessages = (commitsOutput: string) => {
321+
const commits = commitsOutput.split(COMMITS_SEPARATOR).map(commit => {
322+
const [sha, ...splitMessage] = commit.split(' ')
323+
return [sha, splitMessage.join(' ')]
324+
})
325+
return Object.fromEntries(commits)
326+
}
327+
319328
const addCommitDataToBranches = (
320329
branches: Experiment[],
321-
commitMessages: { [sha: string]: string } = {}
322-
): Experiment[] =>
323-
branches.map(branch => {
330+
commitsOutput: string
331+
): Experiment[] => {
332+
const commitMessages = getCommitMessages(commitsOutput)
333+
return branches.map(branch => {
324334
const { sha } = branch
325335
if (sha && commitMessages[sha]) {
326336
branch.displayNameOrParent = formatCommitMessage(commitMessages[sha])
327337
}
328338
return branch
329339
})
340+
}
330341

331342
export const collectExperiments = (
332343
data: ExperimentsOutput,
333344
dvcLiveOnly: boolean,
334-
commitMessages: { [sha: string]: string }
345+
commitsOutput: string
335346
): ExperimentsAccumulator => {
336347
const { workspace, ...branchesObject } = data
337348

@@ -350,7 +361,7 @@ export const collectExperiments = (
350361

351362
collectFromBranchesObject(acc, branchesObject)
352363

353-
acc.branches = addCommitDataToBranches(acc.branches, commitMessages)
364+
acc.branches = addCommitDataToBranches(acc.branches, commitsOutput)
354365

355366
return acc
356367
}

0 commit comments

Comments
 (0)