Emit native armv7 fallback decision artifact from CI signals #10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: armv7 cross-prebuild handoff | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| opencode_version: | |
| description: OpenCode version tag (metadata/source-attempt) | |
| required: true | |
| default: "1.2.10" | |
| bun_version: | |
| description: Bun version tag (metadata/source-attempt) | |
| required: true | |
| default: "1.2.20" | |
| push: | |
| branches: [main, master] | |
| paths: | |
| - .github/workflows/prebuild-armv7.yml | |
| - docs/ci-prebuild-armv7.md | |
| - scripts/ci/build-bun-armv7.sh | |
| - scripts/ci/build-bun-armv7-source.sh | |
| - scripts/ci/build-opencode-armv7.sh | |
| jobs: | |
| armv7-cross-prebuild: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Prepare output directories | |
| run: | | |
| set -euo pipefail | |
| mkdir -p out/assets out/logs out/pkgfile-template out/toolchain out/status | |
| - name: Install cross toolchain and emulation | |
| run: | | |
| set -euo pipefail | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf \ | |
| binutils-arm-linux-gnueabihf libc6-dev-armhf-cross \ | |
| qemu-user-static file jq zip unzip curl ca-certificates \ | |
| nodejs npm python3 | |
| arm-linux-gnueabihf-gcc --version | head -n1 | tee out/toolchain/gcc-version.txt | |
| qemu-arm-static --version | head -n1 | tee out/toolchain/qemu-version.txt | |
| node --version | tee out/toolchain/node-version.txt | |
| npm --version | tee out/toolchain/npm-version.txt | |
| - name: Probe upstream release assets (evidence only) | |
| env: | |
| OPENCODE_VERSION: ${{ github.event.inputs.opencode_version || '1.2.10' }} | |
| BUN_VERSION: ${{ github.event.inputs.bun_version || '1.2.20' }} | |
| run: | | |
| set -euo pipefail | |
| curl -fsSL "https://api.github.com/repos/anomalyco/opencode/releases/tags/v${OPENCODE_VERSION}" -o out/logs/opencode-release.json || true | |
| curl -fsSL "https://api.github.com/repos/oven-sh/bun/releases/tags/bun-v${BUN_VERSION}" -o out/logs/bun-release.json || true | |
| python3 - <<'PY' | |
| import json | |
| from pathlib import Path | |
| variants = ["armv7", "armhf", "arm32", "armv7l", "linux-arm"] | |
| for name in ["opencode-release.json", "bun-release.json"]: | |
| p = Path("out/logs") / name | |
| if not p.exists(): | |
| continue | |
| try: | |
| data = json.loads(p.read_text()) | |
| except Exception: | |
| continue | |
| assets = [a.get("name", "") for a in data.get("assets", [])] | |
| Path(f"out/logs/{name}.assets.txt").write_text("\n".join(assets) + "\n") | |
| hits = [a for a in assets if any(v in a.lower() for v in variants)] | |
| Path(f"out/logs/{name}.arm-candidates.txt").write_text("\n".join(hits) + "\n") | |
| PY | |
| - name: Install host bun for compile-target probing | |
| run: | | |
| set -euo pipefail | |
| curl -fsSL https://bun.sh/install | bash | |
| "$HOME/.bun/bin/bun" --version | tee out/toolchain/bun-host-version.txt | |
| - name: Attempt bun armv7 binary build (source/probe) | |
| env: | |
| BUN_VERSION: ${{ github.event.inputs.bun_version || '1.2.20' }} | |
| continue-on-error: true | |
| run: | | |
| set -euo pipefail | |
| chmod +x scripts/ci/build-bun-armv7.sh | |
| scripts/ci/build-bun-armv7.sh "$BUN_VERSION" out > out/logs/build-bun-armv7.log 2>&1 | |
| - name: Attempt bun armv7 source build (cross-first) | |
| env: | |
| BUN_VERSION: ${{ github.event.inputs.bun_version || '1.2.20' }} | |
| continue-on-error: true | |
| run: | | |
| set -euo pipefail | |
| chmod +x scripts/ci/build-bun-armv7-source.sh | |
| scripts/ci/build-bun-armv7-source.sh "$BUN_VERSION" out > out/logs/build-bun-armv7-source.log 2>&1 | |
| - name: Attempt opencode armv7 binary build (compile/probe) | |
| env: | |
| OPENCODE_VERSION: ${{ github.event.inputs.opencode_version || '1.2.10' }} | |
| continue-on-error: true | |
| run: | | |
| set -euo pipefail | |
| chmod +x scripts/ci/build-opencode-armv7.sh | |
| scripts/ci/build-opencode-armv7.sh "$OPENCODE_VERSION" out > out/logs/build-opencode-armv7.log 2>&1 | |
| - name: Summarize build attempt status | |
| run: | | |
| set -euo pipefail | |
| python3 - <<'PY' | |
| import json | |
| from pathlib import Path | |
| out = Path('out') | |
| assets = sorted([str(p.relative_to(out)) for p in (out/'assets').rglob('*') if p.is_file()]) | |
| status = { | |
| 'bun_armv7_bin_present': any('bun' in p and 'armv7' in p for p in assets), | |
| 'opencode_armv7_bin_present': any('opencode' in p and 'armv7' in p for p in assets), | |
| 'bun_source_attempted': (out/'status'/'bun-source-build-status.json').exists(), | |
| 'assets': assets, | |
| } | |
| (out/'status'/'build-attempt-status.json').write_text(json.dumps(status, indent=2)+"\n") | |
| print(json.dumps(status, indent=2)) | |
| PY | |
| - name: Decide native armv7 fallback requirement | |
| run: | | |
| set -euo pipefail | |
| python3 - <<'PY' | |
| import json | |
| from pathlib import Path | |
| out = Path('out') | |
| status_dir = out / 'status' | |
| def read_json(name): | |
| p = status_dir / name | |
| if not p.exists(): | |
| return None | |
| try: | |
| return json.loads(p.read_text()) | |
| except Exception: | |
| return None | |
| build_attempt = read_json('build-attempt-status.json') or {} | |
| bun_target = read_json('bun-target-support.json') or {} | |
| bun_source = read_json('bun-source-build-status.json') or {} | |
| opencode_pack = read_json('opencode-pack-status.json') or {} | |
| bun_bin_present = bool(build_attempt.get('bun_armv7_bin_present')) | |
| bun_target_supported = bool(bun_target.get('supported')) | |
| bun_source_ok = bun_source.get('status') == 'success' | |
| native_required = (not bun_bin_present) and (not bun_target_supported) and (not bun_source_ok) | |
| reasons = [] | |
| if not bun_target_supported: | |
| reasons.append('bun compile target bun-linux-armv7 unsupported in host bun build mode') | |
| if bun_source.get('status') == 'failed': | |
| reasons.append('bun source cross-build attempt failed to produce armv7-like binary') | |
| if opencode_pack.get('status') == 'failed': | |
| reasons.append('opencode package source unavailable for current flow') | |
| decision = { | |
| 'native_required': native_required, | |
| 'next_path': 'native-armv7-runner' if native_required else 'continue-cross-build', | |
| 'reasons': reasons, | |
| 'signals': { | |
| 'bun_armv7_bin_present': bun_bin_present, | |
| 'bun_target_supported': bun_target_supported, | |
| 'bun_source_status': bun_source.get('status'), | |
| 'opencode_pack_status': opencode_pack.get('status'), | |
| }, | |
| } | |
| (status_dir / 'next-build-path.json').write_text(json.dumps(decision, indent=2) + "\n") | |
| print(json.dumps(decision, indent=2)) | |
| PY | |
| - name: Remove work directory from handoff artifact | |
| run: | | |
| set -euo pipefail | |
| rm -rf out/work | |
| - name: Write pkgfile templates (armv7 handoff) | |
| run: | | |
| set -euo pipefail | |
| cat > out/pkgfile-template/PKGBUILD.template <<'P1' | |
| pkgname=opencode | |
| pkgver=__OPENCODE_VERSION__ | |
| pkgrel=1 | |
| arch=('armv7l') | |
| source=('opencode-linux-armv7-__OPENCODE_VERSION__.tar.gz') | |
| sha256sums=('__SHA256__') | |
| P1 | |
| cat > out/pkgfile-template/debian-control.template <<'P2' | |
| Package: opencode | |
| Version: __OPENCODE_VERSION__ | |
| Architecture: armhf | |
| Maintainer: Hope2333(幽零小喵) <u0catmiao@proton.me> | |
| Description: OpenCode armv7 cross-prebuild handoff template for local Termux final packaging | |
| P2 | |
| - name: Generate manifest | |
| env: | |
| OPENCODE_VERSION: ${{ github.event.inputs.opencode_version || '1.2.10' }} | |
| BUN_VERSION: ${{ github.event.inputs.bun_version || '1.2.20' }} | |
| run: | | |
| set -euo pipefail | |
| python3 - <<'PY' | |
| import hashlib, json, os | |
| from pathlib import Path | |
| items = [] | |
| for p in sorted(Path('out').rglob('*')): | |
| if p.is_file(): | |
| items.append({'path': str(p.relative_to('out')), 'size': p.stat().st_size, 'sha256': hashlib.sha256(p.read_bytes()).hexdigest()}) | |
| manifest = { | |
| 'kind': 'cross-prebuild-handoff', | |
| 'target': 'linux-armv7', | |
| 'opencode_version': os.environ.get('OPENCODE_VERSION'), | |
| 'bun_version': os.environ.get('BUN_VERSION'), | |
| 'git_sha': os.environ.get('GITHUB_SHA', ''), | |
| 'contains_final_termux_runtime': False, | |
| 'goal': 'produce bun and opencode armv7l-linux bins', | |
| 'items': items, | |
| } | |
| Path('out/manifest.json').write_text(json.dumps(manifest, indent=2) + '\n') | |
| PY | |
| (cd out && find . -type f | sort | xargs sha256sum > checksums.txt) | |
| - name: Upload armv7 prebuild handoff bundle | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: armv7-cross-prebuild-handoff | |
| path: out/ | |
| retention-days: 30 |