@@ -16,37 +16,57 @@ public static class EnvironmentFlow
1616 return ( new Dictionary < string , string > ( ) , "none" ) ;
1717 }
1818
19+ /// <summary>
20+ /// Release stages and long-lived branches of the project with the code (the connection's code project, when the
21+ /// code lives elsewhere than the work items) and of <paramref name="project"/> itself.
22+ /// </summary>
1923 public static async Task < List < ( string Key , string ? Guess ) > > DetectAsync ( Session session , string project , CancellationToken ct )
2024 {
25+ var projects = new [ ] { session . Config . CodeProject , project } . Where ( p => ! string . IsNullOrWhiteSpace ( p ) ) . Select ( p => p ! )
26+ . Distinct ( StringComparer . OrdinalIgnoreCase ) . ToList ( ) ;
2127 var keys = new List < string > ( ) ;
22- foreach ( var d in await session . Code . DeploymentsAsync ( project , ct ) )
23- {
24- if ( d . When is not { } when || when < DateTime . UtcNow . AddDays ( - 183 ) ) continue ;
25- keys . Add ( d . Branch ? . StartsWith ( "$/" , StringComparison . Ordinal ) == true ? $ "{ d . Definition } /{ d . Stage } " : Code . Short ( d . Branch ) ?? $ "{ d . Definition } /{ d . Stage } ") ;
26- }
2728 // Long-lived branches of the repositories in use (a commit in the last half year); feature and work branches are
2829 // filtered by ProposeFlow. With several repositories each branch is named with its repository ("D365FO:staging"),
2930 // since the same branch name can mean different environments - or none - in different repositories.
30- try
31+ var active = new List < ( string Id , string Name ) > ( ) ;
32+ foreach ( var p in projects )
3133 {
32- var repos = await session . Client . GetListAsync ( $ "{ AdoClient . Scope ( project ) } _apis/git/repositories", ct ) ;
33- var active = new List < ( string Id , string Name ) > ( ) ;
34- foreach ( var repo in repos . Where ( r => ! Json . Bool ( r , "isDisabled" ) && r . TryGetProperty ( "size" , out var s ) && s . GetInt64 ( ) > 0 ) . Take ( 30 ) )
34+ try
3535 {
36- var id = Json . Str ( repo , "id" ) ?? "" ;
37- var last = await session . Client . GetListAsync ( $ "_apis/git/repositories/{ id } /commits?searchCriteria.$top=1", ct ) ;
38- if ( last . Count > 0 && DateTime . TryParse ( Json . Str ( Json . Obj ( last [ 0 ] , "committer" ) , "date" ) , System . Globalization . CultureInfo . InvariantCulture ,
39- System . Globalization . DateTimeStyles . AdjustToUniversal , out var when ) && when > DateTime . UtcNow . AddDays ( - 183 ) )
40- active . Add ( ( id , Json . Str ( repo , "name" ) ?? id ) ) ;
36+ var repos = await session . Client . GetListAsync ( $ "{ AdoClient . Scope ( p ) } _apis/git/repositories", ct ) ;
37+ foreach ( var repo in repos . Where ( r => ! Json . Bool ( r , "isDisabled" ) && r . TryGetProperty ( "size" , out var s ) && s . GetInt64 ( ) > 0 ) . Take ( 30 ) )
38+ {
39+ var id = Json . Str ( repo , "id" ) ?? "" ;
40+ var last = await session . Client . GetListAsync ( $ "_apis/git/repositories/{ id } /commits?searchCriteria.$top=1", ct ) ;
41+ if ( last . Count > 0 && DateTime . TryParse ( Json . Str ( Json . Obj ( last [ 0 ] , "committer" ) , "date" ) , System . Globalization . CultureInfo . InvariantCulture ,
42+ System . Globalization . DateTimeStyles . AdjustToUniversal , out var when ) && when > DateTime . UtcNow . AddDays ( - 183 ) )
43+ active . Add ( ( id , Json . Str ( repo , "name" ) ?? id ) ) ;
44+ }
4145 }
42- foreach ( var ( id , name ) in active )
46+ catch ( AdoApiException ) { } // no Git, or no Code (Read) scope
47+ }
48+ var several = active . Count > 1 ;
49+ foreach ( var ( id , name ) in active )
50+ {
51+ try
4352 {
4453 var refs = await session . Client . GetListAsync ( $ "_apis/git/repositories/{ id } /refs?filter=heads/&$top=200", ct ) ;
4554 keys . AddRange ( refs . Select ( r => Code . Short ( Json . Str ( r , "name" ) ) ?? "" ) . Where ( n => n . Length > 0 && ! n . Contains ( '/' ) )
46- . Select ( n => active . Count > 1 ? $ "{ name } :{ n } " : n ) ) ;
55+ . Select ( n => several ? $ "{ name } :{ n } " : n ) ) ;
4756 }
57+ catch ( AdoApiException ) { }
4858 }
49- catch ( AdoApiException ) { } // no Git, or no Code (Read) scope
59+ // Release stages deployed in the last half year; a Git stage is named by its branch (with its repository when
60+ // there are several), a TFVC one as "Definition/Stage".
61+ foreach ( var p in projects )
62+ foreach ( var d in await session . Code . DeploymentsAsync ( p , ct ) )
63+ {
64+ if ( d . When is not { } when || when < DateTime . UtcNow . AddDays ( - 183 ) ) continue ;
65+ var branch = Code . Short ( d . Branch ) ;
66+ var repo = active . FirstOrDefault ( a => string . Equals ( a . Id , d . Repository , StringComparison . OrdinalIgnoreCase ) ) . Name ;
67+ keys . Add ( d . Branch ? . StartsWith ( "$/" , StringComparison . Ordinal ) == true || branch is null ? $ "{ d . Definition } /{ d . Stage } "
68+ : several && repo is not null ? $ "{ repo } :{ branch } " : branch ) ;
69+ }
5070 return TraceQueries . ProposeFlow ( keys . Distinct ( StringComparer . OrdinalIgnoreCase ) ) ;
5171 }
5272}
0 commit comments