@@ -21,8 +21,8 @@ import * as core from '@actions/core';
21
21
import { Manifest } from './types/oci/manifest' ;
22
22
import * as tc from '@actions/tool-cache' ;
23
23
import fs from 'fs' ;
24
- import { MEDIATYPE_IMAGE_INDEX_V1 , MEDIATYPE_IMAGE_MANIFEST_V1 } from './types/oci/mediatype' ;
25
- import { MEDIATYPE_IMAGE_MANIFEST_V2 , MEDIATYPE_IMAGE_MANIFEST_LIST_V2 } from './types/docker/mediatype' ;
24
+ import { MEDIATYPE_IMAGE_CONFIG_V1 , MEDIATYPE_IMAGE_INDEX_V1 , MEDIATYPE_IMAGE_MANIFEST_V1 } from './types/oci/mediatype' ;
25
+ import { MEDIATYPE_IMAGE_CONFIG_V1 as DOCKER_MEDIATYPE_IMAGE_CONFIG_V1 , MEDIATYPE_IMAGE_MANIFEST_LIST_V2 , MEDIATYPE_IMAGE_MANIFEST_V2 } from './types/docker/mediatype' ;
26
26
import { DockerHub } from './dockerhub' ;
27
27
28
28
export class HubRepository {
@@ -40,15 +40,20 @@ export class HubRepository {
40
40
return new HubRepository ( repository , token ) ;
41
41
}
42
42
43
- // Unpacks the image layers and returns the path to the extracted image.
44
- // Only OCI indexes/manifest list are supported for now.
45
- public async extractImage ( tag : string , destDir ?: string ) : Promise < string > {
46
- const index = await this . getManifest < Index > ( tag ) ;
43
+ public async getPlatformManifest ( tagOrDigest : string , os ?: string ) : Promise < Manifest > {
44
+ const index = await this . getManifest < Index > ( tagOrDigest ) ;
47
45
if ( index . mediaType != MEDIATYPE_IMAGE_INDEX_V1 && index . mediaType != MEDIATYPE_IMAGE_MANIFEST_LIST_V2 ) {
46
+ core . error ( `Unsupported image media type: ${ index . mediaType } ` ) ;
48
47
throw new Error ( `Unsupported image media type: ${ index . mediaType } ` ) ;
49
48
}
50
- const digest = HubRepository . getPlatformManifestDigest ( index ) ;
51
- const manifest = await this . getManifest < Manifest > ( digest ) ;
49
+ const digest = HubRepository . getPlatformManifestDigest ( index , os ) ;
50
+ return await this . getManifest < Manifest > ( digest ) ;
51
+ }
52
+
53
+ // Unpacks the image layers and returns the path to the extracted image.
54
+ // Only OCI indexes/manifest list are supported for now.
55
+ public async extractImage ( tag : string , destDir ?: string ) : Promise < string > {
56
+ const manifest = await this . getPlatformManifest ( tag ) ;
52
57
53
58
const paths = manifest . layers . map ( async layer => {
54
59
const url = this . blobUrl ( layer . digest ) ;
@@ -99,25 +104,35 @@ export class HubRepository {
99
104
}
100
105
101
106
public async getManifest < T > ( tagOrDigest : string ) : Promise < T > {
102
- const url = `https://registry-1.docker.io/v2/${ this . repo } /manifests/${ tagOrDigest } ` ;
107
+ return await this . registryGet < T > ( tagOrDigest , 'manifests' , [ MEDIATYPE_IMAGE_INDEX_V1 , MEDIATYPE_IMAGE_MANIFEST_LIST_V2 , MEDIATYPE_IMAGE_MANIFEST_V1 , MEDIATYPE_IMAGE_MANIFEST_V2 ] ) ;
108
+ }
109
+
110
+ public async getJSONBlob < T > ( tagOrDigest : string ) : Promise < T > {
111
+ return await this . registryGet < T > ( tagOrDigest , 'blobs' , [ MEDIATYPE_IMAGE_CONFIG_V1 , DOCKER_MEDIATYPE_IMAGE_CONFIG_V1 ] ) ;
112
+ }
113
+
114
+ private async registryGet < T > ( tagOrDigest : string , endpoint : 'manifests' | 'blobs' , accept : Array < string > ) : Promise < T > {
115
+ const url = `https://registry-1.docker.io/v2/${ this . repo } /${ endpoint } /${ tagOrDigest } ` ;
103
116
104
117
const headers = {
105
118
Authorization : `Bearer ${ this . token } ` ,
106
- Accept : [ MEDIATYPE_IMAGE_INDEX_V1 , MEDIATYPE_IMAGE_MANIFEST_LIST_V2 , MEDIATYPE_IMAGE_MANIFEST_V1 , MEDIATYPE_IMAGE_MANIFEST_V2 ] . join ( ', ' )
119
+ Accept : accept . join ( ', ' )
107
120
} ;
121
+
108
122
const resp = await HubRepository . http . get ( url , headers ) ;
109
123
const body = await resp . readBody ( ) ;
110
124
const statusCode = resp . message . statusCode || 500 ;
111
125
if ( statusCode != 200 ) {
126
+ core . error ( `registryGet(${ this . repo } :${ tagOrDigest } ) failed: ${ statusCode } ${ body } ` ) ;
112
127
throw DockerHub . parseError ( resp , body ) ;
113
128
}
114
129
115
130
return < T > JSON . parse ( body ) ;
116
131
}
117
132
118
- private static getPlatformManifestDigest ( index : Index ) : string {
133
+ private static getPlatformManifestDigest ( index : Index , osOverride ?: string ) : string {
119
134
// This doesn't handle all possible platforms normalizations, but it's good enough for now.
120
- let pos : string = os . platform ( ) ;
135
+ let pos : string = osOverride || os . platform ( ) ;
121
136
if ( pos == 'win32' ) {
122
137
pos = 'windows' ;
123
138
}
@@ -150,8 +165,10 @@ export class HubRepository {
150
165
return true ;
151
166
} ) ;
152
167
if ( ! manifest ) {
168
+ core . error ( `Cannot find manifest for ${ pos } /${ arch } /${ variant } ` ) ;
153
169
throw new Error ( `Cannot find manifest for ${ pos } /${ arch } /${ variant } ` ) ;
154
170
}
171
+
155
172
return manifest . digest ;
156
173
}
157
174
}
0 commit comments