diff options
Diffstat (limited to 'packages/monorepo-scripts')
-rw-r--r-- | packages/monorepo-scripts/CHANGELOG.md | 5 | ||||
-rw-r--r-- | packages/monorepo-scripts/package.json | 12 | ||||
-rw-r--r-- | packages/monorepo-scripts/src/globals.d.ts | 8 | ||||
-rw-r--r-- | packages/monorepo-scripts/src/index.ts | 1 | ||||
-rw-r--r-- | packages/monorepo-scripts/src/postpublish_utils.ts | 161 | ||||
-rw-r--r-- | packages/monorepo-scripts/src/utils.ts | 5 |
6 files changed, 189 insertions, 3 deletions
diff --git a/packages/monorepo-scripts/CHANGELOG.md b/packages/monorepo-scripts/CHANGELOG.md new file mode 100644 index 000000000..bb685a436 --- /dev/null +++ b/packages/monorepo-scripts/CHANGELOG.md @@ -0,0 +1,5 @@ +CHANGELOG + +## v0.1.13 - _TBD_ + + * Add postpublish utils diff --git a/packages/monorepo-scripts/package.json b/packages/monorepo-scripts/package.json index 9a4e414e3..3a6fecf6a 100644 --- a/packages/monorepo-scripts/package.json +++ b/packages/monorepo-scripts/package.json @@ -1,8 +1,9 @@ { "name": "@0xproject/monorepo-scripts", "version": "0.1.12", - "private": true, "description": "Helper scripts for the monorepo", + "main": "lib/index.js", + "types": "lib/index.d.ts", "scripts": { "build:watch": "tsc -w", "deps_versions": "node ./lib/deps_versions.js", @@ -19,8 +20,9 @@ "url": "https://github.com/0xProject/0x-monorepo/issues" }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/monorepo-scripts/README.md", + "comment": "// We purposefully use an older version of tslint-config here to avoid creating an import cycle", "devDependencies": { - "@0xproject/tslint-config": "^0.4.10", + "@0xproject/tslint-config": "0.4.8", "@types/glob": "^5.0.33", "@types/node": "^8.0.53", "shx": "^0.2.2", @@ -29,8 +31,12 @@ }, "dependencies": { "@0xproject/utils": "^0.4.1", + "es6-promisify": "^5.0.0", + "async-child-process": "^1.1.1", + "publish-release": "0xproject/publish-release", "chalk": "^2.3.0", "glob": "^7.1.2", - "lodash": "^4.17.4" + "lodash": "^4.17.4", + "semver-sort": "^0.0.4" } } 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..898b00c47 --- /dev/null +++ b/packages/monorepo-scripts/src/postpublish_utils.ts @@ -0,0 +1,161 @@ +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'); + +import { utils } from './utils'; + +const publishReleaseAsync = promisify(publishRelease); +const githubPersonalAccessToken = process.env.GITHUB_PERSONAL_ACCESS_TOKEN_0X_JS; +const generatedDocsDirectoryName = 'generated_docs'; + +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 = { + 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.'); + } + 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: { + fileIncludes: [ + ...tsConfigJSON.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<void> { + 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(cwd: string, packageName: string, version: string, assets: string[]): Promise<void> { + const releaseName = this.getReleaseName(packageName, version); + const tag = this.getTag(packageName, version); + utils.log('POSTPUBLISH: Releasing ', releaseName, '...'); + const finalAssets = this.adjustAssetPaths(cwd, assets); + const result = await publishReleaseAsync({ + token: githubPersonalAccessToken, + owner: '0xProject', + repo: '0x-monorepo', + tag, + name: releaseName, + notes: 'N/A', + draft: false, + prerelease: false, + reuseRelease: true, + reuseDraftOnly: false, + assets, + }); + }, + getTag(packageName: string, version: string) { + return `${packageName}@${version}`; + }, + getReleaseName(subPackageName: string, version: string): string { + const releaseName = `${subPackageName} v${version}`; + return releaseName; + }, + 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 = _.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 + if (_.endsWith(path, '/**/*')) { + path = path.slice(0, -2); + } + return path; + }); + return fileIncludesAdjusted; + }, + 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`, + { + 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, + }); + // Remove the generated docs directory + await execAsync(`rm -rf ${generatedDocsDirectoryName}`, { + cwd, + }); + utils.log(`POSTPUBLISH: Docs uploaded to S3 bucket: ${S3BucketPath}`); + }, +}; 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 + }, +}; |