Upgrade Cloud Composer (Apache Airflow) to a new version. Use when the user asks to upgrade, update, or bump Airflow, Cloud Composer, or Airflow dependencies to a new version...
This skill defines how to upgrade Cloud Composer (Google Cloud's managed Apache Airflow) to a new version in the pulse-data repository. This involves updating the Composer image version and syncing all Python dependencies.
What Claude does: Updates terraform config and pyproject.toml with new versions. What the user does: Provides package list, commits/pushes changes, triggers GitHub Actions, creates PR, verifies DB size.
Check current version: Read recidiviz/tools/deploy/terraform/cloud-composer.tf and find the image_version field (e.g., composer-2.13.8-airflow-2.10.5)
Suggest latest version: Check https://docs.cloud.google.com/composer/docs/composer-versions#images-composer-2 for the latest Cloud Composer 2 version available. Suggest this version to the user but allow them to specify a different target version.
Version format: composer-X.Y.Z-airflow-A.B.C
Search for Dependabot alerts: Check for Dependabot security alerts that might be resolved by this upgrade:
gh api --paginate /repos/Recidiviz/pulse-data/dependabot/alerts --jq '.[] | select(.state == "open" or .state == "dismissed" or .state == "auto_dismissed") | select(.dependency.manifest_path | contains("recidiviz/airflow/pyproject.toml")) | {number, state, package: .dependency.package.name, manifest: .dependency.manifest_path, severity: .security_advisory.severity, url: .html_url}'--paginate to get all alerts (the API paginates at 30 items per page)manifest_path contains recidiviz/airflow/pyproject.toml - these are relevant to Cloud Composer upgradesgh pr list --author app/dependabot --state openrecidiviz/airflow/pyproject.toml (these often fail to actually fix the issue because they only update the pyproject.toml, not the production Composer environment)https://github.com/Recidiviz/pulse-data/security/dependabot/XXXX)Gather upgrade context: Ask the user for the reason for this upgrade:
This information will be used in the PR description later
CRITICAL: Cloud Composer environments include specific pinned versions of all Python packages. You MUST use the exact versions from Google's documentation.
Construct the URL for the package list by replacing dots with dashes in the version string:
https://docs.cloud.google.com/composer/docs/versions-packages#composer-X-Y-Z-airflow-A-B-Ccomposer-2.15.3-airflow-2.10.5, the URL is:
https://docs.cloud.google.com/composer/docs/versions-packages#composer-2-15-3-airflow-2-10-5Ask the user to:
Once the user provides the package list:
Update recidiviz/tools/deploy/terraform/cloud-composer.tf:
Find the image_version line under google_composer_environment.default_v2.config.software_config and update it:
image_version = "composer-X.Y.Z-airflow-A.B.C"
Use the Edit tool to make this change.
CRITICAL: The recidiviz/airflow/pyproject.toml contains ALL dependencies pinned to exact versions. These MUST match the Cloud Composer environment.
Use the update script to update the pyproject.toml efficiently:
Save the package list that the user provided to a temporary file:
cat > /tmp/composer_packages.txt << 'EOF'
[paste user-provided package list here]
EOF
Run the update script:
python .claude/skills/upgrade_cloud_composer/update_pyproject.py \
/tmp/composer_packages.txt \
recidiviz/airflow/pyproject.toml
Review the script output:
Package Name Normalization:
.) or underscores (_) in package names-) for the same packagesbackports.tarfile in docs → backports-tarfile in pyproject.tomljaraco.classes in docs → jaraco-classes in pyproject.tomlNote: The pyproject.toml has a comment explaining why packages are pinned:
# We pin all dependencies to make sure they remain on versions supported by our current
# Cloud Composer environment. We must manually update the dependencies when we update
# our Cloud Composer version.
DO NOT regenerate uv.lock locally.
Prompt the user to perform the following steps:
uv.lock from their branchMajor Airflow version changes may require test updates due to API changes.
Look at recent upgrade PRs (use git log to find PRs that upgraded Cloud Composer) to see if similar test changes are needed:
Common test files that may need updates:
recidiviz/airflow/tests/utils/dag_helper_functions.pyrecidiviz/airflow/tests/utils/kubernetes_helper_functions.pyIf the Airflow version jump is small (e.g., patch version only), test updates are less likely needed.
Prompt the user to check the Airflow metadata DB sizes before creating the PR:
Ask them to check DB sizes in Cloud Monitoring:
composer.googleapis.com/environment/database/airflow/size)Ask them to report back the sizes (e.g., "staging is ~1.3 GiB, prod is ~2.2 GiB")
If either DB size > 3 GiB, warn that the upgrade may timeout and suggest running the metadata maintenance DAG first
Once the user provides the DB sizes, use those values to fill in the PR description template:
Provide the user with a draft PR description using the repo's PR template:
Title format: [Build] Upgrade Cloud Composer to composer-X.Y.Z-airflow-A.B.C
Labels: Type: Dependency Upgrade
Body template:
## Description of the change
Upgrades from Cloud Composer version `composer-OLD-VERSION` to `composer-NEW-VERSION`.
[Explain reason based on context from Step 1.4: security alerts, new features, maintenance, etc.]
[If there are Dependabot alerts being resolved, mention them here, e.g.: "This upgrade addresses security alerts for the `tornado` and `protobuf-python` packages."]
The Airflow metadata DB size in staging is ~X.X GiB and in prod is ~Y.Y GiB,
so we should be ok to upgrade without doing any further DB pruning.
## Type of change
| Label | Description |
|----------------------------- |----------------------------------------------------------------------------------------------------------- |
| Type: Bug | non-breaking change that fixes an issue |
| Type: Feature | non-breaking change that adds functionality |
| Type: Breaking Change | fix or feature that would cause existing functionality to not work as expected |
| Type: Non-breaking refactor | change addresses some tech debt item or prepares for a later change, but does not change functionality |
| Type: Configuration Change | adjusts configuration to achieve some end related to functionality, development, performance, or security |
| Type: Dependency Upgrade | upgrades a project dependency - these changes are not included in release notes |
## Related issues
Closes #XXXXX
[Include any Dependabot alert URLs that will be resolved, e.g.: "Closes https://github.com/Recidiviz/pulse-data/security/dependabot/1393"]
[Include any open Dependabot PRs that will be superseded, e.g.: "Supersedes #51122"]
## Checklists
### Development
**This box MUST be checked by the submitter prior to merging**:
- [x] **Double- and triple-checked that there is no Personally Identifiable Information (PII) being mistakenly added in this pull request**
These boxes should be checked by the submitter prior to merging:
- [ ] Tests have been written to cover the code changed/added as part of this pull request
### Code review
These boxes should be checked by reviewers prior to merging:
- [ ] This pull request has a descriptive title and information useful to a reviewer
- [ ] Potential security implications or infrastructural changes have been considered, if relevant
The user can create the PR using gh pr create or through the GitHub web UI.
Important Note for PR: Remind the user to add a comment to the PR or mention in the description that:
Before merging the PR, remind the user to:
After the PR is merged, remind the user to:
Scenario: Upgrading from composer-2.13.1-airflow-2.10.5 to composer-2.13.8-airflow-2.10.5 to fix security alerts.
Claude actions:
composer-2.13.1-airflow-2.10.5composer-2.13.8-airflow-2.10.5https://docs.cloud.google.com/composer/docs/versions-packages#composer-2-13-8-airflow-2-10-5cloud-composer.tf: image_version = "composer-2.13.8-airflow-2.10.5"/tmp/composer_packages.txt and run update script to update pyproject.tomlUser actions:
See: PR #45946
Scenario: Upgrading from composer-2.9.7-airflow-2.7.3 to composer-2.13.1-airflow-2.10.5 before support end date.
Claude actions:
composer-2.9.7-airflow-2.7.3composer-2.13.1-airflow-2.10.5cloud-composer.tfkubernetes_helper_functions.pyUser actions:
See: PR #42821