chore(manifest): remove obsolete vendor field from template device.to… #87
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: ABI Oracle (SemVer Auto-Tagger) | |
| on: | |
| push: | |
| branches: | |
| - main | |
| permissions: | |
| contents: write | |
| concurrency: | |
| group: abi-oracle | |
| cancel-in-progress: false | |
| jobs: | |
| abi-oracle: | |
| name: Calculate ABI and Bump Version | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.RELEASE_TARGET_TOKEN }} | |
| - name: Setup Toob Ecosystem | |
| uses: ./.github/actions/setup-cli | |
| with: | |
| install-native-deps: "true" | |
| - name: Configure Git Identity | |
| run: | | |
| git config user.name "Toob ABI Oracle" | |
| git config user.email "oracle@toob-boot.io" | |
| - name: Detect Subsystem Changes | |
| id: changes | |
| run: | | |
| echo ">>> Detecting changes in recent commit..." | |
| git fetch --prune --unshallow 2>/dev/null || git fetch --all 2>/dev/null || true | |
| # Ensure the registry submodule is initialized | |
| if [ ! -d "toob-registry/.git" ] && [ ! -f "toob-registry/.git" ]; then | |
| git submodule update --init toob-registry | |
| fi | |
| # Check if a monorepo subsystem changed (direct files, not submodules). | |
| # Diffs from the last matching tag to capture accumulated changes. | |
| check_subsystem() { | |
| local tag_prefix=$1 | |
| shift | |
| local paths=("$@") | |
| local last_tag=$(git describe --tags --match "${tag_prefix}v*" --abbrev=0 2>/dev/null || echo "") | |
| local diff_files="" | |
| if [ -n "$last_tag" ]; then | |
| diff_files=$(git diff --name-only "$last_tag" HEAD 2>/dev/null || echo "") | |
| else | |
| diff_files=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || echo "") | |
| if [ -z "$diff_files" ]; then | |
| diff_files=$(git ls-files) | |
| fi | |
| fi | |
| for file in $diff_files; do | |
| for p in "${paths[@]}"; do | |
| if [[ "$file" == $p* ]]; then | |
| echo "true" | |
| return | |
| fi | |
| done | |
| done | |
| echo "false" | |
| } | |
| # Registry subsystem versioning (chips, arch, drivers, toolchains) | |
| # is handled by the Toob-Registry's own CI pipeline: | |
| # main-release.yml → semver_calc.go → build_registry.go | |
| # The enforcer only manages Core SDK, CLI, and Compiler tags. | |
| CHECK_CORE=$(check_subsystem "core/" "toobloader/core/" "sdk/" "common/") | |
| CHECK_CLI=$(check_subsystem "cli/" "cli/toob-cli/") | |
| CHECK_COMPILER=$(check_subsystem "compiler/" "cli/.pipeline-repo/Dockerfile.compiler" "cli/.pipeline-repo/toob-ci-build.sh" "compiler/") | |
| echo "CHECK_CORE=$CHECK_CORE" >> $GITHUB_ENV | |
| echo "CHECK_CLI=$CHECK_CLI" >> $GITHUB_ENV | |
| echo "CHECK_COMPILER=$CHECK_COMPILER" >> $GITHUB_ENV | |
| echo "Core changed: $CHECK_CORE" | |
| echo "CLI changed: $CHECK_CLI" | |
| echo "Compiler changed: $CHECK_COMPILER" | |
| - name: ABI Orakel (Core SDK) | |
| if: env.CHECK_CORE == 'true' | |
| run: | | |
| echo ">>> [Core Oracle] Starting symbol analysis for Core, SDK, and Common..." | |
| LAST_TAG=$(git describe --tags --match "core/v*" --abbrev=0 2>/dev/null || echo "core/v0.0.0") | |
| RAW_VERSION=${LAST_TAG#core/v} | |
| echo ">>> [Core Oracle] Baseline Tag: $LAST_TAG" | |
| MAJOR=$(echo $RAW_VERSION | cut -d. -f1) | |
| MINOR=$(echo $RAW_VERSION | cut -d. -f2) | |
| PATCH=$(echo $RAW_VERSION | cut -d. -f3) | |
| # If no real baseline exists, create the initial tag and skip diff | |
| if [ "$LAST_TAG" = "core/v0.0.0" ]; then | |
| echo ">>> [Core Oracle] No baseline tag. Creating initial patch release." | |
| PATCH=$((PATCH + 1)) | |
| NEW_TAG="core/v${MAJOR}.${MINOR}.${PATCH}" | |
| if git rev-parse "$NEW_TAG" >/dev/null 2>&1; then | |
| echo ">>> [Core Oracle] Tag $NEW_TAG already exists. Skipping." | |
| else | |
| git tag "$NEW_TAG" | |
| git push origin "$NEW_TAG" || echo ">>> Tag push failed (concurrent run?)" | |
| echo ">>> [Core Oracle] Initial tag $NEW_TAG pushed!" | |
| fi | |
| exit 0 | |
| fi | |
| mkdir -p abi_workspace/current abi_workspace/old | |
| # Build CURRENT code. | |
| # The esp32c6 template is used as a reference target. Core libraries | |
| # are chip-independent — the ABI output is identical for any chip. | |
| echo ">>> Building CURRENT Code..." | |
| toob build --native --manifest toob-registry/chips/esp32c6/template_device.toml | |
| for lib in libtoob_core.a libtoob_libtoob.a libtoob_zcbor.a libtoob_heatshrink.a; do | |
| find . -path '*/builds/*' -name "$lib" -exec cp {} abi_workspace/current/ \; | |
| done | |
| find . -path '*/builds/build_*' -type d -exec rm -rf {} + 2>/dev/null || true | |
| # Build OLD code using git worktree (faster than clone, shares object store) | |
| echo ">>> Building OLD Code from $LAST_TAG..." | |
| git worktree add abi_workspace/old_repo "$LAST_TAG" 2>/dev/null || { | |
| echo ">>> [FATAL] Cannot create worktree for $LAST_TAG" | |
| exit 1 | |
| } | |
| cd abi_workspace/old_repo | |
| git submodule update --init toob-registry | |
| toob build --native --manifest toob-registry/chips/esp32c6/template_device.toml || { | |
| echo ">>> [FATAL] Old build failed. Cannot produce ABI baseline." | |
| cd ../../ | |
| git worktree remove abi_workspace/old_repo --force 2>/dev/null || true | |
| exit 1 | |
| } | |
| for lib in libtoob_core.a libtoob_libtoob.a libtoob_zcbor.a libtoob_heatshrink.a; do | |
| find . -path '*/builds/*' -name "$lib" -exec cp {} ../old/ \; | |
| done | |
| cd ../../ | |
| git worktree remove abi_workspace/old_repo --force 2>/dev/null || true | |
| # Symbol-based ABI diff using the cross-compiler's nm. | |
| # This avoids abidiff's crash on cross-compiled RISC-V ELF files. | |
| # Extract public symbols (T=text, D=data, B=bss) and compare sets. | |
| echo ">>> Running symbol-based ABI diff..." | |
| # Locate the cross-compiler nm (installed during build) | |
| NM_BIN=$(find ~/.toob/toolchains -name "riscv32-esp-elf-nm" 2>/dev/null | head -1) | |
| if [ -z "$NM_BIN" ]; then | |
| NM_BIN="nm" # fallback to host nm | |
| fi | |
| echo ">>> Using nm: $NM_BIN" | |
| BUMP="PATCH" | |
| for lib in libtoob_core.a libtoob_libtoob.a libtoob_zcbor.a libtoob_heatshrink.a; do | |
| OLD_LIB="abi_workspace/old/$lib" | |
| NEW_LIB="abi_workspace/current/$lib" | |
| if [ ! -f "$OLD_LIB" ] || [ ! -f "$NEW_LIB" ]; then | |
| continue | |
| fi | |
| # Extract globally-visible defined symbols (type + name) | |
| $NM_BIN --defined-only -g "$OLD_LIB" 2>/dev/null | awk '{print $2, $3}' | sort -u > /tmp/sym_old.txt | |
| $NM_BIN --defined-only -g "$NEW_LIB" 2>/dev/null | awk '{print $2, $3}' | sort -u > /tmp/sym_new.txt | |
| REMOVED=$(comm -23 /tmp/sym_old.txt /tmp/sym_new.txt | wc -l) | |
| ADDED=$(comm -13 /tmp/sym_old.txt /tmp/sym_new.txt | wc -l) | |
| if [ "$REMOVED" -gt 0 ]; then | |
| echo ">>> [RESULT] $lib: $REMOVED symbols REMOVED (MAJOR)" | |
| comm -23 /tmp/sym_old.txt /tmp/sym_new.txt | head -10 | |
| BUMP="MAJOR" | |
| elif [ "$ADDED" -gt 0 ] && [ "$BUMP" != "MAJOR" ]; then | |
| echo ">>> [RESULT] $lib: $ADDED symbols ADDED (MINOR)" | |
| comm -13 /tmp/sym_old.txt /tmp/sym_new.txt | head -10 | |
| [ "$BUMP" = "PATCH" ] && BUMP="MINOR" | |
| else | |
| echo ">>> [RESULT] $lib: No symbol changes" | |
| fi | |
| done | |
| # Layer 2: Public header diff to catch struct/typedef/enum changes | |
| # that are invisible to nm (same symbol name, different layout). | |
| echo ">>> Running public header analysis..." | |
| HEADER_DIRS="toobloader/core/include sdk/libtoob/include sdk/os_client/include common/include" | |
| for hdir in $HEADER_DIRS; do | |
| [ ! -d "$hdir" ] && continue | |
| DELETED_H=$(git diff --diff-filter=D --name-only "$LAST_TAG" HEAD -- "$hdir" 2>/dev/null | wc -l) | |
| ADDED_H=$(git diff --diff-filter=A --name-only "$LAST_TAG" HEAD -- "$hdir" 2>/dev/null | wc -l) | |
| MODIFIED_H=$(git diff --diff-filter=M --name-only "$LAST_TAG" HEAD -- "$hdir" 2>/dev/null || echo "") | |
| # Deleted public headers = breaking | |
| if [ "$DELETED_H" -gt 0 ]; then | |
| echo ">>> [HEADER] $hdir: $DELETED_H headers DELETED (MAJOR)" | |
| BUMP="MAJOR" | |
| fi | |
| # New public headers = new capability | |
| if [ "$ADDED_H" -gt 0 ] && [ "$BUMP" != "MAJOR" ]; then | |
| echo ">>> [HEADER] $hdir: $ADDED_H new headers (MINOR)" | |
| [ "$BUMP" = "PATCH" ] && BUMP="MINOR" | |
| fi | |
| # Modified headers: check if struct/typedef/enum definitions changed | |
| if [ -n "$MODIFIED_H" ] && [ "$BUMP" != "MAJOR" ]; then | |
| for hfile in $MODIFIED_H; do | |
| # Extract struct, typedef, and enum lines from old and new | |
| OLD_DEFS=$(git show "${LAST_TAG}:${hfile}" 2>/dev/null | grep -E '^\s*(typedef\s|struct\s|enum\s|}\s*\w+)' | sort) | |
| NEW_DEFS=$(cat "$hfile" 2>/dev/null | grep -E '^\s*(typedef\s|struct\s|enum\s|}\s*\w+)' | sort) | |
| if [ "$OLD_DEFS" != "$NEW_DEFS" ]; then | |
| echo ">>> [HEADER] $hfile: type definitions changed (MINOR)" | |
| [ "$BUMP" = "PATCH" ] && BUMP="MINOR" | |
| fi | |
| done | |
| fi | |
| done | |
| echo ">>> [Core Oracle] Final bump type: $BUMP" | |
| case "$BUMP" in | |
| MAJOR) MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 ;; | |
| MINOR) MINOR=$((MINOR + 1)); PATCH=0 ;; | |
| PATCH) PATCH=$((PATCH + 1)) ;; | |
| esac | |
| NEW_TAG="core/v${MAJOR}.${MINOR}.${PATCH}" | |
| echo ">>> [Core Oracle] Calculated new version: $NEW_TAG" | |
| if git rev-parse "$NEW_TAG" >/dev/null 2>&1; then | |
| echo ">>> [Core Oracle] Tag $NEW_TAG already exists. Skipping." | |
| else | |
| git tag "$NEW_TAG" | |
| git push origin "$NEW_TAG" || echo ">>> Tag push failed (concurrent run?)" | |
| echo ">>> [Core Oracle] Tag $NEW_TAG pushed!" | |
| fi | |
| - name: ABI Orakel (CLI) | |
| if: env.CHECK_CLI == 'true' | |
| run: | | |
| echo ">>> [CLI Oracle] Starting Contract analysis for CLI..." | |
| LAST_TAG=$(git describe --tags --match "cli/v*" --abbrev=0 2>/dev/null || echo "cli/v0.0.0") | |
| RAW_VERSION=${LAST_TAG#cli/v} | |
| echo ">>> [CLI Oracle] Baseline Tag: $LAST_TAG" | |
| MAJOR=$(echo $RAW_VERSION | cut -d. -f1) | |
| MINOR=$(echo $RAW_VERSION | cut -d. -f2) | |
| PATCH=$(echo $RAW_VERSION | cut -d. -f3) | |
| mkdir -p cli_abi_workspace | |
| cp cli/toob-cli/internal/ports/ports.go cli_abi_workspace/ports_current.go | |
| if [ "$LAST_TAG" != "cli/v0.0.0" ]; then | |
| git show $LAST_TAG:cli/toob-cli/internal/ports/ports.go > cli_abi_workspace/ports_old.go 2>/dev/null || touch cli_abi_workspace/ports_old.go | |
| else | |
| touch cli_abi_workspace/ports_old.go | |
| fi | |
| echo ">>> Running AST-based Contract Differ..." | |
| cd cli/toob-cli | |
| go build -o /tmp/semver-tool ./internal/ports/cmd/semver | |
| BUMP_TYPE=$(/tmp/semver-tool ../../cli_abi_workspace/ports_old.go ../../cli_abi_workspace/ports_current.go | tail -n 1) | |
| cd ../../ | |
| echo ">>> [RESULT] Contract Differ determined bump type: $BUMP_TYPE" | |
| if [ "$BUMP_TYPE" = "MAJOR" ]; then | |
| MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 | |
| elif [ "$BUMP_TYPE" = "MINOR" ]; then | |
| MINOR=$((MINOR + 1)); PATCH=0 | |
| else | |
| PATCH=$((PATCH + 1)) | |
| fi | |
| NEW_TAG="cli/v${MAJOR}.${MINOR}.${PATCH}" | |
| echo ">>> [CLI Oracle] Calculated new version: $NEW_TAG" | |
| if git rev-parse "$NEW_TAG" >/dev/null 2>&1; then | |
| echo ">>> [CLI Oracle] Tag $NEW_TAG already exists. Skipping." | |
| else | |
| git tag "$NEW_TAG" | |
| git push origin "$NEW_TAG" || echo ">>> Tag push failed (concurrent run?)" | |
| echo ">>> [CLI Oracle] Tag $NEW_TAG pushed!" | |
| fi | |
| - name: ABI Orakel (Compiler Container) | |
| if: env.CHECK_COMPILER == 'true' | |
| run: | | |
| echo ">>> [Compiler Oracle] Starting manifest-based version analysis..." | |
| LAST_TAG=$(git describe --tags --match "compiler/v*" --abbrev=0 2>/dev/null || echo "compiler/v0.0.0") | |
| echo ">>> [Compiler Oracle] Baseline Tag: $LAST_TAG" | |
| CURRENT_VERSION=$(jq -r '.compiler_version' compiler/compiler_manifest.json) | |
| MAJOR=$(echo $CURRENT_VERSION | cut -d. -f1) | |
| MINOR=$(echo $CURRENT_VERSION | cut -d. -f2) | |
| PATCH=$(echo $CURRENT_VERSION | cut -d. -f3) | |
| BUMP="PATCH" | |
| if [ "$LAST_TAG" != "compiler/v0.0.0" ]; then | |
| OLD_MANIFEST=$(git show $LAST_TAG:compiler/compiler_manifest.json 2>/dev/null || echo '{}') | |
| OLD_PROTOCOL=$(echo "$OLD_MANIFEST" | jq -r '.protocol_version // 0') | |
| NEW_PROTOCOL=$(jq -r '.protocol_version' compiler/compiler_manifest.json) | |
| if [ "$OLD_PROTOCOL" != "$NEW_PROTOCOL" ]; then | |
| BUMP="MAJOR" | |
| fi | |
| if [ "$BUMP" = "PATCH" ]; then | |
| OLD_BASE=$(echo "$OLD_MANIFEST" | jq -r '.base_image.image // ""') | |
| NEW_BASE=$(jq -r '.base_image.image' compiler/compiler_manifest.json) | |
| OLD_SYSPKG=$(echo "$OLD_MANIFEST" | jq -cS '.system_packages // []') | |
| NEW_SYSPKG=$(jq -cS '.system_packages' compiler/compiler_manifest.json) | |
| if [ "$OLD_BASE" != "$NEW_BASE" ] || [ "$OLD_SYSPKG" != "$NEW_SYSPKG" ]; then | |
| BUMP="MINOR" | |
| fi | |
| fi | |
| fi | |
| echo ">>> [Compiler Oracle] Bump type: $BUMP" | |
| if [ "$BUMP" = "MAJOR" ]; then | |
| MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 | |
| elif [ "$BUMP" = "MINOR" ]; then | |
| MINOR=$((MINOR + 1)); PATCH=0 | |
| else | |
| PATCH=$((PATCH + 1)) | |
| fi | |
| NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}" | |
| NEW_TAG="compiler/v${NEW_VERSION}" | |
| echo ">>> [Compiler Oracle] New version: $NEW_TAG" | |
| # Check tag existence BEFORE writing to manifest to prevent double-bumps | |
| if git rev-parse "$NEW_TAG" >/dev/null 2>&1; then | |
| echo ">>> [Compiler Oracle] Tag $NEW_TAG already exists. Skipping." | |
| exit 0 | |
| fi | |
| # Update version in manifest and commit | |
| jq --arg v "$NEW_VERSION" '.compiler_version = $v' \ | |
| compiler/compiler_manifest.json > tmp_manifest.json \ | |
| && mv tmp_manifest.json compiler/compiler_manifest.json | |
| git add compiler/compiler_manifest.json | |
| git commit -m "chore(compiler): bump to v${NEW_VERSION} [skip ci]" || true | |
| # Atomic push: commit + tag together to prevent race conditions | |
| git tag "$NEW_TAG" | |
| git push origin HEAD:main "$NEW_TAG" || echo ">>> Push failed (concurrent run?)" | |
| echo ">>> [Compiler Oracle] Tag $NEW_TAG pushed!" | |
| # Create draft release as manual approval gate | |
| CLI_VER=$(jq -r '.cli.version' compiler/compiler_manifest.json) | |
| PROTO_VER=$(jq -r '.protocol_version' compiler/compiler_manifest.json) | |
| BODY="## Compiler v${NEW_VERSION}\n\n" | |
| BODY+="| Property | Value |\n|---|---|\n" | |
| BODY+="| CLI | v${CLI_VER} |\n" | |
| BODY+="| Protocol | v${PROTO_VER} |\n\n" | |
| BODY+="**Publish this release to trigger the Docker image build on the CI server.**" | |
| curl -sf -X POST \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Authorization: token ${{ secrets.RELEASE_TARGET_TOKEN }}" \ | |
| https://api.github.com/repos/Toob-Boot/Toob-Loader/releases \ | |
| -d "{ | |
| \"tag_name\": \"${NEW_TAG}\", | |
| \"name\": \"Compiler v${NEW_VERSION}\", | |
| \"body\": \"$(echo -e "$BODY")\", | |
| \"draft\": true, | |
| \"prerelease\": false | |
| }" && echo ">>> [Compiler Oracle] Draft release created for ${NEW_TAG}" \ | |
| || echo ">>> [Compiler Oracle] Draft creation failed (non-critical)" |