From 36551c0edffda7f08fd07ba3e3555ede18c9f14b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Rz=C4=85d?= Date: Tue, 14 Feb 2023 07:55:36 +0100 Subject: [PATCH] feat(ci): Add image tagging and release (#50) --- .github/workflows/cd.yml | 52 +++++++++-- .github/workflows/ci_terraform.yml | 9 ++ .github/workflows/release.yml | 139 +++++++++++++++++++++++++++++ terraform/ecs/main.tf | 11 +-- terraform/ecs/variables.tf | 4 + terraform/main.tf | 1 + terraform/variables.tf | 4 + 7 files changed, 202 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 3ef481e..057da8e 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -4,17 +4,17 @@ on: workflow_dispatch: inputs: deploy_infra: - description: 'Whether to deploy infrastructure' + description: "Whether to deploy infrastructure" default: true required: true type: boolean deploy_app: - description: 'Whether to deploy app' + description: "Whether to deploy app" default: true required: true type: boolean deploy_prod: - description: 'Whether to deploy to production environment after sucessfull staging deployment' + description: "Whether to deploy to production environment after sucessfull staging deployment" default: false required: true type: boolean @@ -38,11 +38,44 @@ on: concurrency: cd env: - IMAGE_NAME: 'keyserver' + IMAGE_NAME: "keyserver" jobs: + get-version: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.clean_version.outputs.version }} + steps: + - name: Get latest release for image version + id: latest_release + uses: pozetroninc/github-action-get-latest-release@master + with: + repository: ${{ github.repository }} + excludes: draft + + - name: Get release value + id: get_value + uses: actions/github-script@v6 + env: + LATEST_TAG: ${{ steps.latest_release.outputs.release }} + with: + result-encoding: string + script: | + if (context.eventName == "release") { + return context.payload.release.tag_name + } else { + return process.env.LATEST_TAG + } + + - name: Clean version + id: clean_version + run: | + version=$(echo "${{ steps.get_value.outputs.result }}" | sed 's/v//g') + echo "version=$version" >> $GITHUB_OUTPUT + deploy-infra-staging: if: ${{ inputs.deploy_infra }} + needs: [get-version] runs-on: ubuntu-latest environment: name: infra/staging @@ -56,6 +89,7 @@ jobs: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: eu-central-1 + TF_VAR_image_version: ${{ needs.get-version.outputs.version }} - id: deploy-staging uses: WalletConnect/actions/actions/deploy-terraform/@master with: @@ -67,6 +101,7 @@ jobs: deploy-app-staging: if: ${{ inputs.deploy_app }} + needs: [get-version] runs-on: ubuntu-latest environment: name: app/staging @@ -91,7 +126,7 @@ jobs: cluster-name: ${{ env.ENVIRONMENT }}_${{ env.IMAGE_NAME }}_cluster service-name: ${{ env.ENVIRONMENT }}_${{ env.IMAGE_NAME }}-service task-definition-name: ${{ env.ENVIRONMENT }}_${{ env.IMAGE_NAME }} - image-name: ${{ env.ECR_REGISTRY }}/${{ env.IMAGE_NAME }}:latest + image-name: ${{ env.ECR_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.get-version.outputs.version }} validate: if: ${{ always() && contains(join(needs.*.result, ','), 'success') }} @@ -128,7 +163,7 @@ jobs: # Only deploy if tests passed and deployment windows are open # Ignore deployment windows if workflow was started manually if: ${{ always() && inputs.deploy_infra && inputs.deploy_prod && needs.validate.result == 'success' && (needs.deployment_windows.outputs.result == 'yes' || github.event_name == 'workflow_dispatch') }} - needs: [validate, deployment_windows] + needs: [validate, deployment_windows, get-version] runs-on: ubuntu-latest environment: name: infra/prod @@ -142,6 +177,7 @@ jobs: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: eu-central-1 + TF_VAR_image_version: ${{ needs.get-version.outputs.version }} - id: deploy-prod uses: WalletConnect/actions/actions/deploy-terraform/@master with: @@ -155,7 +191,7 @@ jobs: # Only deploy if tests passed and deployment windows are open # Ignore deployment windows if workflow was started manually if: ${{ always() && inputs.deploy_app && inputs.deploy_prod && needs.validate.result == 'success' && (needs.deployment_windows.outputs.result == 'yes' || github.event_name == 'workflow_dispatch') }} - needs: [validate, deployment_windows] + needs: [validate, deployment_windows, get-version] runs-on: ubuntu-latest environment: name: app/prod @@ -180,4 +216,4 @@ jobs: cluster-name: ${{ env.ENVIRONMENT }}_${{ env.IMAGE_NAME }}_cluster service-name: ${{ env.ENVIRONMENT }}_${{ env.IMAGE_NAME }}-service task-definition-name: ${{ env.ENVIRONMENT }}_${{ env.IMAGE_NAME }} - image-name: ${{ env.ECR_REGISTRY }}/${{ env.IMAGE_NAME }}:latest + image-name: ${{ env.ECR_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.get-version.outputs.version }} diff --git a/.github/workflows/ci_terraform.yml b/.github/workflows/ci_terraform.yml index e6df987..1172ed9 100644 --- a/.github/workflows/ci_terraform.yml +++ b/.github/workflows/ci_terraform.yml @@ -79,9 +79,18 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 + # Get latest release for image version + - id: latest_release + uses: pozetroninc/github-action-get-latest-release@master + if: github.event_name != 'release' + with: + repository: ${{ github.repository }} + excludes: draft - name: Run Terraform Plan id: plan uses: WalletConnect/actions/actions/plan-terraform/@master + env: + TF_VAR_image_version: ${{ steps.latest_release.outputs.release }} with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..75a8678 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,139 @@ +name: release + +on: + workflow_dispatch: + workflow_call: + +permissions: + contents: write + packages: write + +jobs: + release: + runs-on: + group: ubuntu-runners + outputs: + version: ${{ steps.clean_version.outputs.version }} + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: "Cocogitto release" + id: release + uses: cocogitto/cocogitto-action@v3 + with: + check: true + check-latest-tag-only: true + release: true + git-user: 'github-actions[bot]' + git-user-email: "github-actions[bot]@users.noreply.github.com" + + - name: "Update version in Cargo.toml" + shell: bash + run: | + version=$(echo "${{ steps.release.outputs.version }}" | sed 's/v//g') + + sed "s/^version = \".*\"\$/version = \"$version\"/" ./Cargo.toml > /tmp/cargo.toml + mv /tmp/cargo.toml ./Cargo.toml + + - name: "Commit version bump" + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: "chore: Bump version for release" + file_pattern: "Cargo.toml Cargo.lock" + commit_user_name: "github-actions[bot]" + commit_user_email: "github-actions[bot]@users.noreply.github.com" + + - name: "Install Rust toolchain (stable)" + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + default: true + + - name: Cache cargo registry + uses: Swatinem/rust-cache@v2 + + - name: "Generate Changelog" + run: cog changelog --at ${{ steps.release.outputs.version }} -t full_hash > GITHUB_CHANGELOG.md + + - name: "Update Github release notes" + uses: softprops/action-gh-release@v1 + with: + body_path: GITHUB_CHANGELOG.md + tag_name: ${{ steps.release.outputs.version }} + token: ${{ secrets.PAT }} + + - id: clean_version + run: | + version=$(echo "${{ steps.release.outputs.version }}" | sed 's/v//g') + echo "version=$version" >> $GITHUB_OUTPUT + + build-container: + runs-on: + group: ubuntu-runners + needs: + - release + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: eu-central-1 + + # Authenticate with ECR + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v1 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + logout: false + + - name: Docker meta + id: meta + uses: docker/metadata-action@v4 + with: + images: | + ${{ steps.login-ecr.outputs.registry }}/keyserver + ghcr.io/${{ github.repository }} + walletconnect/keyserver,enable=false + flavor: | + latest=auto + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=${{ needs.release.outputs.version }} + + # Setup Buildkit + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Build, tag, and push image + uses: docker/build-push-action@v3 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + kick-off-cd: + needs: [build-container] + uses: ./.github/workflows/cd.yml + with: + deploy_app: false + deploy_infra: false + deploy_prod: true + secrets: inherit \ No newline at end of file diff --git a/terraform/ecs/main.tf b/terraform/ecs/main.tf index 7500c11..f041d95 100644 --- a/terraform/ecs/main.tf +++ b/terraform/ecs/main.tf @@ -10,16 +10,7 @@ terraform { } locals { - // TODO: version the image so we can pin it - # pinned_latest_tag = sort(setsubtract(data.aws_ecr_image.service_image.image_tags, ["latest"]))[0] - // TODO: allow caller to pin version - image_tag = data.aws_ecr_image.service_image.image_tags[0] # TODO: var.ecr_app_version == "latest" ? local.pinned_latest_tag : var.ecr_app_version - image = "${var.ecr_repository_url}:${local.image_tag}" -} - -data "aws_ecr_image" "service_image" { - repository_name = "keyserver" - image_tag = "latest" + image = "${var.ecr_repository_url}:${var.image_version}" } # Log Group for our App diff --git a/terraform/ecs/variables.tf b/terraform/ecs/variables.tf index cfce43f..db4f0e7 100644 --- a/terraform/ecs/variables.tf +++ b/terraform/ecs/variables.tf @@ -2,6 +2,10 @@ variable "ecr_repository_url" { type = string } +variable "image_version" { + type = string +} + variable "app_name" { type = string } diff --git a/terraform/main.tf b/terraform/main.tf index b154e0e..603e81a 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -36,6 +36,7 @@ module "ecs" { source = "./ecs" ecr_repository_url = data.aws_ecr_repository.repository.repository_url + image_version = var.image_version app_name = "${terraform.workspace}_${local.app_name}" region = var.region port = 8080 diff --git a/terraform/variables.tf b/terraform/variables.tf index b2e69a4..c42e2b5 100644 --- a/terraform/variables.tf +++ b/terraform/variables.tf @@ -7,6 +7,10 @@ variable "grafana_endpoint" { type = string } +variable "image_version" { + type = string +} + variable "keystore_docdb_primary_instance_class" { type = string }