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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `.github/dependabot.yml` for automated GitHub Actions updates
- `.gitignore` for local settings and Claude plans
- `.claude/` configuration for AI assistant (coding rules, skills, workflow)
- **deploy** action: Wait for ready feature
- Wait for deployment to be reachable before continuing
- New inputs: `wait-for-ready`, `health-endpoint`, `wait-timeout`, `wait-interval`
- Polls deployment URL until HTTP 2xx/3xx or timeout
- PR comment only appears after deployment is healthy (when combined with `comment-on-pr`)

### Changed
- `.pre-commit-config.yaml`: require minimum version 4.5.0
Expand Down
71 changes: 29 additions & 42 deletions deploy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@ Deploys a container image to ZAD Operations Manager.
| `comment-on-pr` | No | `false` | Post/update a comment on the PR with the deployment URL |
| `github-token` | No | `github.token` | GitHub token for PR commenting (defaults to automatic token) |
| `comment-header` | No | `## 🚀 Preview Deployment` | Custom header for the PR comment |
| `wait-for-ready` | No | `false` | Wait for deployment to be reachable |
| `health-endpoint` | No | `/` | Endpoint to check for readiness |
| `wait-timeout` | No | `300` | Maximum wait time in seconds |
| `wait-interval` | No | `10` | Seconds between readiness checks |

## Outputs

| Name | Description |
|------|-------------|
| Name | Description |
|-------|---------------------------------|
| `url` | URL of the deployed application |

## Example Usage
Expand All @@ -30,17 +34,13 @@ Deploys a container image to ZAD Operations Manager.

```yaml
- name: Deploy to ZAD
id: deploy
uses: RijksICTGilde/zad-actions/deploy@v1
with:
api-key: ${{ secrets.ZAD_API_KEY }}
project-id: regel-k4c
project-id: my-project
deployment-name: production
component: editor
image: ghcr.io/minbzk/regelrecht-mvp:latest

- name: Show deployment URL
run: echo "Deployed to ${{ steps.deploy.outputs.url }}"
component: web
image: ghcr.io/org/app:latest
```

### PR Preview with Cloned Config
Expand All @@ -51,11 +51,11 @@ Deploys a container image to ZAD Operations Manager.
uses: RijksICTGilde/zad-actions/deploy@v1
with:
api-key: ${{ secrets.ZAD_API_KEY }}
project-id: regel-k4c
project-id: my-project
deployment-name: pr${{ github.event.pull_request.number }}
component: editor
image: ghcr.io/minbzk/regelrecht-mvp:pr-${{ github.event.number }}
clone-from: production
component: web
image: ghcr.io/org/app:${{ github.sha }}
clone-from: development
```

### PR Preview with Automatic Comment
Expand All @@ -76,8 +76,8 @@ deploy-preview:
project-id: my-project
deployment-name: pr${{ github.event.pull_request.number }}
component: web
image: ghcr.io/org/app:pr-${{ github.event.number }}
clone-from: production
image: ghcr.io/org/app:${{ github.sha }}
clone-from: development
comment-on-pr: true
```

Expand All @@ -87,7 +87,7 @@ The action will create a comment like this on the PR:
>
> Your changes have been deployed to a preview environment:
>
> **URL:** https://web-pr123-my-project.rig.prd1.gn2.quattro.rijksapps.nl
> **URL:** https://web-pr85-my-project.your-domain.example.com
>
> This deployment will be automatically cleaned up when the PR is closed.

Expand All @@ -110,15 +110,15 @@ deploy:
project-id: my-project
deployment-name: pr${{ github.event.pull_request.number }}
component: web
image: ghcr.io/org/app:pr-${{ github.event.number }}
image: ghcr.io/org/app:${{ github.sha }}
```

## Permissions

| Feature | Required Permission |
|---------|---------------------|
| Basic deployment | None (only ZAD API key) |
| PR commenting | `pull-requests: write` |
| Feature | Required Permission |
|------------------|---------------------------|
| Basic deployment | None (only ZAD API key) |
| PR commenting | `pull-requests: write` |

For PR commenting, ensure your job has the required permission (the token defaults to `github.token`):

Expand All @@ -131,12 +131,12 @@ permissions:

The output URL follows the standard ZAD pattern:
```
https://{component}-{deployment}-{project}.rig.prd1.gn2.quattro.rijksapps.nl
https://{component}-{deployment}-{project}.your-domain.example.com
```

For example:
- `component: editor`, `deployment: pr73`, `project: regel-k4c`
- URL: `https://editor-pr73-regel-k4c.rig.prd1.gn2.quattro.rijksapps.nl`
- `component: web`, `deployment: pr85`, `project: my-project`
- URL: `https://web-pr85-my-project.your-domain.example.com`

### Multi-Component Deployment

Expand Down Expand Up @@ -167,8 +167,8 @@ Deploy to different environments based on branch:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy to staging
if: github.ref == 'refs/heads/develop'
- name: Deploy to preview
if: github.ref == 'refs/heads/staging'
uses: RijksICTGilde/zad-actions/deploy@v1
with:
api-key: ${{ secrets.ZAD_API_KEY }}
Expand All @@ -186,36 +186,23 @@ deploy:
deployment-name: production
component: web
image: ghcr.io/org/app:${{ github.sha }}
clone-from: staging
```

### Deploy with Deployment Status Check

Wait for deployment to be healthy:
Wait for deployment to be healthy using the built-in `wait-for-ready` feature:

```yaml
- name: Deploy to ZAD
id: deploy
uses: RijksICTGilde/zad-actions/deploy@v1
with:
api-key: ${{ secrets.ZAD_API_KEY }}
project-id: my-project
deployment-name: production
component: web
image: ghcr.io/org/app:latest

- name: Wait for deployment to be ready
run: |
for i in {1..30}; do
if curl -s -o /dev/null -w "%{http_code}" "${{ steps.deploy.outputs.url }}/health" | grep -q "200"; then
echo "Deployment is healthy!"
exit 0
fi
echo "Waiting for deployment... (attempt $i/30)"
sleep 10
done
echo "Deployment health check timed out"
exit 1
wait-for-ready: true
health-endpoint: /health
```

## How It Works
Expand Down
45 changes: 45 additions & 0 deletions deploy/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,22 @@ inputs:
description: 'Custom header for the PR comment (default: "## 🚀 Preview Deployment")'
required: false
default: '## 🚀 Preview Deployment'
wait-for-ready:
description: 'Wait for deployment to be reachable before continuing'
required: false
default: 'false'
health-endpoint:
description: 'Endpoint to check for readiness (e.g., /, /health)'
required: false
default: '/'
wait-timeout:
description: 'Maximum time to wait for deployment in seconds'
required: false
default: '300'
wait-interval:
description: 'Seconds between readiness checks'
required: false
default: '10'

outputs:
url:
Expand Down Expand Up @@ -181,6 +197,35 @@ runs:
exit 1
fi

- name: Wait for deployment to be ready
if: inputs.wait-for-ready == 'true'
shell: bash
env:
DEPLOYMENT_URL: ${{ steps.deploy.outputs.url }}
HEALTH_ENDPOINT: ${{ inputs.health-endpoint }}
WAIT_TIMEOUT: ${{ inputs.wait-timeout }}
WAIT_INTERVAL: ${{ inputs.wait-interval }}
run: |
URL="${DEPLOYMENT_URL}${HEALTH_ENDPOINT}"
echo "Waiting for $URL to be ready..."

ELAPSED=0
while [ "$ELAPSED" -lt "$WAIT_TIMEOUT" ]; do
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$URL" || echo "000")

if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then
echo "Deployment is ready (HTTP $HTTP_CODE)"
exit 0
fi

echo "Waiting... (HTTP $HTTP_CODE, ${ELAPSED}s elapsed)"
sleep "$WAIT_INTERVAL"
ELAPSED=$((ELAPSED + WAIT_INTERVAL))
done

echo "::error::Deployment did not become ready within ${WAIT_TIMEOUT}s"
exit 1

- name: Comment on PR
if: inputs.comment-on-pr == 'true' && github.event_name == 'pull_request'
shell: bash
Expand Down