Skip to content

Patch and Release OTA #547

Patch and Release OTA

Patch and Release OTA #547

Workflow file for this run

name: Patch and Release OTA
on:
schedule:
- cron: "0 */6 * * *" # Check for update every 6 hours (UTC). GrapheneOS checks every 6 hours.
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
inputs:
device-id:
description: Device code name
required: true
root:
description: Add root to the build
required: false
type: boolean
default: false
magisk-preinit-device:
description: Magisk preinit device. For example, "sda8", "sda15" etc.,
required: false
update-channel:
description: GrapheneOS update channel. Supports `alpha`, `beta` and `stable`. Defaults to `stable`
required: false
env:
CARGO_INCREMENTAL: 1
DEVICE_NAME: ${{ github.event.inputs.device-id }}
INTERACTIVE_MODE: false
GRAPHENEOS_UPDATE_CHANNEL: ${{ github.event.inputs.update-channel }}
RUST_BACKTRACE: short
RUSTUP_MAX_RETRIES: 10
jobs:
build:
runs-on: ubuntu-latest
# Required by publisher step
permissions: write-all
steps:
- name: Check if `magisk-preinit-device` is set when `root` is true
run: |
# Convert inputs to proper boolean values
root=${{ github.event.inputs.root }}
magisk_preinit_device=${{ github.event.inputs.magisk-preinit-device }}
# Ensure that the boolean comparison is correctly handled
if [ "$root" == "true" ] && [ -z "$magisk_preinit_device" ]; then
echo -e "::error:: magisk-preinit-device is required when root is true."
exit 1
fi
- name: Checkout code
uses: actions/checkout@v4
with:
# Allow for switching to github-pages branch
fetch-depth: 0
- name: Read from `env.toml` if exist
if: ${{ github.event_name == 'schedule' }}
run: |
# Check if the file exists
source src/util_functions.sh && check_toml_env
echo "DEVICE_NAME=${DEVICE_NAME}" >> $GITHUB_ENV
echo "GRAPHENEOS_UPDATE_CHANNEL=${GRAPHENEOS[UPDATE_CHANNEL]}" >> $GITHUB_ENV
- name: Check if a build exists already and verify assets
shell: bash
run: |
# Device name is a required parameter
if [[ -z "${DEVICE_NAME}" ]]; then
echo -e "::error::Missing required param \`DEVICE_NAME\`"
exit 1
fi
# Fetch the latest GrapheneOS version and set up the environment
source src/fetcher.sh && get_latest_version
echo "GRAPHENEOS_VERSION=${VERSION[GRAPHENEOS]}" >> $GITHUB_ENV
# Determine if the build is based on magisk or rootless (build flavor)
build_flavor=$([[ ${{ github.event.inputs.root == 'true' }} == 'true' ]] && echo 'magisk' || echo 'rootless')
# Check if the tag exists
if git show-ref --tags ${VERSION[GRAPHENEOS]} --quiet; then
echo -e "Tag with GrapheneOS version ${VERSION[GRAPHENEOS]} already exists. Looking for assets..."
# Fetch the release information for the tag
repo_url="https://api.github.com/repos/${{ github.repository }}/releases/tags/${VERSION[GRAPHENEOS]}"
release_info=$(curl -sL "$repo_url")
# Define required assets
required_assets=(
"${{ env.DEVICE_NAME }}-${VERSION[GRAPHENEOS]}-magisk-*.zip"
"${{ env.DEVICE_NAME }}-${VERSION[GRAPHENEOS]}-magisk-*.zip.csig"
"${{ env.DEVICE_NAME }}-${VERSION[GRAPHENEOS]}-rootless-*.zip"
"${{ env.DEVICE_NAME }}-${VERSION[GRAPHENEOS]}-rootless-*.zip.csig"
)
existing_assets=$(echo "$release_info" | jq -r '.assets[].name')
missing_assets=()
for required_asset in "${required_assets[@]}"; do
# Convert wildcard pattern to regex
regex="${required_asset//\*/.*}"
for asset in "${existing_assets[@]}"; do
# if existing asset matches the required asset, break the loop
if ! [[ $asset =~ $regex ]]; then
missing_assets+=("$required_asset")
break
fi
done
done
if [ ${#missing_assets[@]} -eq 0 ]; then
echo -e "::error::All required assets are present. Exiting..."
exit 1
else
echo -e "Missing assets:"
for missing_asset in "${missing_assets[@]}"; do
echo -e " - $missing_asset"
done
# Grep always throws an error stating it cannot find the file or directory
valid_build=""
for missing_asset in "${missing_assets[@]}"; do
if [[ $missing_asset == *"$build_flavor"* ]]; then
valid_build="$build_flavor"
break
fi
done
# Check if valid_build is either "magisk" or "rootless"
if [[ "$valid_build" == "magisk" ]] || [[ "$valid_build" == "rootless" ]]; then
echo -e "Proceeding with build to create missing assets..."
else
echo -e "::error::Asset with \`$build_flavor\` flavor already exists!"
exit 1
fi
fi
else
echo -e "Tag with GrapheneOS version ${VERSION[GRAPHENEOS]} does not exist. Creating one..."
fi
- name: Setup Git
run: |
# Configure git for pushing changes
git config --global user.email ${{ secrets.EMAIL }} && git config --global user.name PiX
- name: Install Rust stable
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable 2 weeks ago
- name: Build and Cache Rust Dependencies
uses: Swatinem/[email protected]
- name: Install Python
uses: actions/setup-python@v5
with:
python-version: "3.12-dev"
- name: Setup Environment variables
run: |
echo "KEYS_AVB_BASE64=${{ secrets.AVB_KEY }}" >> $GITHUB_ENV
echo "KEYS_CERT_OTA_BASE64=${{ secrets.CERT_OTA }}" >> $GITHUB_ENV
echo "KEYS_OTA_BASE64=${{ secrets.OTA_KEY }}" >> $GITHUB_ENV
- name: Patch OTA
shell: bash
env:
ADDITIONALS_ROOT: ${{ github.event.inputs.root }}
CLEANUP: true
MAGISK_PREINIT: ${{ github.event.inputs.magisk-preinit-device }}
PASSPHRASE_AVB: ${{ secrets.PASSPHRASE_AVB }}
PASSPHRASE_OTA: ${{ secrets.PASSPHRASE_OTA }}
run: |
echo -e "Running release script.."
# Instead of running the script directly,
# we source it to get the variables in the current shell and use them in the next steps by exporting them
. src/main.sh
# Export the variables for the next steps
echo "GRAPHENEOS_OTA_TARGET=${GRAPHENEOS[OTA_TARGET]}" >> $GITHUB_ENV
echo "OUTPUTS_PATCHED_OTA=${OUTPUTS[PATCHED_OTA]}" >> $GITHUB_ENV
echo "WORKDIR=${WORKDIR}" >> $GITHUB_ENV
- name: Generate Changelog
run: |
# Generate a changelog for the release taking the latest GrapheneOS release
echo -e "See [Changelog](https://grapheneos.org/releases#${{ env.GRAPHENEOS_VERSION }})." > ${{ github.workspace }}-CHANGELOG.txt
- name: Make Release
uses: softprops/action-gh-release@v2
with:
body_path: ${{ github.workspace }}-CHANGELOG.txt
files: |
${{ env.OUTPUTS_PATCHED_OTA }}
${{ env.OUTPUTS_PATCHED_OTA }}.csig
name: "${{ env.GRAPHENEOS_VERSION }}"
tag_name: "${{ env.GRAPHENEOS_VERSION }}"
- name: Publish OTA to server
shell: bash
run: |
CURRENT_COMMIT=$(git rev-parse --short HEAD)
FLAVOR=("magisk" "rootless")
root=${{ github.event.inputs.root }}
# Create `magisk` and `rootless` directories if they don't exist
mkdir -p "${FLAVOR}"
# Switch to gh-pages branch
git checkout gh-pages
echo -e "Updating Configs for the new release..."
# If root is true or the the release has `magisk` in <device_name>.json, use magisk flavor
if [ "${root}" = "true" ] || grep -q magisk "${{ env.DEVICE_NAME }}.json"; then
TARGET_FILE="${FLAVOR[0]}/${{ env.DEVICE_NAME }}.json"
else
TARGET_FILE="${FLAVOR[1]}/${{ env.DEVICE_NAME }}.json"
fi
echo -e "Updating Configs for the new release..."
# Check if the target file exists, if not create an empty one to avoid any issues
if [ ! -f "${TARGET_FILE}" ]; then
echo -e "touching ${TARGET_FILE}..."
touch "${TARGET_FILE}"
fi
# Copy from `./` to `./<flavor>/` if same tag doesn't exist in the target file
if ! grep -q "${{ env.GRAPHENEOS_VERSION }}" "${TARGET_FILE}"; then
echo -e "Copying ${{ env.DEVICE_NAME }}.json to ${TARGET_FILE}..."
cp "${{ env.DEVICE_NAME }}.json" "${TARGET_FILE}"
git add "${TARGET_FILE}"
else
echo -e "Deployed version (${{ env.GRAPHENEOS_VERSION }}) is same as current GrapheneOS release (${{ env.GRAPHENEOS_VERSION }}).\nUpdate skipped."
fi
# Commit and push the changes if the working directory is clean
if ! git diff-index --quiet HEAD; then
git commit -m "release("${CURRENT_COMMIT}"): bump GrapheneOS version to ${{ env.GRAPHENEOS_VERSION }}"
git push origin gh-pages
fi
# Switch back to main branch
git checkout main