@@ -20,11 +20,13 @@ export interface TrackedPackageSpec {
2020 keep : number ;
2121}
2222
23+ export const CLI_PACKAGE = "nativescript" ;
24+
2325export const TRACKED_PACKAGES : TrackedPackageSpec [ ] = [
2426 { name : "@nativescript/ios" , toolchains : [ "xcode" , "cocoapods" ] , keep : 12 } ,
2527 { name : "@nativescript/android" , toolchains : [ "compileSdk" , "buildTools" , "jdk" ] , keep : 12 } ,
2628 { name : "@nativescript/visionos" , toolchains : [ "xcode" ] , keep : 6 } ,
27- { name : "nativescript" , toolchains : [ "node" ] , keep : 8 } ,
29+ { name : CLI_PACKAGE , toolchains : [ "node" , "xcode" , "cocoapods" , "compileSdk" , "buildTools" , "jdk "] , keep : 8 } ,
2830] ;
2931
3032/**
@@ -167,90 +169,102 @@ export function classify(entry: VerificationResult): ResultClass {
167169 return ( entry . attempts ?? 1 ) >= 2 ? "confirmed" : "suspect" ;
168170}
169171
172+ interface PinnedBuild {
173+ package : string ;
174+ version : string ;
175+ toolchains : Partial < Record < ToolchainKey , string > > ;
176+ /** The other package the build pinned: the CLI for a runtime, the runtime for the CLI. */
177+ companion : { package : string ; version : string } ;
178+ outcome : ResultClass ;
179+ }
180+
170181/**
171- * A successful result proves every toolchain it pinned for the runtime it
172- * built, and the Node.js major for the CLI it built with. A failure only
173- * speaks about the runtime's toolchains .
182+ * One CI build pins a runtime release and a CLI release together, so it is
183+ * evidence about both: each toolchain for the runtime, and each toolchain plus
184+ * the Node.js major for the CLI .
174185 */
186+ function pinnedBuilds ( entry : VerificationResult ) : PinnedBuild [ ] {
187+ const outcome = classify ( entry ) ;
188+ const runtime = { package : entry . package , version : entry . version } ;
189+ const cli = { package : CLI_PACKAGE , version : entry . with . nativescript } ;
190+ return [
191+ { ...runtime , toolchains : entry . toolchains , companion : cli , outcome } ,
192+ { ...cli , toolchains : { ...entry . toolchains , node : entry . with . node } , companion : runtime , outcome } ,
193+ ] ;
194+ }
195+
175196export function verifiedPairs (
176197 verified : VerificationResult [ ] ,
177198 outcome : ResultClass = "success" ,
178199) : Array < { package : string ; version : string ; toolchain : ToolchainKey ; toolchainVersion : string } > {
179200 return verified
180- . filter ( ( entry ) => classify ( entry ) === outcome )
181- . flatMap ( ( entry ) => [
182- ...Object . entries ( entry . toolchains ) . map ( ( [ toolchain , toolchainVersion ] ) => ( {
183- package : entry . package ,
184- version : entry . version ,
185- toolchain : toolchain as ToolchainKey ,
186- toolchainVersion : toolchainVersion ! ,
201+ . flatMap ( pinnedBuilds )
202+ . filter ( ( build ) => build . outcome === outcome )
203+ . flatMap ( ( build ) =>
204+ ( Object . entries ( build . toolchains ) as Array < [ ToolchainKey , string ] > ) . map ( ( [ toolchain , toolchainVersion ] ) => ( {
205+ package : build . package ,
206+ version : build . version ,
207+ toolchain,
208+ toolchainVersion,
187209 } ) ) ,
188- // A failed runtime build says nothing about the CLI's Node.js support.
189- ...( outcome === "success"
190- ? [
191- {
192- package : "nativescript" ,
193- version : entry . with . nativescript ,
194- toolchain : "node" as ToolchainKey ,
195- toolchainVersion : entry . with . node ,
196- } ,
197- ]
198- : [ ] ) ,
199- ] ) ;
210+ ) ;
211+ }
212+
213+ interface Pin {
214+ key : string ;
215+ version : string ;
216+ /** Companion-package pins take part in blame but are never reported as a toolchain. */
217+ toolchain : boolean ;
200218}
201219
202220/**
203- * A failed build pins several toolchains at once and cannot say which one is
204- * to blame. A failure therefore implicates only toolchain versions that no
205- * successful build of the same release used, and once one of its pinned
206- * versions is the sole suspect of another failure, that version explains the
207- * failure and the rest stay unjudged.
221+ * A failed build pins several things at once and cannot say which one is to
222+ * blame: its toolchains and the other package it was built with. A failure
223+ * therefore implicates only pins that no successful build of the same release
224+ * used, and once one of its pins is the sole suspect of another failure, that
225+ * pin explains the failure and the rest stay unjudged. A failure whose only
226+ * suspect is the companion package says nothing about any toolchain.
208227 */
209228function verifiedFor (
210229 packageName : string ,
211230 version : string ,
212231 verified : VerificationResult [ ] ,
213232 outcome : ResultClass ,
214233) : VersionCompatibility [ "verified" ] {
215- const forThisVersion = ( entries : VerificationResult [ ] ) =>
216- entries . filter ( ( entry ) => entry . package === packageName && entry . version === version ) ;
217- const successes = forThisVersion ( verified ) . filter ( ( entry ) => classify ( entry ) === "success" ) ;
218- const provenToWork = ( toolchain : ToolchainKey , toolchainVersion : string ) =>
219- successes . some ( ( ok ) => {
220- const okVersion = ok . toolchains [ toolchain as Exclude < ToolchainKey , "node" > ] ;
221- return okVersion !== undefined && sameLine ( okVersion , toolchainVersion ) ;
222- } ) ;
234+ const builds = verified
235+ . flatMap ( pinnedBuilds )
236+ . filter ( ( build ) => build . package === packageName && build . version === version ) ;
237+ const successes = builds . filter ( ( build ) => build . outcome === "success" ) ;
238+ const pinsOf = ( build : PinnedBuild ) : Pin [ ] => [
239+ ...Object . entries ( build . toolchains ) . map ( ( [ key , pinned ] ) => ( { key, version : pinned ! , toolchain : true } ) ) ,
240+ { key : build . companion . package , version : build . companion . version , toolchain : false } ,
241+ ] ;
242+ const samePin = ( a : Pin , b : Pin ) => a . key === b . key && ( a . toolchain ? sameLine ( a . version , b . version ) : a . version === b . version ) ;
243+ const provenToWork = ( pin : Pin ) => successes . some ( ( ok ) => pinsOf ( ok ) . some ( ( used ) => samePin ( used , pin ) ) ) ;
223244
224245 const result : VersionCompatibility [ "verified" ] = { } ;
225- const add = ( toolchain : ToolchainKey , toolchainVersion : string ) => {
226- const list = ( result [ toolchain ] ??= [ ] ) ;
227- if ( ! list . includes ( toolchainVersion ) ) {
228- list . push ( toolchainVersion ) ;
246+ const add = ( pin : Pin ) => {
247+ if ( ! pin . toolchain ) {
248+ return ;
249+ }
250+ const list = ( result [ pin . key as ToolchainKey ] ??= [ ] ) ;
251+ if ( ! list . includes ( pin . version ) ) {
252+ list . push ( pin . version ) ;
229253 }
230254 } ;
231255
232256 if ( outcome === "success" ) {
233- for ( const pair of verifiedPairs ( verified , "success" ) ) {
234- if ( pair . package === packageName && pair . version === version ) {
235- add ( pair . toolchain , pair . toolchainVersion ) ;
236- }
257+ for ( const ok of successes ) {
258+ pinsOf ( ok ) . forEach ( add ) ;
237259 }
238260 } else {
239- const suspects = forThisVersion ( verified )
240- . filter ( ( entry ) => classify ( entry ) === outcome )
241- . map ( ( entry ) =>
242- ( Object . entries ( entry . toolchains ) as Array < [ ToolchainKey , string ] > ) . filter (
243- ( [ toolchain , toolchainVersion ] ) => ! provenToWork ( toolchain , toolchainVersion ) ,
244- ) ,
245- ) ;
261+ const suspects = builds
262+ . filter ( ( build ) => build . outcome === outcome )
263+ . map ( ( build ) => pinsOf ( build ) . filter ( ( pin ) => ! provenToWork ( pin ) ) ) ;
246264 const culprits = suspects . filter ( ( pins ) => pins . length === 1 ) . map ( ( [ pin ] ) => pin ) ;
247265 for ( const pins of suspects ) {
248- const explained = culprits . find ( ( [ toolchain , toolchainVersion ] ) =>
249- pins . some ( ( [ key , value ] ) => key === toolchain && sameLine ( value , toolchainVersion ) ) ,
250- ) ;
251- for ( const [ toolchain , toolchainVersion ] of explained ? [ explained ] : pins ) {
252- add ( toolchain , toolchainVersion ) ;
253- }
266+ const explained = culprits . find ( ( culprit ) => pins . some ( ( pin ) => samePin ( pin , culprit ) ) ) ;
267+ ( explained ? [ explained ] : pins ) . forEach ( add ) ;
254268 }
255269 }
256270
0 commit comments