Rust based release manager for JS/TS monorepos, heavily inspired by Vite+ ❤️
publish changelog rust release bun pnpm changeset version bump node
0

Configure Feed

Select the types of activity you want to include in your feed.

migrate CI from GitHub Actions to Tangled Spindles

- Replace .github/workflows/CI.yml with .tangled/workflows/ci.yml
- Replace chrono with time crate to enable macOS cross-compilation from Linux
- All 4 targets build via napi cross-compile (-x / --use-napi-cross)
- cargo-zigbuild and cargo-xwin from nixpkgs (no cargo install needed)
- Publish on release/* branches only, uses TANGLED_REF_NAME for npm tag

authored by

bdbch and committed by
Tangled
(May 24, 2026, 11:09 PM +0300) ce9dc4a6 d4a7a38c

+73 -193
-190
.github/workflows/CI.yml
··· 1 - name: CI 2 - env: 3 - DEBUG: napi:* 4 - APP_NAME: oxrls-native 5 - MACOSX_DEPLOYMENT_TARGET: '10.13' 6 - CARGO_INCREMENTAL: '1' 7 - 'on': 8 - push: 9 - branches: 10 - - main 11 - - 'release/*' 12 - pull_request: null 13 - concurrency: 14 - group: ${{ github.workflow }}-${{ github.ref }} 15 - cancel-in-progress: true 16 - jobs: 17 - lint: 18 - name: Lint 19 - runs-on: ubuntu-latest 20 - steps: 21 - - uses: actions/checkout@v6 22 - - name: Setup node 23 - uses: actions/setup-node@v6 24 - with: 25 - node-version: 24 26 - cache: yarn 27 - - name: Install 28 - uses: dtolnay/rust-toolchain@stable 29 - with: 30 - components: clippy, rustfmt 31 - - name: Install dependencies 32 - run: yarn install 33 - - name: Oxlint 34 - run: yarn lint 35 - - name: Cargo fmt 36 - run: cargo fmt -- --check 37 - - name: Clippy 38 - run: cargo clippy 39 - build: 40 - strategy: 41 - fail-fast: false 42 - matrix: 43 - settings: 44 - - host: macos-latest 45 - target: x86_64-apple-darwin 46 - build: yarn build --target x86_64-apple-darwin 47 - - host: windows-latest 48 - build: yarn build --target x86_64-pc-windows-msvc 49 - target: x86_64-pc-windows-msvc 50 - - host: ubuntu-latest 51 - target: x86_64-unknown-linux-gnu 52 - build: yarn build --target x86_64-unknown-linux-gnu --use-napi-cross 53 - - host: macos-latest 54 - target: aarch64-apple-darwin 55 - build: yarn build --target aarch64-apple-darwin 56 - name: stable - ${{ matrix.settings.target }} - node@22 57 - runs-on: ${{ matrix.settings.host }} 58 - steps: 59 - - uses: actions/checkout@v6 60 - - name: Setup node 61 - uses: actions/setup-node@v6 62 - with: 63 - node-version: 24 64 - cache: yarn 65 - - name: Install 66 - uses: dtolnay/rust-toolchain@stable 67 - with: 68 - toolchain: stable 69 - targets: ${{ matrix.settings.target }} 70 - - name: Cache cargo 71 - uses: actions/cache@v5 72 - with: 73 - path: | 74 - ~/.cargo/registry/index/ 75 - ~/.cargo/registry/cache/ 76 - ~/.cargo/git/db/ 77 - ~/.napi-rs 78 - .cargo-cache 79 - target/ 80 - key: ${{ matrix.settings.target }}-cargo-${{ matrix.settings.host }} 81 - - uses: mlugg/setup-zig@v2 82 - if: ${{ contains(matrix.settings.target, 'musl') }} 83 - with: 84 - version: 0.14.1 85 - - name: Install cargo-zigbuild 86 - uses: taiki-e/install-action@v2 87 - if: ${{ contains(matrix.settings.target, 'musl') }} 88 - env: 89 - GITHUB_TOKEN: ${{ github.token }} 90 - with: 91 - tool: cargo-zigbuild 92 - - name: Setup toolchain 93 - run: ${{ matrix.settings.setup }} 94 - if: ${{ matrix.settings.setup }} 95 - shell: bash 96 - - name: Install dependencies 97 - run: yarn install 98 - - name: Build 99 - run: ${{ matrix.settings.build }} 100 - shell: bash 101 - - name: Build oxrls CLI 102 - run: cargo build --release --bin oxrls 103 - shell: bash 104 - - name: Upload NAPI artifact 105 - uses: actions/upload-artifact@v7 106 - with: 107 - name: bindings-${{ matrix.settings.target }} 108 - path: | 109 - ${{ env.APP_NAME }}.*.node 110 - ${{ env.APP_NAME }}.*.wasm 111 - if-no-files-found: error 112 - - name: Upload oxrls binary 113 - uses: actions/upload-artifact@v7 114 - with: 115 - name: oxrls-${{ matrix.settings.target }} 116 - path: target/release/oxrls* 117 - if-no-files-found: error 118 - test: 119 - name: cargo test - ${{ matrix.settings.target }} 120 - needs: 121 - - build 122 - strategy: 123 - fail-fast: false 124 - matrix: 125 - settings: 126 - - host: windows-latest 127 - target: x86_64-pc-windows-msvc 128 - - host: macos-latest 129 - target: aarch64-apple-darwin 130 - - host: macos-latest 131 - target: x86_64-apple-darwin 132 - - host: ubuntu-latest 133 - target: x86_64-unknown-linux-gnu 134 - runs-on: ${{ matrix.settings.host }} 135 - steps: 136 - - uses: actions/checkout@v6 137 - - name: Install Rust 138 - uses: dtolnay/rust-toolchain@stable 139 - with: 140 - toolchain: stable 141 - targets: ${{ matrix.settings.target }} 142 - - name: Cache cargo 143 - uses: actions/cache@v5 144 - with: 145 - path: | 146 - ~/.cargo/registry/index/ 147 - ~/.cargo/registry/cache/ 148 - ~/.cargo/git/db/ 149 - target/ 150 - key: ${{ matrix.settings.target }}-test-${{ matrix.settings.host }} 151 - - name: Run tests 152 - run: cargo test 153 - publish: 154 - name: Publish 155 - if: startsWith(github.ref, 'refs/heads/release/') 156 - runs-on: ubuntu-latest 157 - permissions: 158 - id-token: write 159 - needs: 160 - - lint 161 - - test 162 - steps: 163 - - uses: actions/checkout@v6 164 - - name: Setup node 165 - uses: actions/setup-node@v6 166 - with: 167 - node-version: 24 168 - cache: yarn 169 - - name: Install dependencies 170 - run: yarn install 171 - - name: create npm dirs 172 - run: yarn napi create-npm-dirs 173 - - name: Download all artifacts 174 - uses: actions/download-artifact@v8 175 - with: 176 - path: artifacts 177 - - name: Move artifacts 178 - run: yarn artifacts 179 - - name: Determine version and tag 180 - run: | 181 - VERSION=$(node -p "require('./package.json').version") 182 - NPM_TAG="${GITHUB_REF_NAME#release/}" 183 - echo "VERSION=$VERSION" >> $GITHUB_ENV 184 - echo "NPM_TAG=$NPM_TAG" >> $GITHUB_ENV 185 - - name: Publish to npm 186 - run: | 187 - echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc 188 - npm publish --access public --tag ${{ env.NPM_TAG }} 189 - env: 190 - NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
+66
.tangled/workflows/ci.yml
··· 1 + when: 2 + - event: ["push", "manual"] 3 + branch: ["main", "release/*"] 4 + - event: ["pull_request"] 5 + branch: ["main"] 6 + 7 + engine: "nixery" 8 + 9 + dependencies: 10 + nixpkgs/nixpkgs-unstable: 11 + - nodejs_24 12 + - yarn 13 + - zig 14 + - llvm 15 + - rustup 16 + - cargo-zigbuild 17 + - cargo-xwin 18 + 19 + environment: 20 + CI: "true" 21 + 22 + steps: 23 + - name: "Install Node dependencies" 24 + command: yarn install 25 + 26 + - name: "Install Rust targets" 27 + command: | 28 + rustup target add \ 29 + x86_64-apple-darwin \ 30 + aarch64-apple-darwin \ 31 + x86_64-pc-windows-msvc 32 + 33 + - name: "Lint" 34 + command: | 35 + cargo fmt -- --check 36 + cargo clippy 37 + 38 + - name: "Build Linux x64" 39 + command: npx napi build --target x86_64-unknown-linux-gnu --release --use-napi-cross 40 + 41 + - name: "Build Windows x64" 42 + command: npx napi build --target x86_64-pc-windows-msvc --release -x 43 + 44 + - name: "Build macOS x64" 45 + command: npx napi build --target x86_64-apple-darwin --release -x 46 + 47 + - name: "Build macOS ARM64" 48 + command: npx napi build --target aarch64-apple-darwin --release -x 49 + 50 + - name: "Build CLI" 51 + command: cargo build --release --bin oxrls 52 + 53 + - name: "Test" 54 + command: cargo test 55 + 56 + - name: "Publish (release/* only)" 57 + command: | 58 + if [ "$TANGLED_REF_TYPE" = "branch" ] && [[ "$TANGLED_REF_NAME" == release/* ]]; then 59 + npx napi create-npm-dirs 60 + cp oxrls-native.linux-x64-gnu.node npm/linux-x64-gnu/ 61 + cp target/x86_64-apple-darwin/release/liboxrls.dylib npm/darwin-x64/oxrls-native.darwin-x64.node 62 + cp target/aarch64-apple-darwin/release/liboxrls.dylib npm/darwin-arm64/oxrls-native.darwin-arm64.node 63 + cp target/x86_64-pc-windows-msvc/release/oxrls.dll npm/win32-x64-msvc/oxrls-native.win32-x64-msvc.node 64 + echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc 65 + npm publish --access public --tag "${TANGLED_REF_NAME#release/}" 66 + fi
+1 -1
Cargo.toml
··· 25 25 inquire = "0.7" 26 26 rand = "0.8" 27 27 indexmap = { version = "2", features = ["serde"] } 28 - chrono = "0.4" 28 + time = { version = "0.3", features = ["formatting"] } 29 29 30 30 [dev-dependencies] 31 31 tempfile = "3"
+6 -2
src/changelog.rs
··· 134 134 pub fn generate_global_changelog_section( 135 135 packages: &[(String, semver::Version, BumpType, Vec<String>)], 136 136 ) -> String { 137 - use chrono::Utc; 137 + use time::OffsetDateTime; 138 138 139 139 let mut lines = Vec::new(); 140 140 141 - let date_str = Utc::now().format("%Y-%m-%d").to_string(); 141 + let date_format = 142 + time::format_description::parse("[year]-[month]-[day]").expect("valid date format"); 143 + let date_str = OffsetDateTime::now_utc() 144 + .format(&date_format) 145 + .expect("valid date"); 142 146 lines.push(format!("## {}", date_str)); 143 147 lines.push(String::new()); 144 148