Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 50 additions & 21 deletions .github/workflows/gadget-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,19 @@ on:
type: string
required: false
default: "."
environment-name:
description: "Staging/Development environment of Gadget App to push code"
environment-name:
description: "Staging/Development environment of Gadget App to push code (required when action is 'push')"
type: string
default: "staging"
Comment thread
TheOrangePuff marked this conversation as resolved.
required: false

# Deployment Control
push-staging:
description: "Boolean to check if push to staging/development Gadget environment"
type: boolean
default: false
action:
description: "Deployment action to perform: 'push' (push to environment) or 'deploy' (deploy to production)"
type: string
required: true
Comment thread
TheOrangePuff marked this conversation as resolved.
test:
description: "Boolean to check if run tests"
type: boolean
default: false
deploy-production:
Comment thread
TheOrangePuff marked this conversation as resolved.
description: "Boolean to check if promot from staging/development to production"
type: boolean
default: false

# Backport Configuration
Expand All @@ -53,12 +49,21 @@ jobs:
push:
name: 🫸 Push to Gadget
runs-on: ubuntu-latest
if: inputs.action == 'push'
env:
GGT_TOKEN: ${{ secrets.gadget-api-token }}
outputs:
push-environment-status: ${{ steps.push-environment.outcome }}
if: inputs.push-staging == true
steps:
- name: Validate environment-name
run: |
if [ -z "${INPUTS_ENVIRONMENT_NAME}" ]; then
echo "::error::environment-name is required when action is 'push'"
exit 1
fi
env:
INPUTS_ENVIRONMENT_NAME: ${{ inputs.environment-name }}

- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
with:
persist-credentials: false
Expand All @@ -72,18 +77,21 @@ jobs:
id: push-environment
working-directory: ${{ inputs.working-directory }}
run: |
ggt push --app=${INPUTS_APP_NAME} --env=${INPUTS_ENVIRONMENT_NAME} --force --allow-unknown-directory
ggt push \
--app=${INPUTS_APP_NAME} \
--env=${INPUTS_ENVIRONMENT_NAME} \
--force --allow-unknown-directory
env:
INPUTS_APP_NAME: ${{ inputs.app-name }}
INPUTS_ENVIRONMENT_NAME: ${{ inputs.environment-name }}

test:
name: 🧪 Test from Gadget
runs-on: ubuntu-latest
if: inputs.test == true && inputs.action == 'push'
needs: push
env:
GGT_TOKEN: ${{ secrets.gadget-api-token }}
needs: push
if: inputs.test == true
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
with:
Expand All @@ -97,7 +105,10 @@ jobs:
- name: Pull client files into env # pull .gadget folder into test runner
working-directory: ${{ inputs.working-directory }}
run: |
ggt pull --app=${INPUTS_APP_NAME} --env=${INPUTS_ENVIRONMENT_NAME} --force --allow-unknown-directory
ggt pull \
--app=${INPUTS_APP_NAME} \
--env=${INPUTS_ENVIRONMENT_NAME} \
--force --allow-unknown-directory
env:
INPUTS_APP_NAME: ${{ inputs.app-name }}
INPUTS_ENVIRONMENT_NAME: ${{ inputs.environment-name }}
Expand Down Expand Up @@ -128,9 +139,11 @@ jobs:
deploy:
name: 🚀 Deploying Gadget
runs-on: ubuntu-latest
if: inputs.action == 'deploy'
env:
GGT_TOKEN: ${{ secrets.gadget-api-token }}
if: inputs.deploy-production == true
INPUTS_APP_NAME: ${{ inputs.app-name }}
TEMP_ENV_NAME: deploy-${{ github.run_id }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
with:
Expand All @@ -141,17 +154,33 @@ jobs:
npm install -g ggt
ggt version

- name: Create temp Gadget environment
run: |
ggt env create ${TEMP_ENV_NAME} \
--app ${INPUTS_APP_NAME}

- name: Push code to temp Gadget environment
working-directory: ${{ inputs.working-directory }}
run: |
ggt push \
--app=${INPUTS_APP_NAME} \
--env=${TEMP_ENV_NAME} \
--force --allow-unknown-directory

- name: Deploy (promote) to Production environment in Gadget
working-directory: ${{ inputs.working-directory }}
run: |
ggt deploy \
--app=${INPUTS_APP_NAME} \
--env=${INPUTS_ENVIRONMENT_NAME} \
--env=${TEMP_ENV_NAME} \
--force --allow-unknown-directory --allow-problems

env:
INPUTS_APP_NAME: ${{ inputs.app-name }}
INPUTS_ENVIRONMENT_NAME: ${{ inputs.environment-name }}
- name: Remove temp Gadget environment
if: always()
run: |
ggt env delete ${TEMP_ENV_NAME} \
--app ${INPUTS_APP_NAME} \
--force

- name: Backport to staging
if: success() && inputs.create-backport-pr
Expand Down
23 changes: 16 additions & 7 deletions docs/gadget-deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ A comprehensive Gadget app deployment workflow supporting push, test, and produc
- **Custom-environment support**: Support for custom development environment name
- **Conditional automated testing**: Automatic test execution controlled by boolean flag
- **Conditional deployment**: Production deployment controlled by boolean flag
- **Temporary environment deployment**: Production deploys create a temporary Gadget environment, push code to it, promote to production, and clean up automatically
- **Force push capabilities**: Ensures code synchronization with `--force` flag
- **Gadget CLI integration**: Uses `ggt` CLI tool for all operations
- **Test validation**: Runs full test suite before production deployment
Expand All @@ -17,11 +18,10 @@ A comprehensive Gadget app deployment workflow supporting push, test, and produc
| **Core Configuration** |
| app-name | ✅ | string | | Gadget App name to deploy to |
| working-directory | ❌ | string | . | Working directory of Gadget App |
| environment-name | | string | staging | Main _development_ environment name |
| environment-name | ⚠️ | string | | Gadget environment name (required when `action: push`) |
| **Deployment Control** |
| push-staging | | boolean | false | Enable production deployment |
| action | | string | | Deployment action: `push` (push to environment) or `deploy` (deploy to production) |
| test | ❌ | boolean | false | Enable testing on development environment |
| deploy-production | ❌ | boolean | false | Enable production deployment |
| **Backport Configuration** |
| create-backport-pr | ❌ | boolean | false | Create a backport PR after deployment |
| backport-target-branch | ❌ | string | staging | Target branch for backport PR |
Expand Down Expand Up @@ -57,7 +57,7 @@ jobs:
app-name: my-gadget-app
working-directory: apps/gadget-app
environment-name: staging
push-staging: true
action: push
secrets:
gadget-api-token: ${{ secrets.GADGET_API_TOKEN }}
```
Expand All @@ -78,6 +78,7 @@ jobs:
with:
app-name: my-gadget-app
environment-name: development
action: push
secrets:
gadget-api-token: ${{ secrets.GADGET_API_TOKEN }}
```
Expand All @@ -98,7 +99,7 @@ jobs:
app-name: my-gadget-app
working-directory: apps/gadget-app
environment-name: staging
push-staging: true
action: push
test: true
secrets:
gadget-api-token: ${{ secrets.GADGET_API_TOKEN }}
Expand All @@ -119,8 +120,16 @@ jobs:
with:
app-name: my-gadget-app
working-directory: apps/gadget-app
environment-name: staging
deploy-production: true
action: deploy
secrets:
gadget-api-token: ${{ secrets.GADGET_API_TOKEN }}
```

When `action: deploy`, the workflow uses a temporary environment strategy to safely promote code to production:

1. **Create** — A temporary Gadget environment named `deploy-<run_id>` is created (e.g. `deploy-12345678`), using the GitHub Actions run ID for uniqueness. This ensures the deployment is isolated from the main development/staging environment.
2. **Push** — The checked-out code is pushed to this temporary environment using `ggt push`.
3. **Deploy** — The temporary environment is promoted to production using `ggt deploy`.
4. **Cleanup** — The temporary environment is deleted after deployment, regardless of success or failure.

This approach avoids deploying uncommitted or unreviewed changes that may exist in the shared staging environment, ensuring only the exact code from the Git ref is promoted to production.