diff --git a/.github/workflows/devPush.yml b/.github/workflows/devPush.yml index 4532901049f..e6187938eb7 100644 --- a/.github/workflows/devPush.yml +++ b/.github/workflows/devPush.yml @@ -271,13 +271,9 @@ jobs: - name: Set git username run: git config --global user.name "webiny-bot" - - name: Version packages (no push, no changelog) + - name: Version and publish to Verdaccio working-directory: dev - run: yarn lerna:version:verdaccio - - - name: Release to Verdaccio - working-directory: dev - run: yarn lerna:publish:verdaccio + run: yarn release --type=verdaccio - name: Create verdaccio-files artifact uses: actions/upload-artifact@v3 @@ -300,8 +296,8 @@ jobs: - name: Create a new Webiny project working-directory: xyz run: > - npx create-webiny-project@next test-project - --tag next --no-interactive + npx create-webiny-project@local-npm test-project + --tag local-npm --no-interactive --assign-to-yarnrc '{"npmRegistryServer":"http://localhost:4873","unsafeHttpWhitelist":["localhost"]}' --template-options '{"region":"${{ env.AWS_REGION }}","storageOperations":"ddb"}' @@ -525,13 +521,9 @@ jobs: - name: Set git username run: git config --global user.name "webiny-bot" - - name: Version packages (no push, no changelog) - working-directory: dev - run: yarn lerna:version:verdaccio - - - name: Release to Verdaccio + - name: Version and publish to Verdaccio working-directory: dev - run: yarn lerna:publish:verdaccio + run: yarn release --type=verdaccio - name: Create verdaccio-files artifact uses: actions/upload-artifact@v3 @@ -554,8 +546,8 @@ jobs: - name: Create a new Webiny project working-directory: xyz run: > - npx create-webiny-project@next test-project - --tag next --no-interactive + npx create-webiny-project@local-npm test-project + --tag local-npm --no-interactive --assign-to-yarnrc '{"npmRegistryServer":"http://localhost:4873","unsafeHttpWhitelist":["localhost"]}' --template-options '{"region":"${{ env.AWS_REGION }}","storageOperations":"ddb-es"}' diff --git a/.github/workflows/nextPush.yml b/.github/workflows/nextPush.yml index dffdbde6c08..1c52eb41ad0 100644 --- a/.github/workflows/nextPush.yml +++ b/.github/workflows/nextPush.yml @@ -271,13 +271,9 @@ jobs: - name: Set git username run: git config --global user.name "webiny-bot" - - name: Version packages (no push, no changelog) + - name: Version and publish to Verdaccio working-directory: next - run: yarn lerna:version:verdaccio - - - name: Release to Verdaccio - working-directory: next - run: yarn lerna:publish:verdaccio + run: yarn release --type=verdaccio - name: Create verdaccio-files artifact uses: actions/upload-artifact@v3 @@ -300,8 +296,8 @@ jobs: - name: Create a new Webiny project working-directory: xyz run: > - npx create-webiny-project@next test-project - --tag next --no-interactive + npx create-webiny-project@local-npm test-project + --tag local-npm --no-interactive --assign-to-yarnrc '{"npmRegistryServer":"http://localhost:4873","unsafeHttpWhitelist":["localhost"]}' --template-options '{"region":"${{ env.AWS_REGION }}","storageOperations":"ddb"}' @@ -525,13 +521,9 @@ jobs: - name: Set git username run: git config --global user.name "webiny-bot" - - name: Version packages (no push, no changelog) - working-directory: next - run: yarn lerna:version:verdaccio - - - name: Release to Verdaccio + - name: Version and publish to Verdaccio working-directory: next - run: yarn lerna:publish:verdaccio + run: yarn release --type=verdaccio - name: Create verdaccio-files artifact uses: actions/upload-artifact@v3 @@ -554,8 +546,8 @@ jobs: - name: Create a new Webiny project working-directory: xyz run: > - npx create-webiny-project@next test-project - --tag next --no-interactive + npx create-webiny-project@local-npm test-project + --tag local-npm --no-interactive --assign-to-yarnrc '{"npmRegistryServer":"http://localhost:4873","unsafeHttpWhitelist":["localhost"]}' --template-options '{"region":"${{ env.AWS_REGION }}","storageOperations":"ddb-es"}' @@ -679,7 +671,14 @@ jobs: workdir: next/cypress message-text: Cypress tests failed! Screenshots have been placed in this thread, good luck. npm-release-unstable: - needs: [init, code-analysis, jest-tests, e2e-wby-cms-ddb-cypress-tests, e2e-wby-cms-ddb-es-cypress-tests] + needs: + [ + init, + code-analysis, + jest-tests, + e2e-wby-cms-ddb-cypress-tests, + e2e-wby-cms-ddb-es-cypress-tests + ] name: NPM release ("unstable" tag) runs-on: webiny-js-4-cores environment: release @@ -720,10 +719,5 @@ jobs: git config --global user.email "webiny-bot@webiny.com" git config --global user.name "webiny-bot" - - name: Version packages - run: | - yarn lerna version 0.0.0-unstable.$(git rev-parse --short HEAD) --force-publish --no-push --no-git-tag-version --no-changelog --yes - git commit -am "chore: version packages" - - - name: Publish packages to NPM - run: yarn lerna publish from-package --dist-tag unstable --yes + - name: Version and publish to NPM + run: yarn release --type=unstable diff --git a/.github/workflows/pullRequests.yml b/.github/workflows/pullRequests.yml index 098703ce21d..734a14f5bb1 100644 --- a/.github/workflows/pullRequests.yml +++ b/.github/workflows/pullRequests.yml @@ -202,21 +202,12 @@ jobs: path: .webiny/cached-packages key: packages-cache-${{ needs.init.outputs.ts }} - - name: Git status - run: git status - - name: Install dependencies run: yarn --immutable - - name: Git status - run: git status && git diff packages-v6/cli/src/bin.js - - name: Build packages run: node scripts/buildWithCache.js --build-overrides='${{ env.BUILD_OVERRIDES }}' - - name: Git status - run: git status - - name: Start Verdaccio local server run: npx pm2 start verdaccio -- -c .verdaccio.yaml @@ -232,17 +223,8 @@ jobs: - name: Set git username run: git config --global user.name "webiny-bot" - - name: Git status - run: git status - - - name: Version packages (no push, no changelog) - run: yarn lerna:version:verdaccio - - - name: Git status - run: git status - - - name: Release to Verdaccio - run: yarn lerna:publish:verdaccio + - name: Version and publish to Verdaccio + run: yarn release --type=verdaccio - name: Upload verdaccio files uses: actions/upload-artifact@v3 @@ -294,8 +276,8 @@ jobs: - name: Create a new Webiny project run: > - npx create-webiny-project@next test-project - --tag next --no-interactive + npx create-webiny-project@local-npm test-project + --tag local-npm --no-interactive --assign-to-yarnrc '{"npmRegistryServer":"http://localhost:4873","unsafeHttpWhitelist":["localhost"]}' --template-options '{"region":"eu-central-1"}' diff --git a/.github/workflows/pullRequestsCommandCypress.yml b/.github/workflows/pullRequestsCommandCypress.yml index f1e545f969b..f9c76e73655 100644 --- a/.github/workflows/pullRequestsCommandCypress.yml +++ b/.github/workflows/pullRequestsCommandCypress.yml @@ -137,13 +137,9 @@ jobs: - name: Set git username run: git config --global user.name "webiny-bot" - - name: Version packages (no push, no changelog) + - name: Version and publish to Verdaccio working-directory: dev - run: yarn lerna:version:verdaccio - - - name: Release to Verdaccio - working-directory: dev - run: yarn lerna:publish:verdaccio + run: yarn release --type=verdaccio - name: Create verdaccio-files artifact uses: actions/upload-artifact@v3 @@ -166,8 +162,8 @@ jobs: - name: Create a new Webiny project working-directory: xyz run: > - npx create-webiny-project@next test-project - --tag next --no-interactive + npx create-webiny-project@local-npm test-project + --tag local-npm --no-interactive --assign-to-yarnrc '{"npmRegistryServer":"http://localhost:4873","unsafeHttpWhitelist":["localhost"]}' --template-options '{"region":"${{ env.AWS_REGION }}","storageOperations":"ddb"}' @@ -404,13 +400,9 @@ jobs: - name: Set git username run: git config --global user.name "webiny-bot" - - name: Version packages (no push, no changelog) - working-directory: dev - run: yarn lerna:version:verdaccio - - - name: Release to Verdaccio + - name: Version and publish to Verdaccio working-directory: dev - run: yarn lerna:publish:verdaccio + run: yarn release --type=verdaccio - name: Create verdaccio-files artifact uses: actions/upload-artifact@v3 @@ -433,8 +425,8 @@ jobs: - name: Create a new Webiny project working-directory: xyz run: > - npx create-webiny-project@next test-project - --tag next --no-interactive + npx create-webiny-project@local-npm test-project + --tag local-npm --no-interactive --assign-to-yarnrc '{"npmRegistryServer":"http://localhost:4873","unsafeHttpWhitelist":["localhost"]}' --template-options '{"region":"${{ env.AWS_REGION }}","storageOperations":"ddb-es"}' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 32b07f7a1a7..a00c35dc529 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,7 @@ name: Release (latest) on: workflow_dispatch: repository_dispatch: - types: [release-latest] + types: [release] env: NODE_OPTIONS: --max_old_space_size=4096 @@ -41,14 +41,5 @@ jobs: - name: Set git username run: git config --global user.name "webiny-bot" - - name: Create a release on GitHub - run: yarn lerna:version:latest - - - name: Release packages to NPM - run: yarn lerna:publish:latest - - - name: Update package versions in the sample project applications' packages - run: 'yarn webiny-versions && yarn prettier:fix && git add . && git commit --m "chore: update package versions (webiny-versions)" --no-verify && git push' - - - name: Update and commit "yarn.lock" file - run: 'yarn && git add yarn.lock && git commit --m "chore: update yarn.lock" --no-verify && git push' + - name: Version and Publish + run: yarn release --type=${{ github.event.client_payload.type }} --tag=${{ github.event.client_payload.tag }} diff --git a/.github/workflows/stablePush.yml b/.github/workflows/stablePush.yml index 3b08465789b..3304c9e749c 100644 --- a/.github/workflows/stablePush.yml +++ b/.github/workflows/stablePush.yml @@ -268,13 +268,9 @@ jobs: - name: Set git username run: git config --global user.name "webiny-bot" - - name: Version packages (no push, no changelog) + - name: Version and publish to Verdaccio working-directory: v5 - run: yarn lerna:version:verdaccio - - - name: Release to Verdaccio - working-directory: v5 - run: yarn lerna:publish:verdaccio + run: yarn release --type=verdaccio - name: Create verdaccio-files artifact uses: actions/upload-artifact@v3 @@ -297,8 +293,8 @@ jobs: - name: Create a new Webiny project working-directory: xyz run: > - npx create-webiny-project@next test-project - --tag next --no-interactive + npx create-webiny-project@local-npm test-project + --tag local-npm --no-interactive --assign-to-yarnrc '{"npmRegistryServer":"http://localhost:4873","unsafeHttpWhitelist":["localhost"]}' --template-options '{"region":"${{ env.AWS_REGION }}","storageOperations":"ddb"}' @@ -515,13 +511,9 @@ jobs: - name: Set git username run: git config --global user.name "webiny-bot" - - name: Version packages (no push, no changelog) - working-directory: v5 - run: yarn lerna:version:verdaccio - - - name: Release to Verdaccio + - name: Version and publish to Verdaccio working-directory: v5 - run: yarn lerna:publish:verdaccio + run: yarn release --type=verdaccio - name: Create verdaccio-files artifact uses: actions/upload-artifact@v3 @@ -544,8 +536,8 @@ jobs: - name: Create a new Webiny project working-directory: xyz run: > - npx create-webiny-project@next test-project - --tag next --no-interactive + npx create-webiny-project@local-npm test-project + --tag local-npm --no-interactive --assign-to-yarnrc '{"npmRegistryServer":"http://localhost:4873","unsafeHttpWhitelist":["localhost"]}' --template-options '{"region":"${{ env.AWS_REGION }}","storageOperations":"ddb-es"}' @@ -717,14 +709,5 @@ jobs: - name: Set git username run: git config --global user.name "webiny-bot" - - name: Create a release on GitHub - run: yarn lerna:version:beta - - - name: Release packages to NPM - run: yarn lerna:publish:beta - - - name: Update package versions in the sample project applications' packages - run: 'yarn webiny-versions && yarn prettier:fix && git add . && git commit --m "chore: update package versions (webiny-versions)" --no-verify && git push' - - - name: Update and commit "yarn.lock" file - run: 'yarn && git add yarn.lock && git commit --m "chore: update yarn.lock" --no-verify && git push' + - name: Version and publish to NPM + run: yarn release --type=beta diff --git a/.gitignore b/.gitignore index 8e5460e02c4..64f0c7035bf 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ schema.graphql !.yarn/sdks !.yarn/versions .pnp.* +lerna.json # TODO remove after moving traffic splitting config to WPC gateway.*.json diff --git a/.yarn/patches/@lerna-publish-npm-3.22.1-469707df67 b/.yarn/patches/@lerna-publish-npm-3.22.1-469707df67 new file mode 100644 index 00000000000..a321ff6d733 --- /dev/null +++ b/.yarn/patches/@lerna-publish-npm-3.22.1-469707df67 @@ -0,0 +1,14 @@ +diff --git a/index.js b/index.js +index 078012845cadbee7cf45de6f101384ed99d269e5..27968d61d9a5bf8a85b8fc2a44e7e012d1dc7e2a 100644 +--- a/index.js ++++ b/index.js +@@ -248,7 +248,8 @@ class PublishCommand extends Command { + } + + verifyWorkingTreeClean() { +- return describeRef(this.execOpts).then(checkWorkingTree.throwIfUncommitted); ++ return Promise.resolve(); ++ // return describeRef(this.execOpts).then(checkWorkingTree.throwIfUncommitted); + } + + detectFromGit() { diff --git a/lerna.json b/example.lerna.json similarity index 85% rename from lerna.json rename to example.lerna.json index c50e606dab6..15dd1f56892 100644 --- a/lerna.json +++ b/example.lerna.json @@ -1,9 +1,6 @@ { - "packages": [ - "packages/*", - "packages-v6/*" - ], - "version": "5.33.2", + "packages": ["packages/*", "packages-v6/*"], + "version": "0.0.0", "npmClient": "yarn", "command": { "version": { diff --git a/package.json b/package.json index bc2fec098ee..959029b35a1 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@commitlint/cli": "^11.0.0", "@commitlint/config-conventional": "^11.0.0", "@deploysentinel/cypress-debugger": "^0.2.5", + "@octokit/rest": "^19.0.5", "@testing-library/cypress": "^8.0.2", "@types/fs-extra": "^8.0.1", "@types/jest": "^24.0.24", @@ -131,7 +132,7 @@ "commit:no-verify": "yarn commit --no-verify", "commit:verify": "yarn lint-staged", "webiny-versions": "node ./scripts/webinyVersions.js", - "release-latest": "node ./scripts/releaseLatest.js", + "trigger-release": "node ./scripts/release/triggerRelease.js", "dispatch-github-event": "node ./scripts/dispatchGitHubEvent.js", "lint-staged": "lint-staged", "postinstall": "yarn node ./scripts/linkWorkspaces.js", @@ -140,6 +141,7 @@ "prettier:check": "yarn prettier --check", "prettier:fix": "yarn prettier --write", "lint:fix": "yarn eslint:fix && yarn prettier:fix", + "release": "node ./scripts/release/index.js", "setup-project": "node scripts/setupProject", "setup-env-files": "node scripts/setupEnvFiles", "setup-cypress": "node scripts/setupCypress", @@ -148,10 +150,6 @@ "test:integration": "cross-env TEST_TYPE=integration yarn test", "test:e2e": "cross-env TEST_TYPE=e2e yarn test", "validate-packages": "node scripts/validatePackages.js", - "lerna:version:latest": "yarn lerna version --force-publish --conventional-graduate --yes", - "lerna:publish:latest": "yarn lerna publish from-package --yes", - "lerna:version:beta": "yarn lerna version --conventional-prerelease --force-publish --preid beta --yes", - "lerna:publish:beta": "yarn lerna publish from-package --dist-tag beta --yes", "lerna:version:verdaccio": "yarn lerna version --conventional-prerelease --force-publish --preid next --no-push --no-changelog --yes", "lerna:publish:verdaccio": "yarn lerna publish from-package --dist-tag next --registry=\"http://localhost:4873\" --no-verify-access --no-verify-registry --yes", "lerna:version:experimental": "yarn lerna version --conventional-prerelease --preid experimental --force-publish --no-push --no-changelog --yes", @@ -210,6 +208,13 @@ ] } }, + "lerna": { + "version": "0.0.0", + "packages": [ + "packages/*", + "packages-v6/*" + ] + }, "resolutions": { "@types/react": "17.0.39", "@types/jsdom": "link:./typings/void", @@ -221,7 +226,8 @@ "codex-tooltip": "1.0.2", "@types/eslint": "8.2.1", "yargs": "^17.3.1", - "@lerna/version@3.22.1": "patch:@lerna/version@npm:3.22.1#.yarn/patches/@lerna-version-npm-3.22.1-97f4c3a7dd" + "@lerna/version@3.22.1": "patch:@lerna/version@npm:3.22.1#.yarn/patches/@lerna-version-npm-3.22.1-97f4c3a7dd", + "@lerna/publish@3.22.1": "patch:@lerna/publish@npm:3.22.1#.yarn/patches/@lerna-publish-npm-3.22.1-469707df67" }, "packageManager": "yarn@3.2.1" } diff --git a/scripts/ConsoleLogger.js b/scripts/ConsoleLogger.js new file mode 100644 index 00000000000..974348489be --- /dev/null +++ b/scripts/ConsoleLogger.js @@ -0,0 +1,54 @@ +const chalk = require("chalk"); + +const logColors = { + log: v => v, + info: chalk.blueBright, + error: chalk.red, + warning: chalk.yellow, + debug: chalk.gray, + success: chalk.green +}; + +const colorizePlaceholders = (type, string) => { + return string.replace(/\%[a-zA-Z]/g, match => { + return logColors[type](match); + }); +}; + +const log = (type, ...args) => { + const prefix = `webiny ${logColors[type](type)}: `; + + const [first, ...rest] = args; + if (typeof first === "string") { + return console.log(prefix + colorizePlaceholders(type, first), ...rest); + } + return console.log(prefix, first, ...rest); +}; + +class ConsoleLogger { + log(...args) { + log("log", ...args); + } + + info(...args) { + log("info", ...args); + } + + success(...args) { + log("success", ...args); + } + + debug(...args) { + log("debug", ...args); + } + + warning(...args) { + log("warning", ...args); + } + + error(...args) { + log("error", ...args); + } +} + +module.exports = { ConsoleLogger }; diff --git a/scripts/release/BetaRelease.js b/scripts/release/BetaRelease.js new file mode 100644 index 00000000000..01aec6fcb11 --- /dev/null +++ b/scripts/release/BetaRelease.js @@ -0,0 +1,26 @@ +const { Release } = require("./Release"); + +class BetaRelease extends Release { + constructor(logger) { + super(logger); + this.setTag("beta"); + this.setVersion(["--conventional-prerelease", "--preid", "beta"]); + this.setCreateGithubRelease(false); + } + + setTag(tag) { + if (tag !== "beta") { + this.logger.warning( + "Beta release can only be published using the %s tag; the requested %s tag will be ignored.", + "beta", + tag + ); + + return; + } + + super.setTag(tag); + } +} + +module.exports = { BetaRelease }; diff --git a/scripts/release/LatestRelease.js b/scripts/release/LatestRelease.js new file mode 100644 index 00000000000..1a40d535c3f --- /dev/null +++ b/scripts/release/LatestRelease.js @@ -0,0 +1,28 @@ +const { Release } = require("./Release"); + +class LatestRelease extends Release { + defaultTag = "latest"; + + constructor(logger) { + super(logger); + this.setTag(this.defaultTag); + this.setVersion("--conventional-graduate"); + this.setCreateGithubRelease(true); + } + + setTag(tag) { + if (tag !== this.defaultTag) { + this.logger.warning( + "Latest release can only be published using the %s tag; the requested %s tag will be ignored.", + this.defaultTag, + tag + ); + + return; + } + + super.setTag(tag); + } +} + +module.exports = { LatestRelease }; diff --git a/scripts/release/Release.js b/scripts/release/Release.js new file mode 100644 index 00000000000..13067d1d414 --- /dev/null +++ b/scripts/release/Release.js @@ -0,0 +1,192 @@ +const fetch = require("node-fetch"); +const pRetry = require("p-retry"); +const semver = require("semver"); +const execa = require("execa"); +const loadJSON = require("load-json-file"); +const writeJSON = require("write-json-file"); +const ConventionalCommitUtilities = require("@lerna/conventional-commits"); +const { Octokit } = require("@octokit/rest"); + +class Release { + tag = undefined; + version = undefined; + createGithubRelease = false; + + constructor(logger) { + if (!logger) { + throw Error(`Missing required constructor argument "logger"!`); + } + + this.logger = logger; + } + + /** + * NPM dist-tag to publish. + * @param tag + */ + setTag(tag) { + this.tag = tag; + } + + /** + * A parameter passed to `lerna version` to generate version. + * Examples: + * Latest: --conventional-graduate + * Beta: --conventional-prerelease --preid beta + * Unstable: 0.0.0-unstable.b7124ae31d + * @param version String | String[] | Function + */ + setVersion(version) { + this.version = version; + } + + setCreateGithubRelease(flag) { + this.createGithubRelease = flag; + } + + async execute() { + this.__validateConfig(); + + this.logger.info("Attempting to release tag %s", this.tag); + + // Generate `lerna.json` using `example.lerna.json`. + { + // Determine current version + const tags = await this.__getTags(); + const mostRecentVersion = this.__getMostRecentVersion( + [tags["latest"], tags[this.tag === "latest" ? "beta" : this.tag]].filter(Boolean) + ); + + this.logger.info("Most recent version is %s", mostRecentVersion); + const lernaJSON = await loadJSON("example.lerna.json"); + lernaJSON.version = mostRecentVersion; + await writeJSON("lerna.json", lernaJSON); + this.logger.info("Lerna config was written to %s", "lerna.json"); + } + + // Run `lerna` to version packages + let version = this.version; + if (typeof this.version === "function") { + version = await this.version(); + } + + if (!Array.isArray(version)) { + version = [version]; + } + + const lernaVersionArgs = [ + "lerna", + "version", + ...version, + "--force-publish", + "--no-changelog", + "--no-git-tag-version", + "--no-push", + "--yes" + ]; + + this.logger.debug(lernaVersionArgs.join(" ")); + await execa("yarn", lernaVersionArgs, { stdio: "inherit" }); + this.logger.info("Packages versioning completed"); + + // Run `lerna` to publish packages + const lernaPublishArgs = [ + "lerna", + "publish", + "from-package", + "--dist-tag", + this.tag, + "--yes" + ]; + + this.logger.debug(lernaPublishArgs.join(" ")); + await execa("yarn", lernaPublishArgs, { stdio: "inherit" }); + this.logger.info(`Packages were published to NPM under %s dist-tag`, this.tag); + + if (this.createGithubRelease) { + // Generate changelog, tag commit, and create Github release. + const lernaJSON = await loadJSON("lerna.json"); + const versionTag = `v${lernaJSON.version}`; + + // Changelog needs to be generated _before_ tagging. + const changelog = await this.__getChangelog(lernaJSON.version); + this.logger.info("Generated release notes"); + + // Create the tag + await execa("git", ["tag", versionTag, "-m", versionTag]); + await execa("git", ["push", "origin", versionTag]); + this.logger.info("Created Git tag %s", versionTag); + + const { data: release } = await this.__createGithubRelease(versionTag, changelog); + this.logger.info("Created Github release: %s", release.html_url); + } + + // Reset all changes made during versioing. + await execa("git", ["reset", "--hard", "HEAD"]); + + this.logger.success("Release process has finished successfully!"); + } + + __validateConfig() { + if (this.createGithubRelease && !process.env.GH_TOKEN) { + throw Error("GH_TOKEN environment variable is not set."); + } + + if (!this.version) { + throw Error( + `Versioning is not configured! Use "setVersion" to configure lerna versioning.` + ); + } + } + + async __getTags() { + const { stdout: npmRegistry } = await execa("npm", ["config", "get", "registry"]); + this.logger.debug("Using NPM registry at %s", npmRegistry); + const getVersion = async () => { + const res = await fetch(`${npmRegistry.replace(/\/$/, "")}/@webiny/cli`); + const json = await res.json(); + + return json["dist-tags"]; + }; + + return pRetry(getVersion, { retries: 5 }); + } + + __getMostRecentVersion(versions) { + return semver.sort(versions).pop().toString(); + } + + async __getChangelog(version) { + const manifest = { + name: "root", + location: process.cwd(), + manifestLocation: process.cwd() + "/package.json" + }; + + return ConventionalCommitUtilities.updateChangelog(manifest, "root", { + rootPath: process.cwd(), + tagPrefix: "v", + version + }).then(({ newEntry }) => { + return newEntry; + }); + } + + async __createGithubRelease(tag, changelog) { + const client = new Octokit({ + auth: `token ${process.env.GH_TOKEN}` + }); + + return client.repos.createRelease({ + owner: "webiny", + repo: "webiny-js", + tag_name: tag, + name: tag, + body: changelog, + draft: true, + prerelease: false + }); + } +} + +module.exports = { Release }; diff --git a/scripts/release/UnstableRelease.js b/scripts/release/UnstableRelease.js new file mode 100644 index 00000000000..bb7e87f021d --- /dev/null +++ b/scripts/release/UnstableRelease.js @@ -0,0 +1,26 @@ +const execa = require("execa"); +const { Release } = require("./Release"); + +class UnstableRelease extends Release { + protectedTags = ["latest", "beta"]; + + constructor(logger) { + super(logger); + this.setTag("unstable"); + this.setVersion(async () => { + const { stdout: commitHash } = await execa("git", ["rev-parse", "--short", "HEAD"]); + return `0.0.0-${this.tag}.${commitHash}`; + }); + this.setCreateGithubRelease(false); + } + + setTag(tag) { + if (this.protectedTags.includes(tag)) { + throw Error(`Protected tag "${tag}" can't be used in an unstable release!`); + } + + super.setTag(tag); + } +} + +module.exports = { UnstableRelease }; diff --git a/scripts/release/VerdaccioRelease.js b/scripts/release/VerdaccioRelease.js new file mode 100644 index 00000000000..49a2733751f --- /dev/null +++ b/scripts/release/VerdaccioRelease.js @@ -0,0 +1,16 @@ +const { Release } = require("./Release"); + +class VerdaccioRelease extends Release { + defaultTag = "local-npm"; + + constructor(logger) { + super(logger); + this.setTag(this.defaultTag); + this.setVersion(() => { + return ["--conventional-prerelease", "--preid", this.tag]; + }); + this.setCreateGithubRelease(false); + } +} + +module.exports = { VerdaccioRelease }; diff --git a/scripts/release/index.js b/scripts/release/index.js new file mode 100644 index 00000000000..0032be50032 --- /dev/null +++ b/scripts/release/index.js @@ -0,0 +1,21 @@ +const yargs = require("yargs"); +const { ConsoleLogger } = require("../ConsoleLogger"); +const { getReleaseType } = require("./releaseTypes"); + +(async () => { + const { type, tag } = yargs.argv; + if (!type) { + throw Error(`Missing required "--type" option.`); + } + + const Release = getReleaseType(type); + + const logger = new ConsoleLogger(); + const release = new Release(logger); + + if (tag) { + release.setTag(tag); + } + + await release.execute(); +})(); diff --git a/scripts/release/releaseTypes.js b/scripts/release/releaseTypes.js new file mode 100644 index 00000000000..4c19ad8c856 --- /dev/null +++ b/scripts/release/releaseTypes.js @@ -0,0 +1,26 @@ +const { LatestRelease } = require("./LatestRelease"); +const { BetaRelease } = require("./BetaRelease"); +const { UnstableRelease } = require("./UnstableRelease"); +const { VerdaccioRelease } = require("./VerdaccioRelease"); + +const releaseTypes = { + latest: LatestRelease, + beta: BetaRelease, + unstable: UnstableRelease, + verdaccio: VerdaccioRelease +}; + +const checkReleaseType = type => { + if (!releaseTypes[type]) { + const possibleTypes = Object.keys(releaseTypes).join(", "); + throw Error(`Unrecognized release type "${type}". Specify one of: ${possibleTypes}.`); + } +}; + +const getReleaseType = type => { + checkReleaseType(type); + + return releaseTypes[type]; +}; + +module.exports = { getReleaseType, checkReleaseType }; diff --git a/scripts/release/triggerRelease.js b/scripts/release/triggerRelease.js new file mode 100644 index 00000000000..b250f2dc38d --- /dev/null +++ b/scripts/release/triggerRelease.js @@ -0,0 +1,57 @@ +#!/usr/bin/env node +const yargs = require("yargs"); +const { Octokit } = require("@octokit/rest"); +const { ConsoleLogger } = require("../ConsoleLogger"); +const { checkReleaseType } = require("./releaseTypes"); + +/** + * A simple script that will trigger the "release" GitHub workflow. + */ + +(async () => { + const { branch, type, token, tag } = yargs.argv; + + try { + if (!branch) { + throw Error(`"--branch" argument missing. Specify a branch you want to release.`); + } + + if (!type) { + throw Error(`"--type" argument missing. Specify one of: latest, beta, unstable.`); + } + + checkReleaseType(type); + + if (!token) { + throw Error( + `"--token" argument missing. Make sure it contains a valid GitHub access token.` + ); + } + + const logger = new ConsoleLogger(); + + logger.info("Branch: %s", branch); + logger.info("Type: %s", type); + if (tag) { + logger.info("Tag: %s", tag); + } + + const octokit = new Octokit({ auth: `token ${token}` }); + + await octokit.repos.createDispatchEvent({ + owner: "webiny", + repo: "webiny-js", + event_type: "release", + client_payload: { + branch, + type, + tag + } + }); + + logger.success("GitHub workflow triggered successfully!"); + logger.info("See action details: %s", "https://github.com/webiny/webiny-js/actions"); + } catch (e) { + logger.error(e.message); + } +})(); diff --git a/scripts/releaseLatest.js b/scripts/releaseLatest.js deleted file mode 100644 index 9020a20624a..00000000000 --- a/scripts/releaseLatest.js +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env node -const { red, cyan, green } = require("chalk"); -const argv = require("yargs").argv; - -const { Octokit } = require("@octokit/rest"); - -/** - * A simple script that will trigger release-latest GitHub workflow. - * Latest releases are deployed from the "v5" branch. - */ - -const RELEASE_BRANCH = "stable"; - -(async () => { - try { - if (!argv.token) { - throw new Error( - `"--token" argument missing. Make sure it contains a valid GitHub access token.` - ); - } - - const octokit = new Octokit({ - auth: argv.token - }); - - console.log(red(`⚠️⚠️⚠️ I hope you know what you're doing.`)); - console.log( - cyan( - `Triggering a GitHub workflow that will release and publish Webiny of the "${RELEASE_BRANCH}" branch.` - ) - ); - - console.log(cyan(`Triggering...`)); - - await octokit.repos.createDispatchEvent({ - owner: "webiny", - repo: "webiny-js", - event_type: "release-latest", - client_payload: { - branch: RELEASE_BRANCH - } - }); - - console.log(green("GitHub workflow successfully triggered.")); - console.log(green("See https://github.com/webiny/webiny-js/actions for action details.")); - } catch (e) { - console.log(red("Something went wrong:")); - console.log(red(e.message)); - } -})(); diff --git a/yarn.lock b/yarn.lock index d62f25e321d..83b979e3ca0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5339,6 +5339,44 @@ __metadata: languageName: node linkType: hard +"@lerna/publish@patch:@lerna/publish@npm:3.22.1#.yarn/patches/@lerna-publish-npm-3.22.1-469707df67::locator=root-workspace-0b6124%40workspace%3A.": + version: 3.22.1 + resolution: "@lerna/publish@patch:@lerna/publish@npm%3A3.22.1#.yarn/patches/@lerna-publish-npm-3.22.1-469707df67::version=3.22.1&hash=ba03d4&locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@evocateur/libnpmaccess": ^3.1.2 + "@evocateur/npm-registry-fetch": ^4.0.0 + "@evocateur/pacote": ^9.6.3 + "@lerna/check-working-tree": 3.16.5 + "@lerna/child-process": 3.16.5 + "@lerna/collect-updates": 3.20.0 + "@lerna/command": 3.21.0 + "@lerna/describe-ref": 3.16.5 + "@lerna/log-packed": 3.16.0 + "@lerna/npm-conf": 3.16.0 + "@lerna/npm-dist-tag": 3.18.5 + "@lerna/npm-publish": 3.18.5 + "@lerna/otplease": 3.18.5 + "@lerna/output": 3.13.0 + "@lerna/pack-directory": 3.16.4 + "@lerna/prerelease-id-from-version": 3.16.0 + "@lerna/prompt": 3.18.5 + "@lerna/pulse-till-done": 3.13.0 + "@lerna/run-lifecycle": 3.16.2 + "@lerna/run-topologically": 3.18.5 + "@lerna/validation-error": 3.13.0 + "@lerna/version": 3.22.1 + figgy-pudding: ^3.5.1 + fs-extra: ^8.1.0 + npm-package-arg: ^6.1.0 + npmlog: ^4.1.2 + p-finally: ^1.0.0 + p-map: ^2.1.0 + p-pipe: ^1.2.0 + semver: ^6.2.0 + checksum: be10b7a3f7f7b25cc4887c17a1408f5206e5c2b1d382171a94a6274e6e9275635121bc5618c513598fdc465596ab5c94279457ae023ff0118145b4ce4d3768de + languageName: node + linkType: hard + "@lerna/pulse-till-done@npm:3.13.0": version: 3.13.0 resolution: "@lerna/pulse-till-done@npm:3.13.0" @@ -6379,6 +6417,15 @@ __metadata: languageName: node linkType: hard +"@octokit/auth-token@npm:^3.0.0": + version: 3.0.2 + resolution: "@octokit/auth-token@npm:3.0.2" + dependencies: + "@octokit/types": ^8.0.0 + checksum: c7204770a6cb1661379c31b5a26779b509324446e61a4902893a69fd471738c817afc470f8ac8d86ad827738cc953046d27fbb87fc81782ff10e366b70241f4e + languageName: node + linkType: hard + "@octokit/auth-unauthenticated@npm:^2.0.0, @octokit/auth-unauthenticated@npm:^2.0.4": version: 2.1.0 resolution: "@octokit/auth-unauthenticated@npm:2.1.0" @@ -6404,6 +6451,21 @@ __metadata: languageName: node linkType: hard +"@octokit/core@npm:^4.1.0": + version: 4.1.0 + resolution: "@octokit/core@npm:4.1.0" + dependencies: + "@octokit/auth-token": ^3.0.0 + "@octokit/graphql": ^5.0.0 + "@octokit/request": ^6.0.0 + "@octokit/request-error": ^3.0.0 + "@octokit/types": ^8.0.0 + before-after-hook: ^2.2.0 + universal-user-agent: ^6.0.0 + checksum: 4e53e02ff3ebe808b74385be0055cc1cce4b548060b20e3f2d5dd1bf7877ff7b6556f11278edc070842bf24aa869f9f59a02638f1b14083eb290b9e297447a2d + languageName: node + linkType: hard + "@octokit/endpoint@npm:^6.0.1": version: 6.0.12 resolution: "@octokit/endpoint@npm:6.0.12" @@ -6437,6 +6499,17 @@ __metadata: languageName: node linkType: hard +"@octokit/graphql@npm:^5.0.0": + version: 5.0.4 + resolution: "@octokit/graphql@npm:5.0.4" + dependencies: + "@octokit/request": ^6.0.0 + "@octokit/types": ^8.0.0 + universal-user-agent: ^6.0.0 + checksum: 8cf65cf7e6608cf3cbc96a2fa902172b4d5dc30e88ee0bae3711bf467a25b828b10cce1aaabb7f82a7580bfbcf7028b91d1dd1a894940945e38ca2deb6509754 + languageName: node + linkType: hard + "@octokit/oauth-app@npm:^3.3.2, @octokit/oauth-app@npm:^3.5.1": version: 3.7.1 resolution: "@octokit/oauth-app@npm:3.7.1" @@ -6512,6 +6585,13 @@ __metadata: languageName: node linkType: hard +"@octokit/openapi-types@npm:^14.0.0": + version: 14.0.0 + resolution: "@octokit/openapi-types@npm:14.0.0" + checksum: 0a1f8f3be998cd82c5a640e9166d43fd183b33d5d36f5e1a9b81608e94d0da87c01ec46c9988f69cd26585d4e2ffc4d3ec99ee4f75e5fe997fc86dad0aa8293c + languageName: node + linkType: hard + "@octokit/plugin-enterprise-rest@npm:^6.0.1": version: 6.0.1 resolution: "@octokit/plugin-enterprise-rest@npm:6.0.1" @@ -6539,7 +6619,18 @@ __metadata: languageName: node linkType: hard -"@octokit/plugin-request-log@npm:^1.0.0": +"@octokit/plugin-paginate-rest@npm:^5.0.0": + version: 5.0.1 + resolution: "@octokit/plugin-paginate-rest@npm:5.0.1" + dependencies: + "@octokit/types": ^8.0.0 + peerDependencies: + "@octokit/core": ">=4" + checksum: cfded297d9f66c7607bd34075eb0c5f7278a1617d6be86115997c0757151c9be2fcf7a8849c2a5cebab56931a263b5cc35742b6227935afe77f5ed61b0627a3d + languageName: node + linkType: hard + +"@octokit/plugin-request-log@npm:^1.0.0, @octokit/plugin-request-log@npm:^1.0.4": version: 1.0.4 resolution: "@octokit/plugin-request-log@npm:1.0.4" peerDependencies: @@ -6570,6 +6661,18 @@ __metadata: languageName: node linkType: hard +"@octokit/plugin-rest-endpoint-methods@npm:^6.7.0": + version: 6.7.0 + resolution: "@octokit/plugin-rest-endpoint-methods@npm:6.7.0" + dependencies: + "@octokit/types": ^8.0.0 + deprecation: ^2.3.1 + peerDependencies: + "@octokit/core": ">=3" + checksum: 513c6c0717d08f3e85848029bd700412b7d9787750f78cc79a3dede356e94b238bf8a518b108f556a7efe626871720dd0466de9f31091578ea4e0f5a016f0ae7 + languageName: node + linkType: hard + "@octokit/plugin-retry@npm:^3.0.9": version: 3.0.9 resolution: "@octokit/plugin-retry@npm:3.0.9" @@ -6677,6 +6780,18 @@ __metadata: languageName: node linkType: hard +"@octokit/rest@npm:^19.0.5": + version: 19.0.5 + resolution: "@octokit/rest@npm:19.0.5" + dependencies: + "@octokit/core": ^4.1.0 + "@octokit/plugin-paginate-rest": ^5.0.0 + "@octokit/plugin-request-log": ^1.0.4 + "@octokit/plugin-rest-endpoint-methods": ^6.7.0 + checksum: ed4c36859aafb64e23f7f708086fe7e2ecda17ffd8c1594817d539f766f5855af79f17f5d225d96d34cd9b97cbfea988dac3df39a7cc928b2d2b7b75ed981056 + languageName: node + linkType: hard + "@octokit/types@npm:^2.0.0, @octokit/types@npm:^2.0.1": version: 2.16.2 resolution: "@octokit/types@npm:2.16.2" @@ -6704,6 +6819,15 @@ __metadata: languageName: node linkType: hard +"@octokit/types@npm:^8.0.0": + version: 8.0.0 + resolution: "@octokit/types@npm:8.0.0" + dependencies: + "@octokit/openapi-types": ^14.0.0 + checksum: 1a0197b2c4c522ac90f145e02b3f8cb048a47f71c2c6bdbf021a03db7dd30ca92a899c0186acb401337f218efe44e60d33cc1cc68715b622bb75bc1a4e79515d + languageName: node + linkType: hard + "@octokit/webhooks-methods@npm:^2.0.0": version: 2.0.0 resolution: "@octokit/webhooks-methods@npm:2.0.0" @@ -35752,6 +35876,7 @@ __metadata: "@commitlint/cli": ^11.0.0 "@commitlint/config-conventional": ^11.0.0 "@deploysentinel/cypress-debugger": ^0.2.5 + "@octokit/rest": ^19.0.5 "@testing-library/cypress": ^8.0.2 "@types/fs-extra": ^8.0.1 "@types/jest": ^24.0.24