diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 7224b20b..ce094d6c 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -23,4 +23,4 @@ runs: - name: Build package shell: bash - run: npm run build:prod + run: npm run build diff --git a/.github/actions/get-prerelease/action.yml b/.github/actions/get-prerelease/action.yml new file mode 100644 index 00000000..ce7acdc3 --- /dev/null +++ b/.github/actions/get-prerelease/action.yml @@ -0,0 +1,30 @@ +name: Return a boolean indicating if the version contains prerelease identifiers + +# +# Returns a simple true/false boolean indicating whether the version indicates it's a prerelease or not. +# +# TODO: Remove once the common repo is public. +# + +inputs: + version: + required: true + +outputs: + prerelease: + value: ${{ steps.get_prerelease.outputs.PRERELEASE }} + +runs: + using: composite + + steps: + - id: get_prerelease + shell: bash + run: | + if [[ "${VERSION}" == *"beta"* || "${VERSION}" == *"alpha"* ]]; then + echo "PRERELEASE=true" >> $GITHUB_OUTPUT + else + echo "PRERELEASE=false" >> $GITHUB_OUTPUT + fi + env: + VERSION: ${{ inputs.version }} diff --git a/.github/actions/get-release-notes/action.yml b/.github/actions/get-release-notes/action.yml new file mode 100644 index 00000000..c89b51a1 --- /dev/null +++ b/.github/actions/get-release-notes/action.yml @@ -0,0 +1,38 @@ +name: Return the release notes extracted from the PR body + +# +# Returns the release notes from the content of a pull request linked to a release branch. It expects the branch name to be in the format release/vX.Y.Z, release/X.Y.Z, release/vX.Y.Z-beta.N. etc. +# +# TODO: Remove once the common repo is public. +# +inputs: + version: + required: true + repo_name: + required: false + repo_owner: + required: true + token: + required: true + +runs: + using: composite + + steps: + - uses: actions/github-script@v7 + id: get_release_notes + with: + result-encoding: string + script: | + const { data: pulls } = await github.rest.pulls.list({ + owner: process.env.REPO_OWNER, + repo: process.env.REPO_NAME, + state: 'all', + head: `${process.env.REPO_OWNER}:release/${process.env.VERSION}`, + }); + core.exportVariable('RELEASE_NOTES', pulls[0].body) + env: + GITHUB_TOKEN: ${{ inputs.token }} + REPO_OWNER: ${{ inputs.repo_owner }} + REPO_NAME: ${{ inputs.repo_name }} + VERSION: ${{ inputs.version }} diff --git a/.github/actions/get-version/action.yml b/.github/actions/get-version/action.yml new file mode 100644 index 00000000..9440ec92 --- /dev/null +++ b/.github/actions/get-version/action.yml @@ -0,0 +1,21 @@ +name: Return the version extracted from the branch name + +# +# Returns the version from the .version file. +# +# TODO: Remove once the common repo is public. +# + +outputs: + version: + value: ${{ steps.get_version.outputs.VERSION }} + +runs: + using: composite + + steps: + - id: get_version + shell: bash + run: | + VERSION=$(head -1 .version) + echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT diff --git a/.github/actions/publish-package/action.yml b/.github/actions/publish-package/action.yml new file mode 100644 index 00000000..abbfcaaa --- /dev/null +++ b/.github/actions/publish-package/action.yml @@ -0,0 +1,46 @@ +name: Publish release to package manager + +inputs: + node-version: + required: true + npm-token: + required: true + version: + required: true + release-directory: + default: './' + +runs: + using: composite + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: ${{ inputs.node-version }} + cache: 'npm' + registry-url: 'https://registry.npmjs.org' + + - name: Build package + uses: ./.github/actions/build + with: + node: ${{ inputs.node-version }} + + - name: Publish release to NPM + shell: bash + working-directory: ${{ inputs.release-directory }} + run: | + if [[ "${VERSION}" == *"beta"* ]]; then + TAG="beta" + elif [[ "${VERSION}" == *"alpha"* ]]; then + TAG="alpha" + else + TAG="latest" + fi + npm publish --provenance --tag $TAG + env: + NODE_AUTH_TOKEN: ${{ inputs.npm-token }} + VERSION: ${{ inputs.version }} diff --git a/.github/actions/release-create/action.yml b/.github/actions/release-create/action.yml new file mode 100644 index 00000000..6a2bf804 --- /dev/null +++ b/.github/actions/release-create/action.yml @@ -0,0 +1,47 @@ +name: Create a GitHub release + +# +# Creates a GitHub release with the given version. +# +# TODO: Remove once the common repo is public. +# + +inputs: + token: + required: true + files: + required: false + name: + required: true + body: + required: true + tag: + required: true + commit: + required: true + draft: + default: false + required: false + prerelease: + default: false + required: false + fail_on_unmatched_files: + default: true + required: false + +runs: + using: composite + + steps: + - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 + with: + body: ${{ inputs.body }} + name: ${{ inputs.name }} + tag_name: ${{ inputs.tag }} + target_commitish: ${{ inputs.commit }} + draft: ${{ inputs.draft }} + prerelease: ${{ inputs.prerelease }} + fail_on_unmatched_files: ${{ inputs.fail_on_unmatched_files }} + files: ${{ inputs.files }} + env: + GITHUB_TOKEN: ${{ inputs.token }} diff --git a/.github/actions/tag-exists/action.yml b/.github/actions/tag-exists/action.yml new file mode 100644 index 00000000..e528612d --- /dev/null +++ b/.github/actions/tag-exists/action.yml @@ -0,0 +1,36 @@ +name: Return a boolean indicating if a tag already exists for the repository + +# +# Returns a simple true/false boolean indicating whether the tag exists or not. +# +# TODO: Remove once the common repo is public. +# + +inputs: + token: + required: true + tag: + required: true + +outputs: + exists: + description: 'Whether the tag exists or not' + value: ${{ steps.tag-exists.outputs.EXISTS }} + +runs: + using: composite + + steps: + - id: check + shell: bash + run: | + GET_API_URL="https://api.github.com/repos/${GITHUB_REPOSITORY}/git/ref/tags/${TAG_NAME}" + http_status_code=$(curl -LI $GET_API_URL -o /dev/null -w '%{http_code}\n' -s -H "Authorization: token ${GITHUB_TOKEN}") + if [ "$http_status_code" -ne "404" ] ; then + echo "EXISTS=true" >> $GITHUB_OUTPUT + else + echo "EXISTS=false" >> $GITHUB_OUTPUT + fi + env: + TAG_NAME: ${{ inputs.tag }} + GITHUB_TOKEN: ${{ inputs.token }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..c6283414 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,78 @@ +name: Create GitHub Release + +on: + pull_request: + types: + - closed + workflow_dispatch: + +permissions: + contents: write + id-token: write # For publishing to npm using --provenance + +env: + NODE_VERSION: 18 + +### TODO: Replace instances of './.github/actions/' w/ `auth0/dx-sdk-actions/` and append `@latest` after the common `dx-sdk-actions` repo is made public. +### TODO: Also remove `get-prerelease`, `get-version`, `release-create`, `tag-create` and `tag-exists` actions from this repo's .github/actions folder once the repo is public. + +jobs: + release: + if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.pull_request.merged && startsWith(github.event.pull_request.head.ref, 'release/')) + runs-on: ubuntu-latest + environment: release + + steps: + # Checkout the code + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # Get the version from the branch name + - id: get_version + uses: ./.github/actions/get-version + + # Get the prerelease flag from the branch name + - id: get_prerelease + uses: ./.github/actions/get-prerelease + with: + version: ${{ steps.get_version.outputs.version }} + + # Get the release notes + # This will expose the release notes as env.RELEASE_NOTES + - id: get_release_notes + uses: ./.github/actions/get-release-notes + with: + token: ${{ secrets.GITHUB_TOKEN }} + version: ${{ steps.get_version.outputs.version }} + repo_owner: ${{ github.repository_owner }} + repo_name: ${{ github.event.repository.name }} + + # Check if the tag already exists + - id: tag_exists + uses: ./.github/actions/tag-exists + with: + tag: ${{ steps.get_version.outputs.version }} + token: ${{ secrets.GITHUB_TOKEN }} + + # If the tag already exists, exit with an error + - if: steps.tag_exists.outputs.exists == 'true' + run: exit 1 + + # Publish the release to our package manager + - uses: ./.github/actions/publish-package + with: + node-version: ${{ env.NODE_VERSION }} + version: ${{ steps.get_version.outputs.version }} + npm-token: ${{ secrets.NPM_TOKEN }} + release-directory: './dist/auth0-angular' + + # Create a release for the tag + - uses: ./.github/actions/release-create + with: + token: ${{ secrets.GITHUB_TOKEN }} + name: ${{ steps.get_version.outputs.version }} + body: ${{ env.RELEASE_NOTES }} + tag: ${{ steps.get_version.outputs.version }} + commit: ${{ github.sha }} + prerelease: ${{ steps.get_prerelease.outputs.prerelease }} diff --git a/.shiprc b/.shiprc index 24218ab3..688dcebe 100644 --- a/.shiprc +++ b/.shiprc @@ -1,4 +1,7 @@ { "packagePath": "projects/auth0-angular", - "postbump": "npm run build" -} + "files": { + ".version": [] + }, + "postbump": "npm run docs" +} \ No newline at end of file diff --git a/.version b/.version new file mode 100644 index 00000000..55540107 --- /dev/null +++ b/.version @@ -0,0 +1 @@ +v2.2.1 \ No newline at end of file diff --git a/package.json b/package.json index 553f2101..4040e4ab 100644 --- a/package.json +++ b/package.json @@ -8,11 +8,10 @@ "start:local:oidc": "node scripts/oidc-provider", "start:local:playground": "ng serve --configuration=local", "prebuild": "npm run update-useragent", - "build": "ng build && npm run build:schematics", - "build:prod": "ng build --configuration=production && npm run build:schematics", + "build:dev": "ng build && npm run build:schematics", + "build": "ng build --configuration=production && npm run build:schematics", "build:schematics": "npm run build --prefix projects/auth0-angular", - "prepublishOnly": "node scripts/prepublish-stopper.js", - "postbuild": "npm run docs", + "postbuild": "cp README.md ./dist/auth0-angular/", "test": "jest", "test:ci": "jest --coverage --silent", "e2e": "ng e2e", @@ -21,7 +20,6 @@ "lint": "ng lint", "docs": "typedoc", "pretty-quick": "pretty-quick", - "release:publish": "node scripts/publish.js", "update-useragent": "node projects/auth0-angular/scripts/update-useragent.js", "server:api": "node api-server.js" }, diff --git a/scripts/prepublish-stopper.js b/scripts/prepublish-stopper.js deleted file mode 100644 index 4ae7dc31..00000000 --- a/scripts/prepublish-stopper.js +++ /dev/null @@ -1,6 +0,0 @@ -const ALLOWED = !!process.env.ALLOWED || !!process.env.CI; - -if (!ALLOWED) { - console.log('Run `npm run release:publish` to publish the package'); - process.exit(1); //which terminates the publish process -} diff --git a/scripts/publish.js b/scripts/publish.js deleted file mode 100644 index e20dfa3e..00000000 --- a/scripts/publish.js +++ /dev/null @@ -1,46 +0,0 @@ -const fs = require('fs'); -const exec = require('./exec'); -const execSync = require('child_process').execSync; -const path = require('path'); - -if (!fs.existsSync('.release')) { - console.error(`There's no release pending publication.`); - process.exit(1); -} - -const tmp = fs.readFileSync('.release', 'utf-8'); -const unpublishedFilePath = path.resolve(tmp, 'unpublished-version'); - -if (!fs.existsSync(unpublishedFilePath)) { - console.error( - `The last release preparation did not complete successfully. Run 'npm run release:clean' and then 'npm run release' to start all over again.` - ); - console.log( - `If the Release PR was already merged into the base branch and only the npm publication is pending, manually run 'npm run build:prod' and then 'ALLOWED=true npm publish ./dist/auth0-angular'.` - ); - process.exit(1); -} - -const unpublishedVersion = fs.readFileSync(unpublishedFilePath, 'utf-8'); - -(async () => { - console.log('Preparing the package for publication...'); - await exec(`git checkout v${unpublishedVersion}`); - - /* - The command below ensures the ./dist folder has prod-ready content. - It will NOT regenerate the docs nor the useragent file, which - should already be updated as part of the last tagged commit. - */ - await exec('npm run build:prod'); - await exec('cp README.md ./dist/auth0-angular/'); - - console.log('Uploading to npm, you might be prompted for the OTP...'); - - execSync(`ALLOWED=true npm publish ./dist/auth0-angular`, { - stdio: 'inherit', - }); - - console.log('Done!'); - await exec('npm run release:clean'); -})();