name: Auto Build & Release Tailscale ACAP on: schedule: - cron: "0 0 * * *" # Every Monday at 03:00 UTC workflow_dispatch: jobs: build-and-release: runs-on: ubuntu-latest steps: # 1. Checkout repo - uses: actions/checkout@v3 with: persist-credentials: true fetch-depth: 0 # 2. Get latest Tailscale version - name: Get latest Tailscale version id: tailscale_version run: | # 1. Start from GitHub latest GH_TAG=$(curl -s https://api.github.com/repos/tailscale/tailscale/releases/latest | jq -r .tag_name) GH_VERSION=${GH_TAG#v} echo "GitHub latest: $GH_VERSION" # 2. See if static ARM build exists for that version if curl -sfI "https://pkgs.tailscale.com/stable/tailscale_${GH_VERSION}_arm.tgz" > /dev/null; then VERSION="$GH_VERSION" echo "Using GitHub latest (has ARM package): $VERSION" else echo "No ARM package for $GH_VERSION, falling back to latest version on pkgs.tailscale.com" # 3. Derive latest version that actually has an ARM tarball VERSION=$( curl -s https://pkgs.tailscale.com/stable/ \ | grep -o 'tailscale_[0-9.]*_arm\.tgz' \ | sed -E 's/^tailscale_([0-9.]+)_arm\.tgz$/\1/' \ | sort -V | tail -n1 ) echo "Fallback version: $VERSION" fi echo "RELEASE_VERSION=$VERSION" >> $GITHUB_ENV echo "version=$VERSION" >> $GITHUB_OUTPUT - name: Get current repo version id: current run: | CURRENT=$(find . -path "*/app/manifest.json" -exec jq -r '.acapPackageConf.setup.version' {} \; | sort -u | head -n1) echo "CURRENT_VERSION=$CURRENT" >> $GITHUB_ENV echo "Current repo version: $CURRENT" - name: Compare versions id: compare run: | echo "Repo version: $CURRENT_VERSION" echo "Latest Tailscale version: $RELEASE_VERSION" echo "Trigger: ${{ github.event_name }}" if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then echo "build_needed=true" >> $GITHUB_ENV echo "Manual trigger — building regardless of version." elif [ "$CURRENT_VERSION" = "$RELEASE_VERSION" ]; then echo "build_needed=false" >> $GITHUB_ENV echo "Already up to date. Skipping build." else echo "build_needed=true" >> $GITHUB_ENV echo "New version detected. Will build." fi # 3. Download Tailscale binaries - name: Download Tailscale binaries if: env.build_needed == 'true' run: | mkdir -p tailscale_bins curl -L "https://pkgs.tailscale.com/stable/tailscale_${RELEASE_VERSION}_arm.tgz" -o tailscale_arm.tgz tar -xzf tailscale_arm.tgz -C tailscale_bins --strip-components=1 mv tailscale_bins/tailscale tailscale_bins/tailscale_arm mv tailscale_bins/tailscaled tailscale_bins/tailscaled_arm curl -L "https://pkgs.tailscale.com/stable/tailscale_${RELEASE_VERSION}_arm64.tgz" -o tailscale_arm64.tgz tar -xzf tailscale_arm64.tgz -C tailscale_bins --strip-components=1 mv tailscale_bins/tailscale tailscale_bins/tailscale_arm64 mv tailscale_bins/tailscaled tailscale_bins/tailscaled_arm64 # 4. Strip binaries to reduce package size - name: Strip binaries if: env.build_needed == 'true' run: | # Install cross-architecture strip tools sudo apt-get update sudo apt-get install -y binutils-aarch64-linux-gnu binutils-arm-linux-gnueabihf # Strip debug info and symbol tables (zero runtime/memory cost) aarch64-linux-gnu-strip -s tailscale_bins/tailscale_arm64 aarch64-linux-gnu-strip -s tailscale_bins/tailscaled_arm64 arm-linux-gnueabihf-strip -s tailscale_bins/tailscale_arm arm-linux-gnueabihf-strip -s tailscale_bins/tailscaled_arm ls -lh tailscale_bins/ # 5. Build each folder, update manifest, and copy .eap files - name: Build all folders if: env.build_needed == 'true' run: | mkdir -p build rm -rf releases mkdir -p releases for folder in */ ; do [[ ! -d "$folder/app" ]] && continue FOLDER_NAME="${folder%/}" # remove trailing slash echo "Processing folder $FOLDER_NAME" # Detect architecture if [[ "$FOLDER_NAME" == arm* ]]; then cp tailscale_bins/tailscale_arm "$folder/app/lib/tailscale" cp tailscale_bins/tailscaled_arm "$folder/app/lib/tailscaled" else cp tailscale_bins/tailscale_arm64 "$folder/app/lib/tailscale" cp tailscale_bins/tailscaled_arm64 "$folder/app/lib/tailscaled" fi # Detect variant suffix for .eap naming if [[ "$FOLDER_NAME" == *_ROOT ]]; then VARIANT="_root" elif [[ "$FOLDER_NAME" == *_acap3 ]]; then VARIANT="_acap3" else VARIANT="" fi # Update version — manifest.json for ACAP 4, package.conf for ACAP 3 if [[ -f "$folder/app/manifest.json" ]]; then sed -i "s/\"version\": \".*\"/\"version\": \"${RELEASE_VERSION}\"/" "$folder/app/manifest.json" elif [[ -f "$folder/app/package.conf" ]]; then IFS='.' read -r MAJOR MINOR MICRO <<< "${RELEASE_VERSION}" sed -i "s/^APPMAJORVERSION=.*/APPMAJORVERSION=${MAJOR}/" "$folder/app/package.conf" sed -i "s/^APPMINORVERSION=.*/APPMINORVERSION=${MINOR}/" "$folder/app/package.conf" sed -i "s/^APPMICROVERSION=.*/APPMICROVERSION=${MICRO}/" "$folder/app/package.conf" fi # Docker build TAG_NAME=$(echo "$FOLDER_NAME" | tr '[:upper:]' '[:lower:]' | tr '/ ' '_') # lowercase and clean echo "Building $TAG_NAME" docker build -f "$folder/Dockerfile" --tag "$TAG_NAME" "$folder" # Extract .eap files into build folder EAP_OUTPUT="./build/${TAG_NAME}" mkdir -p "$EAP_OUTPUT" CID=$(docker create "$TAG_NAME") docker cp "$CID":/opt/app "$EAP_OUTPUT" docker rm "$CID" >/dev/null # Move all .eap files to releases folder, append variant if needed find "$EAP_OUTPUT" -type f -name "*.eap" | while read eap; do BASENAME=$(basename "$eap" .eap) if [[ -n "$VARIANT" ]]; then mv "$eap" "releases/${BASENAME}${VARIANT}.eap" else mv "$eap" "releases/${BASENAME}.eap" fi done done # Clean up rm -rf build tailscale_bins *.tgz # 6. Commit updated manifests and .eap files directly to main - name: Commit updates to main if: env.build_needed == 'true' run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" # Only commit manifests and ACAP 3 package.conf; do not track release artifacts git add */app/manifest.json arm_acap3/app/package.conf if git diff --cached --quiet; then echo "No changes to commit" else git commit -m "Update Tailscale to v${RELEASE_VERSION}" git push https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/Mo3he/Axis_Cam_Tailscale.git main fi # 7. Create GitHub Release with all new .eap files - name: Create GitHub Release if: env.build_needed == 'true' uses: softprops/action-gh-release@v1 with: tag_name: v${{ env.RELEASE_VERSION }} name: "Tailscale VPN ${{ env.RELEASE_VERSION }}" files: releases/* env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}