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

Add :Octo discussion create command #900

Merged
merged 6 commits into from
Feb 25, 2025
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,8 @@ If no command is passed, the argument to `Octo` is treated as a URL from where a
| search | <query> | Search GitHub for issues and PRs matching the [query](https://docs.github.com/en/search-github/searching-on-github/searching-issues-and-pull-requests) |
| run | list | List workflow runs |
| notification | list | Shows current unread notifications |
| discussion | list [repo] | List open discussions for current or specified repo |
| | create [repo] | Create discussion for current or specified repo |

0. `[repo]`: If repo is not provided, it will be derived from `<cwd>/.git/config`.

Expand Down
8 changes: 8 additions & 0 deletions doc/octo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ See |octo-command-examples| for examples.
system clipboard.


:Octo discussion [action] {args} *octo-commands-discussion*

list [repo] Lists all open discussions for the current or specified repo.
In-menu mappings:
<C-y> Copy URL to system clipboard.
create [repo] Creates a new discussion for the current or specified repo.


:Octo repo [action] *octo-commands-repo*

list Lists repos the user owns, contributes, or belongs to.
Expand Down
10 changes: 10 additions & 0 deletions lua/octo/commands.lua
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ function M.setup()
local opts = M.process_varargs(repo, ...)
picker.discussions(opts)
end,
create = function(repo, ...)
local opts = M.process_varargs(repo, ...)

if not opts.repo then
utils.error "No repo found"
return
end

require("octo.discussions").create(opts)
end,
},
milestone = {
list = function(repo, ...)
Expand Down
119 changes: 119 additions & 0 deletions lua/octo/discussions.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
--- Helpers for discussions
local gh = require "octo.gh"
local graphql = require "octo.gh.graphql"
local utils = require "octo.utils"

local M = {}

---@class DiscussionMutationOpts
---@field repo_id string
---@field category_id string
---@field title string
---@field body string

--- Discussion mutation
---@param opts DiscussionMutationOpts
local create_discussion = function(opts)
gh.api.graphql {
query = graphql "create_discussion_mutation",
fields = {
repo_id = opts.repo_id,
category_id = opts.category_id,
title = opts.title,
body = opts.body,
},
jq = ".data.createDiscussion.discussion",
opts = {
cb = gh.create_callback {
success = function(output)
utils.info("Successfully created discussion " .. opts.title)
local resp = vim.json.decode(output)
utils.copy_url(resp.url)
end,
},
},
}
end

---@class Category
---@field id string
---@field name string
---@field emoji string

---Select a category
---@param categories Category[]
---@param cb fun(selected: Category)
local select_a_category = function(categories, cb)
vim.ui.select(categories, {
prompt = "Pick a category: ",
format_item = function(item)
return item.name
end,
}, function(selected)
if selected == nil then
return
end
cb(selected)
end)
end

---@class GetCategoriesOpts
---@field owner string
---@field name string

---Get categories for a repository
---@param opts GetCategoriesOpts
---@param cb fun(selected: Category)
local get_categories = function(opts, cb)
gh.api.graphql {
query = graphql "discussion_categories_query",
jq = ".data.repository.discussionCategories.nodes",
fields = { owner = opts.owner, name = opts.name },
opts = {
cb = gh.create_callback {
success = function(data)
local categories = vim.json.decode(data)
select_a_category(categories, cb)
end,
},
},
}
end

---@class DiscussionOpts
---@field repo string
---@field title string|nil
---@field body string|nil

---Create a discussion for a repository
---@param opts DiscussionOpts
---@return nil
M.create = function(opts)
opts = opts or {}

opts.owner, opts.name = utils.split_repo(opts.repo)
local repo_info = utils.get_repo_info(opts.repo)

if not repo_info.hasDiscussionsEnabled then
utils.error(opts.repo .. " doesn't have discussions enabled")
return
end

opts.repo_id = repo_info.id

if not opts.title then
opts.title = utils.input { prompt = "Creating discussion for " .. opts.repo .. ". Enter title" }
end
if not opts.body then
opts.body = utils.input { prompt = "Discussion body" }
end

local cb = function(selected)
opts.category_id = selected.id

create_discussion(opts)
end
get_categories(opts, cb)
end

return M
31 changes: 31 additions & 0 deletions lua/octo/gh/graphql.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1075,6 +1075,36 @@ query(
}
]] .. fragments.discussion_info

M.discussion_categories_query = [[
query($owner: String!, $name: String!) {
repository(owner: $owner, name: $name) {
discussionCategories(first: 20) {
nodes {
id
name
emoji
}
}
}
}
]]

M.create_discussion_mutation = [[
mutation($repo_id: ID!, $category_id: ID!, $title: String!, $body: String!) {
createDiscussion(input: {
repositoryId: $repo_id,
categoryId: $category_id,
title: $title,
body: $body
}) {
discussion {
id
url
}
}
}
]]

M.discussion_query = [[
query($owner: String!, $name: String!, $number: Int!, $endCursor: String) {
repository(owner: $owner, name: $name) {
Expand Down Expand Up @@ -1701,6 +1731,7 @@ query($owner: String!, $name: String!) {
isMirror
mirrorUrl
hasProjectsEnabled
hasDiscussionsEnabled
projectsUrl
homepageUrl
primaryLanguage {
Expand Down
18 changes: 16 additions & 2 deletions lua/octo/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -727,9 +727,8 @@ function M.get_repo_info(repo)
end

local owner, name = M.split_repo(repo)
local query = graphql "repository_query"
local output = gh.api.graphql {
query = query,
query = graphql "repository_query",
fields = { owner = owner, name = name },
jq = ".data.repository",
opts = { mode = "sync" },
Expand Down Expand Up @@ -1796,4 +1795,19 @@ function M.get_icon(entry)
return M.icons.unknown
end

--
M.copy_url = function(url, register)
register = register or "+"
vim.fn.setreg(register, url, "c")
M.info("Copied '" .. url .. "' to the system clipboard (+ register)")
end

M.input = function(opts)
vim.fn.inputsave()
local value = vim.fn.input(opts)
vim.fn.inputrestore()

return value
end

return M
Loading