diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index a102ac9624..0000000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,360 +0,0 @@ -# Publish / release / deploy packages after a release - -name: deploy - -on: - push: - branches: [main, staging] - workflow_dispatch: - -env: - GITHUB_TOKEN: ${{ secrets.PROSOPONATOR_PAT }} - GH_TOKEN: ${{ secrets.PROSOPONATOR_PAT }} - CARGO_TERM_COLOR: always - NODE_OPTIONS: "--max-old-space-size=4096" - -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - name: Print contexts - env: - GITHUB_CONTEXT: ${{ toJson(github) }} - ENV_CONTEXT: ${{ toJson(env) }} - VARS_CONTEXT: ${{ toJson(vars) }} - JOB_CONTEXT: ${{ toJson(job) }} - STEPS_CONTEXT: ${{ toJson(steps) }} - RUNNER_CONTEXT: ${{ toJson(runner) }} - SECRETS_CONTEXT: ${{ toJson(secrets) }} - STRATEGY_CONTEXT: ${{ toJson(strategy) }} - MATRIX_CONTEXT: ${{ toJson(matrix) }} - NEEDS_CONTEXT: ${{ toJson(needs) }} - INPUTS_CONTEXT: ${{ toJson(inputs) }} - run: | - echo "******************************" - echo "github:" "$GITHUB_CONTEXT" - echo "******************************" - echo "env:" "$ENV_CONTEXT" - echo "******************************" - echo "vars:" "$VARS_CONTEXT" - echo "******************************" - echo "job:" "$JOB_CONTEXT" - echo "******************************" - echo "steps:" "$STEPS_CONTEXT" - echo "******************************" - echo "runner:" "$RUNNER_CONTEXT" - echo "******************************" - echo "secrets:" "$SECRETS_CONTEXT" - echo "******************************" - echo "strategy:" "$STRATEGY_CONTEXT" - echo "******************************" - echo "matrix:" "$MATRIX_CONTEXT" - echo "******************************" - echo "needs:" "$NEEDS_CONTEXT" - echo "******************************" - echo "inputs:" "$INPUTS_CONTEXT" - echo "******************************" - - - run: mkdir -p ~/.npm - - run: mkdir -p ~/.cache/Cypress - - - name: Restore npm cache - uses: actions/cache/restore@v3 - with: - # must restore all cache dirs, and they must exist ahead of this! - path: | - ~/.npm - ~/.cache/Cypress - # note that restoring a cache in github is a pain. The trailing '-' matches any string after the '-', therefore 'abc-' would match a cache named 'abc-1234' or 'abc-5678', etc. - # the problem is 'abc-' will not match a cache named 'abc'! So if you're using wildcard cache name selectors like this, you need a field that changes as the suffix to become the wildcard - # here we're setting the key to an unused cache key so it falls back to the wildcard selector in `restore-keys` - key: some-unused-cache-key - restore-keys: | - npm-${{ runner.os }}-${{ runner.arch }}- - - # Add support for more platforms with QEMU (optional) - # https://github.com/docker/setup-qemu-action - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Dockerhub login - run: | - echo "Logging into Docker Hub." - echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin 2> /dev/null - - - uses: actions/checkout@v3 - - - name: Detect env - id: env - run: | - - set -euxo pipefail # stop on errors, print commands, fail on pipe fails - - VERSION=$(jq -r '.version' < package.json) - - # if version not detected, error - if [[ -z "$VERSION" ]]; then - echo "Failed to get version" - exit 1 - fi - # or if version null - if [[ "$VERSION" == "null" ]]; then - echo "Failed to get version" - exit 1 - fi - - echo "version=$VERSION" - - # export the next version numbers - # shellcheck disable=SC2086 - echo "version=$VERSION" >> $GITHUB_OUTPUT - - # if branch is main, then prod, else staging - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "production" - # shellcheck disable=SC2086 - { - echo "env=production"; - echo "production=true"; - echo "docker_latest_tag=latest"; - echo "docker_version_tag=$VERSION" - } >> $GITHUB_OUTPUT - elif [[ "${{ github.ref }}" == "refs/heads/staging" ]]; then - echo "staging" - # shellcheck disable=SC2086 - { - echo "env=staging"; - echo "staging=true"; - echo "docker_latest_tag=staging"; - echo "docker_version_tag=staging" - } >> $GITHUB_OUTPUT - else - echo "cannot deploy from branch ${{ github.ref }}" - exit 1 - fi - - - uses: actions/setup-node@v3 - with: - node-version-file: '.nvmrc' - - run: npm i -g "npm@$(jq -r .engines.npm < package.json)" - - - run: npm ci - - # build from scratch to ensure nothing bought over from cache - - - name: Build packages - run: | - echo "Building packages..." - npm run build:all - npm run build:all:cjs - - - name: Build JS bundle - run: | - set -euxo pipefail # stop on errors, print commands, fail on pipe fails - - # Copy the rococo env file to production env file - echo "Copying the rococo env to production env file in procaptcha-bundle" - cp ./dev/scripts/env.${{ steps.env.outputs.env }} ./packages/procaptcha-bundle/.env.${{ steps.env.outputs.env }} - - # Navigate to the JS bundle directory and build - echo "Building JS bundle..." - - NODE_ENV="${{ steps.env.outputs.env }}" npm -w @prosopo/procaptcha-bundle run bundle - - - name: Push the JS Bundle to the js-bundle branch - run: | - set -euxo pipefail # stop on errors, print commands, fail on pipe fails - # Checkout js-bundle branch - git fetch origin js-bundle:js-bundle - git checkout js-bundle - - # Copy built bundle to js-bundle branch - cp $(find packages/procaptcha-bundle/dist/bundle/* -maxdepth 0 -not -type d) . - - # set the author in git - git config user.name "prosoponator[bot]" - git config user.email "dev@prosopo.io" - - git add -A - git commit -m 'Deploy JS bundle from staging' || true - - # Push the bundle to js-bundle branch - git push origin js-bundle --force - - # Return to the original branch - git checkout ${{ github.ref }} - - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v2 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: eu-west-1 - - - name: Deploy bundle to AWS S3 - if: ${{ steps.env.outputs.production || steps.env.outputs.staging }} - run: | - if [ "${{ steps.env.outputs.production }}" = "true" ]; then - aws s3 cp packages/procaptcha-bundle/dist/bundle/ s3://js.prosopo.io/js/ --recursive - elif [ "${{ steps.env.outputs.staging }}" = "true" ]; then - aws s3 cp packages/procaptcha-bundle/dist/bundle/ s3://staging-js.prosopo.io/js/ --recursive - fi - - - name: Build docker js_server - run: | - set -euxo pipefail # stop on errors, print commands, fail on pipe fails - - # technically, if the release is for a version which is less than a published version, the following code will have bundles from versions ahead of this one. However, this isn't really a problem, as we just want the latest bundle to be available alongside old ones, not so bothered about newer ones. - - # Set the JS location in the container - JS_FOLDER="/usr/share/nginx/html/js" - - # Get the most recent version of the js_server image - docker pull "prosopo/js_server:${{ steps.env.outputs.docker_latest_tag }}" - - # Create a temporary container from the latest image - echo "Building Docker image..." - OLD_CONTAINER_ID="$(docker create "prosopo/js_server:${{ steps.env.outputs.docker_latest_tag }}")" - - # Remove the old js temp folder - rm -rf ./js_bundles_host_temp - - # Copy out the old files - docker cp "$OLD_CONTAINER_ID:$JS_FOLDER" ./js_bundles_host_temp - - # Build the new image - docker build --file ./docker/images/js.server.dockerfile . -t "prosopo/js_server:${{ steps.env.outputs.docker_version_tag }}" --no-cache - - # Run the new image - NEW_CONTAINER_ID="$(docker create "prosopo/js_server:${{ steps.env.outputs.docker_version_tag }}")" - - # Copy the legacy files across - docker cp ./js_bundles_host_temp/ "$NEW_CONTAINER_ID:$JS_FOLDER/" - - # Copy the new bundle files to the container into a folder with the version name - docker cp packages/procaptcha-bundle/dist/bundle/. "$NEW_CONTAINER_ID:$JS_FOLDER" - - # Start the new container - docker start "$NEW_CONTAINER_ID" - - # Move procaptcha.bundle.js - docker exec "$NEW_CONTAINER_ID" mv "$JS_FOLDER/procaptcha.bundle.js" "$JS_FOLDER/procaptcha.bundle.${{ steps.env.outputs.docker_version_tag }}.js" - - # Symlink JS_FOLDER/procaptcha.bundle.js to JS_FOLDER/procaptcha.bundle.VERSION.js - docker exec "$NEW_CONTAINER_ID" ln -sf "$JS_FOLDER/procaptcha.bundle.${{ steps.env.outputs.docker_version_tag }}.js" "$JS_FOLDER/procaptcha.bundle.js" - - # Commit the changes to the container - docker commit "$NEW_CONTAINER_ID" "prosopo/js_server:${{ steps.env.outputs.docker_version_tag }}" - - # Check this new docker image works locally - docker run -d -p 3080:80 "prosopo/js_server:${{ steps.env.outputs.docker_version_tag }}" - - # Start the bundle demo & run the cypress tests against the new bundle - # npx concurrently "npm run start:bundle" "npm run -w @prosopo/cypress-shared cypress:run:client-bundle-example:js_server" --success "first" --kill-others - - - name: Build the production CLI package - run: | - set -euxo pipefail # stop on errors, print commands, fail on pipe fails - - echo "Building the production CLI package..." - # Copy the rococo env file to production env file - echo "Copying the rococo env to production env file in cli package" - cp ./dev/scripts/env.${{ steps.env.outputs.env }} ./packages/cli/.env.${{ steps.env.outputs.env }} - - # Navigate to the provider CLI directory and build - NODE_ENV="${{ steps.env.outputs.env }}" npm run -w @prosopo/cli build - NODE_ENV="${{ steps.env.outputs.env }}" npm run -w @prosopo/cli bundle - - # this will error if there's already a release for this version. This is by design, if you need to fix a release (e.g. because a deploy failed) then bump the version and try again - - name: Github release - id: github_release - if: ${{ steps.env.outputs.production }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - # do a gh release with the contract sources + bundle - gh release create --generate-notes "v${{ steps.env.outputs.version }}" "./packages/procaptcha-bundle/dist/bundle/procaptcha.bundle.js" - - - name: Npm release - if: ${{ steps.env.outputs.production }} - run: | - if [[ "${{ vars.HOST_GITHUB_ACTIONS }}" == true ]]; then - echo "Running on GitHub Actions" - # Write the npm token to ~/.npmrc - echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc - echo "Publishing to npm dry-run..." - npm run publish:dry-run - echo "Publishing to npm..." - npm run publish - else - echo "Running locally via act, skipping npm publish." - fi - - - name: Docker js_server release - id: docker_js_server_release - run: | - # Push the new image to Docker Hub - echo "Pushing Docker image..." - docker push prosopo/js_server:${{ steps.env.outputs.docker_version_tag }} - - # Push latest - docker tag prosopo/js_server:${{ steps.env.outputs.docker_version_tag }} prosopo/js_server:${{ steps.env.outputs.docker_latest_tag }} - docker push prosopo/js_server:${{ steps.env.outputs.docker_latest_tag }} - - - name: Get Prosopo JS Server Flux App Name - run: | - # shellcheck disable=SC2086 - { - echo "JS_SERVER_FLUX_APP_NAME=${{ steps.env.outputs.env }}_JS_SERVER_FLUX_APP_NAME" | tr '[:lower:]' '[:upper:]'; - } >> $GITHUB_ENV - - - name: echo github env - run: | - echo "GITHUB_ENV: $GITHUB_ENV" - - - name: Print the JS_SERVER name - env: - VAR_NAME: ${{ env.JS_SERVER_FLUX_APP_NAME }} - JS_SERVER_FLUX_APP_NAME: ${{ secrets[env.JS_SERVER_FLUX_APP_NAME] }} - run: | - echo "JS_SERVER_FLUX_APP_NAME: $JS_SERVER_FLUX_APP_NAME" - echo "VAR NAME: $VAR_NAME" - echo "JS_SERVER_FLUX_APP_NAME: $JS_SERVER_FLUX_APP_NAME" - - - name: Redeploy flux docker js_server - env: - PROSOPO_ZELCORE_PRIVATE_KEY: ${{ secrets.PROSOPO_ZELCORE_PRIVATE_KEY }} - PROSOPO_ZELCORE_PUBLIC_KEY: ${{ secrets.PROSOPO_ZELCORE_PUBLIC_KEY }} - run: | - if [[ "${{ steps.docker_js_server_release.outcome }}" == 'success' ]]; then - echo "Installing @prosopo/flux..." - npm i -g @prosopo/flux - echo "Hard redeploying flux docker js_server: ${{ secrets[env.JS_SERVER_FLUX_APP_NAME] }}" - npx flux redeploy ${{ secrets[env.JS_SERVER_FLUX_APP_NAME] }} --hard - else - echo "Skipping flux redeploy." - fi - - - name: Build and push the Provider Container - uses: docker/build-push-action@v5 - with: - context: ${{github.workspace}} - file: ${{github.workspace}}/docker/images/provider.dockerfile - platforms: linux/amd64,linux/arm64 - push: true - tags: prosopo/provider:${{ steps.env.outputs.docker_version_tag }},prosopo/provider:${{ steps.env.outputs.docker_latest_tag }} - - - name: Deploy fail notification - if: failure() - run: | - echo "Deploy failed" - curl -X POST -H 'Content-type: application/json' --data "{\"text\":\":check-failed: Deploy <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ steps.env.outputs.env }} v${{ steps.env.outputs.version }}> failed.\"}" ${{ secrets.SLACKBOT_DEVOPS }} - - - name: Deploy success notification - if: success() - run: | - echo "Deploy succeeded" - curl -X POST -H 'Content-type: application/json' --data "{\"text\":\":check-passed: Deploy <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ steps.env.outputs.env }} v${{ steps.env.outputs.version }}> succeeded.\"}" ${{ secrets.SLACKBOT_DEVOPS }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..2b3e0ab051 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,164 @@ +# release a version into the wild + +name: release + +on: + push: + branches: [main, staging] + workflow_dispatch: + +env: + GITHUB_TOKEN: ${{ secrets.PROSOPONATOR_PAT }} + GH_TOKEN: ${{ secrets.PROSOPONATOR_PAT }} + CARGO_TERM_COLOR: always + NODE_OPTIONS: "--max-old-space-size=4096" + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Print contexts + env: + GITHUB_CONTEXT: ${{ toJson(github) }} + ENV_CONTEXT: ${{ toJson(env) }} + VARS_CONTEXT: ${{ toJson(vars) }} + JOB_CONTEXT: ${{ toJson(job) }} + STEPS_CONTEXT: ${{ toJson(steps) }} + RUNNER_CONTEXT: ${{ toJson(runner) }} + SECRETS_CONTEXT: ${{ toJson(secrets) }} + STRATEGY_CONTEXT: ${{ toJson(strategy) }} + MATRIX_CONTEXT: ${{ toJson(matrix) }} + NEEDS_CONTEXT: ${{ toJson(needs) }} + INPUTS_CONTEXT: ${{ toJson(inputs) }} + run: | + echo "******************************" + echo "github:" "$GITHUB_CONTEXT" + echo "******************************" + echo "env:" "$ENV_CONTEXT" + echo "******************************" + echo "vars:" "$VARS_CONTEXT" + echo "******************************" + echo "job:" "$JOB_CONTEXT" + echo "******************************" + echo "steps:" "$STEPS_CONTEXT" + echo "******************************" + echo "runner:" "$RUNNER_CONTEXT" + echo "******************************" + echo "secrets:" "$SECRETS_CONTEXT" + echo "******************************" + echo "strategy:" "$STRATEGY_CONTEXT" + echo "******************************" + echo "matrix:" "$MATRIX_CONTEXT" + echo "******************************" + echo "needs:" "$NEEDS_CONTEXT" + echo "******************************" + echo "inputs:" "$INPUTS_CONTEXT" + echo "******************************" + + - run: mkdir -p ~/.npm + - run: mkdir -p ~/.cache/Cypress + + - name: Restore npm cache + uses: actions/cache/restore@v3 + with: + # must restore all cache dirs, and they must exist ahead of this! + path: | + ~/.npm + ~/.cache/Cypress + # note that restoring a cache in github is a pain. The trailing '-' matches any string after the '-', therefore 'abc-' would match a cache named 'abc-1234' or 'abc-5678', etc. + # the problem is 'abc-' will not match a cache named 'abc'! So if you're using wildcard cache name selectors like this, you need a field that changes as the suffix to become the wildcard + # here we're setting the key to an unused cache key so it falls back to the wildcard selector in `restore-keys` + key: some-unused-cache-key + restore-keys: | + npm-${{ runner.os }}-${{ runner.arch }}- + + - uses: actions/checkout@v3 + + - name: Detect env + id: env + run: | + + set -euxo pipefail # stop on errors, print commands, fail on pipe fails + + VERSION=$(jq -r '.version' < package.json) + + # if version not detected, error + if [[ -z "$VERSION" ]]; then + echo "Failed to get version" + exit 1 + fi + # or if version null + if [[ "$VERSION" == "null" ]]; then + echo "Failed to get version" + exit 1 + fi + + echo "version=$VERSION" + + # export the next version numbers + # shellcheck disable=SC2086 + echo "version=$VERSION" >> $GITHUB_OUTPUT + + # if branch is main, then prod, else staging + if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then + echo "production" + # shellcheck disable=SC2086 + { + echo "env=production"; + echo "production=true"; + echo "docker_latest_tag=latest"; + echo "docker_version_tag=$VERSION"; + echo "gh_release_tag=v$VERSION" + } >> $GITHUB_OUTPUT + elif [[ "${{ github.ref }}" == "refs/heads/staging" ]]; then + echo "staging" + # shellcheck disable=SC2086 + { + echo "env=staging"; + echo "staging=true"; + echo "docker_latest_tag=staging"; + echo "docker_version_tag=staging"; + echo "gh_release_tag=staging" + } >> $GITHUB_OUTPUT + else + echo "cannot deploy from branch ${{ github.ref }}" + exit 1 + fi + + - uses: actions/setup-node@v3 + with: + node-version-file: '.nvmrc' + - run: npm i -g "npm@$(jq -r .engines.npm < package.json)" + + - run: npm ci + + # check everything builds + - run: npm run build:all + - run: npm run build:all:cjs + - run: npm run bundle:all + + # this will error if there's already a release for this version. This is by design, if you need to fix a release (e.g. because a deploy failed) then bump the version and try again + - name: Github release + id: github_release + if: ${{ steps.env.outputs.production }} || ${{ steps.env.outputs.staging }} + continue-on-error: true # we want to continue even if the release already exists + run: | + gh release create --generate-notes "${{ steps.env.outputs.gh_release_tag }}" + + # this will error if there's already a release for this version. This is by design, if you need to fix a release (e.g. because a deploy failed) then bump the version and try again + - name: Mark Github staging release as prerelease + id: github_release + if: ${{ steps.env.outputs.staging }} + continue-on-error: true # we want to continue even if the release already exists + run: | + gh release edit "${{ steps.env.outputs.gh_release_tag }}" --prerelease + + - name: Release fail notification + if: failure() + run: | + curl -X POST -H 'Content-type: application/json' --data "{\"text\":\":check-failed: Release <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ steps.env.outputs.env }} ${{ steps.env.outputs.gh_release_tag }}> failed.\"}" ${{ secrets.SLACKBOT_DEVOPS }} + + - name: Release success notification + if: success() + run: | + curl -X POST -H 'Content-type: application/json' --data "{\"text\":\":check-passed: Release <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ steps.env.outputs.env }} ${{ steps.env.outputs.gh_release_tag }}> succeeded.\"}" ${{ secrets.SLACKBOT_DEVOPS }}