Add automated dependency update workflow with configurable environment variables#201
Conversation
Co-authored-by: JaclynCodes <218383634+JaclynCodes@users.noreply.github.com>
Co-authored-by: JaclynCodes <218383634+JaclynCodes@users.noreply.github.com>
Co-authored-by: JaclynCodes <218383634+JaclynCodes@users.noreply.github.com>
Co-authored-by: JaclynCodes <218383634+JaclynCodes@users.noreply.github.com>
There was a problem hiding this comment.
1 issue found across 3 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name=".github/workflows/update_dependencies.yml">
<violation number="1" location=".github/workflows/update_dependencies.yml:100">
P2: This sed replacement drops existing upper-bound constraints (e.g., `librosa>=0.11.0,<0.12.0`), so a “latest compatible” update can accidentally loosen requirements and allow incompatible versions. Preserve any trailing constraints instead of replacing the whole line.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| exit 1 | ||
| fi | ||
| # Use word boundaries to match exact package name | ||
| sed -i "s/^${{ inputs.package }}[>=<].*/${{ inputs.package }}>=\ |
There was a problem hiding this comment.
P2: This sed replacement drops existing upper-bound constraints (e.g., librosa>=0.11.0,<0.12.0), so a “latest compatible” update can accidentally loosen requirements and allow incompatible versions. Preserve any trailing constraints instead of replacing the whole line.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/update_dependencies.yml, line 100:
<comment>This sed replacement drops existing upper-bound constraints (e.g., `librosa>=0.11.0,<0.12.0`), so a “latest compatible” update can accidentally loosen requirements and allow incompatible versions. Preserve any trailing constraints instead of replacing the whole line.</comment>
<file context>
@@ -0,0 +1,123 @@
+ exit 1
+ fi
+ # Use word boundaries to match exact package name
+ sed -i "s/^${{ inputs.package }}[>=<].*/${{ inputs.package }}>=\
+ $LATEST/" requirements.txt
+ fi
</file context>
There was a problem hiding this comment.
Pull request overview
Adds a GitHub Actions workflow to (optionally) update Python dependencies and documents the repository’s workflows to make automated maintenance discoverable and repeatable.
Changes:
- Introduces
.github/workflows/update_dependencies.ymlfor scheduled/manual dependency update runs with configurable Python/pip versions. - Adds
docs/workflows.mddescribing available workflows and how to run dependency updates. - Links the new workflows documentation from
docs/README.md.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
.github/workflows/update_dependencies.yml |
New automation for checking/updating requirements.txt and pushing update branches. |
docs/workflows.md |
New documentation describing the dependency update workflow and other existing workflows. |
docs/README.md |
Adds links to the new workflows documentation. |
| # Commit changes if there are any | ||
| if git diff --quiet requirements.txt; then | ||
| echo "No changes to commit" | ||
| exit 0 |
There was a problem hiding this comment.
If the provided inputs.package doesn't exist in requirements.txt, sed will succeed but make no changes, and the workflow exits with "No changes to commit". That makes it hard to distinguish "already up to date" from "package not found". Add an explicit check that the package line exists/matched (e.g., grep before/after) and fail with a clear error when it isn't found.
| # Check for outdated packages | ||
| echo "Checking for outdated packages..." | ||
| pip list --outdated > outdated.txt | ||
| cat outdated.txt | ||
|
|
||
| if [ -s outdated.txt ]; then | ||
| echo "updates_available=true" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "updates_available=false" >> $GITHUB_OUTPUT |
There was a problem hiding this comment.
pip list --outdated produces output even when no packages are outdated (e.g., table headers), so checking -s outdated.txt can incorrectly mark updates_available=true and run the update step every time. Prefer a machine-readable format (e.g., --format=json) and explicitly check whether the parsed list is non-empty (or use a format without headers).
| # Check for outdated packages | |
| echo "Checking for outdated packages..." | |
| pip list --outdated > outdated.txt | |
| cat outdated.txt | |
| if [ -s outdated.txt ]; then | |
| echo "updates_available=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "updates_available=false" >> $GITHUB_OUTPUT | |
| # Check for outdated packages using machine-readable JSON output | |
| echo "Checking for outdated packages..." | |
| pip list --outdated --format=json > outdated.json | |
| cat outdated.json || true | |
| updates_count=$(python - << 'PY' | |
| import json | |
| import pathlib | |
| path = pathlib.Path("outdated.json") | |
| if not path.exists(): | |
| # Treat missing output as no updates | |
| print(0) | |
| else: | |
| try: | |
| data = json.loads(path.read_text()) | |
| except json.JSONDecodeError: | |
| # Treat malformed JSON as no updates | |
| print(0) | |
| else: | |
| # data should be a list of outdated packages | |
| print(len(data) if isinstance(data, list) else 0) | |
| PY | |
| ) | |
| if [ "$updates_count" -gt 0 ]; then | |
| echo "updates_available=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "updates_available=false" >> "$GITHUB_OUTPUT" |
| # Install pip-tools for dependency management | ||
| pip install pip-tools | ||
|
|
||
| # Check for outdated packages |
There was a problem hiding this comment.
The workflow installs pip-tools but never uses it afterward. Either remove this install (to reduce runtime/network and simplify the workflow) or actually use pip-tools for compiling/updating requirements if that was the intent.
| # Install pip-tools for dependency management | |
| pip install pip-tools | |
| # Check for outdated packages | |
| # Check for outdated packages using pip |
| if [ -n "${{ inputs.package }}" ]; then | ||
| if [ -n "${{ inputs.version }}" ]; then | ||
| echo "Updating ${{ inputs.package }} to version \ | ||
| ${{ inputs.version }}" | ||
| # Use word boundaries to match exact package name | ||
| sed -i "s/^${{ inputs.package }}[>=<].*/${{ inputs.package }}==\ | ||
| ${{ inputs.version }}/" requirements.txt | ||
| else |
There was a problem hiding this comment.
inputs.package / inputs.version are interpolated directly into shell and sed commands. A crafted input containing quotes/metacharacters can break the command line and execute unintended shell code, especially since this job has contents: write. Validate inputs against an allowlist regex (e.g., [A-Za-z0-9_.-]+), and escape values before using them in sed (or update requirements via a small Python script instead of shell string interpolation).
| sed -i "s/^${{ inputs.package }}[>=<].*/${{ inputs.package }}==\ | ||
| ${{ inputs.version }}/" requirements.txt | ||
| else | ||
| echo "Updating ${{ inputs.package }} to latest \ | ||
| compatible version" | ||
| # Get latest version compatible with constraints | ||
| LATEST=$(pip index versions "${{ inputs.package }}" | \ | ||
| grep "Available versions:" | head -1 | cut -d: -f2 | \ | ||
| tr ',' '\n' | head -1 | xargs) | ||
| if [ -z "$LATEST" ]; then | ||
| echo "Error: Could not determine latest version for \ | ||
| ${{ inputs.package }}" | ||
| exit 1 | ||
| fi | ||
| # Use word boundaries to match exact package name | ||
| sed -i "s/^${{ inputs.package }}[>=<].*/${{ inputs.package }}>=\ | ||
| $LATEST/" requirements.txt | ||
| fi |
There was a problem hiding this comment.
The sed replacement overwrites the entire requirement line, which will drop additional constraints (e.g., librosa>=0.11.0,<0.12.0 would lose the <0.12.0 cap). This can unintentionally widen constraints and break compatibility. Consider preserving existing upper bounds/extras, or editing only the specific specifier being updated instead of replacing the whole line.
Implements automated Python dependency updates inspired by Next.js's
update_react.ymlpattern, adapted for Python ecosystem.Changes
.github/workflows/update_dependencies.yml: New workflow for dependency managementPYTHON_VERSION(3.11),PIP_VERSION(24.0)contents: write) per security best practices^package[>=<].*regex to prevent substring collisionsdocs/workflows.md: Workflow documentation with usage examplesdocs/README.md: Added workflows documentation linkWorkflow Behavior
Manual dispatch supports targeted updates:
Scheduled runs check all packages but require manual intervention for updates (bulk updates need review). Updates pushed to
automated/update-dependencies-YYYYMMDDbranches.Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.
Summary by cubic
Add a workflow to check and update Python dependencies weekly or on demand, with optional targeted package updates. Uses PYTHON_VERSION=3.11 and PIP_VERSION=24.0, runs only for JaclynCodes, pushes with GITHUB_TOKEN, adds explicit contents: write permissions, and improves regex matching and error handling.
Add docs/workflows.md and link it from docs/README.md.
Written for commit 17eae1b. Summary will update on new commits.