diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml new file mode 100644 index 0000000..01806c3 --- /dev/null +++ b/.github/workflows/auto-release.yml @@ -0,0 +1,46 @@ +name: Auto Build & Release +env: + DOCKER_BUILDKIT: 1 + COMPOSE_DOCKER_CLI_BUILD: 1 + HAVE_TELEGRAM_API_ID: ${{ secrets.TELEGRAM_API_ID != '' }} +on: + schedule: + - cron: '0 * * * *' +concurrency: + group: ${{ github.head_ref || github.run_id }} + cancel-in-progress: true +jobs: + release-check: + permissions: write-all + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Update Env for custom build + run: | + echo "${{ secrets.ENVS }}" >> .env + - name: Should build? + id: should_build + shell: bash + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + should_build=$(python check_resource_updates.py) + if [ "should_build" = "True" ]; then + echo "SHOULD_BUILD=1" >> $GITHUB_OUTPUT + else + echo "SHOULD_BUILD=0" >> $GITHUB_OUTPUT + fi + outputs: + SHOULD_BUILD: ${{ steps.should_build.outputs.SHOULD_BUILD }} + + build-release: + permissions: write-all + needs: release-check + uses: ./.github/workflows/build-apk.yml + if: ${{ needs.release-check.outputs.SHOULD_BUILD == 1 }} + secrets: inherit + with: + TELEGRAM_NO_ROOT_UPLOAD: true + TELEGRAM_ROOT_UPLOAD: true diff --git a/.github/workflows/build-apk.yml b/.github/workflows/build-apk.yml index 2983f70..bd89e0c 100644 --- a/.github/workflows/build-apk.yml +++ b/.github/workflows/build-apk.yml @@ -4,6 +4,18 @@ env: COMPOSE_DOCKER_CLI_BUILD: 1 HAVE_TELEGRAM_API_ID: ${{ secrets.TELEGRAM_API_ID != '' }} on: + workflow_call: + inputs: + TELEGRAM_NO_ROOT_UPLOAD: + description: "Upload Non Rooted APKs to Telegram" + required: false + type: boolean + default: false + TELEGRAM_ROOT_UPLOAD: + description: "Upload Magisk Module from nikhilbadyal/revanced-magisk-module to Telegram" + required: false + type: boolean + default: false workflow_dispatch: inputs: GITHUB_UPLOAD: diff --git a/check_resource_updates.py b/check_resource_updates.py new file mode 100644 index 0000000..54dc40a --- /dev/null +++ b/check_resource_updates.py @@ -0,0 +1,48 @@ +"""Check patching resource updates.""" + +from environs import Env +from loguru import logger + +from main import get_app +from src.config import RevancedConfig +from src.manager.github import GitHubManager +from src.utils import default_build, integration_version_key, patches_version_key + + +def check_if_build_is_required() -> bool: + """Read resource version.""" + env = Env() + env.read_env() + config = RevancedConfig(env) + for app_name in env.list("PATCH_APPS", default_build): + logger.info(f"Checking {app_name}") + app_obj = get_app(config, app_name) + old_integration_version = GitHubManager(env).get_last_version(app_obj, integration_version_key) + old_patches_version = GitHubManager(env).get_last_version(app_obj, patches_version_key) + app_obj.download_patch_resources(config) + if GitHubManager(env).should_trigger_build( + old_integration_version, + app_obj.resource["integrations"]["version"], + ) or GitHubManager(env).should_trigger_build( + old_patches_version, + app_obj.resource["patches"]["version"], + ): + caused_by = { + "app_name": app_name, + "integration": { + "old": old_integration_version, + "new": app_obj.resource["integrations"]["version"], + }, + "patches": { + "old": old_patches_version, + "new": app_obj.resource["patches"]["version"], + }, + } + logger.info(f"New build can be triggered caused by {caused_by}") + print(True) # noqa: FBT003,T201 + return True + print(False) # noqa: FBT003,T201 + return False + + +check_if_build_is_required() diff --git a/pyproject.toml b/pyproject.toml index 6d78be2..8f80d3d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,8 @@ ignore = [ "TRY301", #raise-within-try "PERF203", #try-except-in-loop "UP004", #useless-object-inheritance - "PLR0911" #too many returns + "PLR0911", #too many returns + "S310" # Audit URL open for permitted schemes. ] [tool.ruff.lint.pydocstyle] convention = "numpy" diff --git a/requirements.txt b/requirements.txt index 9821368..fe46b6c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,7 @@ gdown @ git+https://github.com/nikhilbadyal/gdown google-play-scraper==1.2.6 lastversion==3.5.2 loguru==0.7.2 +packaging==24.0 pre-commit==3.7.0 pytz==2024.1 requests==2.31.0 diff --git a/src/manager/__init__.py b/src/manager/__init__.py new file mode 100644 index 0000000..93fa5ad --- /dev/null +++ b/src/manager/__init__.py @@ -0,0 +1 @@ +"""Release patch resource manager.""" diff --git a/src/manager/github.py b/src/manager/github.py new file mode 100644 index 0000000..86e847c --- /dev/null +++ b/src/manager/github.py @@ -0,0 +1,34 @@ +"""Github Manager.""" + +import json +import os +import urllib.request +from pathlib import Path +from typing import Self + +from environs import Env + +from src.app import APP +from src.manager.release_manager import ReleaseManager +from src.utils import branch_name, updates_file + + +class GitHubManager(ReleaseManager): + """Release manager with GitHub.""" + + def __init__(self: Self, env: Env) -> None: + self.update_file_url = ( + f"https://raw.githubusercontent.com/{env.str('GITHUB_REPOSITORY')}/{branch_name}/{updates_file}" + ) + + def get_last_version(self: Self, app: APP, resource_name: str) -> str: + """Get last patched version.""" + if os.getenv("DRY_RUN", default=None): + with Path(updates_file).open() as url: + data = json.load(url) + else: + with urllib.request.urlopen(self.update_file_url) as url: + data = json.load(url) + if data.get(app.app_name): + return str(data[app.app_name][resource_name]) + return "0" diff --git a/src/manager/release_manager.py b/src/manager/release_manager.py new file mode 100644 index 0000000..7604d57 --- /dev/null +++ b/src/manager/release_manager.py @@ -0,0 +1,21 @@ +"""Base release manager.""" + +from typing import Self + +from loguru import logger +from packaging.version import Version + +from src.app import APP + + +class ReleaseManager(object): + """Base Release manager.""" + + def get_last_version(self: Self, app: APP, resource_name: str) -> str: + """Get last patched version.""" + raise NotImplementedError + + def should_trigger_build(self: Self, old_version: str, new_version: str) -> bool: + """Function to check if we should trigger a build.""" + logger.info(f"New version {new_version}, Old version {old_version}") + return Version(new_version) > Version(old_version) # type: ignore[no-any-return] diff --git a/src/utils.py b/src/utils.py index 60eaa48..0436083 100644 --- a/src/utils.py +++ b/src/utils.py @@ -55,6 +55,7 @@ patches_json_version_key = "patches_json_version" implement_method = "Please implement the method" status_code_200 = 200 resource_folder = "apks" +branch_name = "changelogs" def update_changelog(name: str, response: dict[str, str]) -> None: