diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml index ba79fd9..acca05c 100644 --- a/.github/workflows/deploy-dev.yml +++ b/.github/workflows/deploy-dev.yml @@ -12,95 +12,13 @@ concurrency: group: ${{ github.workflow }} cancel-in-progress: false -env: - AWS_ENV_CODE: dev - jobs: deploy: - name: Deploy - - runs-on: ubuntu-latest - timeout-minutes: 30 - - permissions: - id-token: write - contents: read - - steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: Setup Node.js Environment - uses: actions/setup-node@v6 - with: - node-version-file: '.nvmrc' - cache: npm - - - name: Install Dependencies - run: npm ci - - - name: Create Environment Configuration - run: | - echo "${{ vars.ENV_DEV }}" > .env - echo "VITE_BUILD_DATE=$(date -u +'%Y-%m-%d')" >> .env - echo "VITE_BUILD_TIME=$(date -u +'%H:%M:%S')" >> .env - echo "VITE_BUILD_TS=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> .env - echo "VITE_BUILD_COMMIT_SHA=${{ github.sha }}" >> .env - echo "VITE_BUILD_ENV_CODE=${{ env.AWS_ENV_CODE }}" >> .env - echo "VITE_BUILD_WORKFLOW_RUNNER=GitHub Actions" >> .env - echo "VITE_BUILD_WORKFLOW_NAME=${{ github.workflow }}" >> .env - echo "VITE_BUILD_WORKFLOW_RUN_NUMBER=${{ github.run_number }}" >> .env - echo "VITE_BUILD_WORKFLOW_RUN_ATTEMPT=${{ github.run_attempt }}" >> .env - - - name: Build - run: npm run build - - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v6 - with: - aws-region: ${{ vars.AWS_REGION }} - role-to-assume: ${{ vars.AWS_ROLE_ARN_DEV }} - role-session-name: deploy-ionic8-starter-dev - - - name: Install infrastructure dependencies - working-directory: ./infrastructure - run: npm ci - - - name: Create infrastructure .env file - working-directory: ./infrastructure - run: | - echo "${{ vars.CDK_ENV_DEV }}" > .env - echo "โœ… Infrastructure .env file created" - - - name: Build infrastructure - working-directory: ./infrastructure - run: npm run build - - - name: Bootstrap CDK - working-directory: ./infrastructure - run: | - echo "โšก Checking if CDK bootstrap is needed..." - # Try to describe the bootstrap stack to see if it exists - if ! aws cloudformation describe-stacks --stack-name CDKToolkit --region ${{ vars.AWS_REGION }} >/dev/null 2>&1; then - echo "๐Ÿš€ CDK not bootstrapped, bootstrapping now..." - npm run bootstrap - else - echo "โœ… CDK already bootstrapped, skipping..." - fi - - - name: Synthesize CDK stacks - working-directory: ./infrastructure - run: npm run synth - - - name: Deploy CDK stacks - working-directory: ./infrastructure - run: npm run deploy:all -- --require-approval never - - - name: Clean up sensitive files - if: always() - working-directory: ./infrastructure - run: | - echo "๐Ÿงน Cleaning up sensitive files..." - rm -f .env - rm -rf cdk.out - echo "โœ… Sensitive files cleaned up" + name: Deploy to DEV + uses: ./.github/workflows/deploy-reusable.yml + with: + aws_region: ${{ vars.AWS_REGION }} + aws_role_arn: ${{ vars.AWS_ROLE_ARN_DEV }} + env_code: dev + env_file: ${{ vars.ENV_DEV }} + cdk_env_file: ${{ vars.CDK_ENV_DEV }} diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index 421e975..4636f90 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -12,95 +12,13 @@ concurrency: group: ${{ github.workflow }} cancel-in-progress: false -env: - AWS_ENV_CODE: prd - jobs: deploy: - name: Deploy - - runs-on: ubuntu-latest - timeout-minutes: 30 - - permissions: - id-token: write - contents: read - - steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: Setup Node.js Environment - uses: actions/setup-node@v6 - with: - node-version-file: '.nvmrc' - cache: npm - - - name: Install Dependencies - run: npm ci - - - name: Create Environment Configuration - run: | - echo "${{ vars.ENV_PROD }}" > .env - echo "VITE_BUILD_DATE=$(date -u +'%Y-%m-%d')" >> .env - echo "VITE_BUILD_TIME=$(date -u +'%H:%M:%S')" >> .env - echo "VITE_BUILD_TS=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> .env - echo "VITE_BUILD_COMMIT_SHA=${{ github.sha }}" >> .env - echo "VITE_BUILD_ENV_CODE=${{ env.AWS_ENV_CODE }}" >> .env - echo "VITE_BUILD_WORKFLOW_RUNNER=GitHub Actions" >> .env - echo "VITE_BUILD_WORKFLOW_NAME=${{ github.workflow }}" >> .env - echo "VITE_BUILD_WORKFLOW_RUN_NUMBER=${{ github.run_number }}" >> .env - echo "VITE_BUILD_WORKFLOW_RUN_ATTEMPT=${{ github.run_attempt }}" >> .env - - - name: Build - run: npm run build - - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v6 - with: - aws-region: ${{ vars.AWS_REGION }} - role-to-assume: ${{ vars.AWS_ROLE_ARN_PROD }} - role-session-name: deploy-ionic8-starter-prod - - - name: Install infrastructure dependencies - working-directory: ./infrastructure - run: npm ci - - - name: Create infrastructure .env file - working-directory: ./infrastructure - run: | - echo "${{ vars.CDK_ENV_PROD }}" > .env - echo "โœ… Infrastructure .env file created" - - - name: Build infrastructure - working-directory: ./infrastructure - run: npm run build - - - name: Bootstrap CDK - working-directory: ./infrastructure - run: | - echo "โšก Checking if CDK bootstrap is needed..." - # Try to describe the bootstrap stack to see if it exists - if ! aws cloudformation describe-stacks --stack-name CDKToolkit --region ${{ vars.AWS_REGION }} >/dev/null 2>&1; then - echo "๐Ÿš€ CDK not bootstrapped, bootstrapping now..." - npm run bootstrap - else - echo "โœ… CDK already bootstrapped, skipping..." - fi - - - name: Synthesize CDK stacks - working-directory: ./infrastructure - run: npm run synth - - - name: Deploy CDK stacks - working-directory: ./infrastructure - run: npm run deploy:all -- --require-approval never - - - name: Clean up sensitive files - if: always() - working-directory: ./infrastructure - run: | - echo "๐Ÿงน Cleaning up sensitive files..." - rm -f .env - rm -rf cdk.out - echo "โœ… Sensitive files cleaned up" + name: Deploy to PROD + uses: ./.github/workflows/deploy-reusable.yml + with: + aws_region: ${{ vars.AWS_REGION }} + aws_role_arn: ${{ vars.AWS_ROLE_ARN_PROD }} + env_code: prod + env_file: ${{ vars.ENV_PROD }} + cdk_env_file: ${{ vars.CDK_ENV_PROD }} diff --git a/.github/workflows/deploy-qa.yml b/.github/workflows/deploy-qa.yml index c264bb8..14983a6 100644 --- a/.github/workflows/deploy-qa.yml +++ b/.github/workflows/deploy-qa.yml @@ -11,95 +11,13 @@ concurrency: group: ${{ github.workflow }} cancel-in-progress: false -env: - AWS_ENV_CODE: qa - jobs: deploy: - name: Deploy - - runs-on: ubuntu-latest - timeout-minutes: 30 - - permissions: - id-token: write - contents: read - - steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: Setup Node.js Environment - uses: actions/setup-node@v6 - with: - node-version-file: '.nvmrc' - cache: npm - - - name: Install Dependencies - run: npm ci - - - name: Create Environment Configuration - run: | - echo "${{ vars.ENV_QA }}" > .env - echo "VITE_BUILD_DATE=$(date -u +'%Y-%m-%d')" >> .env - echo "VITE_BUILD_TIME=$(date -u +'%H:%M:%S')" >> .env - echo "VITE_BUILD_TS=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> .env - echo "VITE_BUILD_COMMIT_SHA=${{ github.sha }}" >> .env - echo "VITE_BUILD_ENV_CODE=${{ env.AWS_ENV_CODE }}" >> .env - echo "VITE_BUILD_WORKFLOW_RUNNER=GitHub Actions" >> .env - echo "VITE_BUILD_WORKFLOW_NAME=${{ github.workflow }}" >> .env - echo "VITE_BUILD_WORKFLOW_RUN_NUMBER=${{ github.run_number }}" >> .env - echo "VITE_BUILD_WORKFLOW_RUN_ATTEMPT=${{ github.run_attempt }}" >> .env - - - name: Build - run: npm run build - - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v6 - with: - aws-region: ${{ vars.AWS_REGION }} - role-to-assume: ${{ vars.AWS_ROLE_ARN_QA }} - role-session-name: deploy-ionic8-starter-qa - - - name: Install infrastructure dependencies - working-directory: ./infrastructure - run: npm ci - - - name: Create infrastructure .env file - working-directory: ./infrastructure - run: | - echo "${{ vars.CDK_ENV_QA }}" > .env - echo "โœ… Infrastructure .env file created" - - - name: Build infrastructure - working-directory: ./infrastructure - run: npm run build - - - name: Bootstrap CDK - working-directory: ./infrastructure - run: | - echo "โšก Checking if CDK bootstrap is needed..." - # Try to describe the bootstrap stack to see if it exists - if ! aws cloudformation describe-stacks --stack-name CDKToolkit --region ${{ vars.AWS_REGION }} >/dev/null 2>&1; then - echo "๐Ÿš€ CDK not bootstrapped, bootstrapping now..." - npm run bootstrap - else - echo "โœ… CDK already bootstrapped, skipping..." - fi - - - name: Synthesize CDK stacks - working-directory: ./infrastructure - run: npm run synth - - - name: Deploy CDK stacks - working-directory: ./infrastructure - run: npm run deploy:all -- --require-approval never - - - name: Clean up sensitive files - if: always() - working-directory: ./infrastructure - run: | - echo "๐Ÿงน Cleaning up sensitive files..." - rm -f .env - rm -rf cdk.out - echo "โœ… Sensitive files cleaned up" + name: Deploy to QA + uses: ./.github/workflows/deploy-reusable.yml + with: + aws_region: ${{ vars.AWS_REGION }} + aws_role_arn: ${{ vars.AWS_ROLE_ARN_QA }} + env_code: qa + env_file: ${{ vars.ENV_QA }} + cdk_env_file: ${{ vars.CDK_ENV_QA }} diff --git a/.github/workflows/deploy-reusable.yml b/.github/workflows/deploy-reusable.yml new file mode 100644 index 0000000..8fe491a --- /dev/null +++ b/.github/workflows/deploy-reusable.yml @@ -0,0 +1,117 @@ +name: Deploy (Reusable) + +on: + workflow_call: + inputs: + aws_region: + description: 'AWS region to deploy to' + required: false + type: string + default: 'us-east-1' + aws_role_arn: + description: 'AWS IAM Role ARN to assume for deployment' + required: true + type: string + env_code: + description: 'Environment code (e.g. dev, qa, prod)' + required: false + type: string + default: 'dev' + env_file: + description: 'Environment file content' + required: true + type: string + cdk_env_file: + description: 'CDK environment file content' + required: true + type: string + +jobs: + deploy: + name: Deploy + + runs-on: ubuntu-latest + timeout-minutes: 30 + + permissions: + id-token: write + contents: read + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version-file: '.nvmrc' + cache: npm + + - name: Install app dependencies + run: npm ci + + - name: Create app .env file + run: | + echo "${{ inputs.env_file }}" > .env + echo "VITE_BUILD_DATE=$(date -u +'%Y-%m-%d')" >> .env + echo "VITE_BUILD_TIME=$(date -u +'%H:%M:%S')" >> .env + echo "VITE_BUILD_TS=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> .env + echo "VITE_BUILD_COMMIT_SHA=${{ github.sha }}" >> .env + echo "VITE_BUILD_ENV_CODE=${{ inputs.env_code }}" >> .env + echo "VITE_BUILD_WORKFLOW_RUNNER=GitHub Actions" >> .env + echo "VITE_BUILD_WORKFLOW_NAME=${{ github.workflow }}" >> .env + echo "VITE_BUILD_WORKFLOW_RUN_NUMBER=${{ github.run_number }}" >> .env + echo "VITE_BUILD_WORKFLOW_RUN_ATTEMPT=${{ github.run_attempt }}" >> .env + + - name: Build app + run: npm run build + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v6 + with: + aws-region: ${{ inputs.aws_region }} + role-to-assume: ${{ inputs.aws_role_arn }} + role-session-name: deploy-ionic8-starter-${{ inputs.env_code }} + + - name: Install infrastructure dependencies + working-directory: ./infrastructure + run: npm ci + + - name: Create infrastructure .env file + working-directory: ./infrastructure + run: | + echo "${{ inputs.cdk_env_file }}" > .env + echo "โœ… Infrastructure .env file created" + + - name: Build infrastructure + working-directory: ./infrastructure + run: npm run build + + - name: Bootstrap CDK + working-directory: ./infrastructure + run: | + echo "โšก Checking if CDK bootstrap is needed..." + # Try to describe the bootstrap stack to see if it exists + if ! aws cloudformation describe-stacks --stack-name CDKToolkit --region ${{ inputs.aws_region }} >/dev/null 2>&1; then + echo "๐Ÿš€ CDK not bootstrapped, bootstrapping now..." + npm run bootstrap + else + echo "โœ… CDK already bootstrapped, skipping..." + fi + + - name: Synthesize CDK stacks + working-directory: ./infrastructure + run: npm run synth + + - name: Deploy CDK stacks + working-directory: ./infrastructure + run: npm run deploy:all -- --require-approval never + + - name: Clean up sensitive files + if: always() + working-directory: ./infrastructure + run: | + echo "๐Ÿงน Cleaning up sensitive files..." + rm -f .env + rm -rf cdk.out + echo "โœ… Sensitive files cleaned up" diff --git a/docs/DEVOPS_GUIDE.md b/docs/DEVOPS_GUIDE.md index f8cab8d..cfd1a88 100644 --- a/docs/DEVOPS_GUIDE.md +++ b/docs/DEVOPS_GUIDE.md @@ -88,22 +88,17 @@ The project uses GitHub Actions for CI/CD. Below is a detailed description of ea - **Output Format:** All results are summarized in the GitHub Actions step summary for easy review in the UI - **Importance:** Maintains code quality, security posture, and up-to-date dependencies. Provides visibility into test coverage and build health. Acts as an early detection system for quality issues, security vulnerabilities, and outdated packages. -### Deploy to DEV Workflow (`deploy-dev.yml`) +### Deploy (Reusable) Workflow (`deploy-reusable.yml`) -- **Purpose:** Automatically builds and deploys the application to the development environment on AWS with full infrastructure provisioning. -- **Triggers:** - - On push to the `main` branch - - On push of the `dev` tag - - Manual: Via GitHub Actions UI (`workflow_dispatch`) -- **Concurrency:** - - Prevents concurrent deployments; ensures orderly deployment +- **Purpose:** Shared, reusable workflow that handles building and deploying the application to AWS environments with full infrastructure provisioning. This workflow is consumed by the environment-specific deployment workflows (DEV, QA, PROD). +- **Type:** Reusable workflow called via `workflow_call` - **Timeout:** 30 minutes -- **Prerequisites:** - - GitHub Actions variables must be configured: - - `AWS_ROLE_ARN_DEV` - AWS IAM Role ARN for development environment - - `AWS_REGION` - AWS region for deployment - - `ENV_DEV` - Application environment variables - - `CDK_ENV_DEV` - CDK infrastructure environment configuration +- **Input Parameters:** + - `aws_region` (optional, default: `us-east-1`) - AWS region to deploy to + - `aws_role_arn` (required) - AWS IAM Role ARN to assume for deployment + - `env_code` (optional, default: `dev`) - Environment code (e.g., dev, qa, prod) + - `env_file` (required) - Application environment file content + - `cdk_env_file` (required) - CDK infrastructure environment file content - **Main Steps:** 1. Checkout repository 2. Setup Node.js (from `.nvmrc`, with npm cache) @@ -117,8 +112,26 @@ The project uses GitHub Actions for CI/CD. Below is a detailed description of ea 10. Bootstrap CDK (checks if already bootstrapped, skips if so) 11. Synthesize CDK CloudFormation templates 12. Deploy CDK stacks (`npm run deploy:all` with `--require-approval never`) - 13. Clean up sensitive files (`.env`, `cdk.out`) -- **Importance:** Enables rapid deployment of latest changes to development environment for testing and validation. Ensures infrastructure-as-code is always in sync with application deployments. + 13. Clean up sensitive files (`.env` and `cdk.out`) +- **Benefits:** Eliminates code duplication across deployment workflows while maintaining clarity and traceability. Each environment workflow calls this reusable workflow with environment-specific configuration. + +### Deploy to DEV Workflow (`deploy-dev.yml`) + +- **Purpose:** Automatically builds and deploys the application to the development environment on AWS with full infrastructure provisioning. +- **Triggers:** + - On push to the `main` branch + - On push of the `dev` tag + - Manual: Via GitHub Actions UI (`workflow_dispatch`) +- **Concurrency:** + - Prevents concurrent deployments; ensures orderly deployment +- **Implementation:** Calls the [Deploy (Reusable) Workflow](#deploy-reusable-workflow-deploy-reusableyml) with DEV-specific configuration +- **Prerequisites:** + - GitHub Actions variables must be configured: + - `AWS_ROLE_ARN_DEV` - AWS IAM Role ARN for development environment + - `AWS_REGION` - AWS region for deployment + - `ENV_DEV` - Application environment variables + - `CDK_ENV_DEV` - CDK infrastructure environment configuration +- **Importance:** Enables rapid deployment of latest changes to the development environment for testing and validation. Ensures infrastructure-as-code is always in sync with application deployments. ### Deploy to QA Workflow (`deploy-qa.yml`) @@ -128,27 +141,13 @@ The project uses GitHub Actions for CI/CD. Below is a detailed description of ea - On push of the `qa` tag - **Concurrency:** - Prevents concurrent deployments; ensures orderly deployment -- **Timeout:** 30 minutes +- **Implementation:** Calls the [Deploy (Reusable) Workflow](#deploy-reusable-workflow-deploy-reusableyml) with QA-specific configuration - **Prerequisites:** - GitHub Actions variables must be configured: - `AWS_ROLE_ARN_QA` - AWS IAM Role ARN for QA environment - `AWS_REGION` - AWS region for deployment - `ENV_QA` - Application environment variables - `CDK_ENV_QA` - CDK infrastructure environment configuration -- **Main Steps:** (identical to DEV workflow with QA-specific variables) - 1. Checkout repository - 2. Setup Node.js (from `.nvmrc`, with npm cache) - 3. Install application dependencies (`npm ci`) - 4. Create application `.env` file with environment variables and build metadata - 5. Build the application (`npm run build`) - 6. Configure AWS credentials using OIDC (role: `AWS_ROLE_ARN_QA`) - 7. Install infrastructure dependencies - 8. Create infrastructure `.env` file from variables - 9. Build infrastructure code - 10. Bootstrap CDK (checks if already bootstrapped, skips if so) - 11. Synthesize CDK CloudFormation templates - 12. Deploy CDK stacks (`npm run deploy:all` with `--require-approval never`) - 13. Clean up sensitive files (`.env`, `cdk.out`) - **Importance:** Allows testing of release branches in a QA environment before deploying to production. ### Deploy to PROD Workflow (`deploy-prod.yml`) @@ -159,27 +158,13 @@ The project uses GitHub Actions for CI/CD. Below is a detailed description of ea - On push of the `prod` tag - **Concurrency:** - Prevents concurrent deployments; ensures orderly deployment -- **Timeout:** 30 minutes +- **Implementation:** Calls the [Deploy (Reusable) Workflow](#deploy-reusable-workflow-deploy-reusableyml) with PROD-specific configuration - **Prerequisites:** - GitHub Actions variables must be configured: - `AWS_ROLE_ARN_PROD` - AWS IAM Role ARN for production environment - `AWS_REGION` - AWS region for deployment - `ENV_PROD` - Application environment variables - `CDK_ENV_PROD` - CDK infrastructure environment configuration -- **Main Steps:** (identical to DEV/QA workflows with PROD-specific variables) - 1. Checkout repository - 2. Setup Node.js (from `.nvmrc`, with npm cache) - 3. Install application dependencies (`npm ci`) - 4. Create application `.env` file with environment variables and build metadata - 5. Build the application (`npm run build`) - 6. Configure AWS credentials using OIDC (role: `AWS_ROLE_ARN_PROD`) - 7. Install infrastructure dependencies - 8. Create infrastructure `.env` file from variables - 9. Build infrastructure code - 10. Bootstrap CDK (checks if already bootstrapped, skips if so) - 11. Synthesize CDK CloudFormation templates - 12. Deploy CDK stacks (`npm run deploy:all` with `--require-approval never`) - 13. Clean up sensitive files (`.env`, `cdk.out`) - **Importance:** Ensures controlled, traceable deployments to production. Using GitHub releases provides a clear release history and version tracking. ### Build Metadata