Build: Added new publish script.
This commit is contained in:
parent
22dee96f51
commit
e986b09e58
7
misc/admin/lib/changelog.d.ts
vendored
7
misc/admin/lib/changelog.d.ts
vendored
@ -1 +1,8 @@
|
|||||||
|
export declare type Change = {
|
||||||
|
title: string;
|
||||||
|
version: string;
|
||||||
|
date: string;
|
||||||
|
content: string;
|
||||||
|
};
|
||||||
export declare function generate(): Promise<string>;
|
export declare function generate(): Promise<string>;
|
||||||
|
export declare function getLatestChange(): Change;
|
||||||
|
@ -104,3 +104,30 @@ function generate() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.generate = 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;
|
||||||
|
15
misc/admin/lib/cmds/publish.d.ts
vendored
Normal file
15
misc/admin/lib/cmds/publish.d.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/// <reference types="node" />
|
||||||
|
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<string>;
|
||||||
|
export {};
|
203
misc/admin/lib/cmds/publish.js
Normal file
203
misc/admin/lib/cmds/publish.js
Normal file
@ -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}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
2
misc/admin/lib/geturl.d.ts
vendored
2
misc/admin/lib/geturl.d.ts
vendored
@ -12,5 +12,7 @@ export declare type Options = {
|
|||||||
headers?: {
|
headers?: {
|
||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
};
|
};
|
||||||
|
user?: string;
|
||||||
|
password?: string;
|
||||||
};
|
};
|
||||||
export declare function getUrl(href: string, options?: Options): Promise<GetUrlResponse>;
|
export declare function getUrl(href: string, options?: Options): Promise<GetUrlResponse>;
|
||||||
|
@ -77,6 +77,9 @@ function getUrl(href, options) {
|
|||||||
method: (options.method || "GET"),
|
method: (options.method || "GET"),
|
||||||
headers: (options.headers || {}),
|
headers: (options.headers || {}),
|
||||||
};
|
};
|
||||||
|
if (options.user && options.password) {
|
||||||
|
request.auth = `${options.user}:${options.password}`;
|
||||||
|
}
|
||||||
let req = null;
|
let req = null;
|
||||||
switch (nonnull(url.protocol)) {
|
switch (nonnull(url.protocol)) {
|
||||||
case "http:":
|
case "http:":
|
||||||
|
1
misc/admin/lib/github.d.ts
vendored
Normal file
1
misc/admin/lib/github.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
export declare function createRelease(user: string, password: string, tagName: string, title: string, body: string, prerelease?: boolean, commit?: string): Promise<string>;
|
35
misc/admin/lib/github.js
Normal file
35
misc/admin/lib/github.js
Normal file
@ -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;
|
2
misc/admin/lib/log.d.ts
vendored
2
misc/admin/lib/log.d.ts
vendored
@ -8,5 +8,5 @@ export declare type PromptOptions = {
|
|||||||
defaultChoice?: string;
|
defaultChoice?: string;
|
||||||
mask?: string;
|
mask?: string;
|
||||||
};
|
};
|
||||||
export declare function getPrompt(prompt: string, options: PromptOptions): Promise<string>;
|
export declare function getPrompt(prompt: string, options?: PromptOptions): Promise<string>;
|
||||||
export declare function getPassword(prompt: string): Promise<string>;
|
export declare function getPassword(prompt: string): Promise<string>;
|
||||||
|
@ -14,8 +14,8 @@ function getProgressBar(action) {
|
|||||||
lastProgress = progress;
|
lastProgress = progress;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//process.stdin.setRawMode(false);
|
process.stdin.setRawMode(false);
|
||||||
//process.stdin.pause();
|
process.stdin.pause();
|
||||||
if (progress === lastProgress || lastProgress === 100) {
|
if (progress === lastProgress || lastProgress === 100) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -134,7 +134,7 @@ function _getPrompt(prompt, options, callback) {
|
|||||||
}
|
}
|
||||||
function getPrompt(prompt, options) {
|
function getPrompt(prompt, options) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
_getPrompt(prompt, options, (ctrlC, password) => {
|
_getPrompt(prompt, (options || {}), (ctrlC, password) => {
|
||||||
if (ctrlC) {
|
if (ctrlC) {
|
||||||
return reject(new Error("cancelled"));
|
return reject(new Error("cancelled"));
|
||||||
}
|
}
|
||||||
|
2
misc/admin/lib/npm.d.ts
vendored
2
misc/admin/lib/npm.d.ts
vendored
@ -1,2 +1,4 @@
|
|||||||
|
import { Options } from "libnpmpublish";
|
||||||
import { Package } from "./local";
|
import { Package } from "./local";
|
||||||
export declare function getPackage(name: string, version?: string): Promise<Package>;
|
export declare function getPackage(name: string, version?: string): Promise<Package>;
|
||||||
|
export declare function publish(path: string, manifest: any, options: Options): Promise<void>;
|
||||||
|
@ -12,9 +12,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const libnpmpublish_1 = require("libnpmpublish");
|
||||||
const semver_1 = __importDefault(require("semver"));
|
const semver_1 = __importDefault(require("semver"));
|
||||||
const geturl_1 = require("./geturl");
|
const geturl_1 = require("./geturl");
|
||||||
const local_1 = require("./local");
|
const local_1 = require("./local");
|
||||||
|
const log_1 = require("./log");
|
||||||
const cache = {};
|
const cache = {};
|
||||||
function getPackageInfo(name) {
|
function getPackageInfo(name) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
@ -60,3 +62,21 @@ function getPackage(name, version) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.getPackage = getPackage;
|
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;
|
||||||
|
@ -9,6 +9,13 @@ import { getDateTime, repeat } from "./utils";
|
|||||||
|
|
||||||
const changelogPath = resolve("CHANGELOG.md");
|
const changelogPath = resolve("CHANGELOG.md");
|
||||||
|
|
||||||
|
export type Change = {
|
||||||
|
title: string;
|
||||||
|
version: string;
|
||||||
|
date: string;
|
||||||
|
content: string;
|
||||||
|
};
|
||||||
|
|
||||||
export async function generate(): Promise<string> {
|
export async function generate(): Promise<string> {
|
||||||
const lines = fs.readFileSync(changelogPath).toString().trim().split("\n");
|
const lines = fs.readFileSync(changelogPath).toString().trim().split("\n");
|
||||||
|
|
||||||
@ -88,3 +95,28 @@ export async function generate(): Promise<string> {
|
|||||||
return output.join("\n");
|
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;
|
||||||
|
}
|
||||||
|
213
misc/admin/src.ts/cmds/publish.ts
Normal file
213
misc/admin/src.ts/cmds/publish.ts
Normal file
@ -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<string> {
|
||||||
|
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<string, { name: string, gitHead: string, oldVersion: string, newVersion: string }> = { };
|
||||||
|
|
||||||
|
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<string, string> = {
|
||||||
|
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 }`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
@ -12,7 +12,11 @@ export type GetUrlResponse = {
|
|||||||
export type Options = {
|
export type Options = {
|
||||||
method?: string,
|
method?: string,
|
||||||
body?: Uint8Array
|
body?: Uint8Array
|
||||||
|
|
||||||
headers?: { [ key: string] : string },
|
headers?: { [ key: string] : string },
|
||||||
|
|
||||||
|
user?: string,
|
||||||
|
password?: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
function getResponse(request: http.ClientRequest): Promise<GetUrlResponse> {
|
function getResponse(request: http.ClientRequest): Promise<GetUrlResponse> {
|
||||||
@ -72,7 +76,7 @@ export async function getUrl(href: string, options?: Options): Promise<GetUrlRes
|
|||||||
// to this request object
|
// to this request object
|
||||||
const url = parse(href);
|
const url = parse(href);
|
||||||
|
|
||||||
const request = {
|
const request: http.ClientRequestArgs = {
|
||||||
protocol: nonnull(url.protocol),
|
protocol: nonnull(url.protocol),
|
||||||
hostname: nonnull(url.hostname),
|
hostname: nonnull(url.hostname),
|
||||||
port: nonnull(url.port),
|
port: nonnull(url.port),
|
||||||
@ -82,6 +86,10 @@ export async function getUrl(href: string, options?: Options): Promise<GetUrlRes
|
|||||||
headers: (options.headers || { }),
|
headers: (options.headers || { }),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (options.user && options.password) {
|
||||||
|
request.auth = `${ options.user }:${ options.password }`;
|
||||||
|
}
|
||||||
|
|
||||||
let req: http.ClientRequest = null;
|
let req: http.ClientRequest = null;
|
||||||
switch (nonnull(url.protocol)) {
|
switch (nonnull(url.protocol)) {
|
||||||
case "http:":
|
case "http:":
|
||||||
|
27
misc/admin/src.ts/github.ts
Normal file
27
misc/admin/src.ts/github.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { getUrl } from "./geturl";
|
||||||
|
|
||||||
|
export async function createRelease(user: string, password: string, tagName: string, title: string, body: string, prerelease?: boolean, commit?: string): Promise<string> {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
@ -17,8 +17,8 @@ export function getProgressBar(action: string): (percent: number) => void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//process.stdin.setRawMode(false);
|
process.stdin.setRawMode(false);
|
||||||
//process.stdin.pause();
|
process.stdin.pause();
|
||||||
|
|
||||||
if (progress === lastProgress || lastProgress === 100) { return; }
|
if (progress === lastProgress || lastProgress === 100) { return; }
|
||||||
lastProgress = progress;
|
lastProgress = progress;
|
||||||
@ -151,9 +151,9 @@ function _getPrompt(prompt: string, options: PromptOptions, callback: (ctrlC: bo
|
|||||||
stdin.on('data', handler);
|
stdin.on('data', handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPrompt(prompt: string, options: PromptOptions): Promise<string> {
|
export function getPrompt(prompt: string, options?: PromptOptions): Promise<string> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
_getPrompt(prompt, options, (ctrlC, password) => {
|
_getPrompt(prompt, (options || { }), (ctrlC, password) => {
|
||||||
if (ctrlC) {
|
if (ctrlC) {
|
||||||
return reject(new Error("cancelled"));
|
return reject(new Error("cancelled"));
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
|
||||||
|
import { Options, publish as npmPublish } from "libnpmpublish";
|
||||||
import semver from "semver";
|
import semver from "semver";
|
||||||
|
|
||||||
import { getUrl } from "./geturl";
|
import { getUrl } from "./geturl";
|
||||||
import { Package, getPackage as _getPackage } from "./local";
|
import { Package, getPackage as _getPackage } from "./local";
|
||||||
|
import { colorify, getPrompt } from "./log";
|
||||||
|
|
||||||
|
|
||||||
const cache: Record<string, any> = { };
|
const cache: Record<string, any> = { };
|
||||||
@ -46,3 +48,21 @@ export async function getPackage(name: string, version?: string): Promise<Packag
|
|||||||
_ethers_nobuild: !!info._ethers_nobuild,
|
_ethers_nobuild: !!info._ethers_nobuild,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function publish(path: string, manifest: any, options: Options): Promise<void> {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
23
misc/admin/thirdparty.d.ts
vendored
23
misc/admin/thirdparty.d.ts
vendored
@ -2,18 +2,21 @@ declare module "aes-js" {
|
|||||||
export class Counter {
|
export class Counter {
|
||||||
constructor(iv: Uint8Array);
|
constructor(iv: Uint8Array);
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace ModeOfOperation {
|
export namespace ModeOfOperation {
|
||||||
class cbc{
|
class cbc{
|
||||||
constructor(key: Uint8Array, iv: Uint8Array);
|
constructor(key: Uint8Array, iv: Uint8Array);
|
||||||
decrypt(data: Uint8Array): Uint8Array;
|
decrypt(data: Uint8Array): Uint8Array;
|
||||||
encrypt(data: Uint8Array): Uint8Array;
|
encrypt(data: Uint8Array): Uint8Array;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ctr{
|
class ctr{
|
||||||
constructor(key: Uint8Array, counter: Counter);
|
constructor(key: Uint8Array, counter: Counter);
|
||||||
decrypt(data: Uint8Array): Uint8Array;
|
decrypt(data: Uint8Array): Uint8Array;
|
||||||
encrypt(data: Uint8Array): Uint8Array;
|
encrypt(data: Uint8Array): Uint8Array;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace padding {
|
export namespace padding {
|
||||||
export namespace pkcs7 {
|
export namespace pkcs7 {
|
||||||
export function strip(data: Uint8Array): Uint8Array;
|
export function strip(data: Uint8Array): Uint8Array;
|
||||||
@ -21,19 +24,13 @@ declare module "aes-js" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module "tar" {
|
declare module "libnpmpublish" {
|
||||||
export type CreateOptions = {
|
export type Options = {
|
||||||
sync?: boolean,
|
access?: "public" | "restricted";
|
||||||
cwd?: string,
|
npmVersion?: string;
|
||||||
prefix?: string,
|
otp?: string;
|
||||||
gzip?: boolean,
|
token?: string;
|
||||||
portable?: boolean,
|
|
||||||
mtime?: Date
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface Readable {
|
export function publish(path: string, manifest: string, options: Options): Promise<void>
|
||||||
read(): Buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function create(options: CreateOptions, files: Array<string>): Readable;
|
|
||||||
}
|
}
|
||||||
|
@ -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-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",
|
"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",
|
"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"
|
"TODO-sync-github": "node ./admin/cmds/cache-github"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -70,8 +70,7 @@
|
|||||||
"rollup-pluginutils": "2.8.1",
|
"rollup-pluginutils": "2.8.1",
|
||||||
"scrypt-js": "3.0.1",
|
"scrypt-js": "3.0.1",
|
||||||
"semver": "^5.6.0",
|
"semver": "^5.6.0",
|
||||||
"typescript": "3.8.3",
|
"typescript": "3.8.3"
|
||||||
"uglify-es": "3.3.9"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "7.8.4",
|
"@babel/parser": "7.8.4",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user