Skip to content

upload: ask at the terminal whether to send a backup with the report … #60

upload: ask at the terminal whether to send a backup with the report …

upload: ask at the terminal whether to send a backup with the report … #60

Workflow file for this run

name: ipctool-release
on:
push:
branches:
- master
tags:
- 'v*'
workflow_dispatch:
permissions:
contents: write
# the OIDC token openipc.org checks before it takes a build (below)
id-token: write
jobs:
# Create (or reuse) the GitHub release exactly once, before the build
# matrix fans out. Previously every matrix target ran create-release
# against the same tag, so all but the first failed with
# "Validation Failed: already_exists / tag_name". Hoisting it into a
# single pre-job removes that race; using a gh-CLI upsert (view-or-create)
# also means an existing rolling `latest` dev release is reused silently
# instead of erroring on every subsequent build.
release:
runs-on: ubuntu-latest
outputs:
tag_name: ${{ steps.vars.outputs.tag_name }}
git_hash: ${{ steps.vars.outputs.git_hash }}
branch_name: ${{ steps.vars.outputs.branch_name }}
head_tag: ${{ steps.vars.outputs.head_tag }}
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Compute release vars
id: vars
run: |
HEAD_TAG=$(git tag --points-at HEAD)
GIT_HASH=$(git rev-parse --short $GITHUB_SHA)
BRANCH_NAME=$(echo $GITHUB_REF | cut -d'/' -f 3)
if [ -z "$HEAD_TAG" ]; then
TAG_NAME="latest"
RELEASE_NAME="Development Build"
PRERELEASE=true
else
TAG_NAME=${GITHUB_REF}
RELEASE_NAME="Release ${GITHUB_REF}"
PRERELEASE=false
fi
{
echo "head_tag=$HEAD_TAG"
echo "git_hash=$GIT_HASH"
echo "branch_name=$BRANCH_NAME"
echo "tag_name=$TAG_NAME"
echo "release_name=$RELEASE_NAME"
echo "prerelease=$PRERELEASE"
} >> "$GITHUB_OUTPUT"
- name: Ensure release exists
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG_NAME: ${{ steps.vars.outputs.tag_name }}
RELEASE_NAME: ${{ steps.vars.outputs.release_name }}
PRERELEASE: ${{ steps.vars.outputs.prerelease }}
GIT_HASH: ${{ steps.vars.outputs.git_hash }}
run: |
if gh release view "$TAG_NAME" >/dev/null 2>&1; then
echo "Release '$TAG_NAME' already exists — reusing it."
else
FLAGS=()
[ "$PRERELEASE" = "true" ] && FLAGS+=(--prerelease)
gh release create "$TAG_NAME" \
--title "$RELEASE_NAME" \
--notes "Automated build of $GIT_HASH" \
--target "$GITHUB_SHA" \
"${FLAGS[@]}"
fi
build:
needs: release
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- target: arm32
# OpenIPC's Hi3516CV100 toolchain — the canonical 32-bit ARM
# musleabi static build used for all V1..V5 HiSilicon and the
# rest of the 32-bit-ARM camera world.
toolchain_url: https://github.com/OpenIPC/firmware/releases/download/toolchain/toolchain.hisilicon-hi3516cv100.tgz
toolchain_dir: arm-openipc-linux-musleabi_sdk-buildroot
cc: arm-openipc-linux-musleabi-gcc
asset_suffix: ""
publish_s3: true
- target: mips32
toolchain_url: https://github.com/OpenIPC/firmware/releases/download/toolchain/toolchain.ingenic-t31.tgz
toolchain_dir: mipsel-openipc-linux-musl_sdk-buildroot
cc: mipsel-openipc-linux-musl-gcc
asset_suffix: "-mips32"
publish_s3: false
- target: arm64
# Bootlin's prebuilt aarch64 musl cross toolchain. Switch
# to an OpenIPC-hosted tarball once one is published.
toolchain_url: https://toolchains.bootlin.com/downloads/releases/toolchains/aarch64/tarballs/aarch64--musl--stable-2025.08-1.tar.xz
toolchain_dir: aarch64--musl--stable-2025.08-1
cc: aarch64-buildroot-linux-musl-gcc
asset_suffix: "-arm64"
publish_s3: false
env:
UPX_VERSION: 4.2.3
TAG_NAME: ${{ needs.release.outputs.tag_name }}
GIT_HASH: ${{ needs.release.outputs.git_hash }}
BRANCH_NAME: ${{ needs.release.outputs.branch_name }}
HEAD_TAG: ${{ needs.release.outputs.head_tag }}
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Fetch toolchain
run: |
# Download to file (with retries) before extracting — piping
# wget -> tar makes transient stream truncations look like
# corrupt archives; the wget retry only helps with discrete
# files.
wget --tries=3 --timeout=60 -O /tmp/toolchain.tar "${{ matrix.toolchain_url }}"
# `tar xf` autodetects gzip/bzip2/xz so the matrix entries
# can mix archive formats freely.
tar xf /tmp/toolchain.tar -C /opt
rm /tmp/toolchain.tar
- name: Build sources
id: build
run: |
wget -q https://github.com/upx/upx/releases/download/v$UPX_VERSION/upx-$UPX_VERSION-amd64_linux.tar.xz
tar -xf upx-$UPX_VERSION-amd64_linux.tar.xz --strip-components 1
export PATH=/opt/${{ matrix.toolchain_dir }}/bin:$PATH
sudo apt-get install -y cmake
cmake -H. -Bbuild -DCMAKE_C_COMPILER=${{ matrix.cc }} -DCMAKE_BUILD_TYPE=Release
cmake --build build
./upx build/ipcinfo
./upx build/ipctool
cp build/ipctool ipctool-$GIT_HASH
continue-on-error: true
- name: Send warning to Telegram on build failure
env:
TG_TOKEN: ${{ secrets.TELEGRAM_TOKEN_BOT_OPENIPC }}
TG_CHANNEL: ${{ secrets.TELEGRAM_CHANNEL_OPENIPC_DEV }}
if: steps.build.outcome != 'success'
run: |
TG_OPTIONS="-s --connect-timeout 5 --max-time 15"
TG_NOTIFY="Warning, ipctool-${{ matrix.target }} build error..."
TG_HEADER=$(echo -e "\r\n$TG_NOTIFY \r\n\r\nCommit: $GIT_HASH \r\nBranch: $BRANCH_NAME \r\nTag: $TAG_NAME \r\n\r\n\xE2\x9A\xA0 GitHub Actions")
curl $TG_OPTIONS -H "Content-Type: multipart/form-data" -X POST https://api.telegram.org/bot$TG_TOKEN/sendMessage \
-F chat_id=$TG_CHANNEL -F text="$TG_HEADER"
- name: Upload ipctool to release
if: steps.build.outcome == 'success'
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: build/ipctool
asset_name: ipctool${{ matrix.asset_suffix }}
tag: ${{ env.TAG_NAME }}
overwrite: true
- name: Upload ipcinfo to release
if: steps.build.outcome == 'success'
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: build/ipcinfo
asset_name: ipcinfo${{ matrix.asset_suffix }}
tag: ${{ env.TAG_NAME }}
overwrite: true
- name: Publish dev build on S3
if: matrix.publish_s3 && steps.build.outcome == 'success' && env.HEAD_TAG == ''
uses: tpaschalis/s3-sync-action@master
with:
args: --acl public-read
env:
FILE: ./ipctool-${{ env.GIT_HASH }}
AWS_REGION: 'eu-north-1'
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Send binary to Telegram
if: steps.build.outcome == 'success'
# A notification timing out (curl exit 28 against api.telegram.org)
# must never fail a release whose build succeeded and whose assets
# already uploaded — keep it advisory.
continue-on-error: true
env:
TG_TOKEN: ${{ secrets.TELEGRAM_TOKEN_BOT_OPENIPC }}
TG_CHANNEL: ${{ secrets.TELEGRAM_CHANNEL_OPENIPC_DEV }}
run: |
TG_OPTIONS="-s --connect-timeout 5 --max-time 15"
TG_HEADER=$(echo -e "\r\nTarget: ${{ matrix.target }} \r\nCommit: $GIT_HASH \r\nBranch: $BRANCH_NAME \r\nTag: $TAG_NAME \r\n\r\n\xE2\x9C\x85 GitHub Actions")
curl $TG_OPTIONS -H "Content-Type: multipart/form-data" -X POST https://api.telegram.org/bot$TG_TOKEN/sendDocument \
-F chat_id=$TG_CHANNEL -F document="@build/ipctool" -F caption="$TG_HEADER"
# openipc.org serves ipctool to cameras on stock firmware over plain HTTP
# (http://openipc.org/ipctool, for uget) and over NFS, since they have no
# curl and no TLS. It takes each master build once, over a GitHub OIDC
# token (website: service/internal/tools/PUSH.md). Off until the
# repository variable OPENIPC_ORG_TOOLS_PUSH is "true", which is set once
# openipc.org answers the endpoint in production.
#
# Last, and allowed to fail: the release, S3 and Telegram are done by
# now, and an openipc.org outage must not fail a good build. A failure
# still shows on the step.
- name: Push to openipc.org
if: steps.build.outcome == 'success' && env.HEAD_TAG == '' && github.ref == 'refs/heads/master' && vars.OPENIPC_ORG_TOOLS_PUSH == 'true'
continue-on-error: true
run: |
T=$(curl -fsS -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=https://openipc.org" | jq -r .value)
if [ -z "$T" ] || [ "$T" = null ]; then
echo "::error::no OIDC token for openipc.org"; exit 1
fi
# 200 and nothing else: curl -f passes a redirect, and a 302 to the
# home page once hid that the push reached nothing.
code=$(curl -sS --retry 3 -o /tmp/push.json -w '%{http_code}' -X PUT \
-H "Authorization: Bearer $T" \
-H "X-Content-SHA256: $(sha256sum build/ipctool | cut -d' ' -f1)" \
-H "Content-Type: application/octet-stream" \
--data-binary @build/ipctool \
"https://openipc.org/api/v1/tools/ipctool${{ matrix.asset_suffix }}?version=$GIT_HASH")
cat /tmp/push.json; echo
if [ "$code" != 200 ]; then
echo "::error::openipc.org answered $code to the push"; exit 1
fi