From e986b09e581daaf14c061baa2bd908fad6f51dcf Mon Sep 17 00:00:00 2001 From: Richard Moore Date: Sat, 3 Oct 2020 02:20:50 -0400 Subject: [PATCH] Build: Added new publish script. --- misc/admin/lib/changelog.d.ts | 7 + misc/admin/lib/changelog.js | 27 ++++ misc/admin/lib/cmds/publish.d.ts | 15 +++ misc/admin/lib/cmds/publish.js | 203 ++++++++++++++++++++++++++++ misc/admin/lib/geturl.d.ts | 2 + misc/admin/lib/geturl.js | 3 + misc/admin/lib/github.d.ts | 1 + misc/admin/lib/github.js | 35 +++++ misc/admin/lib/log.d.ts | 2 +- misc/admin/lib/log.js | 6 +- misc/admin/lib/npm.d.ts | 2 + misc/admin/lib/npm.js | 20 +++ misc/admin/src.ts/changelog.ts | 32 +++++ misc/admin/src.ts/cmds/publish.ts | 213 ++++++++++++++++++++++++++++++ misc/admin/src.ts/geturl.ts | 10 +- misc/admin/src.ts/github.ts | 27 ++++ misc/admin/src.ts/log.ts | 8 +- misc/admin/src.ts/npm.ts | 20 +++ misc/admin/thirdparty.d.ts | 23 ++-- package.json | 5 +- 20 files changed, 636 insertions(+), 25 deletions(-) create mode 100644 misc/admin/lib/cmds/publish.d.ts create mode 100644 misc/admin/lib/cmds/publish.js create mode 100644 misc/admin/lib/github.d.ts create mode 100644 misc/admin/lib/github.js create mode 100644 misc/admin/src.ts/cmds/publish.ts create mode 100644 misc/admin/src.ts/github.ts diff --git a/misc/admin/lib/changelog.d.ts b/misc/admin/lib/changelog.d.ts index c7b9a76eb..480d6a4d7 100644 --- a/misc/admin/lib/changelog.d.ts +++ b/misc/admin/lib/changelog.d.ts @@ -1 +1,8 @@ +export declare type Change = { + title: string; + version: string; + date: string; + content: string; +}; export declare function generate(): Promise; +export declare function getLatestChange(): Change; diff --git a/misc/admin/lib/changelog.js b/misc/admin/lib/changelog.js index 03e44536d..fd8edcfe3 100644 --- a/misc/admin/lib/changelog.js +++ b/misc/admin/lib/changelog.js @@ -104,3 +104,30 @@ function generate() { }); } exports.generate = generate; +function getLatestChange() { + let result = null; + const lines = fs_1.default.readFileSync(changelogPath).toString().split("\n"); + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const match = line.match(/ethers\/([^\(]*)\(([^\)]*)\)/); + if (match) { + if (result) { + break; + } + result = { + title: line.trim(), + version: match[1].trim(), + date: match[2].trim(), + content: "" + }; + } + else if (result) { + if (!line.trim().match(/^-+$/)) { + result.content += line.trim() + "\n"; + } + } + } + result.content = result.content.trim(); + return result; +} +exports.getLatestChange = getLatestChange; diff --git a/misc/admin/lib/cmds/publish.d.ts b/misc/admin/lib/cmds/publish.d.ts new file mode 100644 index 000000000..84156e223 --- /dev/null +++ b/misc/admin/lib/cmds/publish.d.ts @@ -0,0 +1,15 @@ +/// +import AWS from 'aws-sdk'; +declare type PutInfo = { + ACL: "public-read"; + Body: string | Buffer; + Bucket: string; + ContentType: string; + Key: string; +}; +export declare function putObject(s3: AWS.S3, info: PutInfo): Promise<{ + name: string; + hash: string; +}>; +export declare function invalidate(cloudfront: AWS.CloudFront, distributionId: string): Promise; +export {}; diff --git a/misc/admin/lib/cmds/publish.js b/misc/admin/lib/cmds/publish.js new file mode 100644 index 000000000..d7cb890a4 --- /dev/null +++ b/misc/admin/lib/cmds/publish.js @@ -0,0 +1,203 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const aws_sdk_1 = __importDefault(require("aws-sdk")); +const fs_1 = __importDefault(require("fs")); +const changelog_1 = require("../changelog"); +const config_1 = require("../config"); +const depgraph_1 = require("../depgraph"); +const git_1 = require("../git"); +const github_1 = require("../github"); +const local = __importStar(require("../local")); +const log_1 = require("../log"); +const npm = __importStar(require("../npm")); +const path_1 = require("../path"); +const utils_1 = require("../utils"); +const USER_AGENT = "ethers-dist@0.0.1"; +const TAG = "latest"; +function putObject(s3, info) { + return new Promise((resolve, reject) => { + s3.putObject(info, function (error, data) { + if (error) { + reject(error); + } + else { + resolve({ + name: info.Key, + hash: data.ETag.replace(/"/g, '') + }); + } + }); + }); +} +exports.putObject = putObject; +function invalidate(cloudfront, distributionId) { + return new Promise((resolve, reject) => { + cloudfront.createInvalidation({ + DistributionId: distributionId, + InvalidationBatch: { + CallerReference: `${USER_AGENT}-${parseInt(String((new Date()).getTime() / 1000))}`, + Paths: { + Quantity: 1, + Items: [ + "/\*" + ] + } + } + }, function (error, data) { + if (error) { + console.log(error); + return; + } + resolve(data.Invalidation.Id); + }); + }); +} +exports.invalidate = invalidate; +(function () { + return __awaiter(this, void 0, void 0, function* () { + const dirnames = depgraph_1.getOrdered(); + // @TODO: Fail if there are any untracked files or unchecked in files + const publish = {}; + const progressUpdate = log_1.getProgressBar(log_1.colorify.bold("Finding updated packages...")); + for (let i = 0; i < dirnames.length; i++) { + progressUpdate(i / dirnames.length); + let dirname = dirnames[i]; + let info = local.getPackage(dirname); + let npmInfo = yield npm.getPackage(dirname); + // No change in version, no need to publish + if (info.version === npmInfo.version) { + continue; + } + // Get the latest commit this package was modified at + const path = path_1.resolve("packages", dirname); + const gitHead = yield git_1.getGitTag(path); + if (gitHead == null) { + throw new Error("hmmm..."); + } + publish[dirname] = { + name: info.name, + gitHead: gitHead, + oldVersion: (npmInfo ? npmInfo.version : "NEW"), + newVersion: info.version + }; + } + progressUpdate(1); + console.log(log_1.colorify.bold(`Found ${Object.keys(publish).length} updated pacakges...`)); + Object.keys(publish).forEach((dirname) => { + const info = publish[dirname]; + console.log(` ${log_1.colorify.blue(info.name)} ${utils_1.repeat(" ", 50 - info.name.length - info.oldVersion.length)} ${info.oldVersion} ${log_1.colorify.bold("=>")} ${log_1.colorify.green(info.newVersion)}`); + }); + const publishNames = Object.keys(publish); + publishNames.sort((a, b) => (dirnames.indexOf(a) - dirnames.indexOf(b))); + // Load the token from the encrypted store + const options = { + access: "public", + npmVersion: USER_AGENT, + tag: TAG + }; + try { + const token = (yield config_1.config.get("npm-token")).trim().split("="); + options[token[0]] = token[1]; + } + catch (error) { + switch (error.message) { + case "wrong password": + console.log(log_1.colorify.bold("Wrong password")); + break; + case "cancelled": + break; + default: + console.log(error); + } + console.log(log_1.colorify.red("Aborting.")); + return; + } + console.log(log_1.colorify.bold("Publishing:")); + for (let i = 0; i < publishNames.length; i++) { + const dirname = publishNames[i]; + const path = path_1.resolve("packages", dirname); + const pathJson = path_1.resolve("packages", dirname, "package.json"); + const { gitHead, name, newVersion } = publish[dirname]; + console.log(` ${log_1.colorify.blue(name)} @ ${log_1.colorify.green(newVersion)}`); + local.updateJson(pathJson, { gitHead: gitHead }, true); + const info = utils_1.loadJson(pathJson); + yield npm.publish(path, info, options); + local.updateJson(pathJson, { gitHead: undefined }, true); + } + if (publishNames.indexOf("ethers") >= 0) { + const change = changelog_1.getLatestChange(); + const awsAccessId = yield config_1.config.get("aws-upload-scripts-accesskey"); + const awsSecretKey = yield config_1.config.get("aws-upload-scripts-secretkey"); + // Publish tagged release on GitHub + { + // The password above already succeeded + const username = yield config_1.config.get("github-user"); + const password = yield config_1.config.get("github-release"); + const gitCommit = yield git_1.getGitTag(path_1.resolve("CHANGELOG.md")); + // Publish the release + const beta = false; + const link = yield github_1.createRelease(username, password, change.version, change.title, change.content, beta, gitCommit); + console.log(`${log_1.colorify.bold("Published release:")} ${link}`); + } + // Upload libs to the CDN (as ethers-v5.0 and ethers-5.0.x) + { + const bucketName = yield config_1.config.get("aws-upload-scripts-bucket"); + const originRoot = yield config_1.config.get("aws-upload-scripts-root"); + const s3 = new aws_sdk_1.default.S3({ + apiVersion: '2006-03-01', + accessKeyId: awsAccessId, + secretAccessKey: awsSecretKey + }); + // Upload the libs to ethers-v5.0 and ethers-5.0.x + const fileInfos = [ + { filename: "packages/ethers/dist/ethers.esm.min.js", key: `ethers-${change.version.substring(1)}.esm.min.js` }, + { filename: "packages/ethers/dist/ethers.umd.min.js", key: `ethers-${change.version.substring(1)}.umd.min.js` }, + { filename: "packages/ethers/dist/ethers.esm.min.js", key: "ethers-5.0.esm.min.js" }, + { filename: "packages/ethers/dist/ethers.umd.min.js", key: "ethers-5.0.umd.min.js" }, + ]; + for (let i = 0; i < fileInfos.length; i++) { + const { filename, key } = fileInfos[i]; + const status = yield putObject(s3, { + ACL: "public-read", + Body: fs_1.default.readFileSync(path_1.resolve(filename)), + Bucket: bucketName, + ContentType: "application/javascript; charset=utf-8", + Key: (originRoot + key) + }); + console.log(status); + console.log(`${log_1.colorify.bold("Uploaded:")} https://cdn.ethers.io/lib/${key}`); + } + } + // Flush the edge caches + { + const distributionId = yield config_1.config.get("aws-upload-scripts-distribution-id"); + const cloudfront = new aws_sdk_1.default.CloudFront({ + //apiVersion: '2006-03-01', + accessKeyId: awsAccessId, + secretAccessKey: awsSecretKey + }); + const invalidationId = yield invalidate(cloudfront, distributionId); + console.log(`${log_1.colorify.bold("Invalidating Edge Cache:")} ${invalidationId}`); + } + } + }); +})(); diff --git a/misc/admin/lib/geturl.d.ts b/misc/admin/lib/geturl.d.ts index 718a65f07..1d22e3037 100644 --- a/misc/admin/lib/geturl.d.ts +++ b/misc/admin/lib/geturl.d.ts @@ -12,5 +12,7 @@ export declare type Options = { headers?: { [key: string]: string; }; + user?: string; + password?: string; }; export declare function getUrl(href: string, options?: Options): Promise; diff --git a/misc/admin/lib/geturl.js b/misc/admin/lib/geturl.js index 639da0a3a..5a19233c4 100644 --- a/misc/admin/lib/geturl.js +++ b/misc/admin/lib/geturl.js @@ -77,6 +77,9 @@ function getUrl(href, options) { method: (options.method || "GET"), headers: (options.headers || {}), }; + if (options.user && options.password) { + request.auth = `${options.user}:${options.password}`; + } let req = null; switch (nonnull(url.protocol)) { case "http:": diff --git a/misc/admin/lib/github.d.ts b/misc/admin/lib/github.d.ts new file mode 100644 index 000000000..8384adbec --- /dev/null +++ b/misc/admin/lib/github.d.ts @@ -0,0 +1 @@ +export declare function createRelease(user: string, password: string, tagName: string, title: string, body: string, prerelease?: boolean, commit?: string): Promise; diff --git a/misc/admin/lib/github.js b/misc/admin/lib/github.js new file mode 100644 index 000000000..3acbf3b83 --- /dev/null +++ b/misc/admin/lib/github.js @@ -0,0 +1,35 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const geturl_1 = require("./geturl"); +function createRelease(user, password, tagName, title, body, prerelease, commit) { + return __awaiter(this, void 0, void 0, function* () { + const result = yield geturl_1.getUrl("https:/\/api.github.com/repos/ethers-io/ethers.js/releases", { + body: Buffer.from(JSON.stringify({ + tag_name: tagName, + target_commitish: (commit || "master"), + name: title, + body: body, + //draft: true, + draft: false, + prerelease: !!prerelease + })), + method: "POST", + headers: { + "User-Agent": "ethers-io" + }, + user: user, + password: password + }); + return JSON.parse(Buffer.from(result.body).toString("utf8")).html_url; + }); +} +exports.createRelease = createRelease; diff --git a/misc/admin/lib/log.d.ts b/misc/admin/lib/log.d.ts index 611454133..de9b89f03 100644 --- a/misc/admin/lib/log.d.ts +++ b/misc/admin/lib/log.d.ts @@ -8,5 +8,5 @@ export declare type PromptOptions = { defaultChoice?: string; mask?: string; }; -export declare function getPrompt(prompt: string, options: PromptOptions): Promise; +export declare function getPrompt(prompt: string, options?: PromptOptions): Promise; export declare function getPassword(prompt: string): Promise; diff --git a/misc/admin/lib/log.js b/misc/admin/lib/log.js index eecfcfced..28b102b91 100644 --- a/misc/admin/lib/log.js +++ b/misc/admin/lib/log.js @@ -14,8 +14,8 @@ function getProgressBar(action) { lastProgress = progress; return; } - //process.stdin.setRawMode(false); - //process.stdin.pause(); + process.stdin.setRawMode(false); + process.stdin.pause(); if (progress === lastProgress || lastProgress === 100) { return; } @@ -134,7 +134,7 @@ function _getPrompt(prompt, options, callback) { } function getPrompt(prompt, options) { return new Promise((resolve, reject) => { - _getPrompt(prompt, options, (ctrlC, password) => { + _getPrompt(prompt, (options || {}), (ctrlC, password) => { if (ctrlC) { return reject(new Error("cancelled")); } diff --git a/misc/admin/lib/npm.d.ts b/misc/admin/lib/npm.d.ts index c86ee4fbe..2de39ea75 100644 --- a/misc/admin/lib/npm.d.ts +++ b/misc/admin/lib/npm.d.ts @@ -1,2 +1,4 @@ +import { Options } from "libnpmpublish"; import { Package } from "./local"; export declare function getPackage(name: string, version?: string): Promise; +export declare function publish(path: string, manifest: any, options: Options): Promise; diff --git a/misc/admin/lib/npm.js b/misc/admin/lib/npm.js index 024ea3685..9a2944d8d 100644 --- a/misc/admin/lib/npm.js +++ b/misc/admin/lib/npm.js @@ -12,9 +12,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +const libnpmpublish_1 = require("libnpmpublish"); const semver_1 = __importDefault(require("semver")); const geturl_1 = require("./geturl"); const local_1 = require("./local"); +const log_1 = require("./log"); const cache = {}; function getPackageInfo(name) { return __awaiter(this, void 0, void 0, function* () { @@ -60,3 +62,21 @@ function getPackage(name, version) { }); } exports.getPackage = getPackage; +function publish(path, manifest, options) { + return __awaiter(this, void 0, void 0, function* () { + try { + yield libnpmpublish_1.publish(path, manifest, options); + } + catch (error) { + // We need an OTP + if (error.code === "EOTP") { + const otp = yield log_1.getPrompt(log_1.colorify.bold("Enter OTP: ")); + options.otp = otp.replace(" ", ""); + // Retry with the new OTP + return yield publish(path, manifest, options); + } + throw error; + } + }); +} +exports.publish = publish; diff --git a/misc/admin/src.ts/changelog.ts b/misc/admin/src.ts/changelog.ts index 676e7da59..4593bb239 100644 --- a/misc/admin/src.ts/changelog.ts +++ b/misc/admin/src.ts/changelog.ts @@ -9,6 +9,13 @@ import { getDateTime, repeat } from "./utils"; const changelogPath = resolve("CHANGELOG.md"); +export type Change = { + title: string; + version: string; + date: string; + content: string; +}; + export async function generate(): Promise { const lines = fs.readFileSync(changelogPath).toString().trim().split("\n"); @@ -88,3 +95,28 @@ export async function generate(): Promise { return output.join("\n"); } +export function getLatestChange(): Change { + let result: Change = null; + + const lines = fs.readFileSync(changelogPath).toString().split("\n"); + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const match = line.match(/ethers\/([^\(]*)\(([^\)]*)\)/); + if (match) { + if (result) { break; } + result = { + title: line.trim(), + version: match[1].trim(), + date: match[2].trim(), + content: "" + }; + } else if (result) { + if (!line.trim().match(/^-+$/)) { + result.content += line.trim() + "\n"; + } + } + } + result.content = result.content.trim(); + + return result; +} diff --git a/misc/admin/src.ts/cmds/publish.ts b/misc/admin/src.ts/cmds/publish.ts new file mode 100644 index 000000000..895ea66ab --- /dev/null +++ b/misc/admin/src.ts/cmds/publish.ts @@ -0,0 +1,213 @@ +import AWS from 'aws-sdk'; +import fs from "fs"; + +import { getLatestChange } from "../changelog"; +import { config } from "../config"; +import { getOrdered } from "../depgraph"; +import { getGitTag } from "../git"; +import { createRelease } from "../github"; +import * as local from "../local"; +import { colorify, getProgressBar } from "../log"; +import * as npm from "../npm"; +import { resolve } from "../path"; +import { loadJson, repeat } from "../utils"; + +const USER_AGENT = "ethers-dist@0.0.1"; +const TAG = "latest"; + +type PutInfo = { + ACL: "public-read"; + Body: string | Buffer; + Bucket: string; + ContentType: string; + Key: string; +} + +export function putObject(s3: AWS.S3, info: PutInfo): Promise<{ name: string, hash: string }> { + return new Promise((resolve, reject) => { + s3.putObject(info, function(error, data) { + if (error) { + reject(error); + } else { + resolve({ + name: info.Key, + hash: data.ETag.replace(/"/g, '') + }); + } + }); + }); +} + +export function invalidate(cloudfront: AWS.CloudFront, distributionId: string): Promise { + return new Promise((resolve, reject) => { + cloudfront.createInvalidation({ + DistributionId: distributionId, + InvalidationBatch: { + CallerReference: `${ USER_AGENT }-${ parseInt(String((new Date()).getTime() / 1000)) }`, + Paths: { + Quantity: 1, + Items: [ + "/\*" + ] + } + } + }, function(error, data) { + if (error) { + console.log(error); + return; + } + resolve(data.Invalidation.Id); + }); + }); +} + +(async function() { + const dirnames = getOrdered(); + + // @TODO: Fail if there are any untracked files or unchecked in files + + const publish: Record = { }; + + const progressUpdate = getProgressBar(colorify.bold("Finding updated packages...")); + for (let i = 0; i < dirnames.length; i++) { + progressUpdate(i / dirnames.length); + + let dirname = dirnames[i]; + + let info = local.getPackage(dirname); + let npmInfo = await npm.getPackage(dirname); + + // No change in version, no need to publish + if (info.version === npmInfo.version) { continue; } + + // Get the latest commit this package was modified at + const path = resolve("packages", dirname); + const gitHead = await getGitTag(path); + if (gitHead == null) { throw new Error("hmmm..."); } + + publish[dirname] = { + name: info.name, + gitHead: gitHead, + oldVersion: (npmInfo ? npmInfo.version: "NEW"), + newVersion: info.version + }; + } + progressUpdate(1); + + console.log(colorify.bold(`Found ${ Object.keys(publish).length } updated pacakges...`)); + Object.keys(publish).forEach((dirname) => { + const info = publish[dirname]; + console.log(` ${ colorify.blue(info.name) } ${ repeat(" ", 50 - info.name.length - info.oldVersion.length) } ${ info.oldVersion } ${ colorify.bold("=>") } ${ colorify.green(info.newVersion) }`); + }); + + const publishNames = Object.keys(publish); + publishNames.sort((a, b) => (dirnames.indexOf(a) - dirnames.indexOf(b))); + + // Load the token from the encrypted store + const options: Record = { + access: "public", + npmVersion: USER_AGENT, + tag: TAG + }; + + try { + const token = (await config.get("npm-token")).trim().split("="); + options[token[0]] = token[1]; + } catch (error) { + switch (error.message) { + case "wrong password": + console.log(colorify.bold("Wrong password")); + break; + case "cancelled": + break; + default: + console.log(error); + } + + console.log(colorify.red("Aborting.")); + return; + } + + console.log(colorify.bold("Publishing:")); + for (let i = 0; i < publishNames.length; i++) { + const dirname = publishNames[i]; + const path = resolve("packages", dirname); + const pathJson = resolve("packages", dirname, "package.json"); + + const { gitHead, name, newVersion } = publish[dirname]; + console.log(` ${ colorify.blue(name) } @ ${ colorify.green(newVersion) }`); + + local.updateJson(pathJson, { gitHead: gitHead }, true); + const info = loadJson(pathJson); + await npm.publish(path, info, options); + local.updateJson(pathJson, { gitHead: undefined }, true); + } + + if (publishNames.indexOf("ethers") >= 0) { + const change = getLatestChange(); + + const awsAccessId = await config.get("aws-upload-scripts-accesskey"); + const awsSecretKey = await config.get("aws-upload-scripts-secretkey"); + + // Publish tagged release on GitHub + { + // The password above already succeeded + const username = await config.get("github-user"); + const password = await config.get("github-release"); + + const gitCommit = await getGitTag(resolve("CHANGELOG.md")); + + // Publish the release + const beta = false; + const link = await createRelease(username, password, change.version, change.title, change.content, beta, gitCommit); + console.log(`${ colorify.bold("Published release:") } ${ link }`); + } + + // Upload libs to the CDN (as ethers-v5.0 and ethers-5.0.x) + { + const bucketName = await config.get("aws-upload-scripts-bucket"); + const originRoot = await config.get("aws-upload-scripts-root"); + + const s3 = new AWS.S3({ + apiVersion: '2006-03-01', + accessKeyId: awsAccessId, + secretAccessKey: awsSecretKey + }); + + // Upload the libs to ethers-v5.0 and ethers-5.0.x + const fileInfos: Array<{ filename: string, key: string }> = [ + { filename: "packages/ethers/dist/ethers.esm.min.js", key: `ethers-${ change.version.substring(1) }.esm.min.js` }, + { filename: "packages/ethers/dist/ethers.umd.min.js", key: `ethers-${ change.version.substring(1) }.umd.min.js` }, + { filename: "packages/ethers/dist/ethers.esm.min.js", key: "ethers-5.0.esm.min.js" }, + { filename: "packages/ethers/dist/ethers.umd.min.js", key: "ethers-5.0.umd.min.js" }, + ]; + + for (let i = 0; i < fileInfos.length; i++) { + const { filename, key } = fileInfos[i]; + const status = await putObject(s3, { + ACL: "public-read", + Body: fs.readFileSync(resolve(filename)), + Bucket: bucketName, + ContentType: "application/javascript; charset=utf-8", + Key: (originRoot + key) + }); + console.log(status); + + console.log(`${ colorify.bold("Uploaded:") } https://cdn.ethers.io/lib/${ key }`); + } + } + + // Flush the edge caches + { + const distributionId = await config.get("aws-upload-scripts-distribution-id"); + + const cloudfront = new AWS.CloudFront({ + //apiVersion: '2006-03-01', + accessKeyId: awsAccessId, + secretAccessKey: awsSecretKey + }); + const invalidationId = await invalidate(cloudfront, distributionId); + console.log(`${ colorify.bold("Invalidating Edge Cache:") } ${ invalidationId }`); + } + } +})(); diff --git a/misc/admin/src.ts/geturl.ts b/misc/admin/src.ts/geturl.ts index 7a4d00cf7..05e8c04e0 100644 --- a/misc/admin/src.ts/geturl.ts +++ b/misc/admin/src.ts/geturl.ts @@ -12,7 +12,11 @@ export type GetUrlResponse = { export type Options = { method?: string, body?: Uint8Array + headers?: { [ key: string] : string }, + + user?: string, + password?: string, }; function getResponse(request: http.ClientRequest): Promise { @@ -72,7 +76,7 @@ export async function getUrl(href: string, options?: Options): Promise { + const result = await getUrl("https:/\/api.github.com/repos/ethers-io/ethers.js/releases", { + body: Buffer.from(JSON.stringify({ + tag_name: tagName, + target_commitish: (commit || "master"), + name: title, + body: body, + //draft: true, + draft: false, + prerelease: !!prerelease + })), + method: "POST", + + headers: { + "User-Agent": "ethers-io" + }, + + user: user, + password: password + }); + + + return JSON.parse(Buffer.from(result.body).toString("utf8")).html_url; +} + diff --git a/misc/admin/src.ts/log.ts b/misc/admin/src.ts/log.ts index 670d2f5d2..13c05b52a 100644 --- a/misc/admin/src.ts/log.ts +++ b/misc/admin/src.ts/log.ts @@ -17,8 +17,8 @@ export function getProgressBar(action: string): (percent: number) => void { return; } - //process.stdin.setRawMode(false); - //process.stdin.pause(); + process.stdin.setRawMode(false); + process.stdin.pause(); if (progress === lastProgress || lastProgress === 100) { return; } lastProgress = progress; @@ -151,9 +151,9 @@ function _getPrompt(prompt: string, options: PromptOptions, callback: (ctrlC: bo stdin.on('data', handler); } -export function getPrompt(prompt: string, options: PromptOptions): Promise { +export function getPrompt(prompt: string, options?: PromptOptions): Promise { return new Promise((resolve, reject) => { - _getPrompt(prompt, options, (ctrlC, password) => { + _getPrompt(prompt, (options || { }), (ctrlC, password) => { if (ctrlC) { return reject(new Error("cancelled")); } diff --git a/misc/admin/src.ts/npm.ts b/misc/admin/src.ts/npm.ts index 4e887b517..83f0a40a4 100644 --- a/misc/admin/src.ts/npm.ts +++ b/misc/admin/src.ts/npm.ts @@ -1,8 +1,10 @@ +import { Options, publish as npmPublish } from "libnpmpublish"; import semver from "semver"; import { getUrl } from "./geturl"; import { Package, getPackage as _getPackage } from "./local"; +import { colorify, getPrompt } from "./log"; const cache: Record = { }; @@ -46,3 +48,21 @@ export async function getPackage(name: string, version?: string): Promise { + try { + await npmPublish(path, manifest, options); + + } catch (error) { + + // We need an OTP + if (error.code === "EOTP") { + const otp = await getPrompt(colorify.bold("Enter OTP: ")); + options.otp = otp.replace(" ", ""); + + // Retry with the new OTP + return await publish(path, manifest, options); + } + throw error; + } +} diff --git a/misc/admin/thirdparty.d.ts b/misc/admin/thirdparty.d.ts index de6b8a784..553e901b2 100644 --- a/misc/admin/thirdparty.d.ts +++ b/misc/admin/thirdparty.d.ts @@ -2,18 +2,21 @@ declare module "aes-js" { export class Counter { constructor(iv: Uint8Array); } + export namespace ModeOfOperation { class cbc{ constructor(key: Uint8Array, iv: Uint8Array); decrypt(data: Uint8Array): Uint8Array; encrypt(data: Uint8Array): Uint8Array; } + class ctr{ constructor(key: Uint8Array, counter: Counter); decrypt(data: Uint8Array): Uint8Array; encrypt(data: Uint8Array): Uint8Array; } } + export namespace padding { export namespace pkcs7 { export function strip(data: Uint8Array): Uint8Array; @@ -21,19 +24,13 @@ declare module "aes-js" { } } -declare module "tar" { - export type CreateOptions = { - sync?: boolean, - cwd?: string, - prefix?: string, - gzip?: boolean, - portable?: boolean, - mtime?: Date +declare module "libnpmpublish" { + export type Options = { + access?: "public" | "restricted"; + npmVersion?: string; + otp?: string; + token?: string; }; - export interface Readable { - read(): Buffer; - } - - export function create(options: CreateOptions, files: Array): Readable; + export function publish(path: string, manifest: string, options: Options): Promise } diff --git a/package.json b/package.json index 05a3f47e3..5ad4ce88e 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "build-libs": "node ./misc/admin/lib/cmds/update-exports.js && npm run _build-cjs && npm run _build-esm && node ./misc/admin/lib/cmds/set-build-option cjs && node packages/asm/generate.js && chmod 755 packages/*/lib/bin/*.js", "build-all": "npm run build-libs && npm run build-dist", "update-versions": "npm run clean && npm install && npm run spell-check && npm run build-all && node ./misc/admin/lib/cmds/bump-versions && npm run build-all && node ./misc/admin/lib/cmds/update-hashes && node ./misc/admin/lib/cmds/update-changelog", - "TODO-publish-all": "node ./admin/cmds/publish", + "publish-all": "node ./misc/admin/lib/cmds/publish", "TODO-sync-github": "node ./admin/cmds/cache-github" }, "devDependencies": { @@ -70,8 +70,7 @@ "rollup-pluginutils": "2.8.1", "scrypt-js": "3.0.1", "semver": "^5.6.0", - "typescript": "3.8.3", - "uglify-es": "3.3.9" + "typescript": "3.8.3" }, "dependencies": { "@babel/parser": "7.8.4",