Skip to content

Commit

Permalink
ci: Add update dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
progsource authored Nov 16, 2024
1 parent d0dae09 commit ee4b0cc
Show file tree
Hide file tree
Showing 5 changed files with 383 additions and 0 deletions.
50 changes: 50 additions & 0 deletions .github/workflows/update-dependencies.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Update dependency versions

on:
schedule:
# This cron expression runs the job at 00:00 UTC on the first day of every month
- cron: '0 0 1 * *'
workflow_dispatch: # Allows manual triggering of the workflow

jobs:
update-fetch-content:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install Pipenv
run: pip install pipenv

- name: Install dependencies
run: |
cd tools
pipenv install
- name: Run update scripts
run: |
cd tools
pipenv run python update_dependencies.py .. tmp tools build docs .github
- name: Check for changes
id: check_changes
run: |
git config --local user.name "github-actions"
git config --local user.email "[email protected]"
git add .
git diff --cached --exit-code || echo "changed" >> $GITHUB_ENV
- name: Create Pull Request
if: env.changed == 'changed'
run: |
git commit -m "Update dependency versions"
git push origin HEAD:update-dependency-versions
gh pr create --base main --head update-dependency-versions --title "Update dependency versions" --body "This pull request updates the dependency versions in files."
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ maddy uses [semver versioning](https://semver.org/).

* ![**CHANGED**](https://img.shields.io/badge/-CHANGED-%23e90) Updated google test to v1.15.0.
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) clang-format
* ![**ADDED**](https://img.shields.io/badge/-ADDED-%23099) automatic update dependencies ci

## version 1.3.0 2023-08-26

Expand Down
12 changes: 12 additions & 0 deletions tools/Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
requests = "*"

[dev-packages]

[requires]
python_version = "3.11"
165 changes: 165 additions & 0 deletions tools/Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

155 changes: 155 additions & 0 deletions tools/update_dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
#!/bin/python
#
# maddy update dependencies
# This project is licensed under the MIT license. For more information see the
# LICENSE file.
import os
import re
import requests
import sys

def get_cmake_files(directory, ignored_dirs=None):
"""
Recursively searches for all CMakeLists.txt files in the specified directory,
ignoring specified subdirectories.
Args:
directory (str): The path to the directory to search for CMakeLists.txt files.
ignored_dirs (list): A list of directory names to ignore during the search.
Returns:
list: A list of full paths to all found CMakeLists.txt files.
"""
cmakelists_paths = []
ignored_dirs = ignored_dirs or []

for root, dirs, files in os.walk(directory):
# Modify dirs in place to skip ignored directories
dirs[:] = [d for d in dirs if d not in ignored_dirs]

if "CMakeLists.txt" in files:
cmakelists_paths.append(os.path.join(root, "CMakeLists.txt"))

return cmakelists_paths

def get_last_dependency_version(url):
"""
Retrieves the latest release version tag from a specified GitHub repository.
Args:
url (str): The URL of the GitHub repository in the format
'https://github.com/owner/repo.git' or 'https://github.com/owner/repo'.
Returns:
str: The latest release version tag (e.g., 'v1.2.3') if found,
or raises an Exception if the repository is not found or
if there is an error in the API request.
Raises:
ValueError: If the provided URL is not in the expected format.
Exception: If there is an error fetching data from the GitHub API.
"""
# Remove the .git suffix if it exists
if url.endswith('.git'):
url = url[:-4]

# Split the URL to extract owner and repository name
parts = url.split('/')
if len(parts) < 5 or parts[2] != 'github.com':
raise ValueError(f"Invalid GitHub repository URL {url}")

owner = parts[3]
repo = parts[4]

# GitHub API endpoint for releases
api_url = f"https://api.github.com/repos/{owner}/{repo}/releases/latest"

# Make a GET request to the GitHub API
response = requests.get(api_url)

if response.status_code == 200:
release_data = response.json()
return release_data['tag_name'] # Return the latest version tag
else:
raise Exception(f"Error fetching data from GitHub API: {response.status_code} - {response.text}")

def get_current_version_from_fetch_content(cmake_code):
"""
Extracts the currently used Git tag from a FetchContent call in CMake code.
Args:
cmake_code (str): The CMake code containing the FetchContent call.
Returns:
str: The Git tag used in the FetchContent call, or None if not found.
"""
# Regular expression to match FetchContent_Declare and capture the GIT_TAG argument
pattern = r'FetchContent_Declare\s*\(\s*[^)]+\s*GIT_TAG\s+([^\s)]+)'

match = re.search(pattern, cmake_code)
if match:
return match.group(1) # Return the captured Git tag
return None

def update_fetch_content_versions(cmake_file_path):
"""
Updates the FetchContent blocks in a CMakeLists.txt file to use the latest
version from the corresponding GitHub repositories.
Args:
cmake_file_path (str): The path to the CMakeLists.txt file to be updated.
"""
with open(cmake_file_path, 'r') as file:
cmake_code = file.read()

# Regular expression to find FetchContent blocks
fetch_content_pattern = r'FetchContent_Declare\s*\(\s*(.*?)\s*\)'

# Find all FetchContent blocks
fetch_content_blocks = re.findall(fetch_content_pattern, cmake_code, re.DOTALL)

for block in fetch_content_blocks:
# Extract the GIT_REPOSITORY line
repo_pattern = r'GIT_REPOSITORY\s+([^\s]+)'
repo_match = re.search(repo_pattern, block)

if repo_match:
repo_url = repo_match.group(1)
current_version = get_current_version_from_fetch_content(block)
latest_version = get_last_dependency_version(repo_url)

if current_version != latest_version:
# Replace the old version with the new version in the CMake code
new_block = re.sub(r'GIT_TAG\s+([^\s]+)', f'GIT_TAG {latest_version}', block)
cmake_code = cmake_code.replace(block, new_block)

# Write the updated CMake code back to the file
with open(cmake_file_path, 'w', encoding='utf-8', newline='\n') as file:
file.write(cmake_code.replace('\r\n', '\n')) # Ensure LF line

def main():
"""
Main function to update FetchContent versions in CMakeLists.txt files.
It takes a directory path as an argument and processes all CMakeLists.txt files found,
ignoring specified directories.
"""
if len(sys.argv) < 2:
print("Usage: python update_dependencies.py <directory_path> [ignored_dirs...]")
sys.exit(1)

directory_path = sys.argv[1]
ignored_dirs = sys.argv[2:] # Remaining arguments are ignored directories

if not os.path.isdir(directory_path):
print(f"The provided path '{directory_path}' is not a valid directory.")
sys.exit(1)

cmake_files = get_cmake_files(directory_path, ignored_dirs)

for cmake_file in cmake_files:
print(f"Updating {cmake_file}...")
update_fetch_content_versions(cmake_file)
print(f"Updated {cmake_file} successfully.")

if __name__ == "__main__":
main()

0 comments on commit ee4b0cc

Please sign in to comment.