@@ -21,8 +21,8 @@ import * as core from '@actions/core';
2121import { Manifest } from './types/oci/manifest' ;
2222import * as tc from '@actions/tool-cache' ;
2323import 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' ;
2626import { DockerHub } from './dockerhub' ;
2727
2828export class HubRepository {
@@ -40,15 +40,20 @@ export class HubRepository {
4040 return new HubRepository ( repository , token ) ;
4141 }
4242
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 ) ;
4745 if ( index . mediaType != MEDIATYPE_IMAGE_INDEX_V1 && index . mediaType != MEDIATYPE_IMAGE_MANIFEST_LIST_V2 ) {
46+ core . error ( `Unsupported image media type: ${ index . mediaType } ` ) ;
4847 throw new Error ( `Unsupported image media type: ${ index . mediaType } ` ) ;
4948 }
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 ) ;
5257
5358 const paths = manifest . layers . map ( async layer => {
5459 const url = this . blobUrl ( layer . digest ) ;
@@ -99,25 +104,35 @@ export class HubRepository {
99104 }
100105
101106 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 } ` ;
103116
104117 const headers = {
105118 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 ( ', ' )
107120 } ;
121+
108122 const resp = await HubRepository . http . get ( url , headers ) ;
109123 const body = await resp . readBody ( ) ;
110124 const statusCode = resp . message . statusCode || 500 ;
111125 if ( statusCode != 200 ) {
126+ core . error ( `registryGet(${ this . repo } :${ tagOrDigest } ) failed: ${ statusCode } ${ body } ` ) ;
112127 throw DockerHub . parseError ( resp , body ) ;
113128 }
114129
115130 return < T > JSON . parse ( body ) ;
116131 }
117132
118- private static getPlatformManifestDigest ( index : Index ) : string {
133+ private static getPlatformManifestDigest ( index : Index , osOverride ?: string ) : string {
119134 // 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 ( ) ;
121136 if ( pos == 'win32' ) {
122137 pos = 'windows' ;
123138 }
@@ -150,8 +165,10 @@ export class HubRepository {
150165 return true ;
151166 } ) ;
152167 if ( ! manifest ) {
168+ core . error ( `Cannot find manifest for ${ pos } /${ arch } /${ variant } ` ) ;
153169 throw new Error ( `Cannot find manifest for ${ pos } /${ arch } /${ variant } ` ) ;
154170 }
171+
155172 return manifest . digest ;
156173 }
157174}
0 commit comments