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
40 changes: 40 additions & 0 deletions .github/actions/install-tools/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: 'Install WIT Tools'
description: 'Installs wit-deps and wasm-tools for WIT validation'

inputs:
wit-deps-version:
description: 'Version of wit-deps to install'
required: false
default: '0.5.0'
wasm-tools-version:
description: 'Version of wasm-tools to install'
required: false
default: '1.242.0'

runs:
using: 'composite'
steps:
- name: Setup wasm-tools
uses: bytecodealliance/actions/wasm-tools/setup@v1
with:
version: ${{ inputs.wasm-tools-version }}

- name: Cache wit-deps
id: cache-wit-deps
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: ~/.local/bin/wit-deps
key: wit-deps-${{ inputs.wit-deps-version }}

- name: Install wit-deps
if: steps.cache-wit-deps.outputs.cache-hit != 'true'
shell: bash
run: |
mkdir -p ~/.local/bin
curl -Lo ~/.local/bin/wit-deps \
"https://github.com/bytecodealliance/wit-deps/releases/download/v${{ inputs.wit-deps-version }}/wit-deps-x86_64-unknown-linux-musl"
chmod +x ~/.local/bin/wit-deps

- name: Add wit-deps to PATH
shell: bash
run: echo "$HOME/.local/bin" >> $GITHUB_PATH
37 changes: 37 additions & 0 deletions .github/scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# CI Scripts

## validate-proposals.js

Validates WIT definitions for changed proposals. Used by the CI workflow.

### Prerequisites

- Node.js
- [Wasm-tools](https://github.com/bytecodealliance/Wasm-tools)
- [wit-deps](https://github.com/bytecodealliance/wit-deps)

### Running Locally

```bash
# Validate specific proposals by simulating changed files
WIT_02_FILES='["proposals/cli/wit/cli.wit"]' node .github/scripts/validate-proposals.js

# Validate 0.3 proposals
WIT_03_FILES='["proposals/http/wit-0.3.0-draft/handler.wit"]' node .github/scripts/validate-proposals.js

# Validate multiple proposals
WIT_02_FILES='["proposals/cli/wit/cli.wit", "proposals/http/wit/proxy.wit"]' node .github/scripts/validate-proposals.js
```

### Environment Variables

| Variable | Description |
|----------|-------------|
| `WIT_02_FILES` | JSON array of changed files in `proposals/*/wit/**` |
| `WIT_03_FILES` | JSON array of changed files in `proposals/*/wit-0.3.0-draft/**` |

### What it validates

1. **wit-deps lock** - If `deps.toml` exists, checks that `deps.lock` is up to date
2. **WIT syntax** - Parses WIT files with `Wasm-tools component wit`
3. **Wasm encoding** - Validates Wasm binary encoding with `--Wasm` flag
106 changes: 106 additions & 0 deletions .github/scripts/validate-proposals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/usr/bin/env node

const { execSync } = require('child_process');
const fs = require('fs');

const witPath = (proposal, version) => {
if (version === '0.2') return `proposals/${proposal}/wit`;
if (version === '0.3') return `proposals/${proposal}/wit-0.3.0-draft`;
throw new Error(`Unknown version: ${version}`);
};

const parseFiles = (filesJson) => {
if (!filesJson || filesJson === 'null') return [];
try {
return JSON.parse(filesJson);
} catch {
return [];
}
};

const extractProposals = (files) => {
const proposals = new Set();
for (const f of files) {
const match = f.match(/^proposals\/([^/]+)\//);
if (match) proposals.add(match[1]);
}
return [...proposals].sort();
};

const run = (cmd) => {
console.log(` $ ${cmd}`);
try {
const output = execSync(cmd, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
if (output.trim()) {
console.log(output);
}
return true;
} catch (err) {
if (err.stdout) console.log(err.stdout);
if (err.stderr) console.error(err.stderr);
console.error(` Exit code: ${err.status}`);
return false;
}
};

// Collect proposals to validate from changed files
const toValidate = [];
const filesByVersion = [
[process.env.WIT_02_FILES, '0.2'],
[process.env.WIT_03_FILES, '0.3'],
];

for (const [filesJson, version] of filesByVersion) {
for (const proposal of extractProposals(parseFiles(filesJson))) {
toValidate.push({ proposal, version });
}
}

if (toValidate.length === 0) {
console.log('No proposals to validate');
process.exit(0);
}

let failed = false;

for (const { proposal, version } of toValidate) {
const witDir = witPath(proposal, version);
console.log(`::group::Validating ${proposal} v${version}`);

try {
console.log(` Path: ${witDir}`);

// Check wit-deps lock if deps.toml exists
if (fs.existsSync(`${witDir}/deps.toml`)) {
console.log(' Checking dependencies...');
if (!run(`wit-deps -m "${witDir}"/deps.toml -l "${witDir}"/deps.lock -d "${witDir}"/deps lock --check`)) {
console.log(`::error::wit-deps lock check failed for ${proposal} v${version}`);
failed = true;
}
}

// Validate WIT syntax
console.log(' Validating WIT...');
if (!run(`wasm-tools component wit "${witDir}" -o /dev/null`)) {
console.log(`::error::WIT validation failed for ${proposal} v${version}`);
failed = true;
}

// Validate wasm encoding
console.log(' Validating wasm encoding...');
if (!run(`wasm-tools component wit "${witDir}" --wasm -o /dev/null`)) {
console.log(`::error::wasm encoding failed for ${proposal} v${version}`);
failed = true;
}
} finally {
console.log('::endgroup::');
}
}

if (failed) {
console.log('\n❌ Validation failed');
process.exit(1);
} else {
console.log('\n✅ All proposals validated successfully');
process.exit(0);
}
45 changes: 45 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: CI

on:
push:
branches: [main]
paths:
- 'proposals/**/wit/**'
- 'proposals/**/wit-0.3.0-draft/**'
- '.github/scripts/**'
- '.github/workflows/ci.yml'
pull_request:
branches: [main]
paths:
- 'proposals/**/wit/**'
- 'proposals/**/wit-0.3.0-draft/**'
- '.github/scripts/**'
- '.github/workflows/ci.yml'

jobs:
validate:
name: Validate WIT
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
with:
list-files: json
filters: |
wit-02:
- 'proposals/*/wit/**'
wit-03:
- 'proposals/*/wit-0.3.0-draft/**'

- name: Install tools
if: steps.changes.outputs.wit-02 == 'true' || steps.changes.outputs.wit-03 == 'true'
uses: ./.github/actions/install-tools

- name: Validate changed proposals
if: steps.changes.outputs.wit-02 == 'true' || steps.changes.outputs.wit-03 == 'true'
run: node .github/scripts/validate-proposals.js
env:
WIT_02_FILES: ${{ steps.changes.outputs.wit-02_files }}
WIT_03_FILES: ${{ steps.changes.outputs.wit-03_files }}
21 changes: 21 additions & 0 deletions .github/workflows/lint-gh.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Lint GitHub Actions and Workflows

on:
push:
branches: [main]
paths:
- '.github/workflows/**'
- '.github/actions/**'
pull_request:
branches: [main]
paths:
- '.github/workflows/**'
- '.github/actions/**'

jobs:
actionlint:
name: Lint GitHub Actions
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: rhysd/actionlint@a443f344ff32813837fa49f7aa6cbc478d770e62 # v1.7.9