diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f770849a..cf80e56c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,101 +1,245 @@ +name: Build + +# Trigger the workflow on any push and when a release is published on: push: {} - -name: Build + release: + types: [published] env: PYTHONIOENCODING: utf-8 +# Set the permissions of GITHUB_TOKEN +permissions: + contents: write + jobs: build: name: Build runs-on: windows-2019 + strategy: + matrix: + CI_ARCH: ["x86", "x64"] # Define architectures to build for steps: + # Step 1: Check out the repository - name: Check out sources uses: actions/checkout@v4 - - name: Get Python + + # Step 2: Set up Python environment with the specified architecture + - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.10" architecture: ${{ matrix.CI_ARCH }} - - uses: actions/cache@v4 + + # Step 3: Cache dependencies to speed up builds + - name: Cache dependencies + uses: actions/cache@v4 id: cache-deps with: path: | - venv + .env bookworm/resources - key: ${{ runner.os }}-venv-${{ matrix.CI_ARCH }}-${{ hashFiles('requirements*.txt') }} - - name: Setup dependencies + key: ${{ runner.os }}-env-${{ matrix.CI_ARCH }}-${{ hashFiles('requirements*.txt') }} + + # Step 4: Install dependencies if cache is not hit + - name: Install dependencies + if: steps.cache-deps.outputs.cache-hit != 'true' run: | - python -m venv venv - venv/scripts/activate + python -m venv .env + .env\Scripts\activate pip install invoke invoke dev - if: steps.cache-deps.outputs.cache-hit != 'true' - - name: test code - run: | - venv/scripts/activate - pytest -v - - name: Build code + + # Step 5: Build the project + - name: Build the project run: | - venv/scripts/activate - invoke freeze - invoke copy-executables - invoke make-installer + .env\Scripts\activate + invoke build + invoke create-portable + + # Step 6: Generate translation catalogs and version info (only for x64) - name: Generate translation catalogs and version info if: matrix.CI_ARCH == 'x64' run: | - venv/scripts/activate + .env\Scripts\activate invoke gen-pot invoke update-version-info - - name: Upload portable build + + # Step 7: Upload installer artifact + - name: Upload installer + uses: actions/upload-artifact@v4 + with: + name: Bookworm-setup-${{ matrix.CI_ARCH }} + path: scripts\Bookworm-*-${{ matrix.CI_ARCH }}-setup.exe + + # Step 8: Upload portable version artifact + - name: Upload portable version uses: actions/upload-artifact@v4 with: name: Bookworm-portable-${{ matrix.CI_ARCH }} - path: scripts/builder/dist/${{ matrix.CI_ARCH }}/Bookworm - - name: Upload installer + path: scripts\Bookworm-*-${{ matrix.CI_ARCH }}-portable.zip + + # Step 9: Upload update bundle artifact + - name: Upload update bundle uses: actions/upload-artifact@v4 with: - name: Bookworm-setup-${{ matrix.CI_ARCH }} - path: scripts/Bookworm*setup.exe + name: Bookworm-bundle-${{ matrix.CI_ARCH }} + path: scripts\Bookworm-*-${{ matrix.CI_ARCH }}-update.bundle + + # Step 10: Upload translation catalogs (only for x64) - name: Upload translation catalogs if: matrix.CI_ARCH == 'x64' uses: actions/upload-artifact@v4 with: name: translation-catalogs - path: scripts/*.pot - - name: Upload version info - if: matrix.CI_ARCH == 'x64' && startsWith(github.ref, 'refs/tags') && !github.event_type != 'pull_request' + path: scripts\*.pot + + # Step 11: Upload release info (only for x64 and non-pull_request) + - name: Upload release info + if: matrix.CI_ARCH == 'x64' && startsWith(github.ref, 'refs/tags') && github.event_name != 'pull_request' uses: actions/upload-artifact@v4 with: name: release-info - path: scripts/release-info.json - strategy: - matrix: - CI_ARCH: ["x86", "x64"] - + path: scripts\release-info.json + + generate_update_info: + name: Generate update-info.json + runs-on: windows-2019 + needs: build # Wait for the build job to complete + steps: + # Step 1: Check out the repository + - name: Check out sources + uses: actions/checkout@v4 + + # Step 2: Download update bundles from both architectures + - name: Download update bundle for x64 + uses: actions/download-artifact@v4 + with: + name: Bookworm-bundle-x64 + path: scripts + - name: Download update bundle for x86 + uses: actions/download-artifact@v4 + with: + name: Bookworm-bundle-x86 + path: scripts + + # Step 3: Set up Python environment + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + # Step 4: Install dependencies + - name: Install dependencies + run: | + python -m venv .env + .env\Scripts\activate + pip install invoke + invoke dev + + # Step 5: Generate update-info.json + - name: Generate update-info.json + run: | + .env\Scripts\activate + invoke gen-update-info-file + + # Step 6: Upload update-info.json as an artifact + - name: Upload update-info.json + uses: actions/upload-artifact@v4 + with: + name: update-info + path: update_info.json + deploy: - runs-on: ubuntu-latest - needs: ["build"] + name: Deploy + runs-on: windows-2019 + needs: [build, generate_update_info] # Wait for build and generate_update_info jobs steps: - - uses: actions/download-artifact@v4 + # Step 1: Download all artifacts from previous jobs + - name: Download artifacts + uses: actions/download-artifact@v4 with: - path: ~/artifacts - - name: Zip Artifacts + path: artifacts + + # Step 2: Prepare release assets by moving them into an upload directory + - name: Prepare release assets run: | - mkdir -p upload - zip -r upload/Bookworm-portable-x64.zip Bookworm-portable-x64 - zip -r upload/Bookworm-portable-x86.zip Bookworm-portable-x86 - mv Bookworm-setup-x64/* upload - mv Bookworm-setup-x86/* upload - mv release-info/* upload || echo "No release-info" - mv translation-catalogs/* upload - - working-directory: /home/runner/artifacts - - name: Release - if: startsWith(github.ref, 'refs/tags') && !github.event_type != 'pull_request' + mkdir upload + echo Listing files in artifacts directory... + dir artifacts\ + echo Moving setup files... + move artifacts\Bookworm-setup-x86\* upload\ + move artifacts\Bookworm-setup-x64\* upload\ + echo Moving portable files... + move artifacts\Bookworm-portable-x86\* upload\ + move artifacts\Bookworm-portable-x64\* upload\ + echo Moving bundle files... + move artifacts\Bookworm-bundle-x86\* upload\ + move artifacts\Bookworm-bundle-x64\* upload\ + if exist artifacts\translation-catalogs\* (move artifacts\translation-catalogs\* upload\) else (echo "No translation catalogs") + if exist artifacts\release-info\* (move artifacts\release-info\* upload\) else (echo "No release info") + if exist artifacts\update-info\* (move artifacts\update-info\* upload\) else (echo "No update info") + shell: cmd + + # Step 3: Create a draft release (only when a tag is pushed and not for pull requests) + - name: Create Release + if: startsWith(github.ref, 'refs/tags') && github.event_name != 'pull_request' uses: ncipollo/release-action@v1 with: - artifacts: "/home/runner/artifacts/upload/*" + artifacts: 'upload\*' draft: true generateReleaseNotes: true + + submit_update_info: + name: Submit update_info.json to main + runs-on: windows-2019 + if: github.event_name == 'release' && github.event.action == 'published' # Trigger when the release is published + steps: + # Step 1: Check out the repository + - name: Check out sources + uses: actions/checkout@v4 + + # Step 2: Download update_info.json from the release assets + - name: Download update_info.json from release + env: + PAT_TOKEN: ${{ secrets.PAT_TOKEN }} + run: | + $ReleaseAssetsUrl = "${{ github.event.release.assets_url }}" + Write-Host "Release Assets URL: $ReleaseAssetsUrl" + $AuthHeader = "token $env:PAT_TOKEN" + Write-Host "PAT_TOKEN Length: $($env:PAT_TOKEN.Length)" + $Headers = @{ + Authorization = $AuthHeader + Accept = "application/vnd.github.v3+json" + } + $Assets = Invoke-RestMethod -Headers $Headers -Uri $ReleaseAssetsUrl + Write-Host "Assets: $($Assets | ConvertTo-Json -Depth 3)" + $UpdateInfoAsset = $Assets | Where-Object { $_.name -eq "update_info.json" } + Write-Host "Update Info Asset: $($UpdateInfoAsset | ConvertTo-Json)" + if ($UpdateInfoAsset -ne $null) { + Write-Host "Downloading update_info.json from: $($UpdateInfoAsset.browser_download_url)" + Invoke-WebRequest -Headers $Headers -Uri $UpdateInfoAsset.browser_download_url -OutFile update_info.json + } else { + Write-Error "update_info.json not found in release assets" + exit 1 + } + shell: pwsh + + # Step 3: Set up Git user + - name: Configure Git + run: | + git config user.name "GitHub Action" + git config user.email "action@github.com" + + # Step 4: Create Pull Request to main branch + - name: Create Pull Request + uses: peter-evans/create-pull-request@v5 + with: + token: ${{ secrets.PAT_TOKEN }} + commit-message: 'Update update_info.json after release' + branch: update-info/${{ github.run_id }} + title: 'Update update_info.json after release' + body: 'This Pull Request updates update_info.json after the release is published.' + labels: 'automation' + base: main diff --git a/bookworm/app.py b/bookworm/app.py index baa79a6b..01a015bb 100644 --- a/bookworm/app.py +++ b/bookworm/app.py @@ -13,7 +13,7 @@ version_ex = "2022.1.0.30" url = "https://github.com/blindpandas/bookworm" website = "https://getbookworm.com" -update_url = "https://getbookworm.com/update_info.json" +update_url = "https://github.com/blindpandas/bookworm/blob/main/update_info.json" copyright = f"Copyright (c) 2022 {author} and {display_name} contributors." exit_code = 0 is_frozen = getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS") diff --git a/tasks.py b/tasks.py index 3b325a9f..67720aa8 100644 --- a/tasks.py +++ b/tasks.py @@ -545,6 +545,69 @@ def update_version_info(c): print("Updated version information") +@task +@make_env +def gen_update_info_file(c): + """ + Generate or update the `update_info.json` file with the latest version details, + including download URLs and SHA1 hashes for x86 and x64 builds. + """ + from bookworm import app + from bookworm.utils import generate_sha1hash + + print("Generating update information file...") + + # Get the version info and determine the release channel + version_info = app.get_version_info(app.version) + channel = version_info.get("pre_type", "") # Stable version if no pre_type + + # Define base URLs and file paths for x86 and x64 builds + base_url = f"https://github.com/blindpandas/bookworm/releases/download/{app.version}" + x86_file = f"{app.display_name}-{app.version}-x86-update.bundle" + x64_file = f"{app.display_name}-{app.version}-x64-update.bundle" + x86_download_url = f"{base_url}/{x86_file}" + x64_download_url = f"{base_url}/{x64_file}" + + artifacts_folder = PROJECT_ROOT / "scripts" + x86_bundle_path = artifacts_folder / x86_file + x64_bundle_path = artifacts_folder / x64_file + + # Generate SHA1 hash or use default if file does not exist + x86_sha1hash = generate_sha1hash(x86_bundle_path) if x86_bundle_path.exists() else "example_x86_sha1hash" + x64_sha1hash = generate_sha1hash(x64_bundle_path) if x64_bundle_path.exists() else "example_x64_sha1hash" + + # Construct the update info dictionary + update_info = { + channel or "": { # Ensure stable version uses an empty string key + "version": app.version, + "x86_download": x86_download_url, + "x64_download": x64_download_url, + "x86_sha1hash": x86_sha1hash, + "x64_sha1hash": x64_sha1hash, + } + } + +# update_info_file = artifacts_folder / "update_info.json" + update_info_file = PROJECT_ROOT / "update_info.json" + + # Read the existing data if the file exists, otherwise start with an empty dictionary + try: + with update_info_file.open("r", encoding="utf-8") as f: + existing_data = json.load(f) + except (FileNotFoundError, json.JSONDecodeError): + print("Warning: No valid update_info.json file found. Creating a new one.") + existing_data = {} + + # Update the existing data with the new update information + existing_data.update(update_info) + + # Write the updated data back to the JSON file + with update_info_file.open("w", encoding="utf-8") as f: + json.dump(existing_data, f, indent=2, sort_keys=True) + + print(f"Update information file generated at {update_info_file}") + + def _add_pip_install_args(cmd, context): return "{cmd} --timeout {timeout} --retries {retries}".format( cmd=cmd, diff --git a/tests/test_otau.py b/tests/test_otau.py index c3dd7614..63936676 100644 --- a/tests/test_otau.py +++ b/tests/test_otau.py @@ -9,7 +9,7 @@ def test_is_not_valid_identifier(): def test_is_valid_identifier(): - valid_identifiers = ('', 'a', 'b', 'dev') + valid_identifiers = ('', 'a', 'b', 'rc') for identifier in valid_identifiers: channel = UpdateChannel(identifier)