diff --git a/orbs/shared/jobs/pre-release.yaml b/orbs/shared/jobs/pre-release.yaml new file mode 100644 index 00000000..3a2fc0e7 --- /dev/null +++ b/orbs/shared/jobs/pre-release.yaml @@ -0,0 +1,52 @@ +description: Pre-releases a new version of the application +parameters: + node_client: + description: Build and release a Node.JS gRPC client + type: boolean + default: false + dryrun: + description: Don't actually release, just dryrun the release flow + type: boolean + default: true + machine: + description: Denotes that we're using a machine executor. Will need to set executor manually + type: boolean + default: false + resource_class: + description: The resource class to use for the release + type: string + default: "large" + release_failure_slack_channel: + description: The slack channel to notify if the release fails + type: string + default: "" + executor: + description: The executor to use for the release + type: executor + default: "testbed-docker" +resource_class: << parameters.resource_class >> +executor: << parameters.executor >> +steps: + - setup_environment: + machine: << parameters.machine >> + - when: + condition: << parameters.node_client >> + steps: + - with_node_client_cache: + build: true + - with_node_cache: + save: true + - when: + condition: << parameters.dryrun >> + steps: + - run: + name: Pre-elease (dry run) + command: ./scripts/shell-wrapper.sh ci/release/dryrun.sh + - unless: + condition: << parameters.dryrun >> + steps: + - run: + name: Pre-release + environment: + RELEASE_FAILURE_SLACK_CHANNEL: << parameters.release_failure_slack_channel >> + command: ./scripts/shell-wrapper.sh ci/release/pre-release.sh diff --git a/orbs/shared/jobs/release.yaml b/orbs/shared/jobs/release.yaml index 8a8e9641..f0ef81da 100644 --- a/orbs/shared/jobs/release.yaml +++ b/orbs/shared/jobs/release.yaml @@ -44,7 +44,7 @@ steps: condition: << parameters.dryrun >> steps: - run: - name: Release (Dry-run) + name: Release (dry run) command: ./scripts/shell-wrapper.sh ci/release/dryrun.sh no_output_timeout: << parameters.no_output_timeout >> - unless: diff --git a/orbs/shared/jobs/trigger_rc_release.yaml b/orbs/shared/jobs/trigger_rc_release.yaml new file mode 100644 index 00000000..f496e554 --- /dev/null +++ b/orbs/shared/jobs/trigger_rc_release.yaml @@ -0,0 +1,33 @@ +description: Trigger release a new RC version of the application +parameters: + machine: + description: Denotes that we're using a machine executor. Will need to set executor manually + type: boolean + default: false + resource_class: + description: The resource class to use for the release + type: string + # This is to trigger the release job, small should be enough + default: "small" + release_failure_slack_channel: + description: The slack channel to notify if the release fails + type: string + default: "" + executor: + description: The executor to use for the release + type: executor + default: "testbed-docker" + +resource_class: << parameters.resource_class >> +executor: << parameters.executor >> +steps: + - setup_environment: + machine: << parameters.machine >> + - with_node_cache: + save: true + - checkout + - run: + name: Trigger RC Release + environment: + RELEASE_FAILURE_SLACK_CHANNEL: << parameters.release_failure_slack_channel >> + command: ./scripts/shell-wrapper.sh ci/release/trigger-rc-release.sh diff --git a/shell/ci/release/dryrun.sh b/shell/ci/release/dryrun.sh index bb8724d3..e9949fe3 100755 --- a/shell/ci/release/dryrun.sh +++ b/shell/ci/release/dryrun.sh @@ -36,11 +36,19 @@ git checkout "$CIRCLE_BRANCH" # Squash our branch onto the HEAD (default) branch to mimic # what would happen after merge. -git merge --squash "$OLD_CIRCLE_BRANCH" -git commit -m "$COMMIT_MESSAGE" - -GH_TOKEN="$(gh auth token)" yarn --frozen-lockfile semantic-release --dry-run - -# Handle unstable releasing for CLIs, pre-conditions for this exist -# in the script. -"$DIR/unstable-release.sh" --dry-run +if ! git diff --quiet "$OLD_CIRCLE_BRANCH"; then + git merge --squash "$OLD_CIRCLE_BRANCH" + git commit -m "$COMMIT_MESSAGE" + GH_TOKEN="$(gh auth token)" + if [[ -z $GH_TOKEN ]]; then + echo "Failed to read Github personal access token" >&2 + fi + + GH_TOKEN="$GH_TOKEN" yarn --frozen-lockfile semantic-release --dry-run + + # Handle prereleases for CLIs, pre-conditions for this exist + # in the script. + "$DIR/pre-release.sh" --dry-run +else + echo "No changes to release" +fi diff --git a/shell/ci/release/unstable-release.sh b/shell/ci/release/pre-release.sh similarity index 75% rename from shell/ci/release/unstable-release.sh rename to shell/ci/release/pre-release.sh index b342bfd9..fb72e887 100755 --- a/shell/ci/release/unstable-release.sh +++ b/shell/ci/release/pre-release.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash + # This file contains the logic for releasing unstable code on CLI # containing repositories that have also opted to enablePrereleases # _and_ not release from the default branch (e.g. main). @@ -53,24 +54,17 @@ if [[ "$(yaml_get_field ".arguments.releaseOptions.enablePrereleases" "$(get_ser exit 0 fi -# If our prereleasesBranch is empty, or equal to the default branch -# skip this. This is to enable prereleases to be created from the `main` -# branch thereby skipping the 'unstable' release process entirely. +# Ensure we are on the prerelease branch. The default is main branch. prereleasesBranch="$(yaml_get_field '.arguments.releaseOptions.prereleasesBranch' "$(get_service_yaml)")" -defaultBranch="$(git rev-parse --abbrev-ref origin/HEAD | sed 's/^origin\///')" -if [[ -z $prereleasesBranch ]] || [[ $prereleasesBranch == "$defaultBranch" ]]; then - echo "releaseOptions.prereleasesBranch is empty or equal to the default branch, skipping unstable release" - exit 0 -fi -# If we're not on the default branch, skip. This is to prevent +# If we're not on the prerelease branch, skip. This is to prevent # accidentally releasing from a branch that isn't mean to create # unstable releases that happened to fail releasing for whatever reason. # # Special case, skip this check if we're doing a dry-run since we will # short circuit before we actually create a release. -if [[ $CIRCLE_BRANCH != "$defaultBranch" ]] && [[ $DRYRUN == "false" ]]; then - echo "\$CIRCLE_BRANCH ($CIRCLE_BRANCH) != \$defaultBranch ($defaultBranch), skipping unstable release" +if [[ $CIRCLE_BRANCH != "$prereleasesBranch" ]] && [[ $DRYRUN == "false" ]]; then + echo "\$CIRCLE_BRANCH ($CIRCLE_BRANCH) != \$prereleaseBranch ($prereleasesBranch), skipping prerelease" exit 0 fi @@ -87,22 +81,39 @@ if [[ ! -e "$(get_repo_directory)/.goreleaser.yml" ]]; then exit 0 fi -app_version="v0.0.0-unstable+$(git rev-parse HEAD)" -echo "Creating unstable release ($app_version)" - -make release APP_VERSION="$app_version" - # If we're in dry-run mode, skip creating the release. if [[ $DRYRUN == "true" ]]; then exit 0 fi -# delete unstable release+tag if it exists +# Check commit message on current branch +# Prerelease to rc if the latest commit is chore: Release. +COMMIT_MESSAGE=$(git log --format=%B -n 1) +if [[ $COMMIT_MESSAGE =~ "chore: Release" ]]; then + # Pre-release to rc + echo "Creating prerelease to rc channel" + + # Retrieve the GH_TOKEN + GH_TOKEN=$(gh auth token) + if [[ -z $GH_TOKEN ]]; then + echo "Failed to read Github personal access token" >&2 + fi + # Unset NPM_TOKEN to force it to use the configured ~/.npmrc + NPM_TOKEN='' GH_TOKEN=$GH_TOKEN \ + yarn --frozen-lockfile semantic-release + exit 0 +fi + +# publish unstable release +app_version="v0.0.0-unstable+$(git rev-parse HEAD)" +echo "Creating unstable release ($app_version)" + +make release APP_VERSION="$app_version" +# delete unstable release and unstable tag if it exists gh release delete unstable -y || true git tag --delete unstable || true git push --delete origin unstable || true - -# create unstable release and upload assets to it -gh release create unstable --prerelease --generate-notes ./dist/*.tar.gz ./dist/checksums.txt +# create release and upload assets to it +gh release create unstable --prerelease=true --generate-notes ./dist/*.tar.gz ./dist/checksums.txt run_unstable_include diff --git a/shell/ci/release/release.sh b/shell/ci/release/release.sh index 9a845f59..f9154789 100755 --- a/shell/ci/release/release.sh +++ b/shell/ci/release/release.sh @@ -5,8 +5,8 @@ set -e DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" LIB_DIR="${DIR}/../../lib" -# Read the GH_TOKEN from the file -GH_TOKEN="$(cat "$HOME/.outreach/github.token")" +# Retrieve the GH_TOKEN +GH_TOKEN="$(gh auth token)" if [[ -z $GH_TOKEN ]]; then echo "Failed to read Github personal access token" >&2 fi @@ -40,23 +40,6 @@ unset CIRCLE_PULL_REQUEST unset CI_PULL_REQUEST unset CI_PULL_REQUESTS -ORIGINAL_VERSION=$(git describe --match 'v[0-9]*' --tags --always HEAD) - # Unset NPM_TOKEN to force it to use the configured ~/.npmrc NPM_TOKEN='' GH_TOKEN=$GH_TOKEN \ yarn --frozen-lockfile semantic-release || send_failure_notification - -NEW_VERSION=$(git describe --match 'v[0-9]*' --tags --always HEAD) - -# Determine if we updated by checking the original version from git -# vs the new version (potentially) after we ran semantic-release. -UPDATED=false -if [[ $ORIGINAL_VERSION != "$NEW_VERSION" ]]; then - UPDATED=true -fi - -# If we didn't update, assume we're on a prerelease branch -# and run the unstable-release code. -if [[ $UPDATED == "false" ]]; then - exec "$DIR/unstable-release.sh" -fi diff --git a/shell/ci/release/trigger-rc-release.sh b/shell/ci/release/trigger-rc-release.sh new file mode 100755 index 00000000..a8c48f46 --- /dev/null +++ b/shell/ci/release/trigger-rc-release.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# This script is to add chore: Release comit to the default pre-release +# branch to trigger pre-release. +set -eo pipefail +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" + +# shellcheck source=./../../lib/yaml.sh +source "$DIR/../../lib/yaml.sh" +# shellcheck source=./../../lib/bootstrap.sh +source "$DIR/../../lib/bootstrap.sh" +# shellcheck source=./../../lib/box.sh +source "$DIR/../../lib/box.sh" + +if [[ "$(yaml_get_field ".arguments.releaseOptions.enablePrereleases" "$(get_service_yaml)")" != "true" ]]; then + echo "releaseOptions.enablePrereleases is not true, skipping rc release" + exit 0 +fi + +# Default it to use main branch, should this be configurable? +prereleaseBranch="main" + +if [[ -n "$(yaml_get_field ".arguments.releaseOptions.releaseUser" "$(get_service_yaml)")" ]]; then + releaseUsername="$(yaml_get_field ".arguments.releaseOptions.releaseUser.name" "$(get_service_yaml)")" + releaseUseremail="$(yaml_get_field ".arguments.releaseOptions.releaseUser.email" "$(get_service_yaml)")" +else + releaseUsername=$(get_box_field 'ci.circleci.releaseUser.name') + releaseUseremail=$(get_box_field 'ci.circleci.releaseUser.email') +fi + +git config --global user.name "$releaseUsername" +git config --global user.email "$releaseUseremail" +git checkout $prereleaseBranch + +# Dryrun the semantic-release on prereleaseBranch to check if there is changes to release. +# If not skip the release. +GH_TOKEN=$(gh auth token) +releaseOutput=$(NPM_TOKEN='' GH_TOKEN=$GH_TOKEN yarn --frozen-lockfile semantic-release -d) +echo "$releaseOutput" + +if [[ $releaseOutput != *"Published release"* ]]; then + echo "No release will be created, skipping..." + exit 0 +fi + +git commit -m "chore: Release" --allow-empty +git push origin $prereleaseBranch