Publish #83
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: Publish | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| package: | |
| description: 'Package to release' | |
| required: true | |
| type: choice | |
| options: | |
| - eclipsa | |
| - create-eclipsa | |
| - image | |
| - content | |
| - motion | |
| - markdown | |
| - native-swiftui | |
| - native-android-compose | |
| - native-gtk4 | |
| release_type: | |
| description: 'Version bump type' | |
| required: true | |
| type: choice | |
| options: | |
| - patch | |
| - minor | |
| - major | |
| - alpha-patch | |
| - alpha-minor | |
| - alpha-major | |
| - beta-patch | |
| - beta-minor | |
| - beta-major | |
| permissions: | |
| id-token: write | |
| contents: write | |
| jobs: | |
| prepare: | |
| runs-on: ubuntu-latest | |
| concurrency: | |
| group: publish-${{ inputs.package }} | |
| cancel-in-progress: false | |
| permissions: | |
| contents: write | |
| id-token: write | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| PACKAGE_KEY: ${{ inputs.package }} | |
| INPUT_RELEASE_TYPE: ${{ inputs.release_type }} | |
| outputs: | |
| build_command: ${{ steps.package.outputs.build_command }} | |
| npm_tag: ${{ steps.metadata.outputs.npmTag }} | |
| package_json_path: ${{ steps.package.outputs.package_json_path }} | |
| publish_dir: ${{ steps.package.outputs.publish_dir }} | |
| publish_package_json_path: ${{ steps.package.outputs.publish_package_json_path }} | |
| native_host_matrix: ${{ steps.package.outputs.native_host_matrix }} | |
| tag: ${{ steps.metadata.outputs.tag }} | |
| version: ${{ steps.metadata.outputs.version }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '24' | |
| registry-url: 'https://registry.npmjs.org' | |
| - name: Verify trusted publishing runtime | |
| shell: bash | |
| run: | | |
| node -e " | |
| const parse = (version) => version.replace(/^v/, '').split('.').map(Number); | |
| const gte = (left, right) => { | |
| for (let i = 0; i < Math.max(left.length, right.length); i += 1) { | |
| const a = left[i] ?? 0; | |
| const b = right[i] ?? 0; | |
| if (a > b) return true; | |
| if (a < b) return false; | |
| } | |
| return true; | |
| }; | |
| const nodeVersion = process.versions.node; | |
| const npmVersion = require('child_process').execFileSync('npm', ['--version'], { encoding: 'utf8' }).trim(); | |
| if (!gte(parse(nodeVersion), parse('22.14.0'))) { | |
| throw new Error(\`Trusted publishing requires Node 22.14.0+, got \${nodeVersion}\`); | |
| } | |
| if (!gte(parse(npmVersion), parse('11.5.1'))) { | |
| throw new Error(\`Trusted publishing requires npm 11.5.1+, got \${npmVersion}\`); | |
| } | |
| " | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Resolve package paths | |
| id: package | |
| shell: bash | |
| run: | | |
| case "$PACKAGE_KEY" in | |
| eclipsa) | |
| package_dir="packages/eclipsa" | |
| ;; | |
| create-eclipsa) | |
| package_dir="packages/create-eclipsa" | |
| ;; | |
| image) | |
| package_dir="packages/image" | |
| ;; | |
| content) | |
| package_dir="packages/content" | |
| ;; | |
| motion) | |
| package_dir="packages/motion" | |
| ;; | |
| markdown) | |
| package_dir="packages/markdown" | |
| ;; | |
| native-swiftui) | |
| package_dir="packages/native-swiftui" | |
| ;; | |
| native-android-compose) | |
| package_dir="packages/native-android-compose" | |
| ;; | |
| native-gtk4) | |
| package_dir="packages/native-gtk4" | |
| ;; | |
| *) | |
| echo "Unsupported package: $PACKAGE_KEY" | |
| exit 1 | |
| ;; | |
| esac | |
| package_json_path="$package_dir/package.json" | |
| publish_dir="$package_dir/dist" | |
| publish_package_json_path="$publish_dir/package.json" | |
| build_command="bun run --filter ./$package_dir build" | |
| native_host_matrix="$(node -e " | |
| const packageKey = process.argv[1]; | |
| const matrices = { | |
| 'native-swiftui': [ | |
| { | |
| package: 'native-swiftui', | |
| host: 'macos-14', | |
| artifact: 'darwin-arm64', | |
| package_dir: 'packages/native-swiftui', | |
| build: 'swift build --package-path ./macos-swiftui --product EclipsaNativeMacOS', | |
| output: 'artifacts/darwin-arm64/EclipsaNativeMacOS', | |
| source: 'macos-swiftui/.build/debug/EclipsaNativeMacOS', | |
| }, | |
| { | |
| package: 'native-swiftui', | |
| host: 'macos-13', | |
| artifact: 'darwin-x64', | |
| package_dir: 'packages/native-swiftui', | |
| build: 'swift build --package-path ./macos-swiftui --product EclipsaNativeMacOS', | |
| output: 'artifacts/darwin-x64/EclipsaNativeMacOS', | |
| source: 'macos-swiftui/.build/debug/EclipsaNativeMacOS', | |
| }, | |
| ], | |
| 'native-android-compose': [ | |
| { | |
| package: 'native-android-compose', | |
| host: 'ubuntu-latest', | |
| artifact: 'android-universal', | |
| package_dir: 'packages/native-android-compose', | |
| build: './android-compose/gradlew --project-dir ./android-compose :app:assembleDebug', | |
| output: 'artifacts/android-universal/app-debug.apk', | |
| source: 'android-compose/app/build/outputs/apk/debug/app-debug.apk', | |
| }, | |
| ], | |
| 'native-gtk4': [ | |
| { | |
| package: 'native-gtk4', | |
| host: 'ubuntu-latest', | |
| artifact: 'gtk4-placeholder', | |
| package_dir: 'packages/native-gtk4', | |
| build: 'mkdir -p artifacts/gtk4-placeholder && touch artifacts/gtk4-placeholder/placeholder.json', | |
| output: 'artifacts/gtk4-placeholder/placeholder.json', | |
| source: 'artifacts/gtk4-placeholder/placeholder.json', | |
| }, | |
| ], | |
| }; | |
| process.stdout.write(JSON.stringify(matrices[packageKey] ?? [])); | |
| " "$PACKAGE_KEY")" | |
| if [ ! -r "$package_json_path" ]; then | |
| echo "package.json not found or not readable: $package_json_path" | |
| exit 1 | |
| fi | |
| echo "package_dir=$package_dir" >> "$GITHUB_OUTPUT" | |
| echo "package_json_path=$package_json_path" >> "$GITHUB_OUTPUT" | |
| echo "publish_dir=$publish_dir" >> "$GITHUB_OUTPUT" | |
| echo "publish_package_json_path=$publish_package_json_path" >> "$GITHUB_OUTPUT" | |
| echo "build_command=$build_command" >> "$GITHUB_OUTPUT" | |
| echo "native_host_matrix=$native_host_matrix" >> "$GITHUB_OUTPUT" | |
| - name: Resolve release metadata | |
| id: metadata | |
| shell: bash | |
| run: | | |
| metadata_json="$(bun scripts/release/resolve-release-metadata.ts \ | |
| --package-json '${{ steps.package.outputs.package_json_path }}' \ | |
| --package-key "$PACKAGE_KEY" \ | |
| --release-type "$INPUT_RELEASE_TYPE")" | |
| node -e " | |
| const data = JSON.parse(process.argv[1]); | |
| for (const [key, value] of Object.entries(data)) { | |
| process.stdout.write(\`\${key}=\${value}\n\`); | |
| } | |
| " "$metadata_json" >> "$GITHUB_OUTPUT" | |
| - name: Ensure release refs do not exist already | |
| shell: bash | |
| run: | | |
| if git rev-parse -q --verify "refs/tags/${{ steps.metadata.outputs.tag }}" >/dev/null; then | |
| echo "Tag already exists: ${{ steps.metadata.outputs.tag }}" | |
| exit 1 | |
| fi | |
| if gh release view "${{ steps.metadata.outputs.tag }}" >/dev/null 2>&1; then | |
| echo "Release already exists: ${{ steps.metadata.outputs.tag }}" | |
| exit 1 | |
| fi | |
| build_optimizer_bindings: | |
| if: ${{ inputs.package == 'eclipsa' }} | |
| needs: prepare | |
| runs-on: ${{ matrix.settings.host }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| settings: | |
| - host: macos-latest | |
| target: x86_64-apple-darwin | |
| build: bun ./scripts/run-napi.ts build --platform --release --manifest-path ../eclipsa/compiler/rust/Cargo.toml --package-json-path ./package.json --target-dir ../eclipsa/compiler/rust/target --output-dir ./generated --js-package-name @eclipsa/optimizer --target x86_64-apple-darwin | |
| - host: macos-latest | |
| target: aarch64-apple-darwin | |
| build: bun ./scripts/run-napi.ts build --platform --release --manifest-path ../eclipsa/compiler/rust/Cargo.toml --package-json-path ./package.json --target-dir ../eclipsa/compiler/rust/target --output-dir ./generated --js-package-name @eclipsa/optimizer --target aarch64-apple-darwin | |
| - host: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| build: bun ./scripts/run-napi.ts build --platform --release --manifest-path ../eclipsa/compiler/rust/Cargo.toml --package-json-path ./package.json --target-dir ../eclipsa/compiler/rust/target --output-dir ./generated --js-package-name @eclipsa/optimizer --target x86_64-pc-windows-msvc | |
| - host: windows-latest | |
| target: aarch64-pc-windows-msvc | |
| build: bun ./scripts/run-napi.ts build --platform --release --manifest-path ../eclipsa/compiler/rust/Cargo.toml --package-json-path ./package.json --target-dir ../eclipsa/compiler/rust/target --output-dir ./generated --js-package-name @eclipsa/optimizer --target aarch64-pc-windows-msvc | |
| - host: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| build: bun ./scripts/run-napi.ts build --platform --release --manifest-path ../eclipsa/compiler/rust/Cargo.toml --package-json-path ./package.json --target-dir ../eclipsa/compiler/rust/target --output-dir ./generated --js-package-name @eclipsa/optimizer --target x86_64-unknown-linux-gnu --use-napi-cross | |
| - host: ubuntu-latest | |
| target: aarch64-unknown-linux-gnu | |
| build: bun ./scripts/run-napi.ts build --platform --release --manifest-path ../eclipsa/compiler/rust/Cargo.toml --package-json-path ./package.json --target-dir ../eclipsa/compiler/rust/target --output-dir ./generated --js-package-name @eclipsa/optimizer --target aarch64-unknown-linux-gnu --use-napi-cross | |
| - host: ubuntu-latest | |
| target: x86_64-unknown-linux-musl | |
| build: bun ./scripts/run-napi.ts build --platform --release --manifest-path ../eclipsa/compiler/rust/Cargo.toml --package-json-path ./package.json --target-dir ../eclipsa/compiler/rust/target --output-dir ./generated --js-package-name @eclipsa/optimizer --target x86_64-unknown-linux-musl -x | |
| - host: ubuntu-latest | |
| target: aarch64-unknown-linux-musl | |
| build: bun ./scripts/run-napi.ts build --platform --release --manifest-path ../eclipsa/compiler/rust/Cargo.toml --package-json-path ./package.json --target-dir ../eclipsa/compiler/rust/target --output-dir ./generated --js-package-name @eclipsa/optimizer --target aarch64-unknown-linux-musl -x | |
| - host: ubuntu-latest | |
| target: wasm32-wasip1-threads | |
| build: bun ./scripts/run-napi.ts build --platform --release --manifest-path ../eclipsa/compiler/rust/Cargo.toml --package-json-path ./package.json --target-dir ../eclipsa/compiler/rust/target --output-dir ./generated --js-package-name @eclipsa/optimizer --target wasm32-wasip1-threads | |
| env: | |
| MACOSX_DEPLOYMENT_TARGET: '10.13' | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '24' | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.settings.target }} | |
| - name: Setup Zig | |
| if: ${{ contains(matrix.settings.target, 'musl') }} | |
| uses: mlugg/setup-zig@v2 | |
| with: | |
| version: 0.14.1 | |
| - name: Install cargo-zigbuild | |
| if: ${{ contains(matrix.settings.target, 'musl') }} | |
| uses: taiki-e/install-action@v2 | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| with: | |
| tool: cargo-zigbuild | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Update package version for build | |
| shell: bash | |
| run: | | |
| node -e " | |
| const fs = require('fs'); | |
| const path = process.argv[1]; | |
| const version = process.argv[2]; | |
| const pkg = JSON.parse(fs.readFileSync(path, 'utf8')); | |
| pkg.version = version; | |
| fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + '\n'); | |
| " 'packages/optimizer/package.json' '${{ needs.prepare.outputs.version }}' | |
| - name: Build binding | |
| shell: bash | |
| working-directory: packages/optimizer | |
| run: ${{ matrix.settings.build }} | |
| - name: Verify WASI binding entry | |
| if: ${{ matrix.settings.target == 'wasm32-wasip1-threads' }} | |
| shell: bash | |
| working-directory: packages/optimizer | |
| run: | | |
| node -e "const binding = require('./generated/optimizer.wasi.cjs'); if (typeof binding.compileClient !== 'function') { throw new Error('Expected compileClient export from WASI binding entry.'); }" | |
| - name: Upload binding artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: bindings-${{ matrix.settings.target }} | |
| path: packages/optimizer/generated/* | |
| if-no-files-found: error | |
| build_native_host_artifacts: | |
| if: ${{ inputs.package == 'native-swiftui' || inputs.package == 'native-android-compose' || inputs.package == 'native-gtk4' }} | |
| needs: prepare | |
| runs-on: ${{ matrix.settings.host }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| settings: ${{ fromJson(needs.prepare.outputs.native_host_matrix) }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| - name: Setup Java | |
| if: ${{ matrix.settings.package == 'native-android-compose' }} | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: '21' | |
| - name: Setup Android SDK | |
| if: ${{ matrix.settings.package == 'native-android-compose' }} | |
| uses: android-actions/setup-android@v3 | |
| - name: Install Android SDK packages | |
| if: ${{ matrix.settings.package == 'native-android-compose' }} | |
| shell: bash | |
| run: | | |
| yes | sdkmanager --licenses >/dev/null | |
| sdkmanager "platform-tools" "platforms;android-36" "build-tools;36.0.0" | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Build native host artifact | |
| shell: bash | |
| working-directory: ${{ matrix.settings.package_dir }} | |
| run: ${{ matrix.settings.build }} | |
| - name: Stage native host artifact | |
| shell: bash | |
| working-directory: ${{ matrix.settings.package_dir }} | |
| run: | | |
| mkdir -p "$(dirname '${{ matrix.settings.output }}')" | |
| cp '${{ matrix.settings.source }}' '${{ matrix.settings.output }}' | |
| - name: Upload native host artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.settings.artifact }} | |
| path: ${{ matrix.settings.package_dir }}/${{ matrix.settings.output }} | |
| if-no-files-found: error | |
| publish_eclipsa: | |
| if: ${{ inputs.package == 'eclipsa' }} | |
| needs: | |
| - prepare | |
| - build_optimizer_bindings | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| id-token: write | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '24' | |
| registry-url: 'https://registry.npmjs.org' | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: wasm32-wasip1-threads | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Update package versions for publish | |
| shell: bash | |
| run: | | |
| node -e " | |
| const fs = require('fs'); | |
| const version = process.argv[1]; | |
| const paths = process.argv.slice(2); | |
| for (const path of paths) { | |
| const pkg = JSON.parse(fs.readFileSync(path, 'utf8')); | |
| pkg.version = version; | |
| fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + '\n'); | |
| } | |
| " '${{ needs.prepare.outputs.version }}' 'packages/eclipsa/package.json' 'packages/optimizer/package.json' | |
| - name: Build optimizer JS package | |
| shell: bash | |
| run: bun run --filter @eclipsa/optimizer build:js | |
| - name: Build eclipsa package | |
| if: needs.prepare.outputs.build_command != '' | |
| shell: bash | |
| run: ${{ needs.prepare.outputs.build_command }} | |
| - name: Verify eclipsa dist package metadata | |
| shell: bash | |
| run: | | |
| publish_package_json_path='${{ needs.prepare.outputs.publish_package_json_path }}' | |
| if [ ! -r "$publish_package_json_path" ]; then | |
| echo "dist package.json not found or not readable: $publish_package_json_path" | |
| exit 1 | |
| fi | |
| node -e " | |
| const fs = require('fs'); | |
| const packageJsonPath = process.argv[1]; | |
| const expectedVersion = process.argv[2]; | |
| const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); | |
| if (pkg.private !== false) { | |
| throw new Error(\`Expected private=false in \${packageJsonPath}\`); | |
| } | |
| if (pkg.version !== expectedVersion) { | |
| throw new Error(\`Expected version \${expectedVersion} in \${packageJsonPath}, got \${pkg.version}\`); | |
| } | |
| if (!pkg.repository) { | |
| throw new Error(\`Expected repository in \${packageJsonPath}\`); | |
| } | |
| if (!pkg.exports) { | |
| throw new Error(\`Expected exports in \${packageJsonPath}\`); | |
| } | |
| " "$publish_package_json_path" '${{ needs.prepare.outputs.version }}' | |
| - name: Generate root WASI loader assets | |
| shell: bash | |
| working-directory: packages/optimizer | |
| run: bun run build:native -- --target wasm32-wasip1-threads | |
| - name: Create npm package directories | |
| shell: bash | |
| run: bun run --filter @eclipsa/optimizer create:npm-dirs | |
| - name: Download all binding artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: packages/optimizer/artifacts | |
| pattern: bindings-* | |
| merge-multiple: false | |
| - name: Flatten downloaded binding artifacts | |
| shell: bash | |
| working-directory: packages/optimizer | |
| run: bun ./scripts/prepare-downloaded-artifacts.ts | |
| - name: Sync npm package versions | |
| shell: bash | |
| run: bun run --filter @eclipsa/optimizer version:napi | |
| - name: Hydrate npm package artifacts | |
| shell: bash | |
| run: bun run --filter @eclipsa/optimizer artifacts | |
| - name: Publish optimizer native packages | |
| shell: bash | |
| run: | | |
| publish_args=(--provenance --access public) | |
| if [[ '${{ needs.prepare.outputs.npm_tag }}' != 'latest' ]]; then | |
| publish_args+=(--tag '${{ needs.prepare.outputs.npm_tag }}') | |
| fi | |
| for package_dir in packages/optimizer/npm/*; do | |
| if [[ ! -d "$package_dir" ]]; then | |
| continue | |
| fi | |
| package_json_path="$package_dir/package.json" | |
| if [[ ! -f "$package_json_path" ]]; then | |
| echo "Skipping package without package.json: $package_dir" | |
| continue | |
| fi | |
| package_name="$(node -e "const fs = require('fs'); const pkg = JSON.parse(fs.readFileSync(process.argv[1], 'utf8')); process.stdout.write(pkg.name ?? '');" "$package_json_path")" | |
| package_version="$(node -e "const fs = require('fs'); const pkg = JSON.parse(fs.readFileSync(process.argv[1], 'utf8')); process.stdout.write(pkg.version ?? '');" "$package_json_path")" | |
| if [[ -z "$package_name" || -z "$package_version" ]]; then | |
| echo "Skipping package with invalid name/version: $package_dir" | |
| continue | |
| fi | |
| if npm view "${package_name}@${package_version}" version --json >/dev/null 2>&1; then | |
| echo "Skipping already published package: ${package_name}@${package_version}" | |
| continue | |
| fi | |
| npm publish "$package_dir" "${publish_args[@]}" | |
| done | |
| - name: Pack optimizer tarball | |
| id: pack_optimizer | |
| shell: bash | |
| working-directory: packages/optimizer | |
| run: | | |
| bun ./scripts/sync-package-manifest.ts publish | |
| tarball_output="$(bun pm pack --quiet --destination "$RUNNER_TEMP")" | |
| tarball_output="$(echo "$tarball_output" | tr -d '\r\n')" | |
| if [[ "$tarball_output" = /* ]]; then | |
| tarball_path="$tarball_output" | |
| else | |
| tarball_path="$RUNNER_TEMP/$tarball_output" | |
| fi | |
| if [[ ! -f "$tarball_path" ]]; then | |
| echo "Tarball was not generated at expected path: $tarball_path" | |
| exit 1 | |
| fi | |
| echo "path=$tarball_path" >> "$GITHUB_OUTPUT" | |
| - name: Publish optimizer package | |
| shell: bash | |
| run: | | |
| optimizer_package_json='packages/optimizer/package.json' | |
| package_name="$(node -e "const fs = require('fs'); const pkg = JSON.parse(fs.readFileSync(process.argv[1], 'utf8')); process.stdout.write(pkg.name ?? '');" "$optimizer_package_json")" | |
| package_version="$(node -e "const fs = require('fs'); const pkg = JSON.parse(fs.readFileSync(process.argv[1], 'utf8')); process.stdout.write(pkg.version ?? '');" "$optimizer_package_json")" | |
| if [[ -z "$package_name" || -z "$package_version" ]]; then | |
| echo "Optimizer package.json is missing a valid name/version" | |
| exit 1 | |
| fi | |
| if npm view "${package_name}@${package_version}" version --json >/dev/null 2>&1; then | |
| echo "Skipping already published package: ${package_name}@${package_version}" | |
| exit 0 | |
| fi | |
| publish_args=(npm publish '${{ steps.pack_optimizer.outputs.path }}' --provenance --access public) | |
| if [[ '${{ needs.prepare.outputs.npm_tag }}' != 'latest' ]]; then | |
| publish_args+=(--tag '${{ needs.prepare.outputs.npm_tag }}') | |
| fi | |
| "${publish_args[@]}" | |
| - name: Pack eclipsa tarball | |
| id: pack_eclipsa | |
| shell: bash | |
| run: | | |
| publish_dir='${{ needs.prepare.outputs.publish_dir }}' | |
| tarball_output="$(cd "$publish_dir" && bun pm pack --quiet --destination "$RUNNER_TEMP")" | |
| tarball_output="$(echo "$tarball_output" | tr -d '\r\n')" | |
| if [[ "$tarball_output" = /* ]]; then | |
| tarball_path="$tarball_output" | |
| else | |
| tarball_path="$RUNNER_TEMP/$tarball_output" | |
| fi | |
| if [[ ! -f "$tarball_path" ]]; then | |
| echo "Tarball was not generated at expected path: $tarball_path" | |
| exit 1 | |
| fi | |
| echo "path=$tarball_path" >> "$GITHUB_OUTPUT" | |
| - name: Publish eclipsa package | |
| shell: bash | |
| run: | | |
| publish_args=(npm publish '${{ steps.pack_eclipsa.outputs.path }}' --provenance --access public) | |
| if [[ '${{ needs.prepare.outputs.npm_tag }}' != 'latest' ]]; then | |
| publish_args+=(--tag '${{ needs.prepare.outputs.npm_tag }}') | |
| fi | |
| "${publish_args[@]}" | |
| - name: Restore development manifest | |
| shell: bash | |
| run: bun run --filter @eclipsa/optimizer restore:manifest | |
| - name: Create release with generated notes | |
| shell: bash | |
| run: | | |
| gh release create '${{ needs.prepare.outputs.tag }}' \ | |
| --generate-notes \ | |
| --target '${{ github.sha }}' | |
| publish_other: | |
| if: ${{ inputs.package == 'native-swiftui' || inputs.package == 'native-android-compose' || inputs.package == 'native-gtk4' }} | |
| needs: | |
| - prepare | |
| - build_native_host_artifacts | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| id-token: write | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '24' | |
| registry-url: 'https://registry.npmjs.org' | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Download native host artifacts | |
| if: ${{ inputs.package == 'native-swiftui' || inputs.package == 'native-android-compose' }} | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: ${{ needs.prepare.outputs.publish_dir }}/../artifacts | |
| pattern: '*' | |
| merge-multiple: false | |
| - name: Update package version for publish | |
| shell: bash | |
| run: | | |
| node -e " | |
| const fs = require('fs'); | |
| const path = process.argv[1]; | |
| const version = process.argv[2]; | |
| const pkg = JSON.parse(fs.readFileSync(path, 'utf8')); | |
| pkg.version = version; | |
| if (pkg.private === true) { | |
| pkg.private = false; | |
| } | |
| fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + '\n'); | |
| " '${{ needs.prepare.outputs.package_json_path }}' '${{ needs.prepare.outputs.version }}' | |
| - name: Build package | |
| if: needs.prepare.outputs.build_command != '' | |
| shell: bash | |
| run: | | |
| if [[ '${{ inputs.package }}' == 'native-swiftui' || '${{ inputs.package }}' == 'native-android-compose' || '${{ inputs.package }}' == 'native-gtk4' ]]; then | |
| export ECLIPSA_NATIVE_REQUIRE_HOST_ARTIFACTS=1 | |
| fi | |
| ${{ needs.prepare.outputs.build_command }} | |
| - name: Verify dist package metadata | |
| shell: bash | |
| run: | | |
| publish_package_json_path='${{ needs.prepare.outputs.publish_package_json_path }}' | |
| if [ ! -r "$publish_package_json_path" ]; then | |
| echo "dist package.json not found or not readable: $publish_package_json_path" | |
| exit 1 | |
| fi | |
| node -e " | |
| const fs = require('fs'); | |
| const packageJsonPath = process.argv[1]; | |
| const expectedVersion = process.argv[2]; | |
| const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); | |
| if (pkg.private !== false) { | |
| throw new Error(\`Expected private=false in \${packageJsonPath}\`); | |
| } | |
| if (pkg.version !== expectedVersion) { | |
| throw new Error(\`Expected version \${expectedVersion} in \${packageJsonPath}, got \${pkg.version}\`); | |
| } | |
| if (!pkg.repository) { | |
| throw new Error(\`Expected repository in \${packageJsonPath}\`); | |
| } | |
| if (!pkg.exports) { | |
| throw new Error(\`Expected exports in \${packageJsonPath}\`); | |
| } | |
| " "$publish_package_json_path" '${{ needs.prepare.outputs.version }}' | |
| - name: Verify native host bundle metadata | |
| if: ${{ inputs.package == 'native-swiftui' || inputs.package == 'native-android-compose' || inputs.package == 'native-gtk4' }} | |
| shell: bash | |
| run: | | |
| host_manifest='${{ needs.prepare.outputs.publish_dir }}/host/manifest.json' | |
| if [ ! -r "$host_manifest" ]; then | |
| echo "host manifest not found or not readable: $host_manifest" | |
| exit 1 | |
| fi | |
| node -e " | |
| const fs = require('fs'); | |
| const hostManifestPath = process.argv[1]; | |
| const packageKey = process.argv[2]; | |
| const manifest = JSON.parse(fs.readFileSync(hostManifestPath, 'utf8')); | |
| if (manifest.formatVersion !== 1) { | |
| throw new Error(\`Expected formatVersion=1 in \${hostManifestPath}\`); | |
| } | |
| if (!Array.isArray(manifest.targets)) { | |
| throw new Error(\`Expected targets array in \${hostManifestPath}\`); | |
| } | |
| if (packageKey !== 'native-gtk4' && manifest.targets.length === 0) { | |
| throw new Error(\`Expected at least one bundled target in \${hostManifestPath}\`); | |
| } | |
| " "$host_manifest" '${{ inputs.package }}' | |
| - name: Pack package tarball | |
| id: pack | |
| shell: bash | |
| run: | | |
| publish_dir='${{ needs.prepare.outputs.publish_dir }}' | |
| tarball_output="$(cd "$publish_dir" && bun pm pack --quiet --destination "$RUNNER_TEMP")" | |
| tarball_output="$(echo "$tarball_output" | tr -d '\r\n')" | |
| if [[ "$tarball_output" = /* ]]; then | |
| tarball_path="$tarball_output" | |
| else | |
| tarball_path="$RUNNER_TEMP/$tarball_output" | |
| fi | |
| if [[ ! -f "$tarball_path" ]]; then | |
| echo "Tarball was not generated at expected path: $tarball_path" | |
| exit 1 | |
| fi | |
| echo "path=$tarball_path" >> "$GITHUB_OUTPUT" | |
| - name: Publish package tarball to npm | |
| shell: bash | |
| run: | | |
| publish_args=(npm publish '${{ steps.pack.outputs.path }}' --provenance --access public) | |
| if [[ '${{ needs.prepare.outputs.npm_tag }}' != 'latest' ]]; then | |
| publish_args+=(--tag '${{ needs.prepare.outputs.npm_tag }}') | |
| fi | |
| "${publish_args[@]}" | |
| - name: Create release with generated notes | |
| shell: bash | |
| run: | | |
| gh release create '${{ needs.prepare.outputs.tag }}' \ | |
| --generate-notes \ | |
| --target '${{ github.sha }}' | |
| publish_other_non_native: | |
| if: ${{ inputs.package != 'eclipsa' && inputs.package != 'native-swiftui' && inputs.package != 'native-android-compose' && inputs.package != 'native-gtk4' }} | |
| needs: prepare | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| id-token: write | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '24' | |
| registry-url: 'https://registry.npmjs.org' | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Update package version for publish | |
| shell: bash | |
| run: | | |
| node -e " | |
| const fs = require('fs'); | |
| const path = process.argv[1]; | |
| const version = process.argv[2]; | |
| const pkg = JSON.parse(fs.readFileSync(path, 'utf8')); | |
| pkg.version = version; | |
| if (pkg.private === true) { | |
| pkg.private = false; | |
| } | |
| fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + '\n'); | |
| " '${{ needs.prepare.outputs.package_json_path }}' '${{ needs.prepare.outputs.version }}' | |
| - name: Build package | |
| if: needs.prepare.outputs.build_command != '' | |
| shell: bash | |
| run: ${{ needs.prepare.outputs.build_command }} | |
| - name: Verify dist package metadata | |
| shell: bash | |
| run: | | |
| publish_package_json_path='${{ needs.prepare.outputs.publish_package_json_path }}' | |
| if [ ! -r "$publish_package_json_path" ]; then | |
| echo "dist package.json not found or not readable: $publish_package_json_path" | |
| exit 1 | |
| fi | |
| node -e " | |
| const fs = require('fs'); | |
| const packageJsonPath = process.argv[1]; | |
| const expectedVersion = process.argv[2]; | |
| const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); | |
| if (pkg.private !== false) { | |
| throw new Error(\`Expected private=false in \${packageJsonPath}\`); | |
| } | |
| if (pkg.version !== expectedVersion) { | |
| throw new Error(\`Expected version \${expectedVersion} in \${packageJsonPath}, got \${pkg.version}\`); | |
| } | |
| if (!pkg.repository) { | |
| throw new Error(\`Expected repository in \${packageJsonPath}\`); | |
| } | |
| if (!pkg.exports) { | |
| throw new Error(\`Expected exports in \${packageJsonPath}\`); | |
| } | |
| " "$publish_package_json_path" '${{ needs.prepare.outputs.version }}' | |
| - name: Pack package tarball | |
| id: pack | |
| shell: bash | |
| run: | | |
| publish_dir='${{ needs.prepare.outputs.publish_dir }}' | |
| tarball_output="$(cd "$publish_dir" && bun pm pack --quiet --destination "$RUNNER_TEMP")" | |
| tarball_output="$(echo "$tarball_output" | tr -d '\r\n')" | |
| if [[ "$tarball_output" = /* ]]; then | |
| tarball_path="$tarball_output" | |
| else | |
| tarball_path="$RUNNER_TEMP/$tarball_output" | |
| fi | |
| if [[ ! -f "$tarball_path" ]]; then | |
| echo "Tarball was not generated at expected path: $tarball_path" | |
| exit 1 | |
| fi | |
| echo "path=$tarball_path" >> "$GITHUB_OUTPUT" | |
| - name: Publish package tarball to npm | |
| shell: bash | |
| run: | | |
| publish_args=(npm publish '${{ steps.pack.outputs.path }}' --provenance --access public) | |
| if [[ '${{ needs.prepare.outputs.npm_tag }}' != 'latest' ]]; then | |
| publish_args+=(--tag '${{ needs.prepare.outputs.npm_tag }}') | |
| fi | |
| "${publish_args[@]}" | |
| - name: Create release with generated notes | |
| shell: bash | |
| run: | | |
| gh release create '${{ needs.prepare.outputs.tag }}' \ | |
| --generate-notes \ | |
| --target '${{ github.sha }}' |