name: Nucleation CI/CD
on:
push:
branches: [ main, master ]
paths:
- 'src/**'
- 'Cargo.toml'
- 'Cargo.lock'
- '.github/workflows/**'
pull_request:
branches: [ main, master ]
workflow_dispatch:
permissions:
contents: write
env:
CARGO_TERM_COLOR: always
jobs:
check-version:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
should_release: ${{ steps.check.outputs.should_release }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Get current version
id: version
run: |
VERSION=$(grep -m1 'version = ' Cargo.toml | cut -d '"' -f2)
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Found version: $VERSION"
- name: Check if version changed
id: check
run: |
if [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" =~ ^refs/heads/(main|master)$ ]]; then
if git diff HEAD^ HEAD --name-only | grep -q "Cargo.toml"; then
OLD_VERSION=$(git show HEAD^:Cargo.toml | grep -m1 'version = ' | cut -d '"' -f2)
CURRENT_VERSION=$(grep -m1 'version = ' Cargo.toml | cut -d '"' -f2)
if [[ "$OLD_VERSION" != "$CURRENT_VERSION" ]]; then
echo "should_release=true" >> $GITHUB_OUTPUT
else
echo "should_release=false" >> $GITHUB_OUTPUT
fi
else
echo "should_release=false" >> $GITHUB_OUTPUT
fi
else
echo "should_release=false" >> $GITHUB_OUTPUT
fi
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Run tests
run: |
cargo test # Test default (no features)
build-wasm:
needs: [test, check-version]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
target: wasm32-unknown-unknown
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.lock') }}
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Build Rust
run: cargo build --release - name: Build WASM
run: |
chmod +x ./build-wasm.sh
./build-wasm.sh
- name: Organize output
run: |
mkdir -p release-artifacts
cp -r pkg/* release-artifacts/
cp target/release/libnucleation.* release-artifacts/ || true
cp README.md LICENSE release-artifacts/
- name: Upload nucleation WASM artifacts
uses: actions/upload-artifact@v4
with:
name: nucleation-wasm-v${{ needs.check-version.outputs.version }}-web
path: release-artifacts
build-nucleation:
needs: [test, check-version]
strategy:
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
ext: so
platform: linux-x64
- os: macos-13
target: x86_64-apple-darwin
ext: dylib
platform: macos-x64
- os: macos-14
target: aarch64-apple-darwin
ext: dylib
platform: macos-arm64
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- run: rustup target add ${{ matrix.target }}
- name: Build nucleation native library
run: cargo build --release --target ${{ matrix.target }} --features ffi
- name: Move nucleation library output
run: |
mkdir -p release-artifacts
# Rename the library file to include platform
cp target/${{ matrix.target }}/release/libnucleation.${{ matrix.ext }} release-artifacts/libnucleation-${{ matrix.platform }}.${{ matrix.ext }}
- name: Upload nucleation library artifacts
uses: actions/upload-artifact@v4
with:
name: nucleation-v${{ needs.check-version.outputs.version }}-${{ matrix.platform }}
path: release-artifacts
build-php:
needs: [test, check-version]
strategy:
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
ext: so
platform: linux-x64
php-version: '8.4'
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
ext: so
platform: linux-x64
php-version: '8.3'
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
ext: so
platform: linux-x64
php-version: '8.2'
- os: macos-13
target: x86_64-apple-darwin
ext: dylib
platform: macos-x64
php-version: '8.4'
- os: macos-14
target: aarch64-apple-darwin
ext: dylib
platform: macos-arm64
php-version: '8.4'
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: none
tools: php-config
- name: Setup Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: ${{ matrix.target }}
override: true
- name: Install cargo-php
run: cargo install cargo-php --locked
- name: Install cargo-php (ignore stub generation issues)
run: cargo install cargo-php --locked || echo "cargo-php installation failed, using pre-generated stubs"
- name: Build PHP extension (Linux)
if: runner.os == 'Linux'
run: cargo build --release --target ${{ matrix.target }} --features php
- name: Build PHP extension (macOS)
if: runner.os == 'macOS'
env:
RUSTFLAGS: "-C link-arg=-undefined -C link-arg=dynamic_lookup"
run: cargo build --release --target ${{ matrix.target }} --features php
- name: Use pre-generated PHP stubs
run: |
# Use pre-generated stubs instead of trying to generate them
if [ ! -f nucleation-stubs.php ]; then
echo "Error: nucleation-stubs.php not found in repository"
exit 1
fi
echo "✅ Using pre-generated PHP stubs"
- name: Organize PHP extension output
run: |
mkdir -p release-artifacts
# Copy the extension with descriptive name
if [ "${{ matrix.ext }}" = "so" ]; then
cp target/${{ matrix.target }}/release/libnucleation.so "release-artifacts/nucleation-php${{ matrix.php-version }}-${{ matrix.platform }}.so"
else
cp target/${{ matrix.target }}/release/libnucleation.dylib "release-artifacts/nucleation-php${{ matrix.php-version }}-${{ matrix.platform }}.dylib"
fi
# Copy stubs for IDE support
cp nucleation-stubs.php release-artifacts/
# Create installation instructions
cat > release-artifacts/INSTALL.md << EOF
# Nucleation PHP Extension Installation
## Requirements
- PHP ${{ matrix.php-version }}+
- Platform: ${{ matrix.platform }}
## Installation
### Automatic Installation (Recommended)
\`\`\`bash
# Download and run install script
curl -sSL https://install.nucleation.dev/php | bash
\`\`\`
### Manual Installation
1. Copy the extension file to your PHP extensions directory:
\`\`\`bash
sudo cp nucleation-php${{ matrix.php-version }}-${{ matrix.platform }}.${{ matrix.ext }} \$(php-config --extension-dir)/nucleation.${{ matrix.ext }}
\`\`\`
2. Add to your php.ini or create a conf.d file:
\`\`\`bash
echo "extension=nucleation.${{ matrix.ext }}" | sudo tee \$(php --ini | grep "Scan for additional" | cut -d: -f2 | xargs)/20-nucleation.ini
\`\`\`
3. Restart your web server/PHP-FPM:
\`\`\`bash
# For Apache
sudo systemctl restart apache2
# For Nginx + PHP-FPM
sudo systemctl restart php${{ matrix.php-version }}-fpm nginx
# For development server
# No restart needed
\`\`\`
4. Verify installation:
\`\`\`bash
php -m | grep nucleation
php -r "var_dump(nucleation_version());"
php -r "echo nucleation_hello();"
\`\`\`
## IDE Support
Include \`nucleation-stubs.php\` in your project for full IDE autocompletion:
\`\`\`php
<?php
// At the top of your PHP files or in your IDE configuration
require_once 'path/to/nucleation-stubs.php';
// Now you get full autocompletion
\$schematic = new Nucleation\\Schematic("MyBuilding");
\$schematic->loadFromData(\$data); // <- IDE autocompletes this
\`\`\`
## Usage Examples
\`\`\`php
<?php
// Basic usage
\$schematic = new Nucleation\\Schematic("CoolBuild");
\$schematic->setMetadataAuthor("Builder123");
// Load from file
\$data = file_get_contents("build.litematic");
\$schematic->loadFromData(\$data);
// Get info
\$info = \$schematic->getInfo();
echo "Blocks: " . \$schematic->getBlockCount() . PHP_EOL;
// Convert formats
\$inputData = file_get_contents("input.schem");
\$litematicData = nucleation_convert_format(\$inputData, "litematic");
file_put_contents("output.litematic", \$litematicData);
\`\`\`
EOF
- name: Test PHP extension
run: |
# Install the extension for testing
EXT_DIR=$(php-config --extension-dir)
sudo mkdir -p "$EXT_DIR"
if [ "${{ matrix.ext }}" = "so" ]; then
sudo cp target/${{ matrix.target }}/release/libnucleation.so "$EXT_DIR/nucleation.so"
echo "extension=nucleation.so" | sudo tee $(php --ini | grep "Scan for additional" | cut -d: -f2 | xargs)/20-nucleation.ini
else
sudo cp target/${{ matrix.target }}/release/libnucleation.dylib "$EXT_DIR/nucleation.dylib"
echo "extension=nucleation.dylib" | sudo tee $(php --ini | grep "Scan for additional" | cut -d: -f2 | xargs)/20-nucleation.ini
fi
# Test basic functionality
php -r "var_dump(extension_loaded('nucleation'));" || exit 1
php -r "echo 'Hello test: ' . nucleation_hello() . PHP_EOL;" || exit 1
php -r "print_r(nucleation_version());" || exit 1
echo "✅ PHP extension tests passed!"
- name: Upload PHP extension artifacts
uses: actions/upload-artifact@v4
with:
name: nucleation-php${{ matrix.php-version }}-v${{ needs.check-version.outputs.version }}-${{ matrix.platform }}
path: release-artifacts
publish:
needs: [check-version, build-wasm, build-nucleation, build-php]
if: needs.check-version.outputs.should_release == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Download nucleation WASM
uses: actions/download-artifact@v4
with:
name: nucleation-wasm-v${{ needs.check-version.outputs.version }}-web
path: release-artifacts
- name: Download nucleation (Linux x64)
uses: actions/download-artifact@v4
with:
name: nucleation-v${{ needs.check-version.outputs.version }}-linux-x64
path: release-artifacts
- name: Download nucleation (macOS x64)
uses: actions/download-artifact@v4
with:
name: nucleation-v${{ needs.check-version.outputs.version }}-macos-x64
path: release-artifacts
- name: Download nucleation (macOS ARM64)
uses: actions/download-artifact@v4
with:
name: nucleation-v${{ needs.check-version.outputs.version }}-macos-arm64
path: release-artifacts
- name: Download PHP extensions
uses: actions/download-artifact@v4
with:
pattern: nucleation-php*-v${{ needs.check-version.outputs.version }}-*
path: release-artifacts
merge-multiple: true
- name: Publish to crates.io
uses: actions-rs/cargo@v1
with:
command: publish
args: --allow-dirty --token ${{ secrets.CRATES_IO_TOKEN }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18.x'
registry-url: 'https://registry.npmjs.org'
- name: Update and Publish npm package
run: |
cd release-artifacts
node -e "
const fs = require('fs');
const path = './package.json';
const pkg = JSON.parse(fs.readFileSync(path, 'utf8'));
pkg.version = '${{ needs.check-version.outputs.version }}';
pkg.description = 'A high-performance Minecraft schematic parser and utility library';
pkg.repository = { type: 'git', url: 'https://github.com/Nano112/Nucleation' };
pkg.homepage = 'https://github.com/Nano112/Nucleation';
pkg.author = 'Nano <nano@schem.at>';
pkg.license = 'MIT OR Apache-2.0';
fs.writeFileSync(path, JSON.stringify(pkg, null, 2));
"
npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install maturin & Publish
run: |
pip install maturin
maturin publish --features python --username __token__ --password ${{ secrets.PYPI_API_TOKEN }}
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ needs.check-version.outputs.version }}
name: Release v${{ needs.check-version.outputs.version }}
generate_release_notes: true
files: release-artifacts/**