diff --git a/.github/workflows/update-dependencies.py b/.github/workflows/update-dependencies.py new file mode 100644 index 00000000000..60a49aa684c --- /dev/null +++ b/.github/workflows/update-dependencies.py @@ -0,0 +1,79 @@ +import os +import re +import urllib.request + +import atoma + +try: + from rich import print +except ImportError: + pass + +DEFINITIONS_FILE = "winbuild/build_prepare.py" + +DEPENDENCIES = [ + # Name, GitHub slug, version prefix + ("fribidi", "fribidi/fribidi", "v"), + ("harfbuzz", "harfbuzz/harfbuzz", ""), + ("openjpeg", "uclouvain/openjpeg", "v"), +] + + +def update_version(name: str, slug: str, version_prefix: str) -> str | None: + url = f"https://github.com/{slug}/tags.atom" + print(url) + contents = urllib.request.urlopen(url).read() + feed = atoma.parse_atom_bytes(contents) + link = feed.entries[0].links[0].href + print(link) + new_tag = link.rsplit("/", 1)[1] + print(f"{new_tag=}") + new_version = new_tag.removeprefix(version_prefix) + print(f"{new_version=}") + + with open(DEFINITIONS_FILE) as f: + content = f.read() + content_new = re.sub( + rf"https://github.com/{slug}/archive/{version_prefix}\d+\.\d+\.\d+.zip", + f"https://github.com/{slug}/archive/{version_prefix}{new_version}.zip", + content, + ) + content_new = re.sub( + rf"{name}-\d+\.\d+\.\d+", + rf"{name}-{new_version}", + content_new, + ) + changes_made = content != content_new + print(f"{changes_made=}") + print() + + if changes_made: + # Write the file out again + with open(DEFINITIONS_FILE, "w") as f: + f.write(content_new) + return f"{name} to {new_version}" + + return None + + +def main() -> None: + updates = [] + for name, slug, v_in_tag in DEPENDENCIES: + update = update_version(name, slug, v_in_tag) + if update: + updates.append(update) + + if updates: + commit_message = "Update " + ", ".join(updates) + print(commit_message) + + github_env_file = os.getenv("GITHUB_ENV") + if github_env_file: + with open(github_env_file, "a") as f: + f.write(f"COMMIT_MESSAGE={commit_message}") + else: + print("No updates") + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/update-dependencies.yml b/.github/workflows/update-dependencies.yml new file mode 100644 index 00000000000..3a0e1c8c615 --- /dev/null +++ b/.github/workflows/update-dependencies.yml @@ -0,0 +1,54 @@ +name: "Update dependencies" + +on: + schedule: + - cron: "30 19 * * *" # daily at 19:30 UTC + push: + paths: + - ".github/workflows/update-dependencies.py" + - ".github/workflows/update-dependencies.yml" + pull_request: + paths: + - ".github/workflows/update-dependencies.py" + - ".github/workflows/update-dependencies.yml" + workflow_dispatch: + +env: + FORCE_COLOR: 1 + +jobs: + update_dependencies: + # TODO if: github.repository_owner == 'python-pillow' + name: Update dependencies + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: "3.10" + cache: pip + cache-dependency-path: .github/workflows/update-dependencies.py + + - name: "Check for updates" + run: | + python -m pip install atoma + python .github/workflows/update-dependencies.py + + - name: "Check if there are changes" + id: "changes" + uses: UnicornGlobal/has-changes-action@v1.0.12 + + # behaviour if PR already exists: https://github.com/marketplace/actions/create-pull-request#action-behaviour + - name: "Create PR" + if: steps.changes.outputs.changed == 1 + uses: "peter-evans/create-pull-request@v3" + with: + commit-message: >- + Update dependencies + title: ${{ env.COMMIT_MESSAGE }} + body: "" + labels: "Dependency" + branch: "update/dependencies" + delete-branch: true