Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Projects v2, take 2 #477

Merged
merged 5 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,15 @@ Edit and review GitHub issues and pull requests from the comfort of your favorit
## 🎯 Requirements

- Install [GitHub CLI](https://cli.github.com/)
- If you'd like to use [Projects v2](https://docs.github.com/en/issues/planning-and-tracking-with-projects)
you will need to add the `read:project` scope to your `gh` token. You can
do so by running `gh auth refresh -s read:project`.
- If you'd like to actually modify projects you can instead add the `project`
scope to your token instead.
- Install [plenary.nvim](https://github.com/nvim-lua/plenary.nvim)
- Install [telescope.nvim](https://github.com/nvim-telescope/telescope.nvim)
- Install one of:
- [telescope.nvim](https://github.com/nvim-telescope/telescope.nvim)
- [fzf-lua](https://github.com/ibhagwan/fzf-lua)
- Install [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons)

## 📦 Installation
Expand All @@ -73,6 +80,7 @@ use {
requires = {
'nvim-lua/plenary.nvim',
'nvim-telescope/telescope.nvim',
-- OR 'ibhagwan/fzf-lua',
'nvim-tree/nvim-web-devicons',
},
config = function ()
Expand Down Expand Up @@ -112,9 +120,14 @@ require"octo".setup({
snippet_context_lines = 4; -- number or lines around commented lines
gh_env = {}, -- extra environment variables to pass on to GitHub CLI, can be a table or function returning a table
timeout = 5000, -- timeout for requests between the remote server
default_to_projects_v2 = false, -- use projects v2 for the `Octo card ...` command by default. Both legacy and v2 commands are available under `Octo cardlegacy ...` and `Octo cardv2 ...` respectively.
ui = {
use_signcolumn = true, -- show "modified" marks on the sign column
},
picker = "telescope", -- "telescope" | "fzf-lua"
picker_config = {
use_emojis = false, -- Only used in fzf-lua picker. If you want emojis when viewing the picker set to true.
},
issues = {
order_by = { -- criteria to sort results of `Octo issue list`
field = "CREATED_AT", -- either COMMENTS, CREATED_AT or UPDATED_AT (https://docs.github.com/en/graphql/reference/enums#issueorderfield)
Expand Down
18 changes: 17 additions & 1 deletion doc/octo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,23 @@ Can I use treesitter markdown parser with octo buffers?~
>lua
vim.keymap.set("i", "@", "@<C-x><C-o>", { silent = true, buffer = true })
vim.keymap.set("i", "#", "#<C-x><C-o>", { silent = true, buffer = true })
<


I can't see my v2 projects in issues and/or pull requests!~

(and I see a warning when I open them)

You are missing a scope from the token gh uses. You can add the scope to
your gh token with

`gh auth refresh -s read:project`

Alternatively if you want to be able to modify projects (i.e. add/remove
cards) you need to add the `project` scope to your token instead.

If you don't care about projects v2 you can suppress the warning by setting
`suppress_missing_scope.project_v2 = true` in your Octo config.


CREDITS *octo-credits*

Expand Down
111 changes: 110 additions & 1 deletion lua/octo/commands.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,32 @@ function M.setup()
vim.api.nvim_create_user_command("Octo", function(opts)
require("octo.commands").octo(unpack(opts.fargs))
end, { complete = require("octo.completion").octo_command_complete, nargs = "*" })
local conf = config.values

local card_commands

if conf.default_to_projects_v2 then
card_commands = {
set = function()
M.set_project_v2_card()
end,
remove = function()
M.remove_project_v2_card()
end,
}
else
card_commands = {
add = function()
M.add_project_card()
end,
move = function()
M.move_project_card()
end,
remove = function()
M.remove_project_card()
end,
}
end

-- supported commands
M.commands = {
Expand Down Expand Up @@ -295,7 +321,16 @@ function M.setup()
M.reaction_action "HEART"
end,
},
card = {
card = card_commands,
cardv2 = {
set = function(...)
M.set_project_v2_card()
end,
remove = function()
M.remove_project_v2_card()
end,
},
cardlegacy = {
add = function()
M.add_project_card()
end,
Expand Down Expand Up @@ -1291,6 +1326,80 @@ function M.move_project_card()
end)
end

function M.set_project_v2_card()
local bufnr = vim.api.nvim_get_current_buf()
local buffer = octo_buffers[bufnr]
if not buffer then
return
end

-- show column selection picker
picker.project_columns_v2(function(project_id, field_id, value)
-- add new card
local add_query = graphql("add_project_v2_item_mutation", buffer.node.id, project_id)
gh.run {
args = { "api", "graphql", "--paginate", "-f", string.format("query=%s", add_query) },
cb = function(add_output, add_stderr)
if add_stderr and not utils.is_blank(add_stderr) then
utils.error(add_stderr)
elseif add_output then
local resp = vim.fn.json_decode(add_output)
local update_query = graphql(
"update_project_v2_item_mutation",
project_id,
resp.data.addProjectV2ItemById.item.id,
field_id,
value
)
gh.run {
args = { "api", "graphql", "--paginate", "-f", string.format("query=%s", update_query) },
cb = function(update_output, update_stderr)
if update_stderr and not utils.is_blank(update_stderr) then
utils.error(update_stderr)
elseif update_output then
-- TODO do update here
-- refresh issue/pr details
require("octo").load(buffer.repo, buffer.kind, buffer.number, function(obj)
writers.write_details(bufnr, obj, true)
buffer.node.projectCards = obj.projectCards
end)
end
end,
}
end
end,
}
end)
end

function M.remove_project_v2_card()
local bufnr = vim.api.nvim_get_current_buf()
local buffer = octo_buffers[bufnr]
if not buffer then
return
end

-- show card selection picker
picker.project_cards_v2(function(project_id, item_id)
-- delete card
local query = graphql("delete_project_v2_item_mutation", project_id, item_id)
gh.run {
args = { "api", "graphql", "--paginate", "-f", string.format("query=%s", query) },
cb = function(output, stderr)
if stderr and not utils.is_blank(stderr) then
utils.error(stderr)
elseif output then
-- refresh issue/pr details
require("octo").load(buffer.repo, buffer.kind, buffer.number, function(obj)
buffer.node.projectCards = obj.projectCards
writers.write_details(bufnr, obj, true)
end)
end
end,
}
end)
end

function M.reload(bufnr)
require("octo").load_buffer(bufnr)
end
Expand Down
6 changes: 2 additions & 4 deletions lua/octo/completion.lua
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@ function M.octo_command_complete(argLead, cmdLine)
return get_options(command_keys)
elseif #parts == 2 and vim.tbl_contains(command_keys, parts[2]) or #parts == 3 then
local obj = octo_commands.commands[parts[2]]
if obj then
if type(obj) == "table" then
return get_options(vim.tbl_keys(obj))
end
if type(obj) == "table" then
return get_options(vim.tbl_keys(obj))
end
end
end
Expand Down
13 changes: 13 additions & 0 deletions lua/octo/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ local M = {}
---@field field string
---@field direction "ASC" | "DESC"

---@class OctoMissingScopeConfig
---@field projects_v2 boolean

---@class OctoConfig Octo configuration settings
---@field picker OctoPickers
---@field picker_config OctoPickerConfig
Expand All @@ -60,6 +63,8 @@ local M = {}
---@field snippet_context_lines number
---@field gh_env table
---@field timeout number
---@field default_to_projects_v2 boolean
---@field suppress_missing_scope OctoMissingScopeConfig
---@field ui OctoConfigUi
---@field issues OctoConfigIssues
---@field pull_requests OctoConfigPR
Expand Down Expand Up @@ -98,6 +103,10 @@ function M.get_default_values()
snippet_context_lines = 4,
gh_env = {},
timeout = 5000,
default_to_projects_v2 = false,
suppress_missing_scope = {
projects_v2 = false,
},
ui = {
use_signcolumn = true,
},
Expand Down Expand Up @@ -361,6 +370,10 @@ function M.validate_config()
validate_type(config.enable_builtin, "enable_builtin", "boolean")
validate_type(config.snippet_context_lines, "snippet_context_lines", "number")
validate_type(config.timeout, "timeout", "number")
validate_type(config.default_to_projects_v2, "default_to_projects_v2", "boolean")
if validate_type(config.suppress_missing_scope, "supress_missing_scope", "table") then
validate_type(config.suppress_missing_scope.projects_v2, "supress_missing_scope.projects_v2", "boolean")
end
validate_type(config.gh_env, "gh_env", "table")
validate_type(config.reaction_viewer_hint_icon, "reaction_viewer_hint_icon", "string")
validate_type(config.user_icon, "user_icon", "string")
Expand Down
28 changes: 28 additions & 0 deletions lua/octo/gh/fragments.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
local M = {}

M.projects_v2_fragment = [[
projectItems(first: 100) {
nodes {
id
project {
id
title
}
fieldValues(first: 100) {
nodes {
... on ProjectV2ItemFieldSingleSelectValue {
name
optionId
field {
... on ProjectV2SingleSelectField {
name
}
}
}
}
}
}
}
]]

return M
Loading
Loading