aboutsummaryrefslogtreecommitdiff
path: root/.github/devcontainers-action/lib/utils.js
diff options
context:
space:
mode:
authorJosh Spicer <joshspicer@github.com>2022-08-17 21:36:45 +0300
committerGitHub <noreply@github.com>2022-08-17 21:36:45 +0300
commit4ecc275a8d199cdce98cd462fee612d7f687efe4 (patch)
treef6084dfd933bfcde051a01858c15b7aa99d5c96e /.github/devcontainers-action/lib/utils.js
parentef87daf5af1de5d0031ad946f20e1601f1fb905e (diff)
update action to a82f06a29168a3c6594fb7206dd0afd3af8efdf2
Diffstat (limited to '.github/devcontainers-action/lib/utils.js')
-rw-r--r--.github/devcontainers-action/lib/utils.js300
1 files changed, 39 insertions, 261 deletions
diff --git a/.github/devcontainers-action/lib/utils.js b/.github/devcontainers-action/lib/utils.js
index 38f5604..f0885ce 100644
--- a/.github/devcontainers-action/lib/utils.js
+++ b/.github/devcontainers-action/lib/utils.js
@@ -31,42 +31,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
-var __importDefault = (this && this.__importDefault) || function (mod) {
- return (mod && mod.__esModule) ? mod : { "default": mod };
-};
Object.defineProperty(exports, "__esModule", { value: true });
-exports.getTemplatesAndPackage = exports.getFeaturesAndPackage = exports.pushCollectionsMetadataToOCI = exports.addCollectionsMetadataFile = exports.getGitHubMetadata = exports.tarDirectory = exports.renameLocal = exports.mkdirLocal = exports.writeLocalFile = exports.readLocalFile = void 0;
+exports.ensureDevcontainerCliPresent = exports.isDevcontainerCliAvailable = exports.getGitHubMetadata = exports.renameLocal = exports.mkdirLocal = exports.writeLocalFile = exports.readLocalFile = void 0;
const github = __importStar(require("@actions/github"));
-const tar = __importStar(require("tar"));
const fs = __importStar(require("fs"));
-const core = __importStar(require("@actions/core"));
-const child_process = __importStar(require("child_process"));
const util_1 = require("util");
-const path_1 = __importDefault(require("path"));
+const core = __importStar(require("@actions/core"));
+const exec = __importStar(require("@actions/exec"));
exports.readLocalFile = (0, util_1.promisify)(fs.readFile);
exports.writeLocalFile = (0, util_1.promisify)(fs.writeFile);
exports.mkdirLocal = (0, util_1.promisify)(fs.mkdir);
exports.renameLocal = (0, util_1.promisify)(fs.rename);
-// Filter what gets included in the tar.c
-const filter = (file, _) => {
- // Don't include the archive itself.
- if (file === './devcontainer-features.tgz') {
- return false;
- }
- return true;
-};
-function tarDirectory(path, tgzName) {
- return __awaiter(this, void 0, void 0, function* () {
- return tar.create({ file: tgzName, C: path, filter }, ['.']).then(_ => {
- core.info(`Compressed ${path} directory to file ${tgzName}`);
- });
- });
-}
-exports.tarDirectory = tarDirectory;
function getGitHubMetadata() {
// Insert github repo metadata
const ref = github.context.ref;
- let sourceInformation = {
+ let metadata = {
owner: github.context.repo.owner,
repo: github.context.repo.repo,
ref,
@@ -75,255 +54,54 @@ function getGitHubMetadata() {
// Add tag if parseable
if (ref.includes('refs/tags/')) {
const tag = ref.replace('refs/tags/', '');
- sourceInformation = Object.assign(Object.assign({}, sourceInformation), { tag });
+ metadata = Object.assign(Object.assign({}, metadata), { tag });
}
- return sourceInformation;
+ return metadata;
}
exports.getGitHubMetadata = getGitHubMetadata;
-function tagFeatureAtVersion(featureMetaData) {
- return __awaiter(this, void 0, void 0, function* () {
- const featureId = featureMetaData.id;
- const featureVersion = featureMetaData.version;
- const tagName = `${featureId}_v${featureVersion}`;
- // Get GITHUB_TOKEN from environment
- const githubToken = process.env.GITHUB_TOKEN;
- if (!githubToken) {
- core.setFailed('GITHUB_TOKEN environment variable is not set.');
- return;
- }
- // Setup Octokit client
- const octokit = github.getOctokit(githubToken);
- // Use octokit to get all tags for this repo
- const tags = yield octokit.rest.repos.listTags({
- owner: github.context.repo.owner,
- repo: github.context.repo.repo
- });
- // See if tags for this release was already created.
- const tagExists = tags.data.some(tag => tag.name === tagName);
- if (tagExists) {
- core.info(`Tag ${tagName} already exists. Skipping...`);
- return;
- }
- // Create tag
- const createdTag = yield octokit.rest.git.createTag({
- tag: tagName,
- message: `Feature ${featureId} version ${featureVersion}`,
- object: github.context.sha,
- type: 'commit',
- owner: github.context.repo.owner,
- repo: github.context.repo.repo
- });
- if (createdTag.status === 201) {
- core.info(`Tagged '${tagName}'`);
- }
- else {
- core.setFailed(`Failed to tag '${tagName}'`);
- return;
- }
- // Create reference to tag
- const createdRef = yield octokit.rest.git.createRef({
- owner: github.context.repo.owner,
- repo: github.context.repo.repo,
- ref: `refs/tags/${tagName}`,
- sha: createdTag.data.sha
- });
- if (createdRef.status === 201) {
- core.info(`Created reference for '${tagName}'`);
- }
- else {
- core.setFailed(`Failed to reference of tag '${tagName}'`);
- return;
- }
- });
-}
-function addCollectionsMetadataFile(featuresMetadata, templatesMetadata, opts) {
+function isDevcontainerCliAvailable(cliDebugMode = false) {
return __awaiter(this, void 0, void 0, function* () {
- const p = path_1.default.join('.', 'devcontainer-collection.json');
- const sourceInformation = getGitHubMetadata();
- const metadata = {
- sourceInformation,
- features: featuresMetadata || [],
- templates: templatesMetadata || []
- };
- // Write to the file
- yield (0, exports.writeLocalFile)(p, JSON.stringify(metadata, undefined, 4));
- if (opts.shouldPublishToOCI) {
- pushCollectionsMetadataToOCI(p);
- }
- });
-}
-exports.addCollectionsMetadataFile = addCollectionsMetadataFile;
-function pushArtifactToOCI(version, featureName, artifactPath) {
- return __awaiter(this, void 0, void 0, function* () {
- const exec = (0, util_1.promisify)(child_process.exec);
- const versions = [version, '1.0', '1', 'latest']; // TODO: Generate semantic versions from 'version'
- const sourceInfo = getGitHubMetadata();
- yield Promise.all(versions.map((v) => __awaiter(this, void 0, void 0, function* () {
- const ociRepo = `${sourceInfo.owner}/${sourceInfo.repo}/${featureName}:${v}`;
- try {
- const cmd = `oras push ghcr.io/${ociRepo} \
- --manifest-config /dev/null:application/vnd.devcontainers \
- ./${artifactPath}:application/vnd.devcontainers.layer.v1+tar`;
- yield exec(cmd);
- core.info(`Pushed artifact to '${ociRepo}'`);
- }
- catch (error) {
- if (error instanceof Error)
- core.setFailed(`Failed to push '${ociRepo}': ${error.message}`);
- }
- })));
- });
-}
-function pushCollectionsMetadataToOCI(collectionJsonPath) {
- return __awaiter(this, void 0, void 0, function* () {
- const exec = (0, util_1.promisify)(child_process.exec);
- const sourceInfo = getGitHubMetadata();
- const ociRepo = `${sourceInfo.owner}/${sourceInfo.repo}:latest`;
try {
- const cmd = `oras push ghcr.io/${ociRepo} \
- --manifest-config /dev/null:application/vnd.devcontainers \
- ./${collectionJsonPath}:application/vnd.devcontainers.collection.layer.v1+json`;
- yield exec(cmd);
- core.info(`Pushed collection metadata to '${ociRepo}'`);
+ let cmd = 'devcontainer';
+ let args = ['--version'];
+ if (cliDebugMode) {
+ cmd = 'npx';
+ args = ['-y', './devcontainer.tgz', ...args];
+ }
+ const res = yield exec.getExecOutput(cmd, args, {
+ ignoreReturnCode: true,
+ silent: true
+ });
+ core.info(`Devcontainer CLI version '${res.stdout}' is installed.`);
+ return res.exitCode === 0;
}
- catch (error) {
- if (error instanceof Error)
- core.setFailed(`Failed to push collection metadata '${ociRepo}': ${error.message}`);
+ catch (err) {
+ return false;
}
});
}
-exports.pushCollectionsMetadataToOCI = pushCollectionsMetadataToOCI;
-function loginToGHCR() {
+exports.isDevcontainerCliAvailable = isDevcontainerCliAvailable;
+function ensureDevcontainerCliPresent(cliDebugMode = false) {
return __awaiter(this, void 0, void 0, function* () {
- const exec = (0, util_1.promisify)(child_process.exec);
- // Get GITHUB_TOKEN from environment
- const githubToken = process.env.GITHUB_TOKEN;
- if (!githubToken) {
- core.setFailed('GITHUB_TOKEN environment variable is not set.');
- return;
+ if (yield isDevcontainerCliAvailable(cliDebugMode)) {
+ core.info('devcontainer CLI is already installed');
+ return true;
}
- try {
- yield exec(`oras login ghcr.io -u USERNAME -p ${githubToken}`);
- core.info('Oras logged in successfully!');
+ if (cliDebugMode) {
+ core.error('Cannot remotely fetch CLI in debug mode');
+ return false;
}
- catch (error) {
- if (error instanceof Error)
- core.setFailed(` Oras login failed!`);
- }
- });
-}
-function getFeaturesAndPackage(basePath, opts) {
- return __awaiter(this, void 0, void 0, function* () {
- const { shouldPublishToNPM, shouldTagIndividualFeatures, shouldPublishReleaseArtifacts, shouldPublishToOCI } = opts;
- const featureDirs = fs.readdirSync(basePath);
- let metadatas = [];
- const exec = (0, util_1.promisify)(child_process.exec);
- if (shouldPublishToOCI) {
- yield loginToGHCR();
- }
- yield Promise.all(featureDirs.map((f) => __awaiter(this, void 0, void 0, function* () {
- var _a;
- core.info(`feature ==> ${f}`);
- if (!f.startsWith('.')) {
- const featureFolder = path_1.default.join(basePath, f);
- const featureJsonPath = path_1.default.join(featureFolder, 'devcontainer-feature.json');
- if (!fs.existsSync(featureJsonPath)) {
- core.error(`Feature '${f}' is missing a devcontainer-feature.json`);
- core.setFailed('All features must have a devcontainer-feature.json');
- return;
- }
- const featureMetadata = JSON.parse(fs.readFileSync(featureJsonPath, 'utf8'));
- if (!featureMetadata.id || !featureMetadata.version) {
- core.error(`Feature '${f}' is must defined an id and version`);
- core.setFailed('Incomplete devcontainer-feature.json');
- }
- metadatas.push(featureMetadata);
- const sourceInfo = getGitHubMetadata();
- if (!sourceInfo.owner) {
- core.setFailed('Could not determine repository owner.');
- return;
- }
- const archiveName = `${f}.tgz`;
- // ---- PUBLISH RELEASE ARTIFACTS (classic method) ----
- if (shouldPublishReleaseArtifacts || shouldPublishToOCI) {
- core.info(`** Tar'ing feature`);
- yield tarDirectory(featureFolder, archiveName);
- }
- // ---- PUBLISH TO NPM ----
- if (shouldPublishToOCI) {
- core.info(`** Publishing to OCI`);
- // TODO: CHECK IF THE FEATURE IS ALREADY PUBLISHED UNDER GIVEN TAG
- yield pushArtifactToOCI(featureMetadata.version, f, archiveName);
- }
- // ---- TAG INDIVIDUAL FEATURES ----
- if (shouldTagIndividualFeatures) {
- core.info(`** Tagging individual feature`);
- yield tagFeatureAtVersion(featureMetadata);
- }
- // ---- PUBLISH TO NPM ----
- if (shouldPublishToNPM) {
- core.info(`** Publishing to NPM`);
- // Adds a package.json file to the feature folder
- const packageJsonPath = path_1.default.join(featureFolder, 'package.json');
- // if (!sourceInfo.tag) {
- // core.error(`Feature ${f} is missing a tag! Cannot publish to NPM.`);
- // core.setFailed('All features published to NPM must be tagged with a version');
- // }
- const packageJsonObject = {
- name: `@${sourceInfo.owner}/${f}`,
- version: featureMetadata.version,
- description: `${(_a = featureMetadata.description) !== null && _a !== void 0 ? _a : 'My cool feature'}`,
- author: `${sourceInfo.owner}`,
- keywords: ['devcontainer-features']
- };
- yield (0, exports.writeLocalFile)(packageJsonPath, JSON.stringify(packageJsonObject, undefined, 4));
- core.info(`Feature Folder is: ${featureFolder}`);
- // Run npm pack, which 'tars' the folder
- const packageName = yield exec(`npm pack ./${featureFolder}`);
- if (packageName.stderr) {
- core.error(`${packageName.stderr.toString()}`);
- }
- const publishOutput = yield exec(`npm publish --access public "${packageName.stdout.trim()}"`);
- core.info(publishOutput.stdout);
- if (publishOutput.stderr) {
- core.error(`${publishOutput.stderr}`);
- }
- }
- }
- })));
- if (metadatas.length === 0) {
- core.setFailed('No features found');
- return;
+ try {
+ core.info('Fetching the latest @devcontainer/cli...');
+ const res = yield exec.getExecOutput('npm', ['install', '-g', '@devcontainers/cli'], {
+ ignoreReturnCode: true,
+ silent: true
+ });
+ return res.exitCode === 0;
}
- return metadatas;
- });
-}
-exports.getFeaturesAndPackage = getFeaturesAndPackage;
-function getTemplatesAndPackage(basePath) {
- return __awaiter(this, void 0, void 0, function* () {
- const templateDirs = fs.readdirSync(basePath);
- let metadatas = [];
- yield Promise.all(templateDirs.map((t) => __awaiter(this, void 0, void 0, function* () {
- core.info(`template ==> ${t}`);
- if (!t.startsWith('.')) {
- const templateFolder = path_1.default.join(basePath, t);
- const archiveName = `devcontainer-template-${t}.tgz`;
- // await tarDirectory(templateFolder, archiveName);
- const templateJsonPath = path_1.default.join(templateFolder, 'devcontainer-template.json');
- if (!fs.existsSync(templateJsonPath)) {
- core.error(`Template '${t}' is missing a devcontainer-template.json`);
- core.setFailed('All templates must have a devcontainer-template.json');
- return;
- }
- const templateMetadata = JSON.parse(fs.readFileSync(templateJsonPath, 'utf8'));
- metadatas.push(templateMetadata);
- }
- })));
- if (metadatas.length === 0) {
- core.setFailed('No templates found');
- return;
+ catch (err) {
+ return false;
}
- return metadatas;
});
}
-exports.getTemplatesAndPackage = getTemplatesAndPackage;
+exports.ensureDevcontainerCliPresent = ensureDevcontainerCliPresent;