Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ jobs:
with:
dotnet-version: '10.0.x'

- name: Build tree-sitter-markdown grammar (Linux / macOS)
if: runner.os != 'Windows'
run: bash scripts/build-tree-sitter-markdown.sh

- name: Build tree-sitter-markdown grammar (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: scripts/build-tree-sitter-markdown.ps1

- name: Restore
run: dotnet restore

Expand Down Expand Up @@ -53,18 +62,40 @@ jobs:
- name: Install AOT prerequisites
run: sudo apt-get install -y clang zlib1g-dev

- name: Build tree-sitter-markdown grammar
run: FORCE_BUILD=1 bash scripts/build-tree-sitter-markdown.sh

- name: Verify tree-sitter-markdown symbol
run: |
SO=native/runtimes/linux-x64/native/libtree-sitter-markdown.so
nm -D "$SO" | grep -q "tree_sitter_markdown" || \
(echo "ERROR: tree_sitter_markdown symbol missing from $SO" && exit 1)
echo "Symbol verified in $SO"

- name: Restore
run: dotnet restore

- name: Publish AOT
run: dotnet publish src/Hypa.Cli/Hypa.Cli.csproj -r linux-x64 -c Release -o publish/ /m:1 /p:BuildInParallel=false

- name: Verify libtree-sitter-markdown.so in publish output
run: |
ls -lh publish/libtree-sitter-markdown.so
nm -D publish/libtree-sitter-markdown.so | grep -q "tree_sitter_markdown" || \
(echo "ERROR: tree_sitter_markdown symbol missing from publish output" && exit 1)
echo "Publish output verified."

- name: Smoke test — version
run: ./publish/hypa --version || ./publish/hypa version

- name: Smoke test — doctor
run: ./publish/hypa doctor

- name: Smoke test — markdown provider healthy
run: |
./publish/hypa code index --json | \
python3 -c "import sys,json; h=json.load(sys.stdin)['providerHealth']; md=[p for p in h if p['providerId']=='markdown']; print(md); exit(0 if md and md[0]['status']=='ok' else 1)"

- name: Golden tests
env:
HYPA_BINARY_PATH: ${{ github.workspace }}/publish/hypa
Expand Down
64 changes: 64 additions & 0 deletions .github/workflows/pi-package-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Publish Pi Package

on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag:
description: 'Release tag, for example v0.1.0'
required: true
type: string

permissions:
contents: read
id-token: write

concurrency:
group: pi-package-release-${{ github.ref }}
cancel-in-progress: false

jobs:
publish-pi-package:
name: Publish @hypabolic/pi-hypa
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Resolve version
id: version
shell: pwsh
run: |
$tag = "${{ github.event.inputs.tag }}"
if ([string]::IsNullOrWhiteSpace($tag)) { $tag = $env:GITHUB_REF_NAME }
if ($tag -notmatch '^v\d+\.\d+\.\d+$') { throw "Tag must be vX.Y.Z. Got '$tag'." }
$version = $tag.Substring(1)
"version=$version" >> $env:GITHUB_OUTPUT

- uses: actions/setup-node@v4
with:
node-version: '22'
registry-url: 'https://registry.npmjs.org'

- name: Stamp package version
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
set -euo pipefail
tmp=$(mktemp)
jq --arg version "$VERSION" '.version = $version' packages/pi-hypa/package.json > "$tmp"
mv "$tmp" packages/pi-hypa/package.json

- name: Validate package
working-directory: packages/pi-hypa
run: |
npm ci
npm run build
npm test
npm pack --dry-run

- name: Publish package
working-directory: packages/pi-hypa
run: npm publish --access public
92 changes: 82 additions & 10 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,45 @@ permissions:
contents: write
packages: write

concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false

jobs:
gate:
name: Verify CI
runs-on: ubuntu-latest
steps:
- name: Check CI on tagged commit
env:
GH_TOKEN: ${{ github.token }}
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "Manual dispatch — skipping CI gate"
exit 0
fi

sha="${{ github.sha }}"
runs=$(gh api "repos/${{ github.repository }}/commits/${sha}/check-runs" \
--jq '[.check_runs[] | select(.name | test("Build & Test|AOT Publish|Format"))]')

if [ "$(echo "$runs" | jq 'length')" -eq 0 ]; then
echo "::error::No CI check runs found for ${sha} — run CI before tagging"
exit 1
fi

not_passed=$(echo "$runs" | jq '[.[] | select(.conclusion != "success")] | length')
if [ "$not_passed" -gt 0 ]; then
echo "::error::CI did not fully pass on ${sha}"
echo "$runs" | jq -r '.[] | " \(.name): \(.conclusion)"'
exit 1
fi

echo "$runs" | jq -r '.[] | " \(.name): \(.conclusion)"'

build:
name: Build ${{ matrix.rid }}
needs: [gate]
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
Expand Down Expand Up @@ -49,7 +85,7 @@ jobs:
executable: hypa.exe

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Resolve version
id: version
Expand All @@ -67,14 +103,23 @@ jobs:
"version=$version" >> $env:GITHUB_OUTPUT

- name: Setup .NET
uses: actions/setup-dotnet@v4
uses: actions/setup-dotnet@v5
with:
dotnet-version: '10.0.x'

- name: Install Linux AOT prerequisites
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y clang zlib1g-dev

- name: Build tree-sitter-markdown grammar (Linux / macOS)
if: runner.os != 'Windows'
run: FORCE_BUILD=1 bash scripts/build-tree-sitter-markdown.sh

- name: Build tree-sitter-markdown grammar (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: scripts/build-tree-sitter-markdown.ps1 -Force

- name: Restore
run: dotnet restore

Expand All @@ -90,6 +135,30 @@ jobs:
/p:FileVersion=${{ steps.version.outputs.version }}
/p:InformationalVersion=${{ steps.version.outputs.version }}

- name: Verify grammar in publish output (Linux / macOS)
if: runner.os != 'Windows'
run: |
RID="${{ matrix.rid }}"
PUBLISH_DIR="artifacts/publish/$RID"
case "$RID" in
linux*) GRAMMAR="$PUBLISH_DIR/libtree-sitter-markdown.so" ;;
osx*) GRAMMAR="$PUBLISH_DIR/libtree-sitter-markdown.dylib" ;;
esac
ls -lh "$GRAMMAR"
case "$RID" in
linux*) nm -D "$GRAMMAR" | grep -q "tree_sitter_markdown" || (echo "ERROR: symbol missing" && exit 1) ;;
osx*) nm -gU "$GRAMMAR" | grep -q "tree_sitter_markdown" || (echo "ERROR: symbol missing" && exit 1) ;;
esac
echo "Grammar verified in $RID publish output."

- name: Verify grammar in publish output (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$grammar = "artifacts/publish/${{ matrix.rid }}/tree-sitter-markdown.dll"
if (-not (Test-Path $grammar)) { Write-Error "Grammar DLL missing: $grammar"; exit 1 }
Write-Host "Grammar verified: $grammar"

- name: Package
shell: pwsh
run: |
Expand Down Expand Up @@ -143,9 +212,10 @@ jobs:
publish-sdk:
name: Pack & Publish Hypa.Sdk
runs-on: ubuntu-latest
needs: [gate]

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Resolve version
id: version
Expand All @@ -163,7 +233,7 @@ jobs:
"version=$version" >> $env:GITHUB_OUTPUT

- name: Setup .NET
uses: actions/setup-dotnet@v4
uses: actions/setup-dotnet@v5
with:
dotnet-version: '10.0.x'

Expand Down Expand Up @@ -202,7 +272,7 @@ jobs:
contents: read

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Resolve version
id: version
Expand All @@ -215,7 +285,7 @@ jobs:
"tag=$tag" >> $env:GITHUB_OUTPUT
"version=$version" >> $env:GITHUB_OUTPUT

- uses: actions/setup-node@v4
- uses: actions/setup-node@v5
with:
node-version: '22'

Expand Down Expand Up @@ -259,6 +329,7 @@ jobs:
npm/hypa-platform/package.json > "${STAGE}/package.json"

cp npm/hypa-platform/postinstall.js "${STAGE}/postinstall.js"
cp npm/hypa-platform/README.md "${STAGE}/README.md"

npx --yes npm@^11 publish "./${STAGE}" --access public
done
Expand All @@ -279,6 +350,7 @@ jobs:
npm/hypa/package.json > "${STAGE}/package.json"

cp npm/hypa/bin.js "${STAGE}/bin.js"
cp npm/hypa/README.md "${STAGE}/README.md"

npx --yes npm@^11 publish "./${STAGE}" --access public

Expand All @@ -288,7 +360,7 @@ jobs:
needs: [checksums, publish-sdk, publish-npm]

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Resolve tag
id: version
Expand Down Expand Up @@ -328,7 +400,7 @@ jobs:
contents: read

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Resolve version
id: version
Expand Down Expand Up @@ -374,7 +446,7 @@ jobs:

- name: Push to tap repo
env:
GITHUB_TOKEN: ${{ github.token }}
GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }}
VERSION: ${{ steps.version.outputs.version }}
run: |
git clone --depth=1 \
Expand All @@ -396,7 +468,7 @@ jobs:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Resolve version
id: version
shell: pwsh
Expand Down
44 changes: 44 additions & 0 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<Project>
<!--
Copies native grammar libraries (not shipped in TreeSitter.DotNet) to the
output/publish root of every project that builds. The <Link> element flattens
the file to the output root, matching how TreeSitter.DotNet native assets land
after NuGet RID resolution (e.g. libtree-sitter-bash.so alongside the binary).

Effective RID resolution:
- $(RuntimeIdentifier) when publishing with an explicit -r flag (e.g. linux-x64)
- Otherwise we construct the canonical RID from IsOSPlatform + arch suffix
extracted from $(NETCoreSdkRuntimeIdentifier) via regex, because
$(NETCoreSdkRuntimeIdentifier) is distro-versioned (e.g. ubuntu.24.04-x64)
while our directory names use the portable form (linux-x64).

Build the native library from source using:
bash scripts/build-tree-sitter-markdown.sh (Linux / macOS)
pwsh scripts/build-tree-sitter-markdown.ps1 (Windows)
-->
<PropertyGroup>
<!-- Explicit publish RID takes priority -->
<_MarkdownGrammarRID Condition="'$(RuntimeIdentifier)' != ''">$(RuntimeIdentifier)</_MarkdownGrammarRID>

<!-- Extract the arch suffix (x64, arm64, arm) from the versioned SDK RID -->
<_MarkdownGrammarArch Condition="'$(_MarkdownGrammarRID)' == ''">$([System.Text.RegularExpressions.Regex]::Match('$(NETCoreSdkRuntimeIdentifier)', '-(\w+)$').Groups[1].Value)</_MarkdownGrammarArch>

<!-- Determine portable OS prefix -->
<_MarkdownGrammarOS Condition="'$(_MarkdownGrammarRID)' == '' And $([MSBuild]::IsOSPlatform('Linux'))">linux</_MarkdownGrammarOS>
<_MarkdownGrammarOS Condition="'$(_MarkdownGrammarRID)' == '' And $([MSBuild]::IsOSPlatform('OSX'))">osx</_MarkdownGrammarOS>
<_MarkdownGrammarOS Condition="'$(_MarkdownGrammarRID)' == '' And $([MSBuild]::IsOSPlatform('Windows'))">win</_MarkdownGrammarOS>

<!-- Combine into portable canonical RID -->
<_MarkdownGrammarRID Condition="'$(_MarkdownGrammarRID)' == '' And '$(_MarkdownGrammarOS)' != '' And '$(_MarkdownGrammarArch)' != ''">$(_MarkdownGrammarOS)-$(_MarkdownGrammarArch)</_MarkdownGrammarRID>

<_MarkdownGrammarNativeDir>$(MSBuildThisFileDirectory)native\runtimes\$(_MarkdownGrammarRID)\native\</_MarkdownGrammarNativeDir>
</PropertyGroup>

<ItemGroup Condition="'$(_MarkdownGrammarRID)' != '' And Exists('$(_MarkdownGrammarNativeDir)')">
<Content Include="$(_MarkdownGrammarNativeDir)*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
<Link>%(Filename)%(Extension)</Link>
</Content>
</ItemGroup>
</Project>
Binary file not shown.
13 changes: 13 additions & 0 deletions npm/hypa-platform/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# @hypabolic/hypa-[platform]

Platform-specific native binary for [Hypa](https://www.npmjs.com/package/@hypabolic/hypa).

This package is installed automatically as an optional dependency of `@hypabolic/hypa`. Install the main package instead:

```bash
npm install -g @hypabolic/hypa
```

## License

[Functional Source License 1.1, ALv2 Future License](https://github.com/Hypabolic/Hypa/blob/main/license.md)
2 changes: 1 addition & 1 deletion npm/hypa-platform/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "git+https://github.com/Hypabolic/Hypa.git",
"directory": "npm/hypa-platform"
},
"license": "MIT",
"license": "FSL-1.1-ALv2",
"os": [
"PLACEHOLDER_OS"
],
Expand Down
Loading
Loading