Deploy to DEV #15
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy to DEV | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| force_bootstrap: | |
| description: 'Force CDK bootstrap (check if needed)' | |
| required: false | |
| default: false | |
| type: boolean | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| build-and-push: | |
| name: Build and Push Image | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| permissions: | |
| contents: read | |
| id-token: write | |
| outputs: | |
| image_tag: ${{ steps.semver.outputs.version }} | |
| steps: | |
| # Step 1: Checkout repository | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| # Step 2: Setup Node.js using .nvmrc | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: 'npm' | |
| # Step 3: Configure AWS credentials for role and region | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@v4 | |
| with: | |
| role-to-assume: ${{ vars.AWS_ROLE_ARN_DEV }} | |
| role-session-name: deploy-nestjs-starter-dev | |
| aws-region: ${{ vars.AWS_REGION }} | |
| # Step 4: Install the app dependencies | |
| - name: Install app dependencies | |
| run: npm ci | |
| # Step 5: Build the app | |
| - name: Build application | |
| run: npm run build | |
| # Step 6: Run the app unit tests | |
| - name: Run unit tests | |
| run: npm run test | |
| # Step 7: Install the infrastructure dependencies | |
| - name: Install infrastructure dependencies | |
| working-directory: ./infrastructure | |
| run: npm ci | |
| # Step 8: Create the infrastructure .env file from CDK_ENV_DEV variable | |
| - name: Create infrastructure .env file | |
| working-directory: ./infrastructure | |
| run: | | |
| echo "${{ vars.CDK_ENV_DEV }}" > .env | |
| echo "✅ Infrastructure .env file created" | |
| # Step 9: Build the infrastructure | |
| - name: Build infrastructure | |
| working-directory: ./infrastructure | |
| run: npm run build | |
| # Step 10: Bootstrap the CDK (if needed) | |
| - name: Bootstrap CDK | |
| working-directory: ./infrastructure | |
| run: | | |
| if [ "${{ inputs.force_bootstrap }}" = "true" ]; then | |
| echo "🔄 Force bootstrapping CDK..." | |
| npm run bootstrap | |
| else | |
| 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 | |
| fi | |
| # Step 11: Synthesize the CDK stacks | |
| - name: Synthesize CDK stacks | |
| working-directory: ./infrastructure | |
| run: npm run synth | |
| # Step 12: Deploy the ECR CDK stack | |
| - name: Deploy ECR stack | |
| working-directory: ./infrastructure | |
| run: | | |
| echo "🚀 Deploying ECR stack..." | |
| npx cdk deploy nestjs-starter-ecr-dev --require-approval never | |
| echo "✅ ECR stack deployed successfully" | |
| # Step 13: Generate semver tag | |
| - name: Generate semver tag | |
| id: semver | |
| run: | | |
| # Get version from package.json | |
| PKG_VERSION=$(node -p "require('./package.json').version") | |
| # Generate build metadata from GitHub Actions context | |
| BUILD_NUMBER="${{ github.run_number }}" | |
| BUILD_SHA="${{ github.sha }}" | |
| SHORT_SHA="${BUILD_SHA:0:7}" | |
| # Create semver-compatible tag for ECR (using hyphen instead of plus) | |
| # ECR only allows: [a-zA-Z0-9-_.] characters | |
| SEMVER="${PKG_VERSION}-build.${BUILD_NUMBER}.${SHORT_SHA}" | |
| echo "Package version: ${PKG_VERSION}" | |
| echo "Build number: ${BUILD_NUMBER}" | |
| echo "Short SHA: ${SHORT_SHA}" | |
| echo "Generated semver: ${SEMVER}" | |
| echo "version=${SEMVER}" >> $GITHUB_OUTPUT | |
| # Step 14: Build the app Docker image and publish it to ECR | |
| - name: Build and push Docker image to ECR | |
| run: | | |
| # Get ECR repository URI | |
| ECR_REPOSITORY_URI=$(aws ecr describe-repositories --repository-names nestjs-starter --region ${{ vars.AWS_REGION }} --query 'repositories[0].repositoryUri' --output text) | |
| echo "ECR Repository URI: $ECR_REPOSITORY_URI" | |
| # Login to ECR | |
| aws ecr get-login-password --region ${{ vars.AWS_REGION }} | docker login --username AWS --password-stdin $ECR_REPOSITORY_URI | |
| # Build and tag the image with both latest and semver tags | |
| SEMVER_TAG="${{ steps.semver.outputs.version }}" | |
| echo "🔨 Building Docker image..." | |
| docker build -t $ECR_REPOSITORY_URI:latest -t $ECR_REPOSITORY_URI:$SEMVER_TAG . | |
| # Push both tags | |
| echo "📤 Pushing Docker image with tag: latest" | |
| docker push $ECR_REPOSITORY_URI:latest | |
| echo "📤 Pushing Docker image with tag: $SEMVER_TAG" | |
| docker push $ECR_REPOSITORY_URI:$SEMVER_TAG | |
| echo "✅ Docker images pushed successfully" | |
| echo " - $ECR_REPOSITORY_URI:latest" | |
| echo " - $ECR_REPOSITORY_URI:$SEMVER_TAG" | |
| # Step 15: Clean up sensitive infrastructure files | |
| - 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" | |
| deploy: | |
| name: Deploy to DEV | |
| needs: build-and-push | |
| uses: ./.github/workflows/release-reusable.yml | |
| with: | |
| image_tag: ${{ needs.build-and-push.outputs.image_tag }} | |
| environment: dev | |
| aws_region: ${{ vars.AWS_REGION }} | |
| aws_role_arn: ${{ vars.AWS_ROLE_ARN_DEV }} | |
| cdk_env_content: ${{ vars.CDK_ENV_DEV }} | |
| permissions: | |
| contents: read | |
| id-token: write |