@@ -16,18 +16,14 @@ import {
16
16
} from "@gitpod/gitpod-protocol" ;
17
17
import { log } from "@gitpod/gitpod-protocol/lib/util/logging" ;
18
18
import { PrebuiltWorkspaceState , WithCommitHistory } from "@gitpod/gitpod-protocol/lib/protocol" ;
19
- import { WorkspaceDB } from "@gitpod/gitpod-db/lib" ;
19
+ import { PrebuildWithWorkspace , WorkspaceDB } from "@gitpod/gitpod-db/lib" ;
20
20
import { Config } from "../config" ;
21
21
import { HostContextProvider } from "../auth/host-context-provider" ;
22
22
import { ImageSourceProvider } from "../workspace/image-source-provider" ;
23
23
24
24
const MAX_HISTORY_DEPTH = 100 ;
25
25
26
- enum Match {
27
- None = 0 ,
28
- Loose = 1 ,
29
- Exact = 2 ,
30
- }
26
+ type IncrementalWorkspaceMatch = "none" | "incremental" | "exact" ;
31
27
32
28
@injectable ( )
33
29
export class IncrementalWorkspaceService {
@@ -93,30 +89,44 @@ export class IncrementalWorkspaceService {
93
89
const imageSource = await imageSourcePromise ;
94
90
95
91
// traverse prebuilds by commit history instead of their creationTime, so that we don't match prebuilds created for older revisions but triggered later
96
- for ( const commit of history . commitHistory ) {
97
- const prebuildsForCommit = recentPrebuilds . filter ( ( { prebuild } ) => prebuild . commit === commit ) ;
98
- for ( const entry of prebuildsForCommit ) {
99
- const { prebuild, workspace } = entry ;
100
- const match = this . isMatchForIncrementalBuild (
101
- history ,
102
- config ,
103
- imageSource ,
92
+ const candidates : { candidate : PrebuildWithWorkspace ; index : number } [ ] = [ ] ;
93
+ for ( const recentPrebuild of recentPrebuilds ) {
94
+ const { prebuild, workspace } = recentPrebuild ;
95
+ const { match, index } = this . isMatchForIncrementalBuild (
96
+ history ,
97
+ config ,
98
+ imageSource ,
99
+ prebuild ,
100
+ workspace ,
101
+ includeUnfinishedPrebuilds ,
102
+ ) ;
103
+ if ( match === "exact" ) {
104
+ console . log ( "Found base for incremental build" , {
104
105
prebuild,
105
106
workspace,
106
- includeUnfinishedPrebuilds ,
107
- ) ;
108
- if ( match > Match . None ) {
109
- console . log ( "Found base for incremental build" , {
110
- prebuild,
111
- workspace,
112
- exactMatch : match === Match . Exact ,
113
- } ) ;
114
- return prebuild ;
115
- }
107
+ exactMatch : true ,
108
+ } ) ;
109
+ return prebuild ;
110
+ }
111
+ if ( match === "incremental" ) {
112
+ candidates . push ( { candidate : recentPrebuild , index : index ! } ) ;
116
113
}
117
114
}
118
115
119
- return undefined ;
116
+ if ( candidates . length === 0 ) {
117
+ return undefined ;
118
+ }
119
+
120
+ // Sort by index ASC
121
+ candidates . sort ( ( a , b ) => a . index - b . index ) ;
122
+ const { prebuild, workspace } = candidates [ 0 ] . candidate ;
123
+
124
+ console . log ( "Found base for incremental build" , {
125
+ prebuild,
126
+ workspace,
127
+ exactMatch : false ,
128
+ } ) ;
129
+ return prebuild ;
120
130
}
121
131
122
132
private isMatchForIncrementalBuild (
@@ -126,13 +136,13 @@ export class IncrementalWorkspaceService {
126
136
candidatePrebuild : PrebuiltWorkspace ,
127
137
candidateWorkspace : Workspace ,
128
138
includeUnfinishedPrebuilds ?: boolean ,
129
- ) : Match {
139
+ ) : { match : Omit < IncrementalWorkspaceMatch , "none" > ; index : number } | { match : "none" ; index ?: undefined } {
130
140
// make typescript happy, we know that history.commitHistory is defined
131
141
if ( ! history . commitHistory ) {
132
- return Match . None ;
142
+ return { match : "none" } ;
133
143
}
134
144
if ( ! CommitContext . is ( candidateWorkspace . context ) ) {
135
- return Match . None ;
145
+ return { match : "none" } ;
136
146
}
137
147
138
148
const acceptableStates : PrebuiltWorkspaceState [ ] = [ "available" ] ;
@@ -141,35 +151,40 @@ export class IncrementalWorkspaceService {
141
151
acceptableStates . push ( "queued" ) ;
142
152
}
143
153
if ( ! acceptableStates . includes ( candidatePrebuild . state ) ) {
144
- return Match . None ;
154
+ return { match : "none" } ;
145
155
}
146
156
147
157
// we are only considering full prebuilds (we are not building on top of incremental prebuilds)
148
158
if ( candidateWorkspace . basedOnPrebuildId ) {
149
- return Match . None ;
159
+ return { match : "none" } ;
150
160
}
151
161
152
162
// check if the amount of additional repositories matches the candidate
153
163
if (
154
164
candidateWorkspace . context . additionalRepositoryCheckoutInfo ?. length !==
155
165
history . additionalRepositoryCommitHistories ?. length
156
166
) {
157
- return Match . None ;
167
+ return { match : "none" } ;
158
168
}
159
169
160
170
const candidateCtx = candidateWorkspace . context ;
161
171
162
172
// check for overlapping commit history
173
+ // TODO(gpl) Isn't "candidateCtx.revision" identical to "candidatePrebuild.commit"? If yes, we could do .indexOf once...
174
+ if ( candidateCtx . revision !== candidatePrebuild . commit ) {
175
+ log . warn ( "Prebuild matching: commits mismatch!" , { candidateCtx, candidatePrebuild } ) ;
176
+ }
163
177
if ( ! history . commitHistory . some ( ( sha ) => sha === candidateCtx . revision ) ) {
164
- return Match . None ;
178
+ return { match : "none" } ;
165
179
}
180
+
166
181
// check for overlapping git history for each additional repo
167
182
for ( const subRepo of candidateWorkspace . context . additionalRepositoryCheckoutInfo ?? [ ] ) {
168
183
const matchingRepo = history . additionalRepositoryCommitHistories ?. find (
169
184
( repo ) => repo . cloneUrl === subRepo . repository . cloneUrl ,
170
185
) ;
171
186
if ( ! matchingRepo || ! matchingRepo . commitHistory . some ( ( sha ) => sha === subRepo . revision ) ) {
172
- return Match . None ;
187
+ return { match : "none" } ;
173
188
}
174
189
}
175
190
@@ -179,7 +194,7 @@ export class IncrementalWorkspaceService {
179
194
imageSource,
180
195
parentImageSource : candidateWorkspace . imageSource ,
181
196
} ) ;
182
- return Match . None ;
197
+ return { match : "none" } ;
183
198
}
184
199
185
200
// ensure the tasks haven't changed
@@ -190,14 +205,15 @@ export class IncrementalWorkspaceService {
190
205
prebuildTasks,
191
206
parentPrebuildTasks,
192
207
} ) ;
193
- return Match . None ;
208
+ return { match : "none" } ;
194
209
}
195
210
196
- if ( candidatePrebuild . commit === history . commitHistory [ 0 ] ) {
197
- return Match . Exact ;
211
+ const index = history . commitHistory . indexOf ( candidatePrebuild . commit ) ;
212
+ if ( index === 0 ) {
213
+ return { match : "exact" , index } ;
198
214
}
199
215
200
- return Match . Loose ;
216
+ return { match : "incremental" , index } ;
201
217
}
202
218
203
219
/**
0 commit comments