From 5ee90e3a832540fc1501c1c79320aba7b9842ab3 Mon Sep 17 00:00:00 2001 From: M AL-SOURI Date: Sun, 23 Mar 2025 19:31:24 +0000 Subject: [PATCH 1/3] Trigger final staging deployment --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d71eef5..831f1c5 100644 --- a/README.md +++ b/README.md @@ -55,3 +55,4 @@ It transforms your repository into a deployment engine with zero manual steps. W ## 馃攣 Staging Test Deployment Triggered ## 馃敡 Azure Setup Test ## 馃攣 Final Staging Deployment Triggered +## 馃攣 Staging Final Attempt From d2630b3a6dba4f66c6fae8eea3b9d170bd053123 Mon Sep 17 00:00:00 2001 From: M AL-SOURI Date: Sun, 23 Mar 2025 19:38:17 +0000 Subject: [PATCH 2/3] Update all workflows with dynamic env and naming improvements --- .github/workflows/0-welcome.yml | 2 +- .../workflows/1-configure-label-based-job.yml | 2 +- .../workflows/2-setup-azure-environment.yml | 2 +- .github/workflows/3-spinup-environment.yml | 2 +- .../4-deploy-to-staging-environment.yml | 26 ++---- .../5-deploy-to-prod-environment.yml | 30 ++----- .../workflows/6-destroy-azure-environment.yml | 36 +++------ .github/workflows/deploy-prod.yml | 73 +++++++++-------- .github/workflows/deploy-staging.yml | 69 +++++++++------- .github/workflows/spinup-destroy.yml | 79 ++++++++++++------- 10 files changed, 159 insertions(+), 162 deletions(-) diff --git a/.github/workflows/0-welcome.yml b/.github/workflows/0-welcome.yml index 906a974..4971f54 100644 --- a/.github/workflows/0-welcome.yml +++ b/.github/workflows/0-welcome.yml @@ -1,4 +1,4 @@ -name: Step 0, Welcome +name: Welcome to Auto Deploy Azure # This step triggers after the learner creates a new repository from the template # This workflow updates from step 0 to step 1. diff --git a/.github/workflows/1-configure-label-based-job.yml b/.github/workflows/1-configure-label-based-job.yml index 9b5876b..4ed3be9 100644 --- a/.github/workflows/1-configure-label-based-job.yml +++ b/.github/workflows/1-configure-label-based-job.yml @@ -1,4 +1,4 @@ -name: Step 1, Trigger a job based on labels +name: Trigger Deployments by Label # This step triggers after 0-start.yml. # This workflow updates from step 1 to step 2. diff --git a/.github/workflows/2-setup-azure-environment.yml b/.github/workflows/2-setup-azure-environment.yml index 265f6b0..1fbdb32 100644 --- a/.github/workflows/2-setup-azure-environment.yml +++ b/.github/workflows/2-setup-azure-environment.yml @@ -1,4 +1,4 @@ -name: Step 2, Set up the Azure environment +name: Step 2 路 Initialize Azure Infrastructure # This workflow updates from step 2 to step 3. diff --git a/.github/workflows/3-spinup-environment.yml b/.github/workflows/3-spinup-environment.yml index 63a8f1d..d2c178a 100644 --- a/.github/workflows/3-spinup-environment.yml +++ b/.github/workflows/3-spinup-environment.yml @@ -1,4 +1,4 @@ -name: Step 3, Spin up environment +name: Step 3 路 Spin Up Staging Infrastructure # This workflow updates from step 3 to step 4. diff --git a/.github/workflows/4-deploy-to-staging-environment.yml b/.github/workflows/4-deploy-to-staging-environment.yml index ca9175c..64b3407 100644 --- a/.github/workflows/4-deploy-to-staging-environment.yml +++ b/.github/workflows/4-deploy-to-staging-environment.yml @@ -1,25 +1,22 @@ -name: Step 4, Deploy to staging +name: Step 4 路 Deploy App to Staging Environment # This workflow updates from step 4 to step 5. # This will run after the "Deploy to staging" workflow -# completes on the staging-test branch +# completes on the staging-test-env branch # Reference: https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows on: workflow_dispatch: workflow_run: workflows: ["Deploy to staging"] types: [completed] - branches: [staging-test] + branches: [staging-test-env] permissions: - # Need `contents: read` to checkout the repository. - # Need `contents: write` to update the step metadata. contents: write pull-requests: write jobs: - # Get the current step to only run the main job when the learner is on the same step. get_current_step: name: Check current step number runs-on: ubuntu-latest @@ -36,30 +33,21 @@ jobs: name: On Azure environment created needs: get_current_step runs-on: ubuntu-latest - - # We will only run this action when: - # 1. This repository isn't the template repository. - # 2. The step is currently 4. - # Reference: https://docs.github.com/en/actions/learn-github-actions/contexts - # Reference: https://docs.github.com/en/actions/learn-github-actions/expressions if: >- ${{ !github.event.repository.is_template && needs.get_current_step.outputs.current_step == 4 }} steps: - # We'll need to check out the repository so that we can edit the README. - name: Checkout uses: actions/checkout@v4 with: - fetch-depth: 0 # Let's get all the branches. + fetch-depth: 0 - # Merge the pull open pull request - name: Merge Pull Request - run: gh pr merge --squash staging-test + run: gh pr merge --squash staging-test-env env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # Pull main. - name: Pull main run: | chmod +x ./.github/script/initialize-repository.sh @@ -67,11 +55,11 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # In README.md, switch step 4 for step 5. - name: Update to step 5 uses: skills/action-update-step@v2 with: token: ${{ secrets.GITHUB_TOKEN }} from_step: 4 to_step: 5 - branch_name: staging-test + branch_name: staging-test-env + diff --git a/.github/workflows/5-deploy-to-prod-environment.yml b/.github/workflows/5-deploy-to-prod-environment.yml index a16718a..bdbb163 100644 --- a/.github/workflows/5-deploy-to-prod-environment.yml +++ b/.github/workflows/5-deploy-to-prod-environment.yml @@ -1,10 +1,9 @@ -name: Step 5, Test the deploy to staging workflow +name: Step 5 路 Confirm Staging Deployment Triggers Correctly -# This step triggers after a pull requst is merged to `main`. +# This step triggers after a pull request is merged to `main`. -# This will run after the "Deploy to production"" workflow -# completes on the production-deployment-workflow branch -# Reference: https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows +# It runs after the "Deploy to production" workflow completes +# on the `prod-deploy` branch. on: workflow_dispatch: workflow_run: @@ -13,12 +12,9 @@ on: branches: [main] permissions: - # Need `contents: read` to checkout the repository. - # Need `contents: write` to update the step metadata. contents: write jobs: - # Get the current step to only run the main job when the learner is on the same step. get_current_step: name: Check current step number runs-on: ubuntu-latest @@ -34,30 +30,20 @@ jobs: on_deploy_to_prod: name: On deploy to production needs: get_current_step - - # We will only run this action when: - # 1. This repository isn't the template repository. - # 2. The step is currently 5. - # Reference: https://docs.github.com/en/actions/learn-github-actions/contexts - # Reference: https://docs.github.com/en/actions/learn-github-actions/expressions if: >- ${{ !github.event.repository.is_template && needs.get_current_step.outputs.current_step == 5 }} - - # We'll run Ubuntu for performance instead of Mac or Windows. runs-on: ubuntu-latest - steps: - # We'll need to check out the repository so that we can edit the README. - - name: Checkout + - name: Checkout all branches uses: actions/checkout@v4 with: - fetch-depth: 0 # Let's get all the branches. + fetch-depth: 0 - # In README.md, switch step 5 for step 6. - - name: Update to step 6 + - name: Promote to step 6 in README uses: skills/action-update-step@v2 with: token: ${{ secrets.GITHUB_TOKEN }} from_step: 5 to_step: 6 + diff --git a/.github/workflows/6-destroy-azure-environment.yml b/.github/workflows/6-destroy-azure-environment.yml index 93faf6f..8995d5b 100644 --- a/.github/workflows/6-destroy-azure-environment.yml +++ b/.github/workflows/6-destroy-azure-environment.yml @@ -1,24 +1,20 @@ -name: Step 6, Production deployment cleanup +name: Step 6 路 Cleanup After Production Deployment -# This workflow updates from step 6 to step X. +# This workflow updates from step 6 to step 7 (wrap-up or future step) -# This will run after the "Configure Azure environment" workflow -# completes on the production-deployment-workflow branch -# Reference: https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows +# It triggers after the "Configure Azure environment" workflow completes +# on the `prod-deploy` branch. on: workflow_dispatch: workflow_run: workflows: ["Configure Azure environment"] types: [completed] - branches: [production-deployment-workflow] + branches: [prod-deploy] permissions: - # Need `contents: read` to checkout the repository. - # Need `contents: write` to update the step metadata. contents: write jobs: - # Get the current step to only run the main job when the learner is on the same step. get_current_step: name: Check current step number runs-on: ubuntu-latest @@ -32,32 +28,22 @@ jobs: current_step: ${{ steps.get_step.outputs.current_step }} on_destroy_completed: - name: On destroy completed + name: Cleanup Completed 路 Finalize Progress needs: get_current_step - - # We will only run this action when: - # 1. This repository isn't the template repository. - # 2. The step is currently 6. - # Reference: https://docs.github.com/en/actions/learn-github-actions/contexts - # Reference: https://docs.github.com/en/actions/learn-github-actions/expressions if: >- ${{ !github.event.repository.is_template && needs.get_current_step.outputs.current_step == 6 }} - - # We'll run Ubuntu for performance instead of Mac or Windows. runs-on: ubuntu-latest - steps: - # We'll need to check out the repository so that we can edit the README. - - name: Checkout + - name: Checkout All Branches uses: actions/checkout@v4 with: - fetch-depth: 0 # Let's get all the branches. + fetch-depth: 0 - # In README.md, switch step 6 for step X. - - name: Update to step X + - name: Promote to Step 7 uses: skills/action-update-step@v2 with: token: ${{ secrets.GITHUB_TOKEN }} from_step: 6 - to_step: X + to_step: 7 + diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index c723757..374d781 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -1,7 +1,6 @@ -name: Deploy to production +name: 馃殌 Auto Deploy Azure - Production -# This workflow automatically deploys to production when changes are merged to main -# No manual label is required like in the staging workflow +# Automatically deploys to Azure when pushing to the `main` branch on: push: @@ -10,43 +9,47 @@ on: env: IMAGE_REGISTRY_URL: ghcr.io - ############################################### - ### Replace with GitHub username ### - ############################################### - DOCKER_IMAGE_NAME: msalsouri-azure-ttt - AZURE_WEBAPP_NAME: msalsouri-ttt-app - ############################################### + DOCKER_IMAGE_NAME: ${{ github.repository_owner }}-${{ github.event.repository.name }} + AZURE_WEBAPP_NAME: ${{ github.repository_owner }}-${{ github.event.repository.name }}-app jobs: build: + name: 馃洜 Build Frontend runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 with: node-version: 16 - - name: npm install and build webpack + + - name: Install & Build Webpack run: | - npm install + npm ci npm run build - - uses: actions/upload-artifact@v4 + + - name: Upload Artifacts + uses: actions/upload-artifact@v4 with: - name: webpack artifacts + name: webpack-artifacts path: public/ - Build-Docker-Image: + docker_build: + name: 馃惓 Build & Push Docker Image runs-on: ubuntu-latest needs: build - name: Build image and store in GitHub Container Registry + steps: - - name: Checkout + - name: Checkout repository uses: actions/checkout@v4 - - name: Download built artifact + - name: Download Webpack Artifacts uses: actions/download-artifact@v4 with: - name: webpack artifacts + name: webpack-artifacts path: public - name: Log in to GHCR @@ -56,15 +59,15 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.CR_PAT }} - - name: Extract metadata (tags, labels) for Docker + - name: Extract Metadata id: meta uses: docker/metadata-action@v5 with: - images: ${{env.IMAGE_REGISTRY_URL}}/${{ github.repository }}/${{env.DOCKER_IMAGE_NAME}} + images: ${{ env.IMAGE_REGISTRY_URL }}/${{ github.repository }}/${{ env.DOCKER_IMAGE_NAME }} tags: | type=sha,format=long,prefix= - - name: Build and push Docker image + - name: Build & Push Image uses: docker/build-push-action@v5 with: context: . @@ -72,32 +75,36 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - Deploy-to-Azure: + deploy: + name: 鈽侊笍 Deploy to Azure Web App runs-on: ubuntu-latest - needs: Build-Docker-Image - name: Deploy app container to Azure + needs: docker_build + steps: - - name: "Login via Azure CLI" + - name: Azure Login uses: azure/login@v2 with: creds: ${{ secrets.AZURE_CREDENTIALS }} - - uses: azure/docker-login@v1 + - name: Azure Docker Login + uses: azure/docker-login@v1 with: - login-server: ${{env.IMAGE_REGISTRY_URL}} + login-server: ${{ env.IMAGE_REGISTRY_URL }} username: ${{ github.actor }} password: ${{ secrets.CR_PAT }} - - name: Deploy web app container + - name: Deploy to Web App uses: azure/webapps-deploy@v3 with: - app-name: ${{env.AZURE_WEBAPP_NAME}} - images: ${{env.IMAGE_REGISTRY_URL}}/${{ github.repository }}/${{env.DOCKER_IMAGE_NAME}}:${{github.sha}} + app-name: ${{ env.AZURE_WEBAPP_NAME }} + images: ${{ env.IMAGE_REGISTRY_URL }}/${{ github.repository }}/${{ env.DOCKER_IMAGE_NAME }}:${{ github.sha }} - - name: Azure logout via Azure CLI + - name: Azure Logout uses: azure/CLI@v2 with: inlineScript: | az logout az cache purge az account clear + + diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index 71b0254..76f371f 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -1,4 +1,6 @@ -name: Deploy to staging +name: Auto Deploy Azure - Staging + +# 馃殌 Deploy to staging when 'deploy-staging' label is added to a pull request on: pull_request: @@ -6,54 +8,62 @@ on: env: IMAGE_REGISTRY_URL: ghcr.io - DOCKER_IMAGE_NAME: msalsouri-azure-ttt - AZURE_WEBAPP_NAME: msalsouri-ttt-app + DOCKER_IMAGE_NAME: ${{ github.repository_owner }}-${{ github.event.repository.name }} + AZURE_WEBAPP_NAME: ${{ github.repository_owner }}-${{ github.event.repository.name }}-app jobs: build: - if: contains(github.event.pull_request.labels.*.name, 'stage') + name: Build front-end assets runs-on: ubuntu-latest + if: contains(github.event.pull_request.labels.*.name, 'deploy-staging') steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 with: node-version: 16 - - name: npm install and build webpack + + - name: Install dependencies and build run: | - npm install + npm ci npm run build - - uses: actions/upload-artifact@v4 + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 with: - name: webpack artifacts + name: webpack-artifacts path: public/ - Build-Docker-Image: + docker_build: + name: Build and push Docker image to GHCR runs-on: ubuntu-latest needs: build - name: Build image and store in GitHub Container Registry + steps: - - name: Checkout + - name: Checkout repository uses: actions/checkout@v4 - - name: Download built artifact + - name: Download build artifacts uses: actions/download-artifact@v4 with: - name: webpack artifacts + name: webpack-artifacts path: public - - name: Log in to GHCR + - name: Log in to GitHub Container Registry (GHCR) uses: docker/login-action@v3 with: registry: ${{ env.IMAGE_REGISTRY_URL }} username: ${{ github.actor }} password: ${{ secrets.CR_PAT }} - - name: Extract metadata (tags, labels) for Docker + - name: Generate Docker metadata id: meta uses: docker/metadata-action@v5 with: - images: ${{env.IMAGE_REGISTRY_URL}}/${{ github.repository }}/${{env.DOCKER_IMAGE_NAME}} + images: ${{ env.IMAGE_REGISTRY_URL }}/${{ github.repository }}/${{ env.DOCKER_IMAGE_NAME }} tags: | type=sha,format=long,prefix= @@ -65,33 +75,34 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - Deploy-to-Azure: + deploy: + name: Deploy container to Azure staging runs-on: ubuntu-latest - needs: Build-Docker-Image - name: Deploy app container to Azure + needs: docker_build + steps: - - name: "Login via Azure CLI" + - name: Azure login uses: azure/login@v2 with: creds: ${{ secrets.AZURE_CREDENTIALS }} - - uses: azure/docker-login@v1 + - name: Azure Container Registry login + uses: azure/docker-login@v1 with: - login-server: ${{env.IMAGE_REGISTRY_URL}} + login-server: ${{ env.IMAGE_REGISTRY_URL }} username: ${{ github.actor }} password: ${{ secrets.CR_PAT }} - - name: Deploy web app container + - name: Deploy to Azure Web App uses: azure/webapps-deploy@v3 with: - app-name: ${{env.AZURE_WEBAPP_NAME}} - images: ${{env.IMAGE_REGISTRY_URL}}/${{ github.repository }}/${{env.DOCKER_IMAGE_NAME}}:${{ github.sha }} + app-name: ${{ env.AZURE_WEBAPP_NAME }} + images: ${{ env.IMAGE_REGISTRY_URL }}/${{ github.repository }}/${{ env.DOCKER_IMAGE_NAME }}:${{ github.sha }} - - name: Azure logout via Azure CLI + - name: Clean up Azure session uses: azure/CLI@v2 with: inlineScript: | az logout az cache purge az account clear - diff --git a/.github/workflows/spinup-destroy.yml b/.github/workflows/spinup-destroy.yml index 2c19423..6875611 100644 --- a/.github/workflows/spinup-destroy.yml +++ b/.github/workflows/spinup-destroy.yml @@ -1,4 +1,6 @@ -name: Configure Azure environment +name: 馃彈 Configure Azure Environment + +# This workflow provisions or destroys Azure resources when labeled on: pull_request: @@ -6,62 +8,79 @@ on: env: IMAGE_REGISTRY_URL: ghcr.io - AZURE_RESOURCE_GROUP: cd-with-actions - AZURE_APP_PLAN: actions-ttt-deployment - AZURE_LOCATION: '"North Europe"' - ############################################### - ### Replace with GitHub username ### - ############################################### - AZURE_WEBAPP_NAME: msalsouri-ttt-app + AZURE_RESOURCE_GROUP: auto-deploy-rg + AZURE_APP_PLAN: auto-deploy-app-plan + AZURE_LOCATION: North Europe + AZURE_WEBAPP_NAME: ${{ github.repository_owner }}-${{ github.event.repository.name }}-app jobs: - setup-up-azure-resources: + setup-azure-resources: + name: 馃尡 Spin Up Azure Environment runs-on: ubuntu-latest if: contains(github.event.pull_request.labels.*.name, 'spin up environment') steps: - - name: Checkout repository + - name: Checkout Repository uses: actions/checkout@v4 - - name: Azure login + - name: Azure Login uses: azure/login@v2 with: creds: ${{ secrets.AZURE_CREDENTIALS }} - - name: Create Azure resource group - if: success() + - name: Create Resource Group run: | - az group create --location ${{env.AZURE_LOCATION}} --name ${{env.AZURE_RESOURCE_GROUP}} --subscription ${{secrets.AZURE_SUBSCRIPTION_ID}} + az group create \ + --location "${{ env.AZURE_LOCATION }}" \ + --name "${{ env.AZURE_RESOURCE_GROUP }}" \ + --subscription "${{ secrets.AZURE_SUBSCRIPTION_ID }}" - - name: Create Azure app service plan - if: success() + - name: Create App Service Plan run: | - az appservice plan create --resource-group ${{env.AZURE_RESOURCE_GROUP}} --name ${{env.AZURE_APP_PLAN}} --is-linux --sku F1 --subscription ${{secrets.AZURE_SUBSCRIPTION_ID}} + az appservice plan create \ + --resource-group "${{ env.AZURE_RESOURCE_GROUP }}" \ + --name "${{ env.AZURE_APP_PLAN }}" \ + --is-linux \ + --sku F1 \ + --subscription "${{ secrets.AZURE_SUBSCRIPTION_ID }}" - - name: Create webapp resource - if: success() + - name: Create Azure Web App run: | - az webapp create --resource-group ${{ env.AZURE_RESOURCE_GROUP }} --plan ${{ env.AZURE_APP_PLAN }} --name ${{ env.AZURE_WEBAPP_NAME }} --deployment-container-image-name nginx --subscription ${{secrets.AZURE_SUBSCRIPTION_ID}} + az webapp create \ + --resource-group "${{ env.AZURE_RESOURCE_GROUP }}" \ + --plan "${{ env.AZURE_APP_PLAN }}" \ + --name "${{ env.AZURE_WEBAPP_NAME }}" \ + --deployment-container-image-name nginx \ + --subscription "${{ secrets.AZURE_SUBSCRIPTION_ID }}" - - name: Configure webapp to use GHCR - if: success() + - name: Configure Web App for GHCR run: | - az webapp config container set --docker-custom-image-name nginx --docker-registry-server-password ${{secrets.CR_PAT}} --docker-registry-server-url https://${{env.IMAGE_REGISTRY_URL}} --docker-registry-server-user ${{github.actor}} --name ${{ env.AZURE_WEBAPP_NAME }} --resource-group ${{ env.AZURE_RESOURCE_GROUP }} --subscription ${{secrets.AZURE_SUBSCRIPTION_ID}} + az webapp config container set \ + --docker-custom-image-name nginx \ + --docker-registry-server-url "https://${{ env.IMAGE_REGISTRY_URL }}" \ + --docker-registry-server-user "${{ github.actor }}" \ + --docker-registry-server-password "${{ secrets.CR_PAT }}" \ + --name "${{ env.AZURE_WEBAPP_NAME }}" \ + --resource-group "${{ env.AZURE_RESOURCE_GROUP }}" \ + --subscription "${{ secrets.AZURE_SUBSCRIPTION_ID }}" destroy-azure-resources: + name: 馃Ж Destroy Azure Environment runs-on: ubuntu-latest - if: contains(github.event.pull_request.labels.*.name, 'destroy environment') - steps: - - name: Checkout repository + - name: Checkout Repository uses: actions/checkout@v4 - - name: Azure login + - name: Azure Login uses: azure/login@v2 with: creds: ${{ secrets.AZURE_CREDENTIALS }} - - name: Destroy Azure environment - if: success() + - name: Delete Resource Group run: | - az group delete --name ${{env.AZURE_RESOURCE_GROUP}} --subscription ${{secrets.AZURE_SUBSCRIPTION_ID}} --yes + az group delete \ + --name "${{ env.AZURE_RESOURCE_GROUP }}" \ + --subscription "${{ secrets.AZURE_SUBSCRIPTION_ID }}" \ + --yes + + From d349bb066ccff1e987173143400e962f0a1d7edd Mon Sep 17 00:00:00 2001 From: M AL-SOURI Date: Sun, 23 Mar 2025 20:02:37 +0000 Subject: [PATCH 3/3] Trigger spin-up for dynamic webapp name --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 831f1c5..581130d 100644 --- a/README.md +++ b/README.md @@ -56,3 +56,4 @@ It transforms your repository into a deployment engine with zero manual steps. W ## 馃敡 Azure Setup Test ## 馃攣 Final Staging Deployment Triggered ## 馃攣 Staging Final Attempt +## 馃敡 Create dynamic webapp infrastructure