Skip to content

feat: rustc-style --version with git commit and build date #1608

feat: rustc-style --version with git commit and build date

feat: rustc-style --version with git commit and build date #1608

Workflow file for this run

name: CI
on:
push:
branches: [main, dev]
tags: ["v*"]
pull_request:
branches: [main]
jobs:
format-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm install --ignore-scripts
- run: npx prettier --check .
benchmarks:
if: github.event_name == 'pull_request'
runs-on: ubuntu-22.04
permissions:
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- uses: actions/setup-go@v5
with:
go-version: "1.23"
- name: Install system dependencies
run: |
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-21 main" | sudo tee /etc/apt/sources.list.d/llvm-21.list
sudo apt-get update
sudo apt-get install -y clang-21 lld-21 llvm-21-dev \
cmake make gcc g++ \
autoconf automake libtool \
libzstd-dev zlib1g-dev libsqlite3-dev libcurl4-openssl-dev
sudo ln -sf /usr/bin/clang-21 /usr/bin/clang
sudo ln -sf /usr/bin/llvm-config-21 /usr/bin/llvm-config
- run: npm install
- uses: actions/cache@v4
with:
path: |
vendor/
c_bridges/*.o
key: vendor-${{ runner.os }}-${{ hashFiles('scripts/build-vendor.sh', 'scripts/vendor-pins.sh', 'c_bridges/*.c', 'c_bridges/*.cpp') }}
- run: bash scripts/build-vendor.sh
- run: npm run build
- name: Build tree-sitter TSX objects
run: |
mkdir -p build
TS_SRC=node_modules/tree-sitter-typescript/tsx/src
TS_INCLUDE=node_modules/tree-sitter-typescript
clang -c -O2 -fPIC -I $TS_SRC -I $TS_INCLUDE $TS_SRC/parser.c -o build/tree-sitter-typescript-parser.o
clang -c -O2 -fPIC -I $TS_SRC -I $TS_INCLUDE $TS_SRC/scanner.c -o build/tree-sitter-typescript-scanner.o
clang -c -O2 -fPIC -I vendor/tree-sitter/lib/include c_bridges/treesitter-bridge.c -o build/treesitter-bridge.o
- name: Build native chad
run: node dist/chad-node.js build src/chad-native.ts -o .build/chad --target-cpu=x86-64
- name: Run benchmarks
run: bash benchmarks/run-ci.sh
timeout-minutes: 10
- name: Upload benchmark results
uses: actions/upload-artifact@v4
with:
name: benchmarks
path: docs/public/benchmarks.json
- name: Post benchmark summary
if: github.event_name == 'pull_request'
run: |
RESULTS=$(python3 -c "
import json, os
d = json.load(open('docs/public/benchmarks-all.json'))
prev = {}
try:
import subprocess
old = subprocess.run(['git', 'show', 'origin/main:docs/public/benchmarks.json'], capture_output=True, text=True)
if old.returncode == 0:
prev = json.loads(old.stdout).get('benchmarks', {})
except: pass
lines = ['### Benchmark Results (Linux x86-64)\n', '| Benchmark | C | ChadScript | Go | Node | Place |', '|---|---|---|---|---|---|']
def fmt(val_str):
try:
v = float(val_str.rstrip('smsg/req'))
suffix = ''
for s in ['ms', 'msg/s', 'req/s', 's']:
if val_str.endswith(s):
suffix = s
break
if suffix == 'ms':
return f'{v:.1f}{suffix}'
elif '/' in suffix:
return f'{int(v):,}{suffix}'
else:
return f'{v:.3f}{suffix}'
except (ValueError, TypeError):
return val_str
def rank(b):
r = b['results']
lower = b.get('lower_is_better', True)
chad_v = r.get('chadscript', {}).get('value')
if chad_v is None: return '—'
vals = sorted([v['value'] for v in r.values()], reverse=not lower)
place = vals.index(chad_v) + 1
medals = {1: '\U0001f947', 2: '\U0001f948', 3: '\U0001f949'}
return medals.get(place, f'#{place}')
def delta(k, b):
if k not in prev: return ''
old_v = prev[k].get('results', {}).get('chadscript', {}).get('value')
new_v = b['results'].get('chadscript', {}).get('value')
if old_v is None or new_v is None or old_v == 0: return ''
pct = (new_v - old_v) / old_v * 100
if abs(pct) < 1: return ''
if pct < 0: return f' (\u2193{abs(pct):.0f}%)'
return f' (\u2191{pct:.0f}%)'
compute = {k: b for k, b in d['benchmarks'].items() if b.get('category') != 'cli'}
cli = {k: b for k, b in d['benchmarks'].items() if b.get('category') == 'cli'}
for k, b in sorted(compute.items(), key=lambda x: x[1]['name']):
r = b['results']
def g(lang):
v = r.get(lang, {}).get('label', '—')
return fmt(v) if v != '—' else v
chad_str = f'**{g(\"chadscript\")}{delta(k, b)}**'
lines.append(f\"| {b['name']} | {g('c')} | {chad_str} | {g('go')} | {g('node')} | {rank(b)} |\")
if cli:
cli_names = {'grep': 'grep', 'ripgrep': 'ripgrep', 'node': 'Node.js', 'xxd': 'xxd'}
lines.append('')
lines.append('### CLI Tool Benchmarks\n')
for k, b in sorted(cli.items(), key=lambda x: x[1]['name']):
r = b['results']
competitors = [l for l in r if l != 'chadscript']
chad_v = r.get('chadscript', {}).get('label', '—')
chad_str = f'**{fmt(chad_v)}{delta(k, b)}**'
cols = ' | '.join(f'{fmt(r[c][\"label\"])}' for c in competitors)
comp_names = ' | '.join(c for c in competitors)
if not hasattr(rank, '_cli_header_done'):
all_comps = set()
for kb, bb in cli.items():
all_comps.update(l for l in bb['results'] if l != 'chadscript')
comp_list = sorted(all_comps)
lines.append('| Benchmark | ChadScript | ' + ' | '.join(comp_list) + ' | Place |')
lines.append('|---|---|' + '|'.join(['---'] * len(comp_list)) + '|---|')
rank._cli_header_done = True
row_vals = []
for c in comp_list:
v = r.get(c, {}).get('label', '—')
row_vals.append(fmt(v) if v != '—' else v)
lines.append(f\"| {b['name']} | {chad_str} | {' | '.join(row_vals)} | {rank(b)} |\")
print('\n'.join(lines))
")
EXISTING=$(gh api repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments --jq '[.[] | select(.user.login == "github-actions[bot]" and (.body | startswith("### Benchmark"))) | .id] | last')
if [ -n "$EXISTING" ] && [ "$EXISTING" != "null" ]; then
gh api repos/${{ github.repository }}/issues/comments/$EXISTING -X PATCH -f body="$RESULTS"
else
gh pr comment ${{ github.event.pull_request.number }} --body "$RESULTS"
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build-linux-glibc:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- name: Install system dependencies
run: |
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-21 main" | sudo tee /etc/apt/sources.list.d/llvm-21.list
sudo apt-get update
sudo apt-get install -y clang-21 lld-21 llvm-21-dev \
cmake make gcc g++ \
autoconf automake libtool \
libzstd-dev zlib1g-dev libsqlite3-dev libcurl4-openssl-dev
sudo ln -sf /usr/bin/clang-21 /usr/bin/clang
sudo ln -sf /usr/bin/llvm-config-21 /usr/bin/llvm-config
clang --version 2>&1 | head -2
- name: Install npm dependencies
run: npm install
- name: Cache vendor libraries
uses: actions/cache@v4
with:
path: |
vendor/
c_bridges/*.o
key: vendor-${{ runner.os }}-${{ hashFiles('scripts/build-vendor.sh', 'scripts/vendor-pins.sh', 'c_bridges/*.c', 'c_bridges/*.cpp') }}
- name: Build vendor libraries
run: bash scripts/build-vendor.sh
- name: Build compiler
run: npm run build
- name: Verify vendor libraries
run: |
fail=0
for lib in vendor/bdwgc/libgc.a vendor/yyjson/libyyjson.a vendor/libuv/build/libuv.a vendor/picohttpparser/picohttpparser.o c_bridges/lws-bridge.o c_bridges/multipart-bridge.o c_bridges/regex-bridge.o c_bridges/child-process-bridge.o c_bridges/child-process-spawn.o c_bridges/os-bridge.o c_bridges/strlen-cache.o c_bridges/time-bridge.o c_bridges/base64-bridge.o c_bridges/url-bridge.o c_bridges/uri-bridge.o c_bridges/dotenv-bridge.o c_bridges/watch-bridge.o c_bridges/arena-bridge.o c_bridges/curl-bridge.o c_bridges/compress-bridge.o c_bridges/yaml-bridge.o c_bridges/string-ops-bridge.o c_bridges/llvm-bridge.o c_bridges/llvm-builder-bridge.o c_bridges/lld-bridge.o; do
if [ ! -f "$lib" ]; then
echo "MISSING: $lib"
fail=1
else
echo "OK: $lib ($(wc -c < "$lib") bytes)"
fi
done
if [ "$fail" -eq 1 ]; then
echo "Vendor library build incomplete - aborting before tests"
exit 1
fi
- name: Build tree-sitter TSX objects
run: |
mkdir -p build
TS_SRC=node_modules/tree-sitter-typescript/tsx/src
TS_INCLUDE=node_modules/tree-sitter-typescript
clang -c -O2 -fPIC -I $TS_SRC -I $TS_INCLUDE $TS_SRC/parser.c -o build/tree-sitter-typescript-parser.o
clang -c -O2 -fPIC -I $TS_SRC -I $TS_INCLUDE $TS_SRC/scanner.c -o build/tree-sitter-typescript-scanner.o
clang -c -O2 -fPIC -I vendor/tree-sitter/lib/include c_bridges/treesitter-bridge.c -o build/treesitter-bridge.o
- name: Build native chad
run: node dist/chad-node.js build src/chad-native.ts -o .build/chad --target-cpu=x86-64
- name: Run unit tests (node compiler)
run: npm run test:node
timeout-minutes: 10
- name: Run unit tests (native compiler)
run: npm run test:native
timeout-minutes: 10
- name: Smoke test native chad
run: |
.build/chad build examples/snippets/hello.ts -o /tmp/hello
/tmp/hello
- name: Run examples
run: bash scripts/run-examples.sh
timeout-minutes: 5
- name: Run self-hosting tests
run: node --import tsx --test tests/self-hosting.test.ts
timeout-minutes: 15
- name: Build target SDK
run: bash scripts/build-target-sdk.sh
- name: Package release artifact
run: |
mkdir -p release/lib
cp .build/chad release/
cp build/tree-sitter-typescript-parser.o release/lib/
cp build/tree-sitter-typescript-scanner.o release/lib/
cp build/treesitter-bridge.o release/lib/
cp vendor/tree-sitter/libtree-sitter.a release/lib/
cp vendor/bdwgc/libgc.a release/lib/
cp vendor/yyjson/libyyjson.a release/lib/
cp vendor/libuv/build/libuv.a release/lib/
cp vendor/picohttpparser/picohttpparser.o release/lib/
cp c_bridges/lws-bridge.o release/lib/
cp c_bridges/multipart-bridge.o release/lib/
cp c_bridges/regex-bridge.o release/lib/
cp c_bridges/child-process-bridge.o release/lib/
cp c_bridges/child-process-spawn.o release/lib/
cp c_bridges/os-bridge.o c_bridges/strlen-cache.o release/lib/
cp c_bridges/time-bridge.o c_bridges/base64-bridge.o c_bridges/url-bridge.o c_bridges/uri-bridge.o release/lib/
cp c_bridges/dotenv-bridge.o release/lib/
cp c_bridges/watch-bridge.o c_bridges/arena-bridge.o c_bridges/curl-bridge.o c_bridges/compress-bridge.o c_bridges/yaml-bridge.o c_bridges/string-ops-bridge.o c_bridges/llvm-bridge.o c_bridges/llvm-builder-bridge.o c_bridges/lld-bridge.o release/lib/
tar -czf chadscript-linux-x64.tar.gz -C release chad lib
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: chadscript-linux-x64
path: chadscript-linux-x64.tar.gz
- name: Upload target SDK
uses: actions/upload-artifact@v4
with:
name: chadscript-target-linux-x64
path: chadscript-target-linux-x64.tar.gz
build-macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- name: Install system dependencies
run: |
brew install llvm lld cmake autoconf automake libtool zstd
echo "/opt/homebrew/opt/llvm/bin" >> $GITHUB_PATH
echo "/usr/local/opt/llvm/bin" >> $GITHUB_PATH
- name: Install npm dependencies
run: npm install
- name: Cache vendor libraries
uses: actions/cache@v4
with:
path: |
vendor/
c_bridges/*.o
key: vendor-${{ runner.os }}-${{ hashFiles('scripts/build-vendor.sh', 'scripts/vendor-pins.sh', 'c_bridges/*.c', 'c_bridges/*.cpp') }}
- name: Build vendor libraries
run: bash scripts/build-vendor.sh
- name: Build compiler
run: npm run build
- name: Verify vendor libraries
run: |
fail=0
for lib in vendor/bdwgc/libgc.a vendor/yyjson/libyyjson.a vendor/libuv/build/libuv.a vendor/picohttpparser/picohttpparser.o c_bridges/lws-bridge.o c_bridges/multipart-bridge.o c_bridges/regex-bridge.o c_bridges/child-process-bridge.o c_bridges/child-process-spawn.o c_bridges/os-bridge.o c_bridges/strlen-cache.o c_bridges/time-bridge.o c_bridges/base64-bridge.o c_bridges/url-bridge.o c_bridges/uri-bridge.o c_bridges/dotenv-bridge.o c_bridges/watch-bridge.o c_bridges/arena-bridge.o c_bridges/curl-bridge.o c_bridges/compress-bridge.o c_bridges/yaml-bridge.o c_bridges/string-ops-bridge.o c_bridges/llvm-bridge.o c_bridges/llvm-builder-bridge.o c_bridges/lld-bridge.o; do
if [ ! -f "$lib" ]; then
echo "MISSING: $lib"
fail=1
else
echo "OK: $lib"
fi
done
if [ "$fail" -eq 1 ]; then
echo "Vendor library build incomplete - aborting before tests"
exit 1
fi
- name: Build tree-sitter TSX objects
run: |
mkdir -p build
TS_SRC=node_modules/tree-sitter-typescript/tsx/src
TS_INCLUDE=node_modules/tree-sitter-typescript
clang -c -O2 -fPIC -I $TS_SRC -I $TS_INCLUDE $TS_SRC/parser.c -o build/tree-sitter-typescript-parser.o
clang -c -O2 -fPIC -I $TS_SRC -I $TS_INCLUDE $TS_SRC/scanner.c -o build/tree-sitter-typescript-scanner.o
clang -c -O2 -fPIC -I vendor/tree-sitter/lib/include c_bridges/treesitter-bridge.c -o build/treesitter-bridge.o
- name: Build native chad
run: node dist/chad-node.js build src/chad-native.ts -o .build/chad
- name: Run unit tests (node compiler)
run: npm run test:node
timeout-minutes: 10
- name: Run unit tests (native compiler)
run: npm run test:native
timeout-minutes: 10
- name: Sign macOS binaries
run: |
codesign --sign - --force .build/chad
- name: Smoke test native chad
run: |
.build/chad build examples/snippets/hello.ts -o /tmp/hello
/tmp/hello
- name: Run examples
run: bash scripts/run-examples.sh
timeout-minutes: 5
- name: Run self-hosting tests
run: node --import tsx --test tests/self-hosting.test.ts
timeout-minutes: 15
- name: Build target SDK
run: bash scripts/build-target-sdk.sh
- name: Package release artifact
run: |
mkdir -p release/lib
cp .build/chad release/
cp build/tree-sitter-typescript-parser.o release/lib/
cp build/tree-sitter-typescript-scanner.o release/lib/
cp build/treesitter-bridge.o release/lib/
cp vendor/tree-sitter/libtree-sitter.a release/lib/
cp vendor/bdwgc/libgc.a release/lib/
cp vendor/yyjson/libyyjson.a release/lib/
cp vendor/libuv/build/libuv.a release/lib/
cp vendor/picohttpparser/picohttpparser.o release/lib/
cp c_bridges/lws-bridge.o release/lib/
cp c_bridges/multipart-bridge.o release/lib/
cp c_bridges/regex-bridge.o release/lib/
cp c_bridges/child-process-bridge.o release/lib/
cp c_bridges/child-process-spawn.o release/lib/
cp c_bridges/os-bridge.o c_bridges/strlen-cache.o release/lib/
cp c_bridges/time-bridge.o c_bridges/base64-bridge.o c_bridges/url-bridge.o c_bridges/uri-bridge.o release/lib/
cp c_bridges/dotenv-bridge.o release/lib/
cp c_bridges/watch-bridge.o c_bridges/arena-bridge.o c_bridges/curl-bridge.o c_bridges/compress-bridge.o c_bridges/yaml-bridge.o c_bridges/string-ops-bridge.o c_bridges/llvm-bridge.o c_bridges/llvm-builder-bridge.o c_bridges/lld-bridge.o release/lib/
tar -czf chadscript-macos-arm64.tar.gz -C release chad lib
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: chadscript-macos-arm64
path: chadscript-macos-arm64.tar.gz
- name: Upload target SDK
uses: actions/upload-artifact@v4
with:
name: chadscript-target-macos-arm64
path: chadscript-target-macos-arm64.tar.gz
test-artifact:
needs: [build-linux-glibc, build-macos]
strategy:
matrix:
include:
- os: ubuntu-22.04
artifact: chadscript-linux-x64
- os: macos-latest
artifact: chadscript-macos-arm64
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install system dependencies (Linux)
if: runner.os == 'Linux'
run: |
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
echo "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-21 main" | sudo tee /etc/apt/sources.list.d/llvm-21.list
sudo apt-get update
sudo apt-get install -y clang-21 libsqlite3-dev libzstd-dev zlib1g-dev
sudo ln -sf /usr/bin/clang-21 /usr/bin/clang
- name: Install system dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew install llvm lld zstd
echo "/opt/homebrew/opt/llvm/bin" >> $GITHUB_PATH
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: ${{ matrix.artifact }}
- name: Install via install.sh
run: |
SKIP_PROMPTS=1 CHADSCRIPT_URL="file://$(pwd)/${{ matrix.artifact }}.tar.gz" bash install.sh
echo "$HOME/.chadscript" >> $GITHUB_PATH
- name: Verify binary
run: |
file ~/.chadscript/chad.bin
ls -la ~/.chadscript/lib/
- name: Verify lib/ contains all required artifacts
run: |
fail=0
for lib in \
libgc.a \
libyyjson.a \
libuv.a \
libtree-sitter.a \
picohttpparser.o \
lws-bridge.o \
multipart-bridge.o \
regex-bridge.o \
child-process-bridge.o \
child-process-spawn.o \
os-bridge.o \
strlen-cache.o \
time-bridge.o \
dotenv-bridge.o \
watch-bridge.o \
arena-bridge.o \
string-ops-bridge.o \
llvm-bridge.o \
llvm-builder-bridge.o \
lld-bridge.o \
tree-sitter-typescript-parser.o \
tree-sitter-typescript-scanner.o \
treesitter-bridge.o; do
if [ ! -f "$HOME/.chadscript/lib/$lib" ]; then
echo "MISSING from release: lib/$lib"
fail=1
else
echo "OK: lib/$lib ($(wc -c < "$HOME/.chadscript/lib/$lib") bytes)"
fi
done
if [ "$fail" -eq 1 ]; then
echo ""
echo "ERROR: Release artifact is missing required library files."
echo "Check the 'Package release artifact' step in the build job."
exit 1
fi
echo ""
echo "All $(ls ~/.chadscript/lib/ | wc -l) library files present."
- name: Smoke test - hello world
run: |
echo 'console.log("Hello from release artifact!");' > /tmp/hello.ts
chad run /tmp/hello.ts
- name: Smoke test - compile to binary
run: |
echo 'process.exit(42);' > /tmp/exit42.ts
chad build /tmp/exit42.ts -o /tmp/exit42
/tmp/exit42 || [ $? -eq 42 ]
- name: Smoke test - JSON bridge (libyyjson)
run: |
cat > /tmp/test-json.ts << 'EOF'
interface JsonObj {
name: string;
version: number;
}
const obj = JSON.parse<JsonObj>('{"name":"chad","version":1}');
const back = JSON.stringify(obj);
if (back.includes("chad")) {
console.log("TEST_PASSED");
}
EOF
OUTPUT=$(chad run /tmp/test-json.ts)
echo "$OUTPUT"
echo "$OUTPUT" | grep -q "TEST_PASSED"
- name: Smoke test - regex bridge
run: |
cat > /tmp/test-regex.ts << 'EOF'
function main(): void {
const re = /hello/;
const result = "hello world".match(re);
if (result !== null && result[0] === "hello") {
console.log("TEST_PASSED");
}
}
main();
EOF
OUTPUT=$(chad run /tmp/test-regex.ts)
echo "$OUTPUT"
echo "$OUTPUT" | grep -q "TEST_PASSED"
- name: Smoke test - child_process bridge
run: |
cat > /tmp/test-execsync.ts << 'EOF'
import { execSync } from "child_process";
function main(): void {
const output = execSync("echo bridge_works");
if (output.trim() === "bridge_works") {
console.log("TEST_PASSED");
}
}
main();
EOF
OUTPUT=$(chad run /tmp/test-execsync.ts)
echo "$OUTPUT"
echo "$OUTPUT" | grep -q "TEST_PASSED"
- name: Smoke test - compile hackernews example (exercises HTTP + sqlite bridges)
run: |
chad build examples/apps/hackernews/app.ts -o /tmp/hackernews
file /tmp/hackernews
echo "Hackernews example compiled successfully"
release:
needs: [build-linux-glibc, build-macos, test-artifact]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Publish latest release
uses: softprops/action-gh-release@v2
with:
tag_name: latest
name: Latest Build
body: Automated release from main branch. Download native binaries and target SDKs below.
files: artifacts/**/*.tar.gz
make_latest: "true"
target_commitish: ${{ github.sha }}
tagged-release:
needs: [build-linux-glibc, build-macos, test-artifact]
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
files: artifacts/**/*.tar.gz
generate_release_notes: true