Saltar al contenido
mypipelines
React·Reusable workflow·on: workflow_call

React Deploy S3

React - Deploy to S3

.github/workflows/react-deploy-s3.yml

.github/workflows/react-deploy-s3.yml
name: React - Deploy to S3
on:
workflow_call:
inputs:
runner:
description: 'Runner type'
required: false
type: string
default: 'ubuntu-latest'
environment:
description: 'GitHub environment (develop, staging, production)'
required: false
type: string
default: 'develop'
build_output_dir:
description: 'Build output directory name (must match build artifact)'
required: false
type: string
default: 'build'
aws_role_to_assume:
description: >-
IAM role ARN to assume via GitHub OIDC. When set, no static access
key is sent and AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY are not
read. Empty keeps the static-key path, which is the default so that
existing consumers keep working.
required: false
type: string
default: ''
secrets:
AWS_ACCESS_KEY_ID:
required: true
AWS_SECRET_ACCESS_KEY:
required: true
AWS_REGION:
required: true
AWS_S3_BUCKET:
required: true
AWS_CLOUDFRONT_DISTRIBUTION_ID:
required: false
outputs:
deploy_status:
description: 'Deployment status'
value: ${{ jobs.deploy.outputs.status }}
s3_bucket:
description: 'S3 bucket deployed to'
value: ${{ jobs.deploy.outputs.bucket }}
# Least privilege for what this workflow actually does. Without it the
# job inherits whatever the calling repository's default happens to be,
# which on older repositories is write-all.
permissions:
contents: read
# Inert unless aws_role_to_assume is set. A reusable workflow cannot
# exceed its own declaration, so the OIDC path needs it declared here.
id-token: write
jobs:
deploy:
name: Deploy to S3
runs-on: ${{ inputs.runner }}
environment: ${{ inputs.environment }}
timeout-minutes: 15
outputs:
status: ${{ steps.deploy.outputs.status }}
bucket: ${{ steps.deploy.outputs.bucket }}
steps:
- name: Download build artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: build-output-${{ github.run_id }}
path: ${{ inputs.build_output_dir }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@e1253824e5c10ff9df46874f81ed3ec929e19cfd # v6.3.0
with:
# One step, two paths. A long-lived access key in a repository secret
# is a credential nobody rotates and everybody with write access can
# exfiltrate; OIDC mints a token scoped to this repository that
# expires with the job. The keys are only sent when no role is given,
# because passing both makes the action assume the role *with* the
# static key and the key stays in play.
role-to-assume: ${{ inputs.aws_role_to_assume }}
aws-access-key-id: ${{ inputs.aws_role_to_assume == '' && secrets.AWS_ACCESS_KEY_ID || '' }}
aws-secret-access-key: ${{ inputs.aws_role_to_assume == '' && secrets.AWS_SECRET_ACCESS_KEY || '' }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Deploy to S3
id: deploy
env:
S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
CLOUDFRONT_DISTRIBUTION_ID: ${{ secrets.AWS_CLOUDFRONT_DISTRIBUTION_ID }}
run: |
echo "Deploying to S3 bucket: $S3_BUCKET"
# Sync build output to S3 (delete stale files)
aws s3 sync ${{ inputs.build_output_dir }} "s3://${S3_BUCKET}" --delete
echo "bucket=$S3_BUCKET" >> $GITHUB_OUTPUT
# CloudFront cache invalidation (optional)
if [ -n "$CLOUDFRONT_DISTRIBUTION_ID" ]; then
echo "Invalidating CloudFront distribution: $CLOUDFRONT_DISTRIBUTION_ID"
INVALIDATION_ID=$(aws cloudfront create-invalidation \
--distribution-id "$CLOUDFRONT_DISTRIBUTION_ID" \
--paths "/*" \
--query 'Invalidation.Id' \
--output text)
echo "Invalidation created: $INVALIDATION_ID"
echo "invalidation_id=$INVALIDATION_ID" >> $GITHUB_OUTPUT
else
echo "No CloudFront distribution ID provided, skipping invalidation"
fi
echo "status=success" >> $GITHUB_OUTPUT
# Summary
echo "### Deployment Completed" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| **S3 Bucket** | $S3_BUCKET |" >> $GITHUB_STEP_SUMMARY
echo "| **Environment** | ${{ inputs.environment }} |" >> $GITHUB_STEP_SUMMARY
if [ -n "$CLOUDFRONT_DISTRIBUTION_ID" ]; then
echo "| **CloudFront** | $CLOUDFRONT_DISTRIBUTION_ID |" >> $GITHUB_STEP_SUMMARY
echo "| **Invalidation** | $INVALIDATION_ID |" >> $GITHUB_STEP_SUMMARY
fi
echo "| **Source** | ${{ inputs.build_output_dir }} |" >> $GITHUB_STEP_SUMMARY