feat: initial release of V2X J2735 codec with Python & Node.js bindings #118
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: Core CI & Release | |
| on: | |
| push: | |
| branches: [main] | |
| tags: ['v*'] | |
| pull_request: | |
| branches: [main] | |
| jobs: | |
| verify-version: | |
| name: Verify Version Match | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - run: | | |
| TAG_VERSION=${GITHUB_REF_NAME#v} | |
| FILE_VERSION=$(cat VERSION) | |
| if [[ "$TAG_VERSION" != "$FILE_VERSION"* ]]; then | |
| echo "::error::Version Mismatch! Tag '$TAG_VERSION' vs VERSION '$FILE_VERSION'" | |
| exit 1 | |
| fi | |
| build-core: | |
| name: Build WASM Core | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Cache Emscripten | |
| id: cache-emsdk | |
| uses: actions/cache@v4 | |
| with: | |
| path: emsdk | |
| key: ${{ runner.os }}-emsdk-4.0.10 | |
| - name: Install Emscripten | |
| if: steps.cache-emsdk.outputs.cache-hit != 'true' | |
| run: | | |
| git clone https://github.com/emscripten-core/emsdk.git | |
| cd emsdk && ./emsdk install 4.0.10 && ./emsdk activate 4.0.10 | |
| - name: Compile | |
| run: | | |
| source emsdk/emsdk_env.sh | |
| make wasm | |
| # Create __init__.py files | |
| touch j2735codec/bindings/python/src/j2735codec/generated/__init__.py | |
| touch j2735codec/bindings/python/src/j2735codec/protobuf/__init__.py | |
| - name: Upload Python Artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: python-wasm-binaries | |
| # Use the parent directory to ensure the j2735codec folder structure is preserved | |
| path: j2735codec/bindings/python/src/j2735codec/ | |
| include-hidden-files: true | |
| - name: Upload Node Artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: node-wasm-binaries | |
| path: j2735codec/bindings/node/src/generated/ | |
| test-bindings: | |
| name: Test ${{ matrix.binding }} | |
| needs: build-core | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| binding: [python, node] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download Artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: ${{ matrix.binding }}-wasm-binaries | |
| path: j2735codec/bindings/${{ matrix.binding }}/${{ matrix.binding == 'python' && 'src/j2735codec/' || 'src/generated/' }} | |
| - name: Repair and Verify Structure | |
| run: | | |
| if [ "${{ matrix.binding }}" == "python" ]; then | |
| cd j2735codec/bindings/python/src/j2735codec | |
| touch __init__.py generated/__init__.py protobuf/__init__.py | |
| echo "🔍 Verifying Python Structure:" | |
| ls -R | |
| fi | |
| - name: Setup & Test | |
| run: | | |
| if [ "${{ matrix.binding }}" == "python" ]; then | |
| pip install uv | |
| cd j2735codec/bindings/python | |
| uv sync --reinstall-package j2735codec | |
| uv run pytest tests -s | |
| else | |
| npm install | |
| npm run build -w j2735codec | |
| npm test -w j2735codec | |
| fi | |
| publish-release: | |
| name: Publish Release | |
| needs: [verify-version, test-bindings] | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download Artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Build & Stage Assets | |
| run: | | |
| STAGING="$GITHUB_WORKSPACE/dist_release" | |
| mkdir -p "$STAGING" | |
| VERSION=$(cat VERSION) | |
| # --- 2. Build Python Bindings --- | |
| PY_DIR="j2735codec/bindings/python" | |
| # Clean and Recreate Structure | |
| mkdir -p "$PY_DIR/src/j2735codec/generated" | |
| mkdir -p "$PY_DIR/src/j2735codec/protobuf" | |
| # Copy artifacts - using '.' to ensure we copy contents into the pre-made folders | |
| cp -a artifacts/python-wasm-binaries/. "$PY_DIR/src/j2735codec/" | |
| # RE-INJECT Package Markers (Vital for Wheel packaging) | |
| touch "$PY_DIR/src/j2735codec/__init__.py" | |
| touch "$PY_DIR/src/j2735codec/generated/__init__.py" | |
| touch "$PY_DIR/src/j2735codec/protobuf/__init__.py" | |
| # Debug: Log the tree to the console so we can see what's happening | |
| echo "📂 Final Python Build Tree:" | |
| ls -R "$PY_DIR/src/j2735codec/" | |
| cp LICENSE "$PY_DIR/" | |
| cp NOTICE "$PY_DIR/" | |
| pip install uv | |
| cd "$PY_DIR" | |
| uv build --wheel --out-dir ./dist_local | |
| # Verify Wheel Contents before moving (Security Check) | |
| WHL_FILE=$(ls ./dist_local/*.whl) | |
| if ! unzip -l "$WHL_FILE" | grep -q "j2735codec/generated/j2735codec.wasm"; then | |
| echo "::error::WASM file missing from generated wheel!" | |
| exit 1 | |
| fi | |
| for f in ./dist_local/*; do cp "$f" "$STAGING/$(basename $f)"; done | |
| cd "$GITHUB_WORKSPACE" | |
| # --- 3. Build Node Bindings --- | |
| JS_DIR="j2735codec/bindings/node" | |
| mkdir -p "$JS_DIR/src/generated/" | |
| cp -a artifacts/node-wasm-binaries/. "$JS_DIR/src/generated/" | |
| cp LICENSE "$JS_DIR/" | |
| cp NOTICE "$JS_DIR/" | |
| npm install | |
| npm run build -w j2735codec | |
| cd "$JS_DIR" && npm pack | |
| for f in *.tgz; do cp "$f" "$STAGING/$f"; done | |
| cd "$GITHUB_WORKSPACE" | |
| # --- 4. Package Python Samples --- | |
| SAMPLE_DIR="etx/examples/python" | |
| if [ -d "$SAMPLE_DIR" ]; then | |
| cp LICENSE "$SAMPLE_DIR/" | |
| cp NOTICE "$SAMPLE_DIR/" | |
| # Inject the language wrapper (the wheel) | |
| mkdir -p "$SAMPLE_DIR/j2735codec" | |
| cp "$STAGING"/*.whl "$SAMPLE_DIR/j2735codec/" | |
| cd "$SAMPLE_DIR" | |
| VERSION=$(cat "$GITHUB_WORKSPACE/VERSION") | |
| ZIP_NAME="python-etx-samples-$VERSION.zip" | |
| zip -r "$STAGING/$ZIP_NAME" . \ | |
| -x "*config.json" -x "*/.venv/*" -x "*.venv*" -x "*/.env*" -x "*/__pycache__/*" | |
| cd "$GITHUB_WORKSPACE" | |
| fi | |
| # --- 5. Package Node/TS Samples --- | |
| NODE_SAMPLE_DIR="etx/examples/node" | |
| if [ -d "$NODE_SAMPLE_DIR" ]; then | |
| VERSION=$(cat "$GITHUB_WORKSPACE/VERSION") | |
| PKG_STAGING="$GITHUB_WORKSPACE/node_pkg_temp" | |
| mkdir -p "$PKG_STAGING" | |
| # 1. Copy the source (leaves your repo untouched) | |
| cp -r "$NODE_SAMPLE_DIR"/. "$PKG_STAGING/" | |
| # 2. Rewrite the path to the PORTABLE local path | |
| # This changes the monorepo path to the ZIP-friendly path | |
| sed -i "s|\"j2735codec\": \".*\"|\"j2735codec\": \"file:./j2735codec/j2735codec-$VERSION.tgz\"|g" "$PKG_STAGING/package.json" | |
| # 3. Inject the tarball into the staging area | |
| mkdir -p "$PKG_STAGING/j2735codec" | |
| cp "$STAGING"/j2735codec-$VERSION.tgz "$PKG_STAGING/j2735codec/" | |
| # 4. GENERATE THE LOCKFILE HERE | |
| # This lockfile will now contain the correct, portable reference to the codec | |
| cd "$PKG_STAGING" | |
| npm install --package-lock-only --no-workspaces | |
| # 5. ZIP EVERYTHING | |
| # Now the ZIP contains a package.json and a package-lock.json | |
| # that both point to the local ./j2735codec folder. | |
| ZIP_NAME="node-etx-samples-$VERSION.zip" | |
| zip -r "$STAGING/$ZIP_NAME" . -x "node_modules/*" "dist/*" | |
| # We zip EVERYTHING (*) in this folder, excluding ONLY the junk | |
| zip -r "$STAGING/$ZIP_NAME" . \ | |
| -x "certs/*" "dist/*" "node_modules/*" "config.json" ".env*" "npm-debug.log*" | |
| cd "$GITHUB_WORKSPACE" | |
| rm -rf "$PKG_STAGING" | |
| fi | |
| # --- 6. Finalize Staging --- | |
| cp "$PY_DIR/src/j2735codec/generated/j2735codec.wasm" "$STAGING/j2735codec-$VERSION.wasm" | |
| cp LICENSE "$STAGING/" | |
| cp NOTICE "$STAGING/" | |
| # --- 7. FIXED Safe Cleanup --- | |
| echo "🧹 Performing final cleanup..." | |
| # Do NOT use -delete on a broad glob. Delete specific files. | |
| rm -f "$STAGING"/.DS_Store | |
| rm -f "$STAGING"/.env | |
| rm -f "$STAGING"/default.gitignore | |
| echo "✅ Contents of $STAGING for release:" | |
| ls -la "$STAGING" | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| name: "Release ${{ github.ref_name }}" | |
| files: dist_release/* | |
| generate_release_notes: true |