name: Build and Release run-name: ${{ github.ref_name == 'release' && '[Prod]' || '[Dev]' }} Build ${{ github.run_number }} of branch ${{ github.ref_name }} by @${{ github.actor }} on: push: branches: [release] workflow_dispatch: inputs: summary: description: 'Release Summary' required: false type: string default: '' sandbox: description: 'Deploy to Sandbox' default: true required: true type: boolean deploy: description: 'Deploy to Staging / Prod' default: false required: true type: boolean sandboxNoDbRefresh: description: 'Sandbox Disable Daily DB Refresh' default: false required: true type: boolean skiptests: description: 'Skip Tests' default: false required: true type: boolean ignoreLowerCoverage: description: 'Ignore Lower Coverage' default: false required: true type: boolean updateCoverage: description: 'Update Baseline Coverage' default: false required: true type: boolean jobs: # ----------------------------------------------------------------- # PREPARE # ----------------------------------------------------------------- prepare: name: Prepare Release runs-on: ubuntu-latest outputs: should_deploy: ${{ steps.buildvars.outputs.should_deploy }} pkg_version: ${{ steps.buildvars.outputs.pkg_version }} from_tag: ${{ steps.semver.outputs.nextStrict }} to_tag: ${{ steps.semver.outputs.current }} steps: - uses: actions/checkout@v4 with: fetch-depth: 1 fetch-tags: false - name: Get Next Version (Prod) if: ${{ github.ref_name == 'release' }} id: semver uses: ietf-tools/semver-action@v1 with: token: ${{ github.token }} branch: release skipInvalidTags: true - name: Get Dev Version if: ${{ github.ref_name != 'release' }} id: semverdev uses: ietf-tools/semver-action@v1 with: token: ${{ github.token }} branch: release skipInvalidTags: true noVersionBumpBehavior: 'current' noNewCommitBehavior: 'current' - name: Set Release Flag if: ${{ github.ref_name == 'release' }} run: | echo "IS_RELEASE=true" >> $GITHUB_ENV - name: Create Draft Release uses: ncipollo/release-action@v1.14.0 if: ${{ github.ref_name == 'release' }} with: prerelease: true draft: false commit: ${{ github.sha }} tag: ${{ steps.semver.outputs.nextStrict }} name: ${{ steps.semver.outputs.nextStrict }} body: '*pending*' token: ${{ secrets.GITHUB_TOKEN }} - name: Set Build Variables id: buildvars run: | if [[ $IS_RELEASE ]]; then echo "Using AUTO SEMVER mode: ${{ steps.semver.outputs.nextStrict }}" echo "should_deploy=true" >> $GITHUB_OUTPUT echo "pkg_version=${{ steps.semver.outputs.nextStrict }}" >> $GITHUB_OUTPUT echo "::notice::Release ${{ steps.semver.outputs.nextStrict }} created using branch $GITHUB_REF_NAME" else echo "Using TEST mode: ${{ steps.semverdev.outputs.nextMajorStrict }}.0.0-dev.$GITHUB_RUN_NUMBER" echo "should_deploy=false" >> $GITHUB_OUTPUT echo "pkg_version=${{ steps.semverdev.outputs.nextMajorStrict }}.0.0-dev.$GITHUB_RUN_NUMBER" >> $GITHUB_OUTPUT echo "::notice::Non-production build ${{ steps.semverdev.outputs.nextMajorStrict }}.0.0-dev.$GITHUB_RUN_NUMBER created using branch $GITHUB_REF_NAME" fi # ----------------------------------------------------------------- # TESTS # ----------------------------------------------------------------- tests: name: Run Tests uses: ./.github/workflows/tests.yml if: ${{ github.event.inputs.skiptests == 'false' || github.ref_name == 'release' }} needs: [prepare] with: ignoreLowerCoverage: ${{ github.event.inputs.ignoreLowerCoverage == 'true' }} # ----------------------------------------------------------------- # RELEASE # ----------------------------------------------------------------- release: name: Make Release if: ${{ !failure() && !cancelled() }} needs: [tests, prepare] runs-on: ubuntu-latest permissions: contents: write packages: write env: SHOULD_DEPLOY: ${{needs.prepare.outputs.should_deploy}} PKG_VERSION: ${{needs.prepare.outputs.pkg_version}} FROM_TAG: ${{needs.prepare.outputs.from_tag}} TO_TAG: ${{needs.prepare.outputs.to_tag}} steps: - uses: actions/checkout@v4 with: fetch-depth: 1 fetch-tags: false - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '16' - name: Setup Python uses: actions/setup-python@v5 with: python-version: '3.x' - name: Download a Coverage Results if: ${{ github.event.inputs.skiptests == 'false' || github.ref_name == 'release' }} uses: actions/download-artifact@v4.1.7 with: name: coverage - name: Make Release Build env: DEBIAN_FRONTEND: noninteractive BROWSERSLIST_IGNORE_OLD_DATA: 1 run: | echo "PKG_VERSION: $PKG_VERSION" echo "GITHUB_SHA: $GITHUB_SHA" echo "GITHUB_REF_NAME: $GITHUB_REF_NAME" echo "Running frontend build script..." echo "Compiling native node packages..." yarn rebuild echo "Packaging static assets..." yarn build --base=https://static.ietf.org/dt/$PKG_VERSION/ yarn legacy:build echo "Setting version $PKG_VERSION..." sed -i -r -e "s|^__version__ += '.*'$|__version__ = '$PKG_VERSION'|" ietf/__init__.py sed -i -r -e "s|^__release_hash__ += '.*'$|__release_hash__ = '$GITHUB_SHA'|" ietf/__init__.py sed -i -r -e "s|^__release_branch__ += '.*'$|__release_branch__ = '$GITHUB_REF_NAME'|" ietf/__init__.py - name: Set Production Flags if: ${{ env.SHOULD_DEPLOY == 'true' }} run: | echo "Setting production flags in settings.py..." sed -i -r -e 's/^DEBUG *= *.*$/DEBUG = False/' -e "s/^SERVER_MODE *= *.*\$/SERVER_MODE = 'production'/" ietf/settings.py - name: Make Release Tarball env: DEBIAN_FRONTEND: noninteractive run: | echo "Build release tarball..." mkdir -p /home/runner/work/release tar -czf /home/runner/work/release/release.tar.gz -X dev/build/exclude-patterns.txt . - name: Collect + Push Statics env: DEBIAN_FRONTEND: noninteractive AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_STATIC_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_STATIC_KEY_SECRET }} AWS_DEFAULT_REGION: auto AWS_ENDPOINT_URL: ${{ secrets.CF_R2_ENDPOINT }} run: | echo "Collecting statics..." docker run --rm --name collectstatics -v $(pwd):/workspace ghcr.io/ietf-tools/datatracker-app-base:latest sh dev/build/collectstatics.sh echo "Pushing statics..." cd static aws s3 sync . s3://static/dt/$PKG_VERSION --only-show-errors - name: Augment dockerignore for docker image build env: DEBIAN_FRONTEND: noninteractive run: | cat >> .dockerignore < by ${{ github.triggering_actor }} - <@${{ secrets.SLACK_UID_RJSPARKS }}>", "attachments": [ { "color": "28a745", "fields": [ { "title": "Status", "short": true, "value": "Completed" } ] } ] } env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_GH_BOT }} - name: Notify on Slack (Failure) if: ${{ contains(join(needs.*.result, ','), 'failure') }} uses: slackapi/slack-github-action@v1.26.0 with: channel-id: ${{ secrets.SLACK_GH_BUILDS_CHANNEL_ID }} payload: | { "text": "Datatracker Build by ${{ github.triggering_actor }} - <@${{ secrets.SLACK_UID_RJSPARKS }}>", "attachments": [ { "color": "a82929", "fields": [ { "title": "Status", "short": true, "value": "Failed" } ] } ] } env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_GH_BOT }} # ----------------------------------------------------------------- # SANDBOX # ----------------------------------------------------------------- sandbox: name: Deploy to Sandbox if: ${{ !failure() && !cancelled() && github.event.inputs.sandbox == 'true' }} needs: [prepare, release] runs-on: [self-hosted, dev-server] environment: name: sandbox env: PKG_VERSION: ${{needs.prepare.outputs.pkg_version}} steps: - uses: actions/checkout@v4 - name: Download a Release Artifact uses: actions/download-artifact@v4.1.7 with: name: release-${{ env.PKG_VERSION }} - name: Deploy to containers env: DEBIAN_FRONTEND: noninteractive run: | echo "Reset production flags in settings.py..." sed -i -r -e 's/^DEBUG *= *.*$/DEBUG = True/' -e "s/^SERVER_MODE *= *.*\$/SERVER_MODE = 'development'/" ietf/settings.py echo "Install Deploy to Container CLI dependencies..." cd dev/deploy-to-container npm ci cd ../.. echo "Start Deploy..." node ./dev/deploy-to-container/cli.js --branch ${{ github.ref_name }} --domain dev.ietf.org --appversion ${{ env.PKG_VERSION }} --commit ${{ github.sha }} --ghrunid ${{ github.run_id }} --nodbrefresh ${{ github.event.inputs.sandboxNoDbRefresh }} - name: Cleanup old docker resources env: DEBIAN_FRONTEND: noninteractive run: | docker image prune -a -f # ----------------------------------------------------------------- # STAGING # ----------------------------------------------------------------- staging: name: Deploy to Staging if: ${{ !failure() && !cancelled() && github.event.inputs.deploy == 'true' }} needs: [prepare, release] runs-on: ubuntu-latest environment: name: staging env: PKG_VERSION: ${{needs.prepare.outputs.pkg_version}} steps: - name: Deploy to staging run: | curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer ${{ secrets.GH_INFRA_K8S_TOKEN }}" ${{ secrets.GHA_K8S_DEPLOY_API }} -d '{"ref":"main", "inputs": { "environment":"${{ secrets.GHA_K8S_CLUSTER }}", "app":"datatracker", "appVersion":"${{ env.PKG_VERSION }}" }}' # ----------------------------------------------------------------- # PROD # ----------------------------------------------------------------- prod: name: Deploy to Production if: ${{ !failure() && !cancelled() && github.event.inputs.deploy == 'true' }} needs: [staging] runs-on: ubuntu-latest environment: name: production env: PKG_VERSION: ${{needs.prepare.outputs.pkg_version}} steps: - name: Deploy to production run: | curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer ${{ secrets.GH_INFRA_K8S_TOKEN }}" ${{ secrets.GHA_K8S_DEPLOY_API }} -d '{"ref":"main", "inputs": { "environment":"${{ secrets.GHA_K8S_CLUSTER }}", "app":"datatracker", "appVersion":"${{ env.PKG_VERSION }}" }}'