diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..a843646 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,80 @@ +name: Deploy Tools + +on: + push: + branches: [main] + workflow_dispatch: + +concurrency: + group: tools-deploy + cancel-in-progress: false + +permissions: + contents: read + id-token: write + +env: + VPS_HOST: ${{ secrets.VPS_HOST }} + VPS_USER: ${{ secrets.VPS_USER }} + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + timeout-minutes: 90 + strategy: + fail-fast: false + matrix: + service: [tools-gateway, tools-workers, tools-frontend] + + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 0 + + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@v22 + with: + determinate: false + extra-conf: | + sandbox = false + accept-flake-config = true + + - name: Cache Nix + uses: DeterminateSystems/magic-nix-cache-action@v14 + with: + use-flakehub: false + + - name: Build ${{ matrix.service }} + id: build + run: | + nix build .#${{ matrix.service }} --impure --option sandbox false --print-build-logs + STORE_PATH=$(readlink result) + echo "store-path=$STORE_PATH" >> "$GITHUB_OUTPUT" + echo "✅ ${{ matrix.service }}: $STORE_PATH" + + - name: Setup SSH key + if: github.ref == 'refs/heads/main' + env: + SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }} + run: | + mkdir -p ~/.ssh + echo "$SSH_KEY" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + sed -i 's/\r$//' ~/.ssh/id_ed25519 + ssh-keygen -y -f ~/.ssh/id_ed25519 >/dev/null 2>&1 || { echo "SSH key invalid"; exit 1; } + ssh-keyscan -H "$VPS_HOST" >> ~/.ssh/known_hosts 2>/dev/null + + - name: Deploy ${{ matrix.service }} to VPS + if: github.ref == 'refs/heads/main' + run: | + STORE_PATH="${{ steps.build.outputs.store-path }}" + echo "=== Copying ${{ matrix.service }}: $STORE_PATH ===" + nix copy --to "ssh://${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }}" "$STORE_PATH" + + echo "=== Updating profile ===" + ssh "$VPS_USER@$VPS_HOST" "sudo /nix/var/nix/profiles/default/bin/nix-env --profile /nix/var/nix/profiles/${{ matrix.service }} --set '$STORE_PATH'" + + echo "=== Restarting service ===" + ssh "$VPS_USER@$VPS_HOST" "sudo systemctl restart ${{ matrix.service }}" || echo " ⚠️ restart failed (may not be enabled yet)" + + echo "✅ ${{ matrix.service }} deployed" \ No newline at end of file diff --git a/.github/workflows/notify-parent.yml b/.github/workflows/notify-parent.yml deleted file mode 100644 index 8db6602..0000000 --- a/.github/workflows/notify-parent.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Notify Parent Repo - -on: - push: - branches: - - main - workflow_dispatch: - -jobs: - dispatch: - runs-on: ubuntu-latest - steps: - - name: Trigger root monorepo build - uses: peter-evans/repository-dispatch@v3 - with: - token: ${{ secrets.DISPATCH_TOKEN }} - repository: asepharyana/asepharyana-hub - event-type: submodule-updated - client-payload: | - { - "service": "tools", - "ref": "${{ github.ref }}", - "sha": "${{ github.sha }}", - "actor": "${{ github.actor }}" - } diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..4e9fff3 --- /dev/null +++ b/flake.nix @@ -0,0 +1,119 @@ +{ + description = "Asepharyana Tools — document scanner & media processing tools (Rust gateway/workers + Next.js frontend)"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachSystem [ "x86_64-linux" ] (system: + let + pkgs = import nixpkgs { + inherit system; + config.allowUnfree = true; + }; + + # ── mkApp generator ── + mkApp = { name, src, buildScript, installScript, nativeBuildInputs ? [], buildInputs ? [] }: + pkgs.stdenv.mkDerivation { + inherit name src; + + nativeBuildInputs = with pkgs; [ + cacert curl gcc gnumake openssl pkg-config python3 libclang + ] ++ nativeBuildInputs; + + buildInputs = with pkgs; [ + nodejs openssl stdenv.cc.cc.lib libffi + ] ++ buildInputs; + + LIBCLANG_PATH = "${pkgs.libclang.lib}/lib"; + LD_LIBRARY_PATH = "${pkgs.libclang.lib}/lib:${pkgs.stdenv.cc.cc.lib}/lib:${pkgs.libffi}/lib"; + NIX_ENFORCE_PURITY = "0"; + + SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; + NODE_EXTRA_CA_CERTS = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; + NODE_ENV = "production"; + + phases = [ "unpackPhase" "buildPhase" "installPhase" ]; + buildPhase = '' + export HOME="$TMPDIR" CARGO_HOME="$TMPDIR/.cargo-${name}" + SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt + '' + buildScript; + installPhase = installScript; + }; + + cargoDeps = with pkgs; [ rustc cargo clang cmake pkg-config openssl.dev zlib ]; + + tools-gateway = mkApp { + name = "tools-gateway-0.1.0"; + src = ./.; + nativeBuildInputs = cargoDeps ++ [ pkgs.tesseract ]; + + buildScript = '' + cd backend + echo "=== Building tools-gateway ===" + cargo build --release --features tesseract --bin tools-gateway 2>&1 + ''; + + installScript = '' + mkdir -p $out/bin + cp target/release/tools-gateway $out/bin/tools-gateway + ''; + }; + + tools-workers = mkApp { + name = "tools-workers-0.1.0"; + src = ./.; + nativeBuildInputs = cargoDeps ++ [ pkgs.tesseract pkgs.leptonica ]; + + buildScript = '' + cd backend + echo "=== Building tools-workers ===" + cargo build --release --features tesseract --bin tools-workers 2>&1 + ''; + + installScript = '' + mkdir -p $out/bin + cp target/release/tools-workers $out/bin/tools-workers + ''; + }; + + tools-frontend = mkApp { + name = "tools-frontend-0.1.0"; + src = ./.; + nativeBuildInputs = with pkgs; [ bun ]; + + buildScript = '' + cd frontend + echo "=== Installing dependencies ===" + bun install 2>&1 + echo "=== Building Next.js ===" + bun run build 2>&1 + ''; + + installScript = '' + mkdir -p $out/share/tools-frontend $out/bin + cp -r .next $out/share/tools-frontend/ + cp -r public $out/share/tools-frontend/ 2>/dev/null || true + cp package.json $out/share/tools-frontend/ + cp -r node_modules $out/share/tools-frontend/ + cat > $out/bin/tools-frontend << WRAPPER +#!${pkgs.runtimeShell} +exec ${pkgs.bun}/bin/bun run --cwd $out/share/tools-frontend start +WRAPPER + chmod +x $out/bin/tools-frontend + ''; + }; + in + { + packages = { + inherit tools-gateway tools-workers tools-frontend; + default = tools-gateway; + }; + + devShells.default = pkgs.mkShell { + buildInputs = with pkgs; [ nodejs-slim_22 bun rustc cargo tesseract leptonica ]; + }; + }); +} \ No newline at end of file