diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9215a87fc..885badc1b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,18 +3,37 @@ name: CI Checks on: pull_request: branches: - - main - master push: branches: - - main - master permissions: contents: read # to fetch code (actions/checkout) jobs: - Tests: + release_checks: + name: Release Checks + runs-on: ubuntu-latest + if: contains( github.event.pull_request.head.ref, 'release') + steps: + - name: Checkout Source + uses: actions/checkout@v3 + + - name: Get version + run: | + echo "RELEASE_VERSION=$(npm pkg get version)" >> $GITHUB_ENV + + - name: Is valid release? + uses: actions/github-script@v6 + with: + script: | + if (process.env.RELEASE_VERSION.includes('RC')) { + core.setFailed('Release candidates are not valid releases!') + } + + tests: + name: Libary Tests permissions: contents: read # to fetch code (actions/checkout) checks: write # to create new checks (coverallsapp/github-action) @@ -31,18 +50,24 @@ jobs: - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} + - name: Install Dependencies - run: npm clean-install + run: npm ci --ignore-scripts + - name: Lint run: npm run lint + - name: Integration Tests run: npm run test:integration + - name: Test Coverage run: npm run test:coverage + - name: Report test coverage to Coveralls.io if: matrix.node == '16' uses: coverallsapp/github-action@master with: github-token: ${{ secrets.GITHUB_TOKEN }} + - name: TypeScript Test run: npx --package typescript tsc --project test diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml new file mode 100644 index 000000000..1f28a18bd --- /dev/null +++ b/.github/workflows/create-release.yml @@ -0,0 +1,113 @@ +name: "Create Release PR" + +on: + workflow_dispatch: + inputs: + versionType: + description: "What kind of version bump is this?" + required: true + type: choice + options: + - major + - minor + - patch + - premajor + - preminor + - prepatch + - prerelease + baseBranch: + description: "What base branch should be used for this release?" + required: false + type: string + dryRun: + description: "Should publish be a dry run?" + required: false + default: false + type: boolean + +jobs: + create-release: + name: Create Release + runs-on: ubuntu-latest + env: + DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} + ACTOR: ${{ github.actor }} + steps: + - name: Get Auth Token + uses: tibdex/github-app-token@v1 + id: get_auth_token + with: + app_id: ${{ vars.RELEASE_OPS_APP_ID }} + private_key: ${{ secrets.RELEASE_OPS_PRIVATE_KEY }} + + - name: Define job env vars + env: + GH_TOKEN: ${{ steps.get_auth_token.outputs.token }} + run: | + isPR=$(gh api repos/${{ github.repository }}/pulls | jq -r '${{ format('.[].head.ref=="{0}"', inputs.baseBranch) }} // false' ) + ACTOR_INFO=$(gh api /users/${{ env.ACTOR }}) + ACTOR_ID=$(echo $ACTOR_INFO | jq -r '.id') + ACTOR_EMAIL="$ACTOR_ID+$ACTOR@users.noreply.github.com" + ACTOR_NAME=$(echo $ACTOR_INFO | jq -r '.name') + + echo "HAS_PR=$isPR" >> $GITHUB_ENV + echo "ACTOR_NAME=$ACTOR_NAME" >> $GITHUB_ENV + echo "ACTOR_EMAIL=$ACTOR_EMAIL" >> $GITHUB_ENV + + - name: Checkout Source + uses: actions/checkout@v3 + with: + token: ${{ steps.get_auth_token.outputs.token }} + ref: ${{ inputs.baseBranch || env.DEFAULT_BRANCH }} + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 16 + registry-url: 'https://registry.npmjs.org' + scope: ${{ vars.NPM_SCOPE }} # If this is not an organization I have to specify this. + + - name: Install dependencies + run: npm ci --ignore-scripts + + - name: Bump Version (${{ inputs.versionType }}) + run: | + SHORT_SHA=$(echo ${{ github.sha }} | cut -c-7) + VERSION=$(npm version ${{ inputs.versionType }} ${{ startsWith(inputs.versionType, 'pre') && '--preid=RC' || '' }} --no-git-tag-version) + echo "VERSION=${VERSION%-*}" >> $GITHUB_ENV + echo "RC_VERSION=${VERSION#*-}" >> $GITHUB_ENV + echo "FULL_VERSION=$VERSION" >> $GITHUB_ENV + + - name: Commit changes + id: commit-version-bump + uses: EndBug/add-and-commit@v9.1.1 + with: + author_name: ${{ env.ACTOR_NAME }} + author_email: ${{ env.ACTOR_EMAIL }} + committer_name: "release-ops[bot]" + committer_email: "124938743+release-ops[bot]@users.noreply.github.com" + message: "Bumping Package - ${{ env.FULL_VERSION }}" + push: ${{ env.HAS_PR == 'true' }} # Update existing release branch if available and this is a pre release variant, aka new release candidate + + # If version bump is not a pre-release and not a dry run, create release PR for human review + - name: Open Release PR + id: create-pr + if: ${{ env.HAS_PR == 'false' && !inputs.dryRun && inputs.versionType != 'prerelease' }} + uses: peter-evans/create-pull-request@v4 + with: + token: ${{ steps.get_auth_token.outputs.token }} + delete-branch: true + branch: "release/${{ env.VERSION }}" + title: "Release: ${{ env.VERSION }}" + labels: "release, automated" + author: "${{ env.ACTOR_NAME }} <${{ env.ACTOR_EMAIL }}>" + committer: "release-ops[bot] <124938743+release-ops[bot]@users.noreply.github.com>" + commit-message: "Bumping Package - ${{ env.FULL_VERSION }}" + draft: ${{ startsWith(inputs.versionType, 'pre') }} + + # If a version bump was pushed or a new release pr was created, publish the new variant as long as it's not an official release + - name: Publish pre-release package ${{ inputs.dryRun && '(Dry Run)' || '' }} + if: ${{ startsWith(inputs.versionType, 'pre') && (steps.create-pr.outputs.pull-request-operation == 'created' || steps.commit-version-bump.outputs.pushed == 'true') }} + env: + NODE_AUTH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} + run: npm publish --access public ${{ inputs.dryRun && '--dry-run' || '' }} --tag RC diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml new file mode 100644 index 000000000..24aced7a7 --- /dev/null +++ b/.github/workflows/release-tag.yml @@ -0,0 +1,41 @@ +name: "Generate & Ship Release #ShipIt" + +on: + push: + tags: + - release-** +jobs: + create-github-release: + name: Create GitHub Release + runs-on: ubuntu-latest + steps: + - name: Checkout Source + uses: actions/checkout@v3 + + - name: Create release from tag + uses: ncipollo/release-action@v1.12.0 + with: + makeLatest: true + generateReleaseNotes: true + + publish-version: + name: Publish Version + runs-on: ubuntu-latest + steps: + - name: Checkout Source + uses: actions/checkout@v3 + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 16 + registry-url: 'https://registry.npmjs.org' + scope: ${{ vars.NPM_SCOPE }} # If this is not an organization I have to specify this. + + - name: Prepare for publish + run: npm ci --ignore-scripts + + - name: Publish package + env: + NODE_AUTH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} + run: npm publish --access public diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml new file mode 100644 index 000000000..c84288f27 --- /dev/null +++ b/.github/workflows/tag-release.yml @@ -0,0 +1,78 @@ +name: "Tag Release Commit" + +on: + pull_request: + types: + - closed + branches: + - master + +jobs: + was_merged: + name: Was PR Merged? + runs-on: ubuntu-latest + outputs: + result: ${{ steps.merge_check.outputs.result }} + env: + PR_BRANCH: ${{ github.event.pull_request.head.ref }} + steps: + - id: merge_check + run: echo "result=${{ github.event.pull_request.merged == true }}" >> $GITHUB_OUTPUT + + is_release: + name: Is PR a release? + runs-on: ubuntu-latest + outputs: + result: ${{ steps.merge_check.outputs.result }} + env: + PR_BRANCH: ${{ github.event.pull_request.head.ref }} + steps: + - id: merge_check + run: echo "result=${{ contains( env.PR_BRANCH, 'release') }}" >> $GITHUB_OUTPUT + + tag-merge-commit: + name: Tag release merge commit + needs: + - was_merged + - is_release + if: ${{ needs.was_merged.outputs.result }} && ${{ needs.is_release.result }} + env: + PR_BRANCH: ${{ github.event.pull_request.head.ref }} + ACTOR_ID: ${{ github.event.pull_request.merged_by.id }} + MERGE_AT: ${{ github.event.pull_request.merged_at }} + MERGE_COMMIT_SHA: ${{ github.event.pull_request.merge_commit_sha }} + runs-on: ubuntu-latest + steps: + - name: Get Auth Token + uses: tibdex/github-app-token@v1 + id: get_auth_token + with: + app_id: ${{ vars.RELEASE_OPS_APP_ID }} + private_key: ${{ secrets.RELEASE_OPS_PRIVATE_KEY }} + + - name: Checkout Source + uses: actions/checkout@v3 + with: + token: ${{ steps.get_auth_token.outputs.token }} + + - name: Tag commit with version + env: + GH_TOKEN: ${{ steps.get_auth_token.outputs.token }} + ACTOR: ${{ github.actor }} + run: | + ACTOR_INFO=$(gh api /users/$ACTOR) + ACTOR_ID=$(echo $ACTOR_INFO | jq -r '.id') + ACTOR_EMAIL="$ACTOR_ID+$ACTOR@users.noreply.github.com" + ACTOR_NAME=$(echo $ACTOR_INFO | jq -r '.name') + TAG_NAME=release-${PR_BRANCH##*/} + + git config --global user.name 'release-ops[bot]' + git config --global user.email 'release-ops[bot]@users.noreply.github.com' + + git tag -a $TAG_NAME \ + -m "Automated Release $TAG_NAME" \ + -m "" \ + -m "" \ + -m "Merged By: $ACTOR_NAME <$ACTOR_EMAIL>" \ + -m "Merged At: $MERGED_AT" $MERGE_COMMIT_SHA + git push origin $TAG_NAME