@@ -8,7 +8,7 @@ import * as uuidv4 from 'uuid/v4';
88import { WorkspaceFactory } from "../../../src/workspace/workspace-factory" ;
99import { injectable , inject } from "inversify" ;
1010import { TraceContext } from "@gitpod/gitpod-protocol/lib/util/tracing" ;
11- import { User , StartPrebuildContext , Workspace , CommitContext , PrebuiltWorkspaceContext , WorkspaceContext , WithSnapshot , WithPrebuild } from "@gitpod/gitpod-protocol" ;
11+ import { User , StartPrebuildContext , Workspace , CommitContext , PrebuiltWorkspaceContext , WorkspaceContext , WithSnapshot , WithPrebuild , TaskConfig } from "@gitpod/gitpod-protocol" ;
1212import { log } from '@gitpod/gitpod-protocol/lib/util/logging' ;
1313import { LicenseEvaluator } from '@gitpod/licensor/lib' ;
1414import { Feature } from '@gitpod/licensor/lib/api' ;
@@ -56,7 +56,62 @@ export class WorkspaceFactoryEE extends WorkspaceFactory {
5656 }
5757 }
5858
59- let ws = await this . createForCommit ( { span} , user , commitContext , normalizedContextURL ) ;
59+ const config = await this . configProvider . fetchConfig ( { span} , user , context . actual ) ;
60+ const imageSource = await this . imageSourceProvider . getImageSource ( ctx , user , context . actual , config ) ;
61+
62+ // Walk back the commit history to find suitable parent prebuild to start an incremental prebuild on.
63+ let ws ;
64+ for ( const parent of ( context . commitHistory || [ ] ) ) {
65+ const parentPrebuild = await this . db . trace ( { span} ) . findPrebuiltWorkspaceByCommit ( commitContext . repository . cloneUrl , parent ) ;
66+ if ( ! parentPrebuild ) {
67+ continue ;
68+ }
69+ if ( parentPrebuild . state !== 'available' ) {
70+ continue ;
71+ }
72+ log . debug ( `Considering parent prebuild for ${ commitContext . revision } ` , parentPrebuild ) ;
73+ const buildWorkspace = await this . db . trace ( { span} ) . findById ( parentPrebuild . buildWorkspaceId ) ;
74+ if ( ! buildWorkspace ) {
75+ continue ;
76+ }
77+ if ( ! ! buildWorkspace . basedOnPrebuildId ) {
78+ continue ;
79+ }
80+ if ( JSON . stringify ( imageSource ) !== JSON . stringify ( buildWorkspace . imageSource ) ) {
81+ log . debug ( `Skipping parent prebuild: Outdated image` , {
82+ imageSource,
83+ parentImageSource : buildWorkspace . imageSource ,
84+ } ) ;
85+ continue ;
86+ }
87+ const filterPrebuildTasks = ( tasks : TaskConfig [ ] = [ ] ) => ( tasks
88+ . map ( task => Object . keys ( task )
89+ . filter ( key => [ 'before' , 'init' , 'prebuild' ] . includes ( key ) )
90+ // @ts -ignore
91+ . reduce ( ( obj , key ) => ( { ...obj , [ key ] : task [ key ] } ) , { } ) )
92+ . filter ( task => Object . keys ( task ) . length > 0 ) ) ;
93+ const prebuildTasks = filterPrebuildTasks ( config . tasks ) ;
94+ const parentPrebuildTasks = filterPrebuildTasks ( buildWorkspace . config . tasks ) ;
95+ if ( JSON . stringify ( prebuildTasks ) !== JSON . stringify ( parentPrebuildTasks ) ) {
96+ log . debug ( `Skipping parent prebuild: Outdated prebuild tasks` , {
97+ prebuildTasks,
98+ parentPrebuildTasks,
99+ } ) ;
100+ continue ;
101+ }
102+ const incrementalPrebuildContext : PrebuiltWorkspaceContext = {
103+ title : `Incremental prebuild of "${ commitContext . title } "` ,
104+ originalContext : commitContext ,
105+ prebuiltWorkspace : parentPrebuild ,
106+ }
107+ ws = await this . createForPrebuiltWorkspace ( { span} , user , incrementalPrebuildContext , normalizedContextURL ) ;
108+ break ;
109+ }
110+
111+ if ( ! ws ) {
112+ // No suitable parent prebuild was found -- create a (fresh) full prebuild.
113+ ws = await this . createForCommit ( { span} , user , commitContext , normalizedContextURL ) ;
114+ }
60115 ws . type = "prebuild" ;
61116 ws = await this . db . trace ( { span} ) . store ( ws ) ;
62117
@@ -82,7 +137,7 @@ export class WorkspaceFactoryEE extends WorkspaceFactory {
82137
83138 protected async createForPrebuiltWorkspace ( ctx : TraceContext , user : User , context : PrebuiltWorkspaceContext , normalizedContextURL : string ) : Promise < Workspace > {
84139 this . requireEELicense ( Feature . FeaturePrebuild ) ;
85- const span = TraceContext . startSpan ( "createForStartPrebuild " , ctx ) ;
140+ const span = TraceContext . startSpan ( "createForPrebuiltWorkspace " , ctx ) ;
86141
87142 const fallback = await this . fallbackIfOutPrebuildTime ( ctx , user , context , normalizedContextURL ) ;
88143 if ( ! ! fallback ) {
0 commit comments