@@ -173,32 +173,13 @@ public override FindResults FindName(string packageName, bool includePrerelease,
173
173
return new FindResults ( stringResponse : new string [ ] { } , hashtableResponse : emptyHashResponses , responseType : acrFindResponseType ) ;
174
174
}
175
175
176
- /* response returned looks something like:
177
- * "registry": "myregistry.azurecr.io"
178
- * "imageName": "hello-world"
179
- * "tags": [
180
- * {
181
- * ""name"": ""1.0.0"",
182
- * ""digest"": ""sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a"",
183
- * ""createdTime"": ""2023-12-23T18:06:48.9975733Z"",
184
- * ""lastUpdateTime"": ""2023-12-23T18:06:48.9975733Z"",
185
- * ""signed"": false,
186
- * ""changeableAttributes"": {
187
- * ""deleteEnabled"": true,
188
- * ""writeEnabled"": true,
189
- * ""readEnabled"": true,
190
- * ""listEnabled"": true
191
- * }
192
- * }]
193
- */
194
176
List < Hashtable > latestVersionResponse = new List < Hashtable > ( ) ;
195
177
List < JToken > allVersionsList = foundTags [ "tags" ] . ToList ( ) ;
196
178
allVersionsList . Reverse ( ) ;
197
179
198
- foreach ( var packageVersion in allVersionsList )
180
+ foreach ( var pkgVersionTagInfo in allVersionsList )
199
181
{
200
- var packageVersionStr = packageVersion . ToString ( ) ;
201
- using ( JsonDocument pkgVersionEntry = JsonDocument . Parse ( packageVersionStr ) )
182
+ using ( JsonDocument pkgVersionEntry = JsonDocument . Parse ( pkgVersionTagInfo . ToString ( ) ) )
202
183
{
203
184
JsonElement rootDom = pkgVersionEntry . RootElement ;
204
185
if ( ! rootDom . TryGetProperty ( "name" , out JsonElement pkgVersionElement ) )
@@ -218,7 +199,11 @@ public override FindResults FindName(string packageName, bool includePrerelease,
218
199
if ( ! pkgVersion . IsPrerelease || includePrerelease )
219
200
{
220
201
// Versions are always in descending order i.e 5.0.0, 3.0.0, 1.0.0 so grabbing the first match suffices
221
- latestVersionResponse . Add ( new Hashtable ( ) { { packageName , packageVersionStr } } ) ;
202
+ latestVersionResponse . Add ( GetACRMetadata ( registry , packageName , pkgVersion , acrAccessToken , out errRecord ) ) ;
203
+ if ( errRecord != null )
204
+ {
205
+ return new FindResults ( stringResponse : new string [ ] { } , hashtableResponse : latestVersionResponse . ToArray ( ) , responseType : acrFindResponseType ) ;
206
+ }
222
207
223
208
break ;
224
209
}
@@ -339,26 +324,9 @@ public override FindResults FindVersionGlobbing(string packageName, VersionRange
339
324
return new FindResults ( stringResponse : new string [ ] { } , hashtableResponse : emptyHashResponses , responseType : acrFindResponseType ) ;
340
325
}
341
326
342
- /* response returned looks something like:
343
- * "registry": "myregistry.azurecr.io"
344
- * "imageName": "hello-world"
345
- * "tags": [
346
- * {
347
- * ""name"": ""1.0.0"",
348
- * ""digest"": ""sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a"",
349
- * ""createdTime"": ""2023-12-23T18:06:48.9975733Z"",
350
- * ""lastUpdateTime"": ""2023-12-23T18:06:48.9975733Z"",
351
- * ""signed"": false,
352
- * ""changeableAttributes"": {
353
- * ""deleteEnabled"": true,
354
- * ""writeEnabled"": true,
355
- * ""readEnabled"": true,
356
- * ""listEnabled"": true
357
- * }
358
- * }]
359
- */
360
327
List < Hashtable > latestVersionResponse = new List < Hashtable > ( ) ;
361
328
List < JToken > allVersionsList = foundTags [ "tags" ] . ToList ( ) ;
329
+ allVersionsList . Reverse ( ) ;
362
330
foreach ( var packageVersion in allVersionsList )
363
331
{
364
332
var packageVersionStr = packageVersion . ToString ( ) ;
@@ -387,7 +355,11 @@ public override FindResults FindVersionGlobbing(string packageName, VersionRange
387
355
continue ;
388
356
}
389
357
390
- latestVersionResponse . Add ( new Hashtable ( ) { { packageName , packageVersionStr } } ) ;
358
+ latestVersionResponse . Add ( GetACRMetadata ( registry , packageName , pkgVersion , acrAccessToken , out errRecord ) ) ;
359
+ if ( errRecord != null )
360
+ {
361
+ return new FindResults ( stringResponse : new string [ ] { } , hashtableResponse : latestVersionResponse . ToArray ( ) , responseType : acrFindResponseType ) ;
362
+ }
391
363
}
392
364
}
393
365
}
@@ -453,59 +425,17 @@ public override FindResults FindVersion(string packageName, string version, Reso
453
425
}
454
426
455
427
_cmdletPassedIn . WriteVerbose ( "Getting tags" ) ;
456
- var foundTags = FindAcrImageTags ( registry , packageName , requiredVersion . ToString ( ) , acrAccessToken , out errRecord ) ;
457
- if ( errRecord != null || foundTags == null )
428
+ List < Hashtable > results = new List < Hashtable >
458
429
{
459
- return new FindResults ( stringResponse : new string [ ] { } , hashtableResponse : emptyHashResponses , responseType : acrFindResponseType ) ;
460
- }
461
-
462
- /* response returned looks something like:
463
- * "registry": "myregistry.azurecr.io"
464
- * "imageName": "hello-world"
465
- * "tags": [
466
- * {
467
- * ""name"": ""1.0.0"",
468
- * ""digest"": ""sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a"",
469
- * ""createdTime"": ""2023-12-23T18:06:48.9975733Z"",
470
- * ""lastUpdateTime"": ""2023-12-23T18:06:48.9975733Z"",
471
- * ""signed"": false,
472
- * ""changeableAttributes"": {
473
- * ""deleteEnabled"": true,
474
- * ""writeEnabled"": true,
475
- * ""readEnabled"": true,
476
- * ""listEnabled"": true
477
- * }
478
- * }]
479
- */
480
- List < Hashtable > requiredVersionResponse = new List < Hashtable > ( ) ;
481
-
482
- var packageVersionStr = foundTags [ "tag" ] . ToString ( ) ;
483
- using ( JsonDocument pkgVersionEntry = JsonDocument . Parse ( packageVersionStr ) )
430
+ GetACRMetadata ( registry , packageName , requiredVersion , acrAccessToken , out errRecord )
431
+ } ;
432
+ if ( errRecord != null )
484
433
{
485
- JsonElement rootDom = pkgVersionEntry . RootElement ;
486
- if ( ! rootDom . TryGetProperty ( "name" , out JsonElement pkgVersionElement ) )
487
- {
488
- errRecord = new ErrorRecord (
489
- new InvalidOrEmptyResponse ( $ "Response does not contain version element ('name') for package '{ packageName } ' in '{ Repository . Name } '.") ,
490
- "FindNameFailure" ,
491
- ErrorCategory . InvalidResult ,
492
- this ) ;
493
-
494
- return new FindResults ( stringResponse : Utils . EmptyStrArray , hashtableResponse : emptyHashResponses , responseType : acrFindResponseType ) ;
495
- }
496
-
497
- if ( NuGetVersion . TryParse ( pkgVersionElement . ToString ( ) , out NuGetVersion pkgVersion ) )
498
- {
499
- _cmdletPassedIn . WriteDebug ( $ "'{ packageName } ' version parsed as '{ pkgVersion } '") ;
500
-
501
- if ( pkgVersion == requiredVersion )
502
- {
503
- requiredVersionResponse . Add ( new Hashtable ( ) { { packageName , packageVersionStr } } ) ;
504
- }
505
- }
434
+ return new FindResults ( stringResponse : new string [ ] { } , hashtableResponse : results . ToArray ( ) , responseType : acrFindResponseType ) ;
506
435
}
507
436
508
- return new FindResults ( stringResponse : new string [ ] { } , hashtableResponse : requiredVersionResponse . ToArray ( ) , responseType : acrFindResponseType ) ;
437
+
438
+ return new FindResults ( stringResponse : new string [ ] { } , hashtableResponse : results . ToArray ( ) , responseType : acrFindResponseType ) ;
509
439
}
510
440
511
441
/// <summary>
@@ -709,6 +639,24 @@ internal async Task<HttpContent> GetAcrBlobAsync(string registry, string reposit
709
639
710
640
internal JObject FindAcrImageTags ( string registry , string repositoryName , string version , string acrAccessToken , out ErrorRecord errRecord )
711
641
{
642
+ /* response returned looks something like:
643
+ * "registry": "myregistry.azurecr.io"
644
+ * "imageName": "hello-world"
645
+ * "tags": [
646
+ * {
647
+ * ""name"": ""1.0.0"",
648
+ * ""digest"": ""sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a"",
649
+ * ""createdTime"": ""2023-12-23T18:06:48.9975733Z"",
650
+ * ""lastUpdateTime"": ""2023-12-23T18:06:48.9975733Z"",
651
+ * ""signed"": false,
652
+ * ""changeableAttributes"": {
653
+ * ""deleteEnabled"": true,
654
+ * ""writeEnabled"": true,
655
+ * ""readEnabled"": true,
656
+ * ""listEnabled"": true
657
+ * }
658
+ * }]
659
+ */
712
660
try
713
661
{
714
662
string resolvedVersion = string . Equals ( version , "*" , StringComparison . OrdinalIgnoreCase ) ? null : $ "/{ version } ";
@@ -722,6 +670,141 @@ internal JObject FindAcrImageTags(string registry, string repositoryName, string
722
670
}
723
671
}
724
672
673
+ internal Hashtable GetACRMetadata ( string registry , string packageName , NuGetVersion requiredVersion , string acrAccessToken , out ErrorRecord errRecord )
674
+ {
675
+ Hashtable requiredVersionResponse = new Hashtable ( ) ;
676
+
677
+ var foundTags = FindAcrManifest ( registry , packageName , requiredVersion . ToNormalizedString ( ) , acrAccessToken , out errRecord ) ;
678
+ if ( errRecord != null || foundTags == null )
679
+ {
680
+ return requiredVersionResponse ;
681
+ }
682
+
683
+ /* Response returned looks something like:
684
+ * {
685
+ * "schemaVersion": 2,
686
+ * "config": {
687
+ * "mediaType": "application/vnd.unknown.config.v1+json",
688
+ * "digest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
689
+ * "size": 0
690
+ * },
691
+ * "layers": [
692
+ * {
693
+ * "mediaType": "application/vnd.oci.image.layer.nondistributable.v1.tar+gzip'",
694
+ * "digest": "sha256:7c55c7b66cb075628660d8249cc4866f16e34741c246a42ed97fb23ccd4ea956",
695
+ * "size": 3533,
696
+ * "annotations": {
697
+ * "org.opencontainers.image.title": "test_module.1.0.0.nupkg",
698
+ * "metadata": "{\"GUID\":\"45219bf4-10a4-4242-92d6-9bfcf79878fd\",\"FunctionsToExport\":[],\"CompanyName\":\"Anam\",\"CmdletsToExport\":[],\"VariablesToExport\":\"*\",\"Author\":\"Anam Navied\",\"ModuleVersion\":\"1.0.0\",\"Copyright\":\"(c) Anam Navied. All rights reserved.\",\"PrivateData\":{\"PSData\":{\"Tags\":[\"Test\",\"CommandsAndResource\",\"Tag2\"]}},\"RequiredModules\":[],\"Description\":\"This is a test module, for PSGallery team internal testing. Do not take a dependency on this package. This version contains tags for the package.\",\"AliasesToExport\":[]}"
699
+ * }
700
+ * }
701
+ * ]
702
+ * }
703
+ */
704
+
705
+ Tuple < string , string > metadataTuple = GetMetadataProperty ( foundTags , packageName , out Exception exception ) ;
706
+ if ( exception != null )
707
+ {
708
+ errRecord = new ErrorRecord ( exception , "FindNameFailure" , ErrorCategory . InvalidResult , this ) ;
709
+
710
+ return requiredVersionResponse ;
711
+ }
712
+
713
+ string metadataPkgName = metadataTuple . Item1 ;
714
+ string metadata = metadataTuple . Item2 ;
715
+ using ( JsonDocument metadataJSONDoc = JsonDocument . Parse ( metadata ) )
716
+ {
717
+ JsonElement rootDom = metadataJSONDoc . RootElement ;
718
+ if ( ! rootDom . TryGetProperty ( "ModuleVersion" , out JsonElement pkgVersionElement ) &&
719
+ ! rootDom . TryGetProperty ( "Version" , out pkgVersionElement ) )
720
+ {
721
+ errRecord = new ErrorRecord (
722
+ new InvalidOrEmptyResponse ( $ "Response does not contain 'ModuleVersion' or 'Version' property in metadata for package '{ packageName } ' in '{ Repository . Name } '.") ,
723
+ "FindNameFailure" ,
724
+ ErrorCategory . InvalidResult ,
725
+ this ) ;
726
+
727
+ return requiredVersionResponse ;
728
+ }
729
+
730
+ if ( NuGetVersion . TryParse ( pkgVersionElement . ToString ( ) , out NuGetVersion pkgVersion ) )
731
+ {
732
+ _cmdletPassedIn . WriteDebug ( $ "'{ packageName } ' version parsed as '{ pkgVersion } '") ;
733
+
734
+ if ( pkgVersion == requiredVersion )
735
+ {
736
+ requiredVersionResponse . Add ( metadataPkgName , metadata ) ;
737
+ }
738
+ }
739
+ }
740
+
741
+ return requiredVersionResponse ;
742
+ }
743
+
744
+ internal Tuple < string , string > GetMetadataProperty ( JObject foundTags , string packageName , out Exception exception )
745
+ {
746
+ exception = null ;
747
+ var emptyTuple = new Tuple < string , string > ( string . Empty , string . Empty ) ;
748
+ var layers = foundTags [ "layers" ] ;
749
+ if ( layers == null || layers [ 0 ] == null )
750
+ {
751
+ exception = new InvalidOrEmptyResponse ( $ "Response does not contain 'layers' element in manifest for package '{ packageName } ' in '{ Repository . Name } '.") ;
752
+
753
+ return emptyTuple ;
754
+ }
755
+
756
+ var annotations = layers [ 0 ] [ "annotations" ] ;
757
+ if ( annotations == null )
758
+ {
759
+ exception = new InvalidOrEmptyResponse ( $ "Response does not contain 'annotations' element in manifest for package '{ packageName } ' in '{ Repository . Name } '.") ;
760
+
761
+ return emptyTuple ;
762
+ }
763
+
764
+ if ( annotations [ "metadata" ] == null )
765
+ {
766
+ exception = new InvalidOrEmptyResponse ( $ "Response does not contain 'metadata' element in manifest for package '{ packageName } ' in '{ Repository . Name } '.") ;
767
+
768
+ return emptyTuple ;
769
+ }
770
+
771
+ var metadata = annotations [ "metadata" ] . ToString ( ) ;
772
+
773
+ var metadataPkgNameJToken = annotations [ "packageName" ] ;
774
+ if ( metadataPkgNameJToken == null )
775
+ {
776
+ exception = new InvalidOrEmptyResponse ( $ "Response does not contain 'packageName' element for package '{ packageName } ' in '{ Repository . Name } '.") ;
777
+
778
+ return emptyTuple ;
779
+ }
780
+
781
+ string metadataPkgName = metadataPkgNameJToken . ToString ( ) ;
782
+ if ( string . IsNullOrWhiteSpace ( metadataPkgName ) )
783
+ {
784
+ exception = new InvalidOrEmptyResponse ( $ "Response element 'packageName' is empty for package '{ packageName } ' in '{ Repository . Name } '.") ;
785
+
786
+ return emptyTuple ;
787
+ }
788
+
789
+ return new Tuple < string , string > ( metadataPkgName , metadata ) ;
790
+ }
791
+
792
+ internal JObject FindAcrManifest ( string registry , string packageName , string version , string acrAccessToken , out ErrorRecord errRecord )
793
+ {
794
+ try
795
+ {
796
+ var createManifestUrl = string . Format ( acrManifestUrlTemplate , registry , packageName , version ) ;
797
+ _cmdletPassedIn . WriteDebug ( $ "GET manifest url: { createManifestUrl } ") ;
798
+
799
+ var defaultHeaders = GetDefaultHeaders ( acrAccessToken ) ;
800
+ return GetHttpResponseJObjectUsingDefaultHeaders ( createManifestUrl , HttpMethod . Get , defaultHeaders , out errRecord ) ;
801
+ }
802
+ catch ( HttpRequestException e )
803
+ {
804
+ throw new HttpRequestException ( "Error finding ACR manifest: " + e . Message ) ;
805
+ }
806
+ }
807
+
725
808
internal async Task < string > GetStartUploadBlobLocation ( string registry , string pkgName , string acrAccessToken )
726
809
{
727
810
try
@@ -1113,7 +1196,7 @@ internal bool PushNupkgACR(string psd1OrPs1File, string outputNupkgDir, string p
1113
1196
FileInfo nupkgFile = new FileInfo ( fullNupkgFile ) ;
1114
1197
var fileSize = nupkgFile . Length ;
1115
1198
var fileName = System . IO . Path . GetFileName ( fullNupkgFile ) ;
1116
- string fileContent = CreateJsonContent ( nupkgDigest , configDigest , fileSize , fileName , jsonString ) ;
1199
+ string fileContent = CreateJsonContent ( nupkgDigest , configDigest , fileSize , fileName , pkgName , jsonString ) ;
1117
1200
File . WriteAllText ( configFilePath , fileContent ) ;
1118
1201
1119
1202
_cmdletPassedIn . WriteVerbose ( "Create the manifest layer" ) ;
@@ -1130,7 +1213,8 @@ private string CreateJsonContent(
1130
1213
string nupkgDigest ,
1131
1214
string configDigest ,
1132
1215
long nupkgFileSize ,
1133
- string fileName ,
1216
+ string fileName ,
1217
+ string packageName ,
1134
1218
string jsonString )
1135
1219
{
1136
1220
StringBuilder stringBuilder = new StringBuilder ( ) ;
@@ -1167,6 +1251,8 @@ private string CreateJsonContent(
1167
1251
jsonWriter . WritePropertyName ( "annotations" ) ;
1168
1252
jsonWriter . WriteStartObject ( ) ;
1169
1253
jsonWriter . WritePropertyName ( "org.opencontainers.image.title" ) ;
1254
+ jsonWriter . WriteValue ( packageName ) ;
1255
+ jsonWriter . WritePropertyName ( "org.opencontainers.image.description" ) ;
1170
1256
jsonWriter . WriteValue ( fileName ) ;
1171
1257
jsonWriter . WritePropertyName ( "metadata" ) ;
1172
1258
jsonWriter . WriteValue ( jsonString ) ;
0 commit comments