From ca25b816fabe15ce1ebc539c0316beba813683b8 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 13 Mar 2018 15:29:12 +0100 Subject: move scripts to monorepro-scripts --- packages/monorepo-scripts/src/globals.d.ts | 8 ++ packages/monorepo-scripts/src/index.ts | 1 + packages/monorepo-scripts/src/postpublish_utils.ts | 86 ++++++++++++++++++++++ packages/monorepo-scripts/src/utils.ts | 5 ++ 4 files changed, 100 insertions(+) create mode 100644 packages/monorepo-scripts/src/globals.d.ts create mode 100644 packages/monorepo-scripts/src/index.ts create mode 100644 packages/monorepo-scripts/src/postpublish_utils.ts create mode 100644 packages/monorepo-scripts/src/utils.ts (limited to 'packages/monorepo-scripts/src') diff --git a/packages/monorepo-scripts/src/globals.d.ts b/packages/monorepo-scripts/src/globals.d.ts new file mode 100644 index 000000000..757ae4097 --- /dev/null +++ b/packages/monorepo-scripts/src/globals.d.ts @@ -0,0 +1,8 @@ +declare module 'async-child-process'; +declare module 'publish-release'; +declare module 'es6-promisify'; + +// semver-sort declarations +declare module 'semver-sort' { + const desc: (versions: string[]) => string[]; +} diff --git a/packages/monorepo-scripts/src/index.ts b/packages/monorepo-scripts/src/index.ts new file mode 100644 index 000000000..95c96ebe8 --- /dev/null +++ b/packages/monorepo-scripts/src/index.ts @@ -0,0 +1 @@ +export { postpublishUtils } from './postpublish_utils'; diff --git a/packages/monorepo-scripts/src/postpublish_utils.ts b/packages/monorepo-scripts/src/postpublish_utils.ts new file mode 100644 index 000000000..2f27e15cb --- /dev/null +++ b/packages/monorepo-scripts/src/postpublish_utils.ts @@ -0,0 +1,86 @@ +import * as promisify from 'es6-promisify'; +import { execAsync } from 'async-child-process'; +import * as _ from 'lodash'; +import * as publishRelease from 'publish-release'; +import semverSort = require('semver-sort'); + +import { utils } from './utils'; + +const publishReleaseAsync = promisify(publishRelease); +const githubPersonalAccessToken = process.env.GITHUB_PERSONAL_ACCESS_TOKEN_0X_JS; +const generatedDocsDirectoryName = 'generated_docs'; + +export interface TagAndVersion { + tag: string; + version: string; +} + +export const postpublishUtils = { + getLatestTagAndVersionAsync(subPackageName: string): Promise { + const subPackagePrefix = `${subPackageName}@`; + const gitTagsCommand = `git tag -l "${subPackagePrefix}*"`; + return execAsync(gitTagsCommand).then((result: any) => { + if (!_.isEmpty(result.stderr)) { + throw new Error(result.stderr); + } + const tags = result.stdout.trim().split('\n'); + const versions = tags.map((tag: string) => { + return tag.slice(subPackagePrefix.length); + }); + const sortedVersions = semverSort.desc(versions); + const latestVersion = sortedVersions[0]; + const latestTag = subPackagePrefix + latestVersion; + return { + tag: latestTag, + version: latestVersion, + }; + }); + }, + publishReleaseNotesAsync(tag: string, releaseName: string, assets: string[]) { + utils.log('POSTPUBLISH: Releasing ', releaseName, '...'); + return publishReleaseAsync({ + token: githubPersonalAccessToken, + owner: '0xProject', + repo: '0x.js', + tag, + name: releaseName, + notes: 'N/A', + draft: false, + prerelease: false, + reuseRelease: true, + reuseDraftOnly: false, + assets, + }); + }, + getReleaseName(subPackageName: string, version: string): string { + const releaseName = `${subPackageName} v${version}`; + return releaseName; + }, + async standardPostPublishAsync(subPackageName: string): Promise { + const result: TagAndVersion = await this.getLatestTagAndVersionAsync(subPackageName); + const releaseName = this.getReleaseName(subPackageName, result.version); + const assets: string[] = []; + await this.publishReleaseNotesAsync(result.tag, releaseName, assets); + }, + adjustFileIncludePaths(fileIncludes: string[], cwd: string): string[] { + const fileIncludesAdjusted = _.map(fileIncludes, fileInclude => { + let path; + if (_.startsWith(fileInclude, '../')) { + path = `${cwd}/../${fileInclude}`; + } else if (_.startsWith(fileInclude, './')) { + path = `${cwd}/../${fileInclude.substr(2)}`; + } else { + path = `${cwd}/${fileInclude}`; + } + + // HACK: tsconfig.json needs wildcard directory endings as `/**/*` + // but TypeDoc needs it as `/**` in order to pick up files at the root + if (_.endsWith(path, '/**/*')) { + path = path.slice(0, -2); + } + return path; + }); + return fileIncludesAdjusted; + }, + generatedDocsDirectoryName, +}; diff --git a/packages/monorepo-scripts/src/utils.ts b/packages/monorepo-scripts/src/utils.ts new file mode 100644 index 000000000..5423cabd9 --- /dev/null +++ b/packages/monorepo-scripts/src/utils.ts @@ -0,0 +1,5 @@ +export const utils = { + log(...args: any[]): void { + console.log(...args); // tslint:disable-line:no-console + }, +}; -- cgit v1.2.3 From a2e848a7fafbae4df51de6f05fd53a6abf78a593 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 13 Mar 2018 16:55:50 +0100 Subject: Fix lint issues --- packages/monorepo-scripts/src/postpublish_utils.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'packages/monorepo-scripts/src') diff --git a/packages/monorepo-scripts/src/postpublish_utils.ts b/packages/monorepo-scripts/src/postpublish_utils.ts index 2f27e15cb..e04c31649 100644 --- a/packages/monorepo-scripts/src/postpublish_utils.ts +++ b/packages/monorepo-scripts/src/postpublish_utils.ts @@ -1,5 +1,5 @@ -import * as promisify from 'es6-promisify'; import { execAsync } from 'async-child-process'; +import * as promisify from 'es6-promisify'; import * as _ from 'lodash'; import * as publishRelease from 'publish-release'; import semverSort = require('semver-sort'); @@ -16,7 +16,7 @@ export interface TagAndVersion { } export const postpublishUtils = { - getLatestTagAndVersionAsync(subPackageName: string): Promise { + async getLatestTagAndVersionAsync(subPackageName: string): Promise { const subPackagePrefix = `${subPackageName}@`; const gitTagsCommand = `git tag -l "${subPackagePrefix}*"`; return execAsync(gitTagsCommand).then((result: any) => { @@ -36,7 +36,7 @@ export const postpublishUtils = { }; }); }, - publishReleaseNotesAsync(tag: string, releaseName: string, assets: string[]) { + async publishReleaseNotesAsync(tag: string, releaseName: string, assets: string[]) { utils.log('POSTPUBLISH: Releasing ', releaseName, '...'); return publishReleaseAsync({ token: githubPersonalAccessToken, -- cgit v1.2.3 From ee29ed26ff1d754fa13576840c08267b8b5707ba Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 13 Mar 2018 17:36:12 +0100 Subject: Use async/await instead of promise syntax --- packages/monorepo-scripts/src/postpublish_utils.ts | 29 +++++++++++----------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'packages/monorepo-scripts/src') diff --git a/packages/monorepo-scripts/src/postpublish_utils.ts b/packages/monorepo-scripts/src/postpublish_utils.ts index e04c31649..6c8771c6f 100644 --- a/packages/monorepo-scripts/src/postpublish_utils.ts +++ b/packages/monorepo-scripts/src/postpublish_utils.ts @@ -19,22 +19,21 @@ export const postpublishUtils = { async getLatestTagAndVersionAsync(subPackageName: string): Promise { const subPackagePrefix = `${subPackageName}@`; const gitTagsCommand = `git tag -l "${subPackagePrefix}*"`; - return execAsync(gitTagsCommand).then((result: any) => { - if (!_.isEmpty(result.stderr)) { - throw new Error(result.stderr); - } - const tags = result.stdout.trim().split('\n'); - const versions = tags.map((tag: string) => { - return tag.slice(subPackagePrefix.length); - }); - const sortedVersions = semverSort.desc(versions); - const latestVersion = sortedVersions[0]; - const latestTag = subPackagePrefix + latestVersion; - return { - tag: latestTag, - version: latestVersion, - }; + const result = await execAsync(gitTagsCommand); + if (!_.isEmpty(result.stderr)) { + throw new Error(result.stderr); + } + const tags = result.stdout.trim().split('\n'); + const versions = tags.map((tag: string) => { + return tag.slice(subPackagePrefix.length); }); + const sortedVersions = semverSort.desc(versions); + const latestVersion = sortedVersions[0]; + const latestTag = subPackagePrefix + latestVersion; + return { + tag: latestTag, + version: latestVersion, + }; }, async publishReleaseNotesAsync(tag: string, releaseName: string, assets: string[]) { utils.log('POSTPUBLISH: Releasing ', releaseName, '...'); -- cgit v1.2.3 From dba1b8a7e92ebd18132e0e714d5109f87b9ab7a9 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 13 Mar 2018 17:55:16 +0100 Subject: Consolidate docs generation and uploading logic --- packages/monorepo-scripts/src/postpublish_utils.ts | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'packages/monorepo-scripts/src') diff --git a/packages/monorepo-scripts/src/postpublish_utils.ts b/packages/monorepo-scripts/src/postpublish_utils.ts index 6c8771c6f..a36408ccd 100644 --- a/packages/monorepo-scripts/src/postpublish_utils.ts +++ b/packages/monorepo-scripts/src/postpublish_utils.ts @@ -81,5 +81,31 @@ export const postpublishUtils = { }); return fileIncludesAdjusted; }, + async generateAndUploadDocsAsync( + dirname: string, + cwd: string, + includedFiles: string[], + version: string, + S3BucketPath: string, + ) { + const jsonFilePath = `${dirname}/../${postpublishUtils.generatedDocsDirectoryName}/index.json`; + const projectFiles = includedFiles.join(' '); + const result = await execAsync( + `JSON_FILE_PATH=${jsonFilePath} PROJECT_FILES="${projectFiles}" yarn docs:json`, + { + cwd, + }, + ); + if (!_.isEmpty(result.stderr)) { + throw new Error(result.stderr); + } + const fileName = `v${version}.json`; + utils.log(`POSTPUBLISH: Doc generation successful, uploading docs... as ${fileName}`); + const s3Url = S3BucketPath + fileName; + await execAsync(`S3_URL=${s3Url} yarn upload_docs_json`, { + cwd, + }); + utils.log(`POSTPUBLISH: Docs uploaded to S3 bucket: ${S3BucketPath}`); + }, generatedDocsDirectoryName, }; -- cgit v1.2.3 From f7c1e10b5ac112866ee55e7fededdb37c890d30f Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 14 Mar 2018 14:07:24 +0100 Subject: Move configuration into package.json configs section --- packages/monorepo-scripts/src/postpublish_utils.ts | 141 ++++++++++++++------- 1 file changed, 97 insertions(+), 44 deletions(-) (limited to 'packages/monorepo-scripts/src') diff --git a/packages/monorepo-scripts/src/postpublish_utils.ts b/packages/monorepo-scripts/src/postpublish_utils.ts index a36408ccd..55c44ca63 100644 --- a/packages/monorepo-scripts/src/postpublish_utils.ts +++ b/packages/monorepo-scripts/src/postpublish_utils.ts @@ -10,37 +10,95 @@ const publishReleaseAsync = promisify(publishRelease); const githubPersonalAccessToken = process.env.GITHUB_PERSONAL_ACCESS_TOKEN_0X_JS; const generatedDocsDirectoryName = 'generated_docs'; -export interface TagAndVersion { - tag: string; +export interface PostpublishConfigs { + cwd: string; + packageName: string; version: string; + assets: string[]; + docPublishConfigs: DocPublishConfigs; +} + +export interface DocPublishConfigs { + fileIncludes: string[]; + s3BucketPath: string; + s3StagingBucketPath: string; } export const postpublishUtils = { - async getLatestTagAndVersionAsync(subPackageName: string): Promise { - const subPackagePrefix = `${subPackageName}@`; - const gitTagsCommand = `git tag -l "${subPackagePrefix}*"`; - const result = await execAsync(gitTagsCommand); - if (!_.isEmpty(result.stderr)) { - throw new Error(result.stderr); + generateConfig(packageJSON: any, tsConfigJSON: any, cwd: string): PostpublishConfigs { + if (_.isUndefined(packageJSON.name)) { + throw new Error('name field required in package.json. Cannot publish release notes to Github.'); } - const tags = result.stdout.trim().split('\n'); - const versions = tags.map((tag: string) => { - return tag.slice(subPackagePrefix.length); - }); - const sortedVersions = semverSort.desc(versions); - const latestVersion = sortedVersions[0]; - const latestTag = subPackagePrefix + latestVersion; - return { - tag: latestTag, - version: latestVersion, + if (_.isUndefined(packageJSON.version)) { + throw new Error('version field required in package.json. Cannot publish release notes to Github.'); + } + const postpublishConfig = _.get(packageJSON, 'config.postpublish', {}); + const configs: PostpublishConfigs = { + cwd, + packageName: packageJSON.name, + version: packageJSON.version, + assets: _.get(postpublishConfig, 'assets', []), + docPublishConfigs: { + // Include any external packages that are part of the 0x.js public interface + // to this array so that TypeDoc picks it up and adds it to the Docs JSON + // So far, we only have @0xproject/types as part of 0x.js's public interface. + fileIncludes: [ + ...(tsConfigJSON as any).include, + ..._.get(postpublishConfig, 'docPublishConfigs.extraFileIncludes', []), + ], + s3BucketPath: _.get(postpublishConfig, 'docPublishConfigs.s3BucketPath'), + s3StagingBucketPath: _.get(postpublishConfig, 'docPublishConfigs.s3StagingBucketPath'), + }, }; + return configs; + }, + async runAsync(packageJSON: any, tsConfigJSON: any, cwd: string): Promise { + const configs = this.generateConfig(packageJSON, tsConfigJSON, cwd); + const release = await this.publishReleaseNotesAsync( + configs.cwd, + configs.packageName, + configs.version, + configs.assets, + ); + if ( + !_.isUndefined(configs.docPublishConfigs.s3BucketPath) || + !_.isUndefined(configs.docPublishConfigs.s3StagingBucketPath) + ) { + utils.log('POSTPUBLISH: Release successful, generating docs...'); + await postpublishUtils.generateAndUploadDocsAsync( + configs.cwd, + configs.docPublishConfigs.fileIncludes, + configs.version, + configs.docPublishConfigs.s3BucketPath, + ); + } else { + utils.log(`POSTPUBLISH: No S3Bucket config found for ${packageJSON.name}. Skipping doc JSON generation.`); + } + }, + async publishDocsToStagingAsync(packageJSON: any, tsConfigJSON: any, cwd: string) { + const configs = this.generateConfig(packageJSON, tsConfigJSON, cwd); + if (_.isUndefined(configs.docPublishConfigs.s3StagingBucketPath)) { + utils.log('config.postpublish.docPublishConfigs.s3StagingBucketPath entry in package.json not found!'); + return; + } + + utils.log('POSTPUBLISH: Generating docs...'); + await postpublishUtils.generateAndUploadDocsAsync( + configs.cwd, + configs.docPublishConfigs.fileIncludes, + configs.version, + configs.docPublishConfigs.s3StagingBucketPath, + ); }, - async publishReleaseNotesAsync(tag: string, releaseName: string, assets: string[]) { + async publishReleaseNotesAsync(cwd: string, packageName: string, version: string, assets: string[]): Promise { + const releaseName = this.getReleaseName(packageName, version); + const tag = this.getTag(packageName, version); utils.log('POSTPUBLISH: Releasing ', releaseName, '...'); - return publishReleaseAsync({ + const finalAssets = this.adjustAssetPaths(cwd, assets); + const result = await publishReleaseAsync({ token: githubPersonalAccessToken, owner: '0xProject', - repo: '0x.js', + repo: '0x-monorepo', tag, name: releaseName, notes: 'N/A', @@ -51,26 +109,23 @@ export const postpublishUtils = { assets, }); }, + getTag(packageName: string, version: string) { + return `${packageName}@${version}`; + }, getReleaseName(subPackageName: string, version: string): string { const releaseName = `${subPackageName} v${version}`; return releaseName; }, - async standardPostPublishAsync(subPackageName: string): Promise { - const result: TagAndVersion = await this.getLatestTagAndVersionAsync(subPackageName); - const releaseName = this.getReleaseName(subPackageName, result.version); - const assets: string[] = []; - await this.publishReleaseNotesAsync(result.tag, releaseName, assets); + adjustAssetPaths(cwd: string, assets: string[]) { + const finalAssets: string[] = []; + _.each(assets, (asset: string) => { + finalAssets.push(`${cwd}/${asset}`); + }); + return finalAssets; }, adjustFileIncludePaths(fileIncludes: string[], cwd: string): string[] { const fileIncludesAdjusted = _.map(fileIncludes, fileInclude => { - let path; - if (_.startsWith(fileInclude, '../')) { - path = `${cwd}/../${fileInclude}`; - } else if (_.startsWith(fileInclude, './')) { - path = `${cwd}/../${fileInclude.substr(2)}`; - } else { - path = `${cwd}/${fileInclude}`; - } + let path = _.startsWith(fileInclude, './') ? `${cwd}/${fileInclude.substr(2)}` : `${cwd}/${fileInclude}`; // HACK: tsconfig.json needs wildcard directory endings as `/**/*` // but TypeDoc needs it as `/**` in order to pick up files at the root @@ -81,15 +136,10 @@ export const postpublishUtils = { }); return fileIncludesAdjusted; }, - async generateAndUploadDocsAsync( - dirname: string, - cwd: string, - includedFiles: string[], - version: string, - S3BucketPath: string, - ) { - const jsonFilePath = `${dirname}/../${postpublishUtils.generatedDocsDirectoryName}/index.json`; - const projectFiles = includedFiles.join(' '); + async generateAndUploadDocsAsync(cwd: string, fileIncludes: string[], version: string, S3BucketPath: string) { + const fileIncludesAdjusted = this.adjustFileIncludePaths(fileIncludes, cwd); + const projectFiles = fileIncludesAdjusted.join(' '); + const jsonFilePath = `${cwd}/${generatedDocsDirectoryName}/index.json`; const result = await execAsync( `JSON_FILE_PATH=${jsonFilePath} PROJECT_FILES="${projectFiles}" yarn docs:json`, { @@ -105,7 +155,10 @@ export const postpublishUtils = { await execAsync(`S3_URL=${s3Url} yarn upload_docs_json`, { cwd, }); + // Remove the generated docs directory + await execAsync(`rm -rf ${generatedDocsDirectoryName}`, { + cwd, + }); utils.log(`POSTPUBLISH: Docs uploaded to S3 bucket: ${S3BucketPath}`); }, - generatedDocsDirectoryName, }; -- cgit v1.2.3 From 28abcef1cac095e61d4eb94d42870d3f608d9a97 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 14 Mar 2018 14:32:45 +0100 Subject: Remove outdated comment --- packages/monorepo-scripts/src/postpublish_utils.ts | 3 --- 1 file changed, 3 deletions(-) (limited to 'packages/monorepo-scripts/src') diff --git a/packages/monorepo-scripts/src/postpublish_utils.ts b/packages/monorepo-scripts/src/postpublish_utils.ts index 55c44ca63..d90d50fba 100644 --- a/packages/monorepo-scripts/src/postpublish_utils.ts +++ b/packages/monorepo-scripts/src/postpublish_utils.ts @@ -39,9 +39,6 @@ export const postpublishUtils = { version: packageJSON.version, assets: _.get(postpublishConfig, 'assets', []), docPublishConfigs: { - // Include any external packages that are part of the 0x.js public interface - // to this array so that TypeDoc picks it up and adds it to the Docs JSON - // So far, we only have @0xproject/types as part of 0x.js's public interface. fileIncludes: [ ...(tsConfigJSON as any).include, ..._.get(postpublishConfig, 'docPublishConfigs.extraFileIncludes', []), -- cgit v1.2.3 From 83ae7ba08d55fa964bf7b7a985aea0fe1520c5c7 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Wed, 14 Mar 2018 14:49:09 +0100 Subject: Fix linter issuesx --- packages/monorepo-scripts/src/postpublish_utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/monorepo-scripts/src') diff --git a/packages/monorepo-scripts/src/postpublish_utils.ts b/packages/monorepo-scripts/src/postpublish_utils.ts index d90d50fba..898b00c47 100644 --- a/packages/monorepo-scripts/src/postpublish_utils.ts +++ b/packages/monorepo-scripts/src/postpublish_utils.ts @@ -40,7 +40,7 @@ export const postpublishUtils = { assets: _.get(postpublishConfig, 'assets', []), docPublishConfigs: { fileIncludes: [ - ...(tsConfigJSON as any).include, + ...tsConfigJSON.include, ..._.get(postpublishConfig, 'docPublishConfigs.extraFileIncludes', []), ], s3BucketPath: _.get(postpublishConfig, 'docPublishConfigs.s3BucketPath'), -- cgit v1.2.3