Skip to content

Commit ae32ab8

Browse files
committed
feat: better handling of server installation path
The plugin should not assume its folder is writable. Instead, try to search for a writable folder by checking the data folder and the runtime paths. Also allows the user to give the path to the server's executable intead of always compiling it. All of this makes the plugin friendlier to restricted/read-only environments, like nix.
1 parent 3d2828a commit ae32ab8

7 files changed

Lines changed: 151 additions & 28 deletions

File tree

doc/gitlab.nvim.txt

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ Table of Contents *gitlab.nvim.table-of-contents*
2727
- Troubleshooting |gitlab.nvim.troubleshooting|
2828
- Api |gitlab.nvim.api|
2929

30-
3130
OVERVIEW *gitlab.nvim.overview*
3231

3332
This Neovim plugin is designed to make it easy to review Gitlab MRs from within
@@ -41,12 +40,10 @@ the editor. This means you can do things like:
4140
- View and manage pipeline Jobs
4241
- Upload files, jump to the browser, and a lot more!
4342

44-
4543
REQUIREMENTS *gitlab.nvim.requirements*
4644

4745
- Go >= v1.19
4846

49-
5047
QUICK START *gitlab.nvim.quick-start*
5148

5249
1. Install Go
@@ -137,14 +134,16 @@ Here an example how to use a custom `auth_provider`:
137134
}
138135
<
139136

140-
141137
CONFIGURING THE PLUGIN *gitlab.nvim.configuring-the-plugin*
142138

143139
Here is the default setup function. All of these values are optional, and if
144140
you call this function with no values the defaults will be used:
145141
>lua
146142
require("gitlab").setup({
147-
port = nil, -- The port of the Go server, which runs in the background, if omitted or `nil` the port will be chosen automatically
143+
server = {
144+
binary = nil, -- The path to the server binary. If omitted or nil, the server will be built
145+
port = nil, -- The port of the Go server, which runs in the background. If omitted or `nil` the port will be chosen automatically
146+
},
148147
log_path = vim.fn.stdpath("cache") .. "/gitlab.nvim.log", -- Log path for the Go server
149148
config_path = nil, -- Custom path for `.gitlab.nvim` file, please read the "Connecting to Gitlab" section
150149
debug = {
@@ -381,7 +380,6 @@ First, check out the branch that you want to review locally:
381380
Then open Neovim. To begin, try running the `summary` command or the `review`
382381
command.
383382

384-
385383
THE SUMMARY VIEW *gitlab.nvim.the-summary-view*
386384

387385
The `summary` action will open the MR title and description:
@@ -396,7 +394,6 @@ separate pane underneath the description. This can be disabled, and these
396394
fields can be reordered or removed. Please see the `settings.info` section of
397395
the configuration.
398396

399-
400397
REVIEWING AN MR *gitlab.nvim.reviewing-an-mr*
401398

402399
The `review` action will open a diff of the changes. You can leave comments
@@ -498,7 +495,6 @@ You can add or remove labels from the current MR.
498495
These labels will be visible in the summary panel, as long as you provide the
499496
"fields" string in your setup function under the `setting.info.fields` block.
500497

501-
502498
SIGNS AND DIAGNOSTICS *gitlab.nvim.signs-and-diagnostics*
503499

504500
By default when reviewing files, you will see diagnostics for comments that
@@ -532,7 +528,6 @@ You may skip resolved discussions by toggling `discussion_signs.skip_resolved_di
532528
in your setup function to `true`. By default, discussions from this plugin
533529
are shown at the INFO severity level (see :h vim.diagnostic.severity).
534530

535-
536531
EMOJIS *gitlab.nvim.emojis*
537532

538533
You can add or remove emojis from a note or comment in the discussion tree.
@@ -541,7 +536,6 @@ To see who has reacted with an emoji, hover over the emoji. A popup will
541536
appear with anyone who has responded with that emoji. You can only delete
542537
emojis that you have responded with.
543538

544-
545539
UPLOADING FILES *gitlab.nvim.uploading-files*
546540

547541
To attach a file to an MR description, reply, comment, and so forth use the
@@ -554,7 +548,6 @@ current line.
554548

555549
Use the `keymaps.popup.perform_action` to send the changes to Gitlab.
556550

557-
558551
MR APPROVALS *gitlab.nvim.mr-approvals*
559552

560553
You can approve or revoke approval for an MR with the `approve` and `revoke`
@@ -574,7 +567,6 @@ this command to work.
574567
<
575568
See |gitlab.nvim.merge| for more help on this function.
576569

577-
578570
CREATING AN MR *gitlab.nvim.creating-an-mr*
579571

580572
To create an MR for the current branch, make sure you have the branch checked
@@ -598,7 +590,6 @@ To re-trigger failed jobs in the pipeline manually, use the
598590
new Neovim buffer, use your `keymaps.popup.perform_linewise_action`
599591
keybinding.
600592

601-
602593
REVIEWERS AND ASSIGNEES *gitlab.nvim.reviewers-and-assignees*
603594

604595
The `add_reviewer` and `delete_reviewer` actions, as well as the `add_assignee`
@@ -678,7 +669,7 @@ by a |motion|.
678669
Either the operator or the motion can be preceded by a count, so that `3sj` is
679670
equivalent to `s3j`, and they both create a comment for the current line and
680671
three more lines downwards. Similarly, both `2s`|ap| and `s2`|ap| create a suggestion
681-
for two "outer" paragraphs.
672+
for two "outer" paragraphs.
682673

683674
The operators force |linewise| visual selection, so they work correctly even
684675
if the motion itself works |characterwise| (e.g., |i(| for selecting the inner

flake.lock

Lines changed: 61 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
inputs = {
3+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
4+
flake-utils.url = "github:numtide/flake-utils";
5+
};
6+
7+
outputs = { self, flake-utils, nixpkgs }:
8+
flake-utils.lib.eachDefaultSystem (system:
9+
let
10+
pkgs = import nixpkgs { inherit system; config.allowUnfree = true; };
11+
gitlab-nvim-server = pkgs.buildGoModule {
12+
pname = "gitlab.nvim-server";
13+
version = "git";
14+
src = ./.;
15+
vendorHash = "sha256-OLAKTdzqynBDHqWV5RzIpfc3xZDm6uYyLD4rxbh0DMg=";
16+
postInstall = ''
17+
cp -r ${./cmd/config} $out/bin/config
18+
mv $out/bin/cmd $out/bin/gitlab.nvim
19+
'';
20+
};
21+
gitlab-nvim = pkgs.vimUtils.buildVimPlugin {
22+
name = "gitlab.nvim";
23+
src = ./.;
24+
doCheck = false;
25+
};
26+
in
27+
rec {
28+
formatter = pkgs.nixpkgs-fmt;
29+
packages.gitlab-nvim-server = gitlab-nvim-server;
30+
packages.gitlab-nvim = gitlab-nvim;
31+
packages.default = packages.gitlab-nvim;
32+
}
33+
);
34+
}

lua/gitlab/init.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ local function setup(args)
4444
return
4545
end
4646

47-
server.build() -- Builds the Go binary if it doesn't exist
4847
state.merge_settings(args) -- Merges user settings with default settings
48+
server.build() -- Builds the Go binary if it doesn't exist
4949
state.set_global_keymaps() -- Sets keymaps that are not bound to a specific buffer
5050
require("gitlab.colors") -- Sets colors
5151
reviewer.init()

lua/gitlab/job.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ local M = {}
66

77
M.run_job = function(endpoint, method, body, callback)
88
local state = require("gitlab.state")
9-
local args = { "-s", "-X", (method or "POST"), string.format("localhost:%s", state.settings.port) .. endpoint }
9+
local args = { "-s", "-X", (method or "POST"), string.format("localhost:%s", state.settings.server.port) .. endpoint }
1010

1111
if body ~= nil then
1212
local encoded_body = vim.json.encode(body)

lua/gitlab/server.lua

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ end
3030

3131
-- Starts the Go server and call the callback provided
3232
M.start = function(callback)
33-
local port = tonumber(state.settings.port) or 0
33+
local port = tonumber(state.settings.server.port) or 0
3434
local parsed_port = nil
3535
local callback_called = false
3636

@@ -51,7 +51,7 @@ M.start = function(callback)
5151
settings = settings:gsub('"', '\\"')
5252
end
5353

54-
local command = string.format('"%s" "%s"', state.settings.bin, settings)
54+
local command = string.format('"%s" "%s"', state.settings.server.binary, settings)
5555

5656
local job_id = vim.fn.jobstart(command, {
5757
on_stdout = function(_, data)
@@ -61,7 +61,7 @@ M.start = function(callback)
6161
port = line:match("Server started on port:%s+(%d+)")
6262
if port ~= nil then
6363
parsed_port = port
64-
state.settings.port = port
64+
state.settings.server.port = port
6565
break
6666
end
6767
end
@@ -105,26 +105,54 @@ end
105105
-- Builds the Go binary with the current Git tag.
106106
M.build = function(override)
107107
local file_path = u.current_file_path()
108-
local parent_dir = vim.fn.fnamemodify(file_path, ":h:h:h:h")
108+
state.settings.root_path = vim.fn.fnamemodify(file_path, ":h:h:h:h")
109+
110+
-- If the user provided a path to the server, don't build it.
111+
if state.settings.server.binary ~= nil then
112+
local binary_exists = vim.loop.fs_stat(state.settings.server.binary)
113+
if binary_exists == nil then
114+
u.notify(string.format("The user-provided server path (%s) does not exist.", state.settings.server.binary), vim.log.levels.ERROR)
115+
end
116+
return
117+
end
118+
119+
-- If the user did not provide a path, we build it and place it in either the data path, or the
120+
-- first writable path we find in the runtime.
121+
local datapath = vim.fn.stdpath('data')
122+
local runtimepath = vim.api.nvim_list_runtime_paths()
123+
table.insert(runtimepath, 1, datapath)
124+
125+
local bin_folder
126+
for _, path in ipairs(runtimepath) do
127+
local ok, err = vim.loop.fs_access(path, 'w')
128+
if err == nil and ok ~= nil and ok then
129+
bin_folder = path .. u.path_separator .. "gitlab.nvim" .. u.path_separator .. "bin"
130+
if vim.fn.mkdir(bin_folder, "p") == 1 then
131+
state.settings.server.binary = bin_folder .. u.path_separator .. "server"
132+
break
133+
end
134+
end
135+
end
109136

110-
local bin_name = u.is_windows() and "bin.exe" or "bin"
111-
state.settings.root_path = parent_dir
112-
state.settings.bin = parent_dir .. u.path_separator .. "cmd" .. u.path_separator .. bin_name
137+
if state.settings.server.binary == nil then
138+
u.notify("Could not find a writable folder in the runtime path to save the server to.", vim.log.levels.ERROR)
139+
return
140+
end
113141

114142
if not override then
115-
local binary_exists = vim.loop.fs_stat(state.settings.bin)
143+
local binary_exists = vim.loop.fs_stat(state.settings.server.binary)
116144
if binary_exists ~= nil then
117145
return
118146
end
119147
end
120148

121-
local version_output = vim.system({ "git", "describe", "--tags", "--always" }, { cwd = parent_dir }):wait()
149+
local version_output = vim.system({ "git", "describe", "--tags", "--always" }, { cwd = state.settings.root_path }):wait()
122150
local version = version_output.code == 0 and vim.trim(version_output.stdout) or "unknown"
123151

124152
local ldflags = string.format("-X main.Version=%s", version)
125153
local res = vim
126154
.system(
127-
{ "go", "build", "-ldflags", ldflags, "-o", bin_name },
155+
{ "go", "build", "-buildvcs=false", "-ldflags", ldflags, "-o", state.settings.server.binary },
128156
{ cwd = state.settings.root_path .. u.path_separator .. "cmd" }
129157
)
130158
:wait()
@@ -133,6 +161,12 @@ M.build = function(override)
133161
u.notify(string.format("Failed to install with status code %d:\n%s", res.code, res.stderr), vim.log.levels.ERROR)
134162
return false
135163
end
164+
165+
local Path = require("plenary.path")
166+
local src = Path:new(state.settings.root_path .. u.path_separator .. "cmd" .. u.path_separator .. "config" )
167+
local dest = Path:new(bin_folder .. u.path_separator .. "config")
168+
src:copy({ destination = dest, recursive = true, override = true })
169+
136170
u.notify("Installed successfully!", vim.log.levels.INFO)
137171
return true
138172
end
@@ -185,7 +219,7 @@ M.get_version = function(callback)
185219
local version_output = vim.system({ "git", "describe", "--tags", "--always" }, { cwd = parent_dir }):wait()
186220
local plugin_version = version_output.code == 0 and vim.trim(version_output.stdout) or "unknown"
187221

188-
local args = { "-s", "-X", "GET", string.format("localhost:%s/version", state.settings.port) }
222+
local args = { "-s", "-X", "GET", string.format("localhost:%s/version", state.settings.server.port) }
189223

190224
-- We call the "/version" endpoint here instead of through the regular jobs pattern because earlier versions of the plugin
191225
-- may not have it. We handle a 404 as an "unknown" version error.

lua/gitlab/state.lua

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ end
4545
M.settings = {
4646
auth_provider = M.default_auth_provider,
4747
file_separator = u.path_separator,
48-
port = nil, -- choose random port
48+
server = {
49+
binary = nil, -- path to the server binary. if nil, it will be compiled, otherwise the existing binary at this path will be used
50+
port = nil, -- choose random port
51+
},
4952
debug = {
5053
request = false,
5154
response = false,

0 commit comments

Comments
 (0)