Automating Atomic Poetry Dependency Updates with Bash

Dependency management is a crucial aspect of any project. Keeping your dependencies up to date ensures security, stability, and access to the latest features. However, simply running poetry update can be risky. What if you have 25 outdated packages, and one of them breaks your project? Rolling back becomes tricky because all updates are bundled into one commit.

This is where atomic updates come in. By updating one package at a time and committing each change separately, you get fine-grained control over your dependencies. In this post, I’ll demonstrate how to automate this process with a Bash script.

Why Automate the Process?

Manually updating packages with poetry update <package-name> can be time-consuming and repetitive, especially if your project has several outdated dependencies. Imagine running this command for each of 25 packages, and then manually committing each change. It becomes tedious, error-prone, and slows down your workflow.

Here’s why automating the process is important:

  • Efficiency: Instead of running individual update commands and making commits for each, the script automates the entire process in a loop. It checks for outdated packages, runs the update, commits the changes, and moves on to the next—without manual intervention.

  • Consistency: Automation ensures that all updates follow a consistent process. You won’t forget to commit a change or make inconsistent commit messages—everything is handled systematically by the script.

  • Focus on What Matters: Rather than spending your time running commands, you can focus on reviewing important changes, like release notes or resolving breaking changes introduced by updates. Let the script handle the grunt work.

The Developer's Responsibility

While automation makes dependency updates easier, it’s still the developer’s responsibility to ensure compatibility. Your project’s pyproject.toml file should specify dependency version constraints that prevent major breaking changes. For example, specifying something like:

wagtail = ">=6.1,<6.2"

ensures that when you update Wagtail, only compatible versions within this range will be installed. This minimizes the risk of major updates that could break your project.

Even with these safeguards, it’s essential to thoroughly test your project after updating dependencies to ensure nothing breaks. Automation can save you time, but you need to verify that everything works as expected.

Tools Like Renovate and Dependabot

There are dedicated tools like Renovate and Dependabot that help automate dependency updates by creating pull requests whenever an update is available. These tools integrate with GitHub and other platforms, providing a more structured way to handle updates.

However, there are times when such tools might not be available or suitable for the project you're working on—whether due to limitations in the development environment or specific project needs. This is where having a custom solution like a custom Bash script can be particularly useful.

The Script

Here’s the Bash script I wrote

#!/bin/bash

echo "Checking for outdated packages..."

# Checking outdated packages with Poetry
outdated_packages=$(poetry show --outdated | awk '{print $1, $2, $3}')

echo "Starting the update process..."

# Read the outdated packages list line by line
echo "$outdated_packages" | while read -r line; do
    read -ra ADDR <<<"$line"
    package_name=${ADDR[0]}
    current_version=${ADDR[1]}
    latest_version=${ADDR[2]}

    # Update package
    echo "Attempting to update $package_name from $current_version to $latest_version..."
    if poetry update "$package_name"; then
        git add poetry.lock
        git commit -m "🐍📦 Update $package_name ($current_version -> $latest_version)"
        echo "Successfully updated and committed $package_name"
    else
        echo "Failed to update $package_name. Continuing to next package..."
    fi

done

echo "Dependency update process completed."

How It Works

  1. Check for outdated packages: The script starts by listing all outdated packages using poetry show --outdated. This command outputs the package name, current version, and the latest available version.

  2. Update each package: For each outdated package, the script runs poetry update <package-name>. If the update succeeds, the changes are committed to Git with a message that clearly shows the version upgrade (e.g., 🐍📦 Update requests (2.25.0 -> 2.32.3)).

  3. Handle errors: If an update fails (e.g., due to incompatibility issues), the script skips that package and moves on to the next, allowing the rest of the updates to proceed.

Why Atomic Updates Matter

The key advantage of this approach is that it provides granularity. When you commit each update individually, you can easily revert just one problematic package update without affecting others. For instance, if requests v2.32.3 breaks your project, you can roll back only that update, while keeping other updates intact.

Here’s how you would revert a single update:

git revert <commit-hash>

This undo command creates a new commit that reverses the changes from the specified commit—leaving the rest of your updates untouched.

Conclusion

By using this Bash script, you can keep your Poetry dependencies up to date while minimizing the risk of breaking changes. The use of atomic commits ensures that each update is easily traceable, and if something goes wrong, you have the power to roll back only the problematic update.

If you have access to tools like Renovate or Dependabot, they can provide even more automation and control over your updates. However, for projects where those tools aren’t available, this script provides a powerful and flexible alternative.

I've created a GitHub Gist with the full script—feel free to try it out in your own project!


Did you find this article valuable?

Support Victor Miti by becoming a sponsor. Any amount is appreciated!