Skip to content

lawallet-nwc-release #9

lawallet-nwc-release

lawallet-nwc-release #9

name: Update LaWallet NWC
on:
repository_dispatch:
types: [lawallet-nwc-release]
workflow_dispatch:
inputs:
version:
description: "LaWallet NWC version to package, with or without a leading v"
required: true
type: string
image:
description: "Full Docker image tag. Defaults to masize/lawallet-nwc:<version>."
required: false
type: string
listener_image:
description: "Full listener image tag. Defaults to masize/lawallet-nwc-listener:<version>."
required: false
type: string
permissions:
contents: read
concurrency:
group: update-lawallet-nwc-${{ github.event.client_payload.version || inputs.version || github.run_id }}
cancel-in-progress: false
jobs:
update:
name: Update Umbrel package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: master
persist-credentials: false
- name: Resolve package inputs
id: package
env:
DISPATCH_VERSION: ${{ github.event.client_payload.version }}
DISPATCH_IMAGE: ${{ github.event.client_payload.image }}
DISPATCH_LISTENER_IMAGE: ${{ github.event.client_payload.listener_image }}
INPUT_VERSION: ${{ inputs.version }}
INPUT_IMAGE: ${{ inputs.image }}
INPUT_LISTENER_IMAGE: ${{ inputs.listener_image }}
run: |
set -euo pipefail
VERSION="${DISPATCH_VERSION:-${INPUT_VERSION:-}}"
VERSION="${VERSION#v}"
if [ -z "${VERSION}" ]; then
echo "::error::Missing LaWallet NWC version."
exit 1
fi
IMAGE="${DISPATCH_IMAGE:-${INPUT_IMAGE:-}}"
if [ -z "${IMAGE}" ]; then
IMAGE="masize/lawallet-nwc:${VERSION}"
fi
LISTENER_IMAGE="${DISPATCH_LISTENER_IMAGE:-${INPUT_LISTENER_IMAGE:-}}"
if [ -z "${LISTENER_IMAGE}" ]; then
LISTENER_IMAGE="masize/lawallet-nwc-listener:${VERSION}"
fi
BRANCH_VERSION="$(printf "%s" "${VERSION}" | tr -cd "0-9A-Za-z._-")"
{
echo "version=${VERSION}"
echo "image=${IMAGE}"
echo "listener_image=${LISTENER_IMAGE}"
echo "branch=automation/lawallet-nwc-${BRANCH_VERSION}"
} >> "${GITHUB_OUTPUT}"
- name: Update package files
env:
VERSION: ${{ steps.package.outputs.version }}
IMAGE: ${{ steps.package.outputs.image }}
LISTENER_IMAGE: ${{ steps.package.outputs.listener_image }}
SOURCE_REPOSITORY: ${{ github.event.client_payload.source_repository }}
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
SRC_REPO="${SOURCE_REPOSITORY:-lawalletio/lawallet-nwc}"
# Best-effort fetch of the published GitHub Release notes for this
# version. If the release (or token) is unavailable, RELEASE_BODY stays
# empty and the package falls back to a versioned pointer note.
RELEASE_BODY="$(gh release view "v${VERSION}" --repo "${SRC_REPO}" --json body --jq '.body' 2>/dev/null || true)"
export SRC_REPO RELEASE_BODY
python3 <<'PY'
import os
import re
from pathlib import Path
version = os.environ["VERSION"]
image = os.environ["IMAGE"]
listener_image = os.environ["LISTENER_IMAGE"]
src_repo = os.environ.get("SRC_REPO") or "lawalletio/lawallet-nwc"
release_body = os.environ.get("RELEASE_BODY", "") or ""
def replace_once(path, pattern, replacement):
file_path = Path(path)
original = file_path.read_text()
updated, count = re.subn(pattern, replacement, original, count=1, flags=re.MULTILINE)
if count != 1:
raise SystemExit(f"Expected exactly one match in {path}, found {count}")
file_path.write_text(updated)
def replace_optional(path, pattern, replacement):
# 0 or 1 matches: tolerates compose files that don't include the
# service yet (e.g. the listener before it lands in the package).
file_path = Path(path)
original = file_path.read_text()
updated, count = re.subn(pattern, replacement, original, count=1, flags=re.MULTILINE)
if count > 1:
raise SystemExit(f"Expected at most one match in {path}, found {count}")
if count:
file_path.write_text(updated)
replace_once(
"lawallet-nwc/umbrel-app.yml",
r"^version:\s*.*$",
lambda match: f'version: "{version}"',
)
for compose_file in ("lawallet-nwc/docker-compose.yml", "test/docker-compose.regtest.yml"):
replace_once(
compose_file,
r"^(\s+image:\s+)masize/lawallet-nwc:[^\s]+$",
lambda match: f"{match.group(1)}{image}",
)
replace_optional(
compose_file,
r"^(\s+image:\s+)masize/lawallet-nwc-listener:[^\s]+$",
lambda match: f"{match.group(1)}{listener_image}",
)
replace_once(
"README.md",
r"^(- Published image: `)masize/lawallet-nwc:[^`]+(`)$",
lambda match: f"{match.group(1)}{image}{match.group(2)}",
)
# Keep the Umbrel "update available" note in sync with the release.
# Distill the GitHub Release body into a concise note, falling back to
# a versioned pointer when the body is empty or just the changelog stub.
release_url = f"https://github.com/{src_repo}/releases/tag/v{version}"
text = re.sub(r"<!--.*?-->", "", release_body, flags=re.DOTALL)
kept = []
for line in text.splitlines():
stripped = line.strip()
if re.match(r"^#\s*v?\d", stripped): # "# v1.2.3" title
continue
if re.match(r"^##\s+release date\b", stripped, re.I):
continue
if re.match(r"^\d{4}-\d{2}-\d{2}$", stripped): # bare date line
continue
kept.append(line.rstrip())
cleaned = re.sub(r"\n{3,}", "\n\n", "\n".join(kept)).strip()
is_stub = (not cleaned) or ("no merged prs" in cleaned.lower())
if is_stub:
note = f"LaWallet NWC {version}."
else:
limit = 1500
if len(cleaned) > limit:
cleaned = cleaned[:limit].rstrip() + "…"
note = cleaned
note = f"{note}\n\nFull release notes: {release_url}"
# Literal block scalar (|-) preserves line breaks; every line is
# indented two spaces so arbitrary markdown can't break out of the
# YAML block. Replaces the whole releaseNotes block (key line through
# the line before the next top-level key, or EOF).
block = "releaseNotes: |-\n" + "\n".join(
((" " + ln).rstrip() if ln else "") for ln in note.splitlines()
) + "\n"
notes_path = Path("lawallet-nwc/umbrel-app.yml")
content = notes_path.read_text()
content, count = re.subn(
r"^releaseNotes:.*?(?=^\S|\Z)",
lambda _match: block,
content,
count=1,
flags=re.DOTALL | re.MULTILINE,
)
if count != 1:
raise SystemExit(f"Expected exactly one releaseNotes block, found {count}")
notes_path.write_text(content)
PY
grep -n 'version:' lawallet-nwc/umbrel-app.yml
grep -RIn 'image: masize/lawallet-nwc' lawallet-nwc/docker-compose.yml test/docker-compose.regtest.yml
grep -n 'Published image:' README.md
echo '--- releaseNotes ---'
sed -n '/^releaseNotes:/,$p' lawallet-nwc/umbrel-app.yml
- name: Open and merge package update pull request
env:
GH_TOKEN: ${{ secrets.UMBREL_APP_STORE_UPDATE_TOKEN }}
VERSION: ${{ steps.package.outputs.version }}
IMAGE: ${{ steps.package.outputs.image }}
BRANCH: ${{ steps.package.outputs.branch }}
SOURCE_REPOSITORY: ${{ github.event.client_payload.source_repository }}
SOURCE_RUN_URL: ${{ github.event.client_payload.source_run_url }}
run: |
set -euo pipefail
if [ -z "${GH_TOKEN}" ]; then
echo "::error::Missing UMBREL_APP_STORE_UPDATE_TOKEN. Configure a token with contents and pull request write access to lawalletio/umbrel-app-store."
exit 1
fi
if git diff --quiet; then
echo "LaWallet NWC package is already up to date."
exit 0
fi
git diff --check
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
git checkout -B "${BRANCH}"
git add README.md lawallet-nwc/umbrel-app.yml lawallet-nwc/docker-compose.yml test/docker-compose.regtest.yml
git commit -m "Update LaWallet NWC to ${VERSION}"
git push --force-with-lease origin "${BRANCH}"
BODY_FILE="$(mktemp)"
{
echo "Updates the Umbrel package for LaWallet NWC ${VERSION}."
echo
echo "- Sets the Umbrel app version to ${VERSION}"
echo "- Updates Docker image references to ${IMAGE}"
echo "- Keeps the local regtest smoke stack on the same image tag"
if [ -n "${SOURCE_REPOSITORY}" ]; then
echo
echo "Triggered by ${SOURCE_REPOSITORY}."
fi
if [ -n "${SOURCE_RUN_URL}" ]; then
echo "Source run: ${SOURCE_RUN_URL}"
fi
} > "${BODY_FILE}"
if gh pr view "${BRANCH}" --repo "${GITHUB_REPOSITORY}" >/dev/null 2>&1; then
gh pr edit "${BRANCH}" \
--repo "${GITHUB_REPOSITORY}" \
--title "Update LaWallet NWC to ${VERSION}" \
--body-file "${BODY_FILE}"
else
gh pr create \
--repo "${GITHUB_REPOSITORY}" \
--base master \
--head "${BRANCH}" \
--title "Update LaWallet NWC to ${VERSION}" \
--body-file "${BODY_FILE}"
fi
PR_URL="$(gh pr view "${BRANCH}" --repo "${GITHUB_REPOSITORY}" --json url --jq .url)"
echo "Merging ${PR_URL}"
gh pr merge "${PR_URL}" \
--repo "${GITHUB_REPOSITORY}" \
--squash \
--delete-branch \
--subject "Update LaWallet NWC to ${VERSION}" \
--body "Automated Umbrel package update for ${IMAGE}."