Skip to content

Commit

Permalink
publish Templates with metadata attached to manifest
Browse files Browse the repository at this point in the history
  • Loading branch information
joshspicer authored Jul 31, 2024
1 parent 0ab3f98 commit ae6907e
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 7 deletions.
7 changes: 3 additions & 4 deletions src/spec-configuration/containerCollectionsOCIPush.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { requestEnsureAuthenticated } from './httpOCIRegistry';
// Devcontainer Spec (features) : https://containers.dev/implementors/features-distribution/#oci-registry
// Devcontainer Spec (templates): https://github.com/devcontainers/spec/blob/main/proposals/devcontainer-templates-distribution.md#oci-registry
// OCI Spec : https://github.com/opencontainers/distribution-spec/blob/main/spec.md#push
export async function pushOCIFeatureOrTemplate(params: CommonParams, ociRef: OCIRef, pathToTgz: string, tags: string[], collectionType: string, featureAnnotations = {}): Promise<string | undefined> {
export async function pushOCIFeatureOrTemplate(params: CommonParams, ociRef: OCIRef, pathToTgz: string, tags: string[], collectionType: string, annotations: { [key: string]: string } = {}): Promise<string | undefined> {
const { output } = params;

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

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

let annotations: { [key: string]: string } = featureAnnotations;
// Specific registries look for certain optional metadata
// in the manifest, in this case for UI presentation.
if (ociRef.registry === 'ghcr.io') {
Expand Down
4 changes: 2 additions & 2 deletions src/spec-node/collectionCommonUtils/publishCommandImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function getSemanticTags(version: string, tags: string[], output: Log) {
return semanticVersions;
}

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

output.write(`Fetching published versions...`, LogLevel.Info);
Expand All @@ -54,7 +54,7 @@ export async function doPublishCommand(params: CommonParams, version: string, oc
if (!!semanticTags) {
output.write(`Publishing tags: ${semanticTags.toString()}...`, LogLevel.Info);
const pathToTgz = path.join(outputDir, archiveName);
const digest = await pushOCIFeatureOrTemplate(params, ociRef, pathToTgz, semanticTags, collectionType, featureAnnotations);
const digest = await pushOCIFeatureOrTemplate(params, ociRef, pathToTgz, semanticTags, collectionType, annotations);
if (!digest) {
output.write(`(!) ERR: Failed to publish ${collectionType}: '${ociRef.resource}'`, LogLevel.Error);
return;
Expand Down
9 changes: 8 additions & 1 deletion src/spec-node/templatesCLI/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,14 @@ async function templatesPublish({
}

const archiveName = getArchiveName(t.id, collectionType);
const publishResult = await doPublishCommand(params, t.version, templateRef, outputDir, collectionType, archiveName);

// Properties here are available on the manifest without needing to download the full Template archive.
const templateAnnotations = {
'dev.containers.metadata': JSON.stringify(t),
};
output.write(`Template Annotations: ${JSON.stringify(templateAnnotations)}`, LogLevel.Debug);

const publishResult = await doPublishCommand(params, t.version, templateRef, outputDir, collectionType, archiveName, templateAnnotations);
if (!publishResult) {
output.write(`(!) ERR: Failed to publish '${resource}'`, LogLevel.Error);
process.exit(1);
Expand Down

0 comments on commit ae6907e

Please sign in to comment.