Skip to content

Commit 6c6aebf

Browse files
authored
publish Templates with metadata attached to manifest (#865)
1 parent 0ab3f98 commit 6c6aebf

File tree

3 files changed

+13
-7
lines changed

3 files changed

+13
-7
lines changed

src/spec-configuration/containerCollectionsOCIPush.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { requestEnsureAuthenticated } from './httpOCIRegistry';
1111
// Devcontainer Spec (features) : https://containers.dev/implementors/features-distribution/#oci-registry
1212
// Devcontainer Spec (templates): https://github.com/devcontainers/spec/blob/main/proposals/devcontainer-templates-distribution.md#oci-registry
1313
// OCI Spec : https://github.com/opencontainers/distribution-spec/blob/main/spec.md#push
14-
export async function pushOCIFeatureOrTemplate(params: CommonParams, ociRef: OCIRef, pathToTgz: string, tags: string[], collectionType: string, featureAnnotations = {}): Promise<string | undefined> {
14+
export async function pushOCIFeatureOrTemplate(params: CommonParams, ociRef: OCIRef, pathToTgz: string, tags: string[], collectionType: string, annotations: { [key: string]: string } = {}): Promise<string | undefined> {
1515
const { output } = params;
1616

1717
output.write(`-- Starting push of ${collectionType} '${ociRef.id}' to '${ociRef.resource}' with tags '${tags.join(', ')}'`);
@@ -25,7 +25,7 @@ export async function pushOCIFeatureOrTemplate(params: CommonParams, ociRef: OCI
2525
const dataBytes = fs.readFileSync(pathToTgz);
2626

2727
// Generate Manifest for given feature/template artifact.
28-
const manifest = await generateCompleteManifestForIndividualFeatureOrTemplate(output, dataBytes, pathToTgz, ociRef, collectionType, featureAnnotations);
28+
const manifest = await generateCompleteManifestForIndividualFeatureOrTemplate(output, dataBytes, pathToTgz, ociRef, collectionType, annotations);
2929
if (!manifest) {
3030
output.write(`Failed to generate manifest for ${ociRef.id}`, LogLevel.Error);
3131
return;
@@ -268,14 +268,13 @@ async function putBlob(params: CommonParams, blobPutLocationUriPath: string, oci
268268
// Generate a layer that follows the `application/vnd.devcontainers.layer.v1+tar` mediaType as defined in
269269
// Devcontainer Spec (features) : https://containers.dev/implementors/features-distribution/#oci-registry
270270
// Devcontainer Spec (templates): https://github.com/devcontainers/spec/blob/main/proposals/devcontainer-templates-distribution.md#oci-registry
271-
async function generateCompleteManifestForIndividualFeatureOrTemplate(output: Log, dataBytes: Buffer, pathToTgz: string, ociRef: OCIRef, collectionType: string, featureAnnotations = {}): Promise<ManifestContainer | undefined> {
271+
async function generateCompleteManifestForIndividualFeatureOrTemplate(output: Log, dataBytes: Buffer, pathToTgz: string, ociRef: OCIRef, collectionType: string, annotations: { [key: string]: string } = {}): Promise<ManifestContainer | undefined> {
272272
const tgzLayer = await calculateDataLayer(output, dataBytes, path.basename(pathToTgz), DEVCONTAINER_TAR_LAYER_MEDIATYPE);
273273
if (!tgzLayer) {
274274
output.write(`Failed to calculate tgz layer.`, LogLevel.Error);
275275
return undefined;
276276
}
277277

278-
let annotations: { [key: string]: string } = featureAnnotations;
279278
// Specific registries look for certain optional metadata
280279
// in the manifest, in this case for UI presentation.
281280
if (ociRef.registry === 'ghcr.io') {

src/spec-node/collectionCommonUtils/publishCommandImpl.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export function getSemanticTags(version: string, tags: string[], output: Log) {
3939
return semanticVersions;
4040
}
4141

42-
export async function doPublishCommand(params: CommonParams, version: string, ociRef: OCIRef, outputDir: string, collectionType: string, archiveName: string, featureAnnotations = {}) {
42+
export async function doPublishCommand(params: CommonParams, version: string, ociRef: OCIRef, outputDir: string, collectionType: string, archiveName: string, annotations: { [key: string]: string } = {}) {
4343
const { output } = params;
4444

4545
output.write(`Fetching published versions...`, LogLevel.Info);
@@ -54,7 +54,7 @@ export async function doPublishCommand(params: CommonParams, version: string, oc
5454
if (!!semanticTags) {
5555
output.write(`Publishing tags: ${semanticTags.toString()}...`, LogLevel.Info);
5656
const pathToTgz = path.join(outputDir, archiveName);
57-
const digest = await pushOCIFeatureOrTemplate(params, ociRef, pathToTgz, semanticTags, collectionType, featureAnnotations);
57+
const digest = await pushOCIFeatureOrTemplate(params, ociRef, pathToTgz, semanticTags, collectionType, annotations);
5858
if (!digest) {
5959
output.write(`(!) ERR: Failed to publish ${collectionType}: '${ociRef.resource}'`, LogLevel.Error);
6060
return;

src/spec-node/templatesCLI/publish.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,14 @@ async function templatesPublish({
8888
}
8989

9090
const archiveName = getArchiveName(t.id, collectionType);
91-
const publishResult = await doPublishCommand(params, t.version, templateRef, outputDir, collectionType, archiveName);
91+
92+
// Properties here are available on the manifest without needing to download the full Template archive.
93+
const templateAnnotations = {
94+
'dev.containers.metadata': JSON.stringify(t),
95+
};
96+
output.write(`Template Annotations: ${JSON.stringify(templateAnnotations)}`, LogLevel.Debug);
97+
98+
const publishResult = await doPublishCommand(params, t.version, templateRef, outputDir, collectionType, archiveName, templateAnnotations);
9299
if (!publishResult) {
93100
output.write(`(!) ERR: Failed to publish '${resource}'`, LogLevel.Error);
94101
process.exit(1);

0 commit comments

Comments
 (0)