Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved github action workflow for update #270

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
244 changes: 194 additions & 50 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion bookworm/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
63 changes: 63 additions & 0 deletions tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion tests/test_otau.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down