Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

197 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿš€ deploy.nvim

A powerful Neovim plugin for seamlessly deploying files to remote servers using rsync as the transfer backend.

โœจ Features

  • ๐Ÿ“ค Fast File Deployment - Deploy files to remote servers on save and/or with a single command
  • ๐ŸŽฏ Multiple Host Support - Configure multiple deployment targets
  • ๐Ÿ”ง Custom Rewrite Functions - Transform file paths before deployment or abort deployment
  • ๐Ÿ“ Auto Directory Creation - Automatically creates remote directories if they don't exist
  • ๐ŸŽจ Custom Host Input - Deploy to ad-hoc addresses on the fly
  • โšก Async Operations - Non-blocking deployments using nvim-nio

๐Ÿ“‹ Requirements

  • Neovim >= 0.9.0
  • rsync installed on your system
  • SSH access to remote servers without password (exchanged SSH keys)
  • nvim-nio - Dependency for this plugin

๐Ÿ“ฆ Installation

{
  "KoinBanks/deploy.nvim",
  dependencies = { "nvim-neotest/nvim-nio" },
  config = function()
    require("deploy").setup({
      -- your configuration here
    })
  end,
}
use {
  "KoinBanks/deploy.nvim",
  requires = { "nvim-neotest/nvim-nio" },
  config = function()
    require("deploy").setup({
      -- your configuration here
    })
  end,
}
Plug 'nvim-neotest/nvim-nio'
Plug 'KoinBanks/deploy.nvim'

" In your init.vim or init.lua:
lua << EOF
require("deploy").setup({
  -- your configuration here
})
EOF

โš™๏ธ Configuration

Basic Setup

require("deploy").setup({
  timeout = 3, -- rsync timeout in seconds
  hosts = {
    {
      label = "Production Server",
      address = "prod.example.com",
    },
    {
      label = "Staging Server",
      address = "staging.example.com",
    },
  },
  mappings = {
    {
      fs = "~/projects/myapp",
      remote = "/var/www/myapp",
    },
  },
})

Advanced Configuration with Rewrite Functions

require("deploy").setup({
  timeout = 5,
  hosts = {
    {
      label = "Production",
      address = "prod.example.com",
      -- Optional: Transform paths before deployment for this host
      rewrite = function(context)
        -- context.source: local file path
        -- context.destination: remote file path
        -- context.address: host address
        -- context.extension: file extension

        -- Example: Skip deployment for test files
        if context.source:match("%.test%.") then
          return false -- abort deployment
        end

        -- Modify the destination path
        context.destination = context.destination:gsub("%.dev%.", ".")
        -- Return nil or nothing to continue deployment
      end,
    },
    {
      label = "Development",
      address = "dev.example.com",
    },
  },
  mappings = {
    {
      fs = "~/projects/frontend",
      remote = "/var/www/html",
      -- Optional: Transform paths for this mapping
      rewrite = function(context)
        -- Example: Deploy .ts files as .js files
        if context.extension == "ts" then
          context.destination = context.destination:gsub("%.ts$", ".js")
        end
      end,
    },
    {
      fs = "~/projects/backend",
      remote = "/opt/backend",
    },
  },
})

๐ŸŽฎ Usage

Commands

Deploy Current File

:Deploy file
" or
:Deploy buffer

Deploys the current buffer to a remote server. You'll be prompted to select a host.

Toggle Auto-Deploy on Save

:Deploy toggle

Enables or disables automatic deployment whenever you save a file.

Lua API

local deploy = require("deploy.lib")

-- Deploy a specific file
deploy.deploy_file("/path/to/file.lua", {
  silent = false, -- Show notifications
  deploy_to_last_host = false, -- Prompt for host selection
})

-- Deploy to last used host without prompting
deploy.deploy_file("/path/to/file.lua", {
  deploy_to_last_host = true,
})

-- Toggle auto-deploy on save
deploy.toggle_deploy_on_save()

-- Enable auto-deploy on save
deploy.toggle_deploy_on_save(true)

-- Disable auto-deploy on save
deploy.toggle_deploy_on_save(false)

-- Check if a file is deployable
if deploy.is_deployable("/path/to/file.lua") then
  print("File can be deployed")
end

-- Get the mapping for a file
local mapping = deploy.get_file_mapping("/path/to/file.lua")
if mapping then
  print("Local: " .. mapping.fs)
  print("Remote: " .. mapping.remote)
end

Keybindings Example

vim.keymap.set("n", "<leader>df", ":Deploy file<CR>", { desc = "Deploy current file" })
vim.keymap.set("n", "<leader>dt", ":Deploy toggle<CR>", { desc = "Toggle deploy on save" })

-- Or using Lua API
vim.keymap.set("n", "<leader>df", function()
  require("deploy.lib").deploy_file(vim.fn.expand("%:p"), { silent = false })
end, { desc = "Deploy current file" })

vim.keymap.set("n", "<leader>dl", function()
  require("deploy.lib").deploy_file(vim.fn.expand("%:p"), {
    silent = false,
    deploy_to_last_host = true,
  })
end, { desc = "Deploy to last host" })

## ๐Ÿ” How It Works

1. **File Mapping**: When you deploy a file, deploy.nvim checks your `mappings` configuration to find which local path matches your file
2. **Host Selection**: You're prompted to select a destination host (or it uses the last selected host)
3. **Path Transformation**: The local path is transformed to the remote path based on the mapping
4. **Rewrite Functions**: If configured, rewrite functions are executed (mapping rewrite first, then host rewrite)
5. **Deployment**: `rsync` is used to transfer the file over SSH
6. **Error Handling**: If the remote directory doesn't exist, it's automatically created and deployment is retried

## ๐Ÿ“š Configuration Types

### DeployHost

```lua
---@class DeployHost
---@field address string The host address (e.g., "example.com" or "192.168.1.100")
---@field label string A human-readable label for the host
---@field rewrite? function Optional function to transform paths for this host

DeployMapping

---@class DeployMapping
---@field fs string Local filesystem folder (e.g., "~/projects/myapp")
---@field remote string Remote folder (e.g., "/var/www/myapp")
---@field rewrite? function Optional function to transform paths for this mapping

DeployConfig

---@class DeployConfig
---@field timeout number Rsync timeout in seconds (default: 3)
---@field hosts DeployHost[] Array of deployment hosts
---@field mappings DeployMapping[] Array of path mappings

๐Ÿฉบ Health Check

Run :checkhealth deploy to verify your setup and check for:

  • Rsync installation
  • SSH connectivity
  • Configuration issues

๐Ÿค Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

๐Ÿ“„ License

MIT

๐Ÿ™ Acknowledgments

  • Built with nvim-nio for async operations
  • Uses rsync for reliable file transfers

About

Neovim plugin that allows easy deployment of source files through SFTP or Rsync.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages