Release 0.11.2 #46
Workflow file for this run
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: Release | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Release version to scrub, with or without leading v" | |
| required: true | |
| type: string | |
| release_notes: | |
| description: "Optional extra release text path to scrub during preflight" | |
| required: false | |
| type: string | |
| default: "" | |
| pr_number: | |
| description: "Optional release PR number whose body should be scrubbed" | |
| required: false | |
| type: string | |
| default: "" | |
| push: | |
| tags: | |
| - 'v*' | |
| permissions: | |
| contents: write | |
| jobs: | |
| scrub-public-text-preflight: | |
| if: github.event_name == 'workflow_dispatch' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable | |
| - name: Scrub public release text before tag | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| RELEASE_NOTES: ${{ inputs.release_notes }} | |
| RELEASE_PR_NUMBER: ${{ inputs.pr_number }} | |
| RELEASE_VERSION: ${{ inputs.version }} | |
| run: | | |
| set -euo pipefail | |
| version="${RELEASE_VERSION#v}" | |
| if [ -z "$version" ]; then | |
| echo "scrub-public-text failed: release preflight requires a version" >&2 | |
| exit 1 | |
| fi | |
| changelog_section="$(mktemp)" | |
| awk -v version="$version" ' | |
| index($0, "## [" version "]") == 1 { in_section=1; print; next } | |
| in_section && /^## \[/ { exit } | |
| in_section { print } | |
| ' CHANGELOG.md > "$changelog_section" | |
| if [ ! -s "$changelog_section" ]; then | |
| echo "scrub-public-text failed: CHANGELOG.md has no section for v${version}" >&2 | |
| exit 1 | |
| fi | |
| files=("$changelog_section") | |
| if [ -n "$RELEASE_NOTES" ]; then | |
| if [ ! -f "$RELEASE_NOTES" ]; then | |
| echo "scrub-public-text failed: missing release notes file ${RELEASE_NOTES}" >&2 | |
| exit 1 | |
| fi | |
| files+=("$RELEASE_NOTES") | |
| fi | |
| if [ -n "$RELEASE_PR_NUMBER" ]; then | |
| pr_body="$(mktemp)" | |
| gh pr view "$RELEASE_PR_NUMBER" --json body --jq .body > "$pr_body" | |
| files+=("$pr_body") | |
| fi | |
| cargo run -p xtask -- scrub-public-text "${files[@]}" | |
| build: | |
| if: github.event_name == 'push' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: macos-latest | |
| target: aarch64-apple-darwin | |
| artifact: gaze-aarch64-apple-darwin | |
| - os: ubuntu-24.04 | |
| target: x86_64-unknown-linux-gnu | |
| artifact: gaze-x86_64-linux-gnu | |
| runs-on: ${{ matrix.os }} | |
| env: | |
| GAZE_RELEASE_FEATURES: document,proxy | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Build | |
| run: cargo build --release --bin gaze --target ${{ matrix.target }} --features "$GAZE_RELEASE_FEATURES" | |
| - name: Package | |
| run: | | |
| mkdir -p dist | |
| cp target/${{ matrix.target }}/release/gaze dist/${{ matrix.artifact }} | |
| chmod +x dist/${{ matrix.artifact }} | |
| (cd dist && shasum -a 256 ${{ matrix.artifact }} > ${{ matrix.artifact }}.sha256) | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: ${{ matrix.artifact }} | |
| path: dist/* | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: ${{ matrix.artifact }} | |
| path: smoke | |
| - name: Smoke artifact | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| bin="smoke/${{ matrix.artifact }}" | |
| chmod +x "$bin" | |
| "$bin" --version | |
| "$bin" clean --help | grep -q -- '--session-scope' | |
| "$bin" clean --help | grep -q -- '--ner-model-dir' | |
| "$bin" clean --help | grep -q -- '--ner-locale' | |
| "$bin" clean --help | grep -q -- '--rulepack-bundled' | |
| "$bin" clean --help | grep -q -- '--rulepack-path' | |
| "$bin" document --help | grep -q 'clean' | |
| "$bin" proxy --help | grep -q 'serve' | |
| "$bin" proxy --help | grep -q 'start' | |
| "$bin" proxy --help | grep -q 'stop' | |
| "$bin" proxy --help | grep -q 'status' | |
| "$bin" proxy --help | grep -q 'restart' | |
| clean_json="$(printf 'alice@example.invalid' | "$bin" clean)" | |
| clean_text="$(python3 -c 'import json,sys; print(json.load(sys.stdin)["clean_text"])' <<< "$clean_json")" | |
| grep -q '<' <<< "$clean_text" || (echo "smoke failed: no token in output"; exit 1) | |
| restore_request="$(python3 -c 'import json,sys; v=json.load(sys.stdin); print(json.dumps({"session_blob": v["session_blob"], "text": v["clean_text"]}))' <<< "$clean_json")" | |
| restored_json="$(printf '%s' "$restore_request" | "$bin" restore)" | |
| python3 -c 'import json,sys; assert json.load(sys.stdin)["text"] == "alice@example.invalid"' <<< "$restored_json" | |
| policy="$(mktemp)" | |
| cat > "$policy" <<'POLICY' | |
| [session] | |
| scope = "persistent" | |
| ttl_secs = 86400 | |
| [policy.rulepacks] | |
| bundled = ["core", "core-extended"] | |
| [[rule]] | |
| kind = "class" | |
| class = "custom:ip_address" | |
| action = "tokenize" | |
| [[rule]] | |
| kind = "default" | |
| action = "preserve" | |
| POLICY | |
| extended_json="$(printf 'host 192.0.2.1' | "$bin" clean --policy="$policy")" | |
| extended_text="$(python3 -c 'import json,sys; print(json.load(sys.stdin)["clean_text"])' <<< "$extended_json")" | |
| grep -q 'Custom:ip_address' <<< "$extended_text" || (echo "smoke failed: core-extended did not tokenize IP fixture"; exit 1) | |
| smoke_home="$(mktemp -d)" | |
| proxy_port="$(python3 - <<'PY' | |
| import socket | |
| s = socket.socket() | |
| s.bind(("127.0.0.1", 0)) | |
| print(s.getsockname()[1]) | |
| s.close() | |
| PY | |
| )" | |
| export HOME="$smoke_home" | |
| trap '"$bin" proxy stop --force >/dev/null 2>&1 || true; rm -rf "$smoke_home"' EXIT | |
| # Capture `proxy status` stdout via $() instead of piping into `grep -q`. | |
| # grep -q closes stdin on first match → upstream gaze hits EPIPE on | |
| # the next println and the CLI panic hook emits {"error":"Pipeline","exit":3}. | |
| # The $() form lets gaze finish writing before grep inspects the result. | |
| # Underlying SIGPIPE tolerance is tracked as a v0.8.2 follow-up. | |
| status_out="$("$bin" proxy status)"; grep -q 'not running' <<< "$status_out" | |
| "$bin" proxy start --bind "127.0.0.1:$proxy_port" | |
| sleep 1 | |
| status_out="$("$bin" proxy status)"; grep -q 'running' <<< "$status_out" | |
| "$bin" proxy restart --force | |
| sleep 1 | |
| status_out="$("$bin" proxy status)"; grep -q 'running' <<< "$status_out" | |
| "$bin" proxy stop --force | |
| status_out="$("$bin" proxy status)"; grep -q 'not running' <<< "$status_out" | |
| release: | |
| if: github.event_name == 'push' | |
| needs: build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| path: dist | |
| merge-multiple: true | |
| - name: Scrub public release text before publication | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| version="${GITHUB_REF_NAME#v}" | |
| changelog_section="$(mktemp)" | |
| awk -v version="$version" ' | |
| index($0, "## [" version "]") == 1 { in_section=1; print; next } | |
| in_section && /^## \[/ { exit } | |
| in_section { print } | |
| ' CHANGELOG.md > "$changelog_section" | |
| if [ ! -s "$changelog_section" ]; then | |
| echo "scrub-public-text failed: CHANGELOG.md has no section for ${GITHUB_REF_NAME}" >&2 | |
| exit 1 | |
| fi | |
| cargo run -p xtask -- scrub-public-text "$changelog_section" | |
| - name: Generate NER checksums | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| hf_repo="$(sed -n 's/^HF_REPO="\([^"]*\)"/\1/p' scripts/fetch/fetch-ner-model.sh)" | |
| hf_commit_sha="$(sed -n 's/^HF_COMMIT_SHA="\([^"]*\)"/\1/p' scripts/fetch/fetch-ner-model.sh)" | |
| if [ -z "$hf_repo" ] || [ -z "$hf_commit_sha" ]; then | |
| echo "failed to read HF_REPO/HF_COMMIT_SHA from scripts/fetch/fetch-ner-model.sh" >&2 | |
| exit 2 | |
| fi | |
| work_dir="$(mktemp -d)" | |
| trap 'rm -rf "$work_dir"' EXIT | |
| cd "$work_dir" | |
| fetch_raw() { | |
| local source_file="$1" | |
| local dest_file="$2" | |
| local url="https://huggingface.co/${hf_repo}/resolve/${hf_commit_sha}/${source_file}" | |
| curl -fL --retry 3 -o "$dest_file" "$url" | |
| } | |
| fetch_raw "onnx/model_int8.onnx" "model.onnx" | |
| fetch_raw "tokenizer.json" "tokenizer.json" | |
| fetch_raw "tokenizer_config.json" "tokenizer_config.json" | |
| fetch_raw "config.json" "config.json" | |
| fetch_raw "special_tokens_map.json" "special_tokens_map.json" | |
| fetch_raw "vocab.txt" "vocab.txt" | |
| cp "${GITHUB_WORKSPACE}/crates/gaze-recognizers/assets/ner/labels.davlan-mbert.json" labels.json | |
| shasum -a 256 \ | |
| model.onnx \ | |
| tokenizer.json \ | |
| tokenizer_config.json \ | |
| config.json \ | |
| special_tokens_map.json \ | |
| vocab.txt \ | |
| labels.json \ | |
| > "${GITHUB_WORKSPACE}/dist/SHA256SUMS.ner" | |
| - uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2 | |
| with: | |
| files: dist/* | |
| prerelease: ${{ contains(github.ref, '-rc') || contains(github.ref, '-alpha') || contains(github.ref, '-beta') }} | |
| generate_release_notes: true |