Skip to content

Commit b435ecb

Browse files
authored
Call Studio API will all refs available on the Git remote (#4580)
1 parent 8ed8cb5 commit b435ecb

File tree

9 files changed

+103
-27
lines changed

9 files changed

+103
-27
lines changed

extension/src/data/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ type LocalExperimentsOutput = {
1616
rowOrder: { branch: string; sha: string }[]
1717
}
1818

19-
type RemoteExperimentsOutput = { remoteExpRefs: string }
19+
type RemoteExperimentsOutput = { lsRemoteOutput: string }
2020

2121
export type ExperimentsOutput = LocalExperimentsOutput | RemoteExperimentsOutput
2222

2323
export const isRemoteExperimentsOutput = (
2424
data: ExperimentsOutput
2525
): data is RemoteExperimentsOutput =>
26-
(data as RemoteExperimentsOutput).remoteExpRefs !== undefined
26+
(data as RemoteExperimentsOutput).lsRemoteOutput !== undefined
2727

2828
export abstract class BaseData<
2929
T extends

extension/src/experiments/data/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,15 +191,15 @@ export class ExperimentsData extends BaseData<ExperimentsOutput> {
191191
}
192192

193193
private async updateRemoteExpRefs() {
194-
const [remoteExpRefs] = await Promise.all([
194+
const [lsRemoteOutput] = await Promise.all([
195195
this.internalCommands.executeCommand(
196196
AvailableCommands.GIT_GET_REMOTE_EXPERIMENT_REFS,
197197
this.dvcRoot
198198
),
199199
this.isReady()
200200
])
201201

202-
this.notifyChanged({ remoteExpRefs })
202+
this.notifyChanged({ lsRemoteOutput })
203203
}
204204

205205
private waitForInitialLocalData() {

extension/src/experiments/index.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,8 @@ export class Experiments extends BaseRepository<TableData> {
184184

185185
public async setState(data: ExperimentsOutput) {
186186
if (isRemoteExperimentsOutput(data)) {
187-
const { remoteExpRefs } = data
188-
this.experiments.transformAndSetRemote(remoteExpRefs)
187+
const { lsRemoteOutput } = data
188+
this.experiments.transformAndSetRemote(lsRemoteOutput)
189189
return this.webviewMessages.sendWebviewMessage()
190190
}
191191

@@ -598,8 +598,11 @@ export class Experiments extends BaseRepository<TableData> {
598598
}
599599

600600
public async setStudioBaseUrl(studioToken: string | undefined) {
601-
await this.isReady()
602-
await this.studio.setBaseUrl(studioToken)
601+
await Promise.all([this.isReady(), this.experiments.isReady()])
602+
await this.studio.setBaseUrl(
603+
studioToken,
604+
this.experiments.getRemoteExpRefs()
605+
)
603606
return this.webviewMessages.sendWebviewMessage()
604607
}
605608

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

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { collectExperiments } from './collect'
1+
import { collectExperiments, collectRemoteExpDetails } from './collect'
22
import { generateTestExpShowOutput } from '../../test/util/experiments'
33
import { ExpShowOutput } from '../../cli/dvc/contract'
44

@@ -101,3 +101,36 @@ describe('collectExperiments', () => {
101101
])
102102
})
103103
})
104+
105+
describe('collectRemoteExpDetails', () => {
106+
it('should parse the git ls-remote output', () => {
107+
const output = `263e4408e42a0e215b0f70b36b2ab7b65a160d7e refs/exps/a9/b32d14966b9be1396f2211d9eb743359708a07/vital-taal
108+
d4f2a35773ead55b7ce4b596f600e98360e49372 refs/exps/a9/b32d14966b9be1396f2211d9eb743359708a07/whole-bout
109+
5af79e8d5e53f4e41221b6a166121d96d50b630a refs/exps/a9/d8057e088d46842f15c3b6d1bb2e4befd5f677/deism-bots
110+
21745a4aa76daf59b49ec81480fe7a89c7ea8fb2 refs/exps/a9/d8057e088d46842f15c3b6d1bb2e4befd5f677/inter-gulf
111+
390aef747f45fc49ec8928b24771f8950d057393 refs/exps/a9/d8057e088d46842f15c3b6d1bb2e4befd5f677/known-flus
112+
142a803b83ff784ba1106cc4ad0ba03310da6186 refs/exps/a9/d8057e088d46842f15c3b6d1bb2e4befd5f677/tight-lira
113+
21ce298cd1743405a0d73f5cb4cf52289ffa3276 refs/exps/bf/6ca8a35911bc6e62fb9bcaa506d4f4e185450c/crumb-orcs`
114+
const { remoteExpRefs, remoteExpShas } = collectRemoteExpDetails(output)
115+
expect(remoteExpRefs).toStrictEqual([
116+
'refs/exps/a9/b32d14966b9be1396f2211d9eb743359708a07/vital-taal',
117+
'refs/exps/a9/b32d14966b9be1396f2211d9eb743359708a07/whole-bout',
118+
'refs/exps/a9/d8057e088d46842f15c3b6d1bb2e4befd5f677/deism-bots',
119+
'refs/exps/a9/d8057e088d46842f15c3b6d1bb2e4befd5f677/inter-gulf',
120+
'refs/exps/a9/d8057e088d46842f15c3b6d1bb2e4befd5f677/known-flus',
121+
'refs/exps/a9/d8057e088d46842f15c3b6d1bb2e4befd5f677/tight-lira',
122+
'refs/exps/bf/6ca8a35911bc6e62fb9bcaa506d4f4e185450c/crumb-orcs'
123+
])
124+
expect(remoteExpShas).toStrictEqual(
125+
new Set([
126+
'263e4408e42a0e215b0f70b36b2ab7b65a160d7e',
127+
'd4f2a35773ead55b7ce4b596f600e98360e49372',
128+
'5af79e8d5e53f4e41221b6a166121d96d50b630a',
129+
'21745a4aa76daf59b49ec81480fe7a89c7ea8fb2',
130+
'390aef747f45fc49ec8928b24771f8950d057393',
131+
'142a803b83ff784ba1106cc4ad0ba03310da6186',
132+
'21ce298cd1743405a0d73f5cb4cf52289ffa3276'
133+
])
134+
)
135+
})
136+
})

extension/src/experiments/model/collect.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -483,11 +483,15 @@ export const collectRunningInWorkspace = (
483483
}
484484
}
485485

486-
export const collectRemoteExpShas = (remoteExpRefs: string): Set<string> => {
486+
export const collectRemoteExpDetails = (
487+
lsRemoteOutput: string
488+
): { remoteExpShas: Set<string>; remoteExpRefs: string[] } => {
489+
const remoteExpRefs: string[] = []
487490
const remoteExpShas = new Set<string>()
488-
for (const ref of trimAndSplit(remoteExpRefs)) {
489-
const [sha] = ref.split(/\s/)
491+
for (const shaAndRef of trimAndSplit(lsRemoteOutput)) {
492+
const [sha, ref] = shaAndRef.split(/\s+/)
490493
remoteExpShas.add(sha)
494+
remoteExpRefs.push(ref.trim())
491495
}
492-
return remoteExpShas
496+
return { remoteExpRefs, remoteExpShas }
493497
}

extension/src/experiments/model/index.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
collectAddRemoveCommitsDetails,
77
collectExperiments,
88
collectOrderedCommitsAndExperiments,
9-
collectRemoteExpShas,
9+
collectRemoteExpDetails,
1010
collectRunningInQueue,
1111
collectRunningInWorkspace
1212
} from './collect'
@@ -80,6 +80,7 @@ export class ExperimentsModel extends ModelWithPersistence {
8080
private filters: Map<string, FilterDefinition> = new Map()
8181

8282
private remoteExpShas?: Set<string>
83+
private remoteExpRefs: string[] = []
8384
private pushing = new Set<string>()
8485

8586
private currentSorts: SortDefinition[]
@@ -174,9 +175,12 @@ export class ExperimentsModel extends ModelWithPersistence {
174175
this.setColoredStatus(runningExperiments)
175176
}
176177

177-
public transformAndSetRemote(remoteExpRefs: string) {
178-
const remoteExpShas = collectRemoteExpShas(remoteExpRefs)
178+
public transformAndSetRemote(lsRemoteOutput: string) {
179+
const { remoteExpShas, remoteExpRefs } =
180+
collectRemoteExpDetails(lsRemoteOutput)
179181
this.remoteExpShas = remoteExpShas
182+
this.remoteExpRefs = remoteExpRefs
183+
this.deferred.resolve()
180184
}
181185

182186
public toggleStars(ids: string[]) {
@@ -539,6 +543,10 @@ export class ExperimentsModel extends ModelWithPersistence {
539543
return this.availableBranchesToSelect
540544
}
541545

546+
public getRemoteExpRefs() {
547+
return this.remoteExpRefs
548+
}
549+
542550
public hasDvcLiveOnlyRunning() {
543551
return !!this.dvcLiveOnlyExpName
544552
}

extension/src/experiments/studio.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ export class Studio extends Disposable {
1919
return !!this.baseUrl
2020
}
2121

22-
public async setBaseUrl(studioToken: string | undefined) {
22+
public async setBaseUrl(
23+
studioToken: string | undefined,
24+
remoteExpRefs: string[]
25+
) {
2326
if (!studioToken) {
2427
this.baseUrl = undefined
2528
return
@@ -30,7 +33,7 @@ export class Studio extends Disposable {
3033
this.dvcRoot
3134
)
3235

33-
this.baseUrl = await this.getBaseUrl(studioToken, gitRemote)
36+
this.baseUrl = await this.getBaseUrl(studioToken, gitRemote, remoteExpRefs)
3437
}
3538

3639
public getLink(sha: string) {
@@ -40,12 +43,16 @@ export class Studio extends Disposable {
4043
return `${this.baseUrl}?showOnlySelected=1&experimentReferences=${sha}&activeExperimentReferences=${sha}%3Aprimary`
4144
}
4245

43-
private async getBaseUrl(studioToken: string, gitRemoteUrl: string) {
46+
private async getBaseUrl(
47+
studioToken: string,
48+
gitRemoteUrl: string,
49+
remoteExpRefs: string[]
50+
) {
4451
try {
4552
const response = await fetch(`${STUDIO_URL}/webhook/dvc`, {
4653
body: JSON.stringify({
4754
client: 'vscode',
48-
refs: [null],
55+
refs: { pushed: remoteExpRefs },
4956
repo_url: gitRemoteUrl
5057
}),
5158
headers: {

extension/src/test/suite/experiments/index.test.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ import { MAX_SELECTED_EXPERIMENTS } from '../../../experiments/model/status'
9494
import { Pipeline } from '../../../pipeline'
9595
import { ColumnLike } from '../../../experiments/columns/like'
9696
import * as Clipboard from '../../../vscode/clipboard'
97+
import { STUDIO_URL } from '../../../setup/webview/contract'
9798

9899
const { openFileInEditor } = FileSystem
99100

@@ -680,20 +681,23 @@ suite('Experiments Test Suite', () => {
680681
}).timeout(WEBVIEW_TEST_TIMEOUT)
681682

682683
it("should handle a message to copy an experiment's Studio link", async () => {
683-
const { mockMessageReceived, experiments } =
684+
const { mockMessageReceived, experiments, gitReader } =
684685
await buildExperimentsWebview({ disposer: disposable })
685686

686687
const viewUrl =
687688
'https://studio.iterative.ai/user/demo-user/projects/demo-ynm6t3jxdx'
688689

689-
stub(Fetch, 'default').resolves({
690+
const mockGitRemoteUrl = '[email protected]:iterative/vscode-dvc-demo.git'
691+
stub(gitReader, 'getRemoteUrl').resolves(mockGitRemoteUrl)
692+
const mockStudioToken = 'isat_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB'
693+
const mockFetch = stub(Fetch, 'default').resolves({
690694
json: () =>
691695
Promise.resolve({
692696
url: viewUrl
693697
})
694698
} as unknown as Fetch.Response)
695699

696-
await experiments.setStudioBaseUrl('isat_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB')
700+
await experiments.setStudioBaseUrl(mockStudioToken)
697701
const mockWriteToClipboard = stub(Clipboard, 'writeToClipboard')
698702
const writeToClipboardCalled = new Promise(resolve =>
699703
mockWriteToClipboard.callsFake(() => {
@@ -707,6 +711,23 @@ suite('Experiments Test Suite', () => {
707711
payload: 'exp-e7a67'
708712
})
709713

714+
expect(mockFetch).to.be.calledWith(`${STUDIO_URL}/webhook/dvc`, {
715+
body: JSON.stringify({
716+
client: 'vscode',
717+
refs: {
718+
pushed: [
719+
'refs/exps/a9/b32d14966b9be1396f2211d9eb743359708a07/test-branch'
720+
]
721+
},
722+
repo_url: mockGitRemoteUrl
723+
}),
724+
headers: {
725+
Authorization: `token ${mockStudioToken}`,
726+
'Content-Type': 'application/json'
727+
},
728+
method: 'POST'
729+
})
730+
710731
await writeToClipboardCalled
711732
const link =
712733
viewUrl +

extension/src/test/suite/experiments/util.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export const buildExperiments = ({
3838
dvcRoot = dvcDemoPath,
3939
expShow = expShowFixture,
4040
gitLog = gitLogFixture,
41-
remoteExpRefs = remoteExpRefsFixture,
41+
lsRemoteOutput = remoteExpRefsFixture,
4242
rowOrder = rowOrderFixture,
4343
stageList = 'train'
4444
}: {
@@ -47,7 +47,7 @@ export const buildExperiments = ({
4747
dvcRoot?: string
4848
expShow?: ExpShowOutput
4949
gitLog?: string
50-
remoteExpRefs?: string
50+
lsRemoteOutput?: string
5151
rowOrder?: { branch: string; sha: string }[]
5252
stageList?: string | null
5353
}) => {
@@ -103,7 +103,7 @@ export const buildExperiments = ({
103103
gitLog,
104104
rowOrder
105105
}),
106-
experiments.setState({ remoteExpRefs })
106+
experiments.setState({ lsRemoteOutput })
107107
])
108108

109109
return {
@@ -144,7 +144,7 @@ export const buildExperimentsWebview = async (inputs: {
144144
dvcRoot?: string
145145
expShow?: ExpShowOutput
146146
gitLog?: string
147-
remoteExpRefs?: string
147+
lsRemoteOutput?: string
148148
rowOrder?: { branch: string; sha: string }[]
149149
stageList?: string | null
150150
}) => {

0 commit comments

Comments
 (0)