Skip to content

Commit

Permalink
Release (#440)
Browse files Browse the repository at this point in the history
* Feat: Enable sorting discussions by original comment (#422)
* Feat: Improve popup UX (#426)
* Feat: Automatically update MR summary details (#427)
* Feat: Show update progress in winbar (#432)
* Feat: Abbreviate winbar (#439)
* Fix: Note Creation Bug (#441)
* Fix: Checking whether comment can be created (#434)
* Fix: Syntax in discussion tree (#433)
* fix: improve indication of resolved threads and drafts (#442)
* Docs: Various minor improvements (#445)

---------

Co-authored-by: Jakub F. Bortlík <[email protected]>
  • Loading branch information
harrisoncramer and jakubbortlik authored Dec 11, 2024
1 parent be02733 commit 495e64c
Show file tree
Hide file tree
Showing 32 changed files with 883 additions and 567 deletions.
2 changes: 1 addition & 1 deletion .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Thank you for taking time to contribute to this plugin! Please follow these step

It's possible that the feature you want is already implemented, or does not belong in `gitlab.nvim` at all. By creating an issue first you can have a conversation with the maintainers about the functionality first. While this is not strictly necessary, it greatly increases the likelihood that your merge request will be accepted.

2. Fork the repository, and create a new feature branch for your desired functionality. Make your changes.
2. Fork the repository, and create a new feature branch off the `develop` branch for your desired functionality. Make your changes.

If you are using Lazy as a plugin manager, the easiest way to work on changes is by setting a specific path for the plugin that points to your repository locally. This is what I do:

Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/go.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ on:
branches:
- main
- develop
paths:
- 'cmd/**' # Ignore changes to the Lua code
- 'go.sum'
- 'go.mod'
jobs:
go_lint:
name: Lint Go 💅
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/lua.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ on:
branches:
- main
- develop
paths:
- 'lua/**' # Ignore changes to the Go code
jobs:
lua_lint:
name: Lint Lua 💅
Expand Down
54 changes: 25 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ This Neovim plugin is designed to make it easy to review Gitlab MRs from within
- View and manage pipeline Jobs
- Upload files, jump to the browser, and a lot more!

![Screenshot 2024-01-13 at 10 43 32 AM](https://github.com/harrisoncramer/gitlab.nvim/assets/32515581/8dd8b961-a6b5-4e09-b87f-dc4a17b14149)
![Screenshot 2024-01-13 at 10 43 17 AM](https://github.com/harrisoncramer/gitlab.nvim/assets/32515581/079842de-e8a4-45c5-98c2-dcafc799c904)
![Screenshot 2024-12-08 at 5 43 53 PM](https://github.com/user-attachments/assets/cb9e94e3-3817-4846-ba44-16ec06ea7654)

https://github.com/harrisoncramer/gitlab.nvim/assets/32515581/dc5c07de-4ae6-4335-afe1-d554e3804372

Expand All @@ -36,47 +35,48 @@ For more detailed information about the Lua APIs please run `:h gitlab.nvim.api`
With <a href="https://github.com/folke/lazy.nvim">Lazy</a>:

```lua
return {
{
"harrisoncramer/gitlab.nvim",
dependencies = {
"MunifTanjim/nui.nvim",
"nvim-lua/plenary.nvim",
"sindrets/diffview.nvim",
"stevearc/dressing.nvim", -- Recommended but not required. Better UI for pickers.
"nvim-tree/nvim-web-devicons" -- Recommended but not required. Icons in discussion tree.
"nvim-tree/nvim-web-devicons", -- Recommended but not required. Icons in discussion tree.
},
enabled = true,
build = function () require("gitlab.server").build(true) end, -- Builds the Go binary
config = function()
require("gitlab").setup()
end,
}
```

And with Packer:
And with <a href="https://github.com/lewis6991/pckr.nvim">pckr.nvim</a>:

```lua
use {
"harrisoncramer/gitlab.nvim",
requires = {
"MunifTanjim/nui.nvim",
"nvim-lua/plenary.nvim",
"sindrets/diffview.nvim"
"stevearc/dressing.nvim", -- Recommended but not required. Better UI for pickers.
"nvim-tree/nvim-web-devicons", -- Recommended but not required. Icons in discussion tree.
},
build = function()
require("gitlab.server").build()
end,
branch = "develop",
config = function()
require("diffview") -- We require some global state from diffview
local gitlab = require("gitlab")
gitlab.setup()
end,
}
{
"harrisoncramer/gitlab.nvim",
requires = {
"MunifTanjim/nui.nvim",
"nvim-lua/plenary.nvim",
"sindrets/diffview.nvim",
"stevearc/dressing.nvim", -- Recommended but not required. Better UI for pickers.
"nvim-tree/nvim-web-devicons", -- Recommended but not required. Icons in discussion tree.
},
run = function() require("gitlab.server").build() end, -- Builds the Go binary
config = function()
require("diffview") -- We require some global state from diffview
require("gitlab").setup()
end,
}
```

Add `branch = "develop",` to your configuration if you want to use the (possibly unstable) development version of `gitlab.nvim`.

## Contributing

Contributions to the plugin are welcome. Please read [.github/CONTRIBUTING.md](.github/CONTRIBUTING.md) before you start working on a pull request.

## Connecting to Gitlab

This plugin requires an <a href="https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#create-a-personal-access-token">auth token</a> to connect to Gitlab. The token can be set in the root directory of the project in a `.gitlab.nvim` environment file, or can be set via a shell environment variable called `GITLAB_TOKEN` instead. If both are present, the `.gitlab.nvim` file will take precedence.
Expand Down Expand Up @@ -122,7 +122,3 @@ For a list of all these settings please run `:h gitlab.nvim.configuring-the-plug
The plugin sets up a number of useful keybindings in the special buffers it creates, and some global keybindings as well. Refer to the relevant section of the manual `:h gitlab.nvim.keybindings` for more details.

For more information about each of these commands, and about the APIs in general, run `:h gitlab.nvim.api`

## Contributing

Contributions to the plugin are welcome. Please read [.github/CONTRIBUTING.md](.github/CONTRIBUTING.md) before you start working on a pull request.
45 changes: 21 additions & 24 deletions after/syntax/gitlab.vim
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,26 @@ if filereadable($VIMRUNTIME . '/syntax/markdown.vim')
source $VIMRUNTIME/syntax/markdown.vim
endif

syntax match Date "\v\d+\s+\w+\s+ago"
highlight link Date GitlabDate

execute 'syntax match Unresolved /\s' . g:gitlab_discussion_tree_unresolved . '\s\?/'
highlight link Unresolved GitlabUnresolved

execute 'syntax match Resolved /\s' . g:gitlab_discussion_tree_resolved . '\s\?/'
highlight link Resolved GitlabResolved

execute 'syntax match GitlabDiscussionOpen /^\s*' . g:gitlab_discussion_tree_expander_open . '/'
highlight link GitlabDiscussionOpen GitlabExpander

execute 'syntax match GitlabDiscussionClosed /^\s*' . g:gitlab_discussion_tree_expander_closed . '/'
highlight link GitlabDiscussionClosed GitlabExpander

execute 'syntax match Draft /' . g:gitlab_discussion_tree_draft . '/'
highlight link Draft GitlabDraft

execute 'syntax match Username "@[a-zA-Z0-9.]\+"'
highlight link Username GitlabUsername

execute 'syntax match Mention "\%(' . g:gitlab_discussion_tree_expander_open . '\|'
\ . g:gitlab_discussion_tree_expander_closed . '\)\@<!@[a-zA-Z0-9.]*"'
highlight link Mention GitlabMention
let expanders = '^\s*\%(' . g:gitlab_discussion_tree_expander_open . '\|' . g:gitlab_discussion_tree_expander_closed . '\)'
let username = '@[a-zA-Z0-9.]\+'

" Covers times like '14 days ago', 'just now', as well as 'October 3, 2024'
let time_ago = '\d\+ \w\+ ago'
let formatted_date = '\w\+ \{1,2}\d\{1,2}, \d\{4}'
let date = '\%(' . time_ago . '\|' . formatted_date . '\|just now\)'

let published = date . ' \%(' . g:gitlab_discussion_tree_resolved . '\|' . g:gitlab_discussion_tree_unresolved . '\|' . g:gitlab_discussion_tree_unlinked . '\)\?'
let state = ' \%(' . published . '\|' . g:gitlab_discussion_tree_draft . '\)'

execute 'syntax match GitlabNoteHeader "' . expanders . username . state . '" contains=GitlabDate,GitlabUnresolved,GitlabUnlinked,GitlabResolved,GitlabExpander,GitlabDraft,GitlabUsername'

execute 'syntax match GitlabDate "' . date . '" contained'
execute 'syntax match GitlabUnresolved "' . g:gitlab_discussion_tree_unresolved . '" contained'
execute 'syntax match GitlabUnlinked "' . g:gitlab_discussion_tree_unlinked . '" contained'
execute 'syntax match GitlabResolved "' . g:gitlab_discussion_tree_resolved . '" contained'
execute 'syntax match GitlabExpander "' . expanders . '" contained'
execute 'syntax match GitlabDraft "' . g:gitlab_discussion_tree_draft . '" contained'
execute 'syntax match GitlabUsername "' . username . '" contained'
execute 'syntax match GitlabMention "' . username . '"'

let b:current_syntax = 'gitlab'
47 changes: 36 additions & 11 deletions cmd/app/list_discussions.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"net/http"
"sort"
"sync"
"time"

"encoding/json"

Expand All @@ -19,8 +20,16 @@ func Contains[T comparable](elems []T, v T) bool {
return false
}

type SortBy string

const (
SortByLatestReply SortBy = "latest_reply"
SortByOriginalComment SortBy = "original_comment"
)

type DiscussionsRequest struct {
Blacklist []string `json:"blacklist" validate:"required"`
SortBy SortBy `json:"sort_by"`
}

type DiscussionsResponse struct {
Expand All @@ -30,20 +39,30 @@ type DiscussionsResponse struct {
Emojis map[int][]*gitlab.AwardEmoji `json:"emojis"`
}

type SortableDiscussions []*gitlab.Discussion
type SortableDiscussions struct {
Discussions []*gitlab.Discussion
SortBy SortBy
}

func (n SortableDiscussions) Len() int {
return len(n)
func (d SortableDiscussions) Len() int {
return len(d.Discussions)
}

func (d SortableDiscussions) Less(i int, j int) bool {
iTime := d[i].Notes[len(d[i].Notes)-1].CreatedAt
jTime := d[j].Notes[len(d[j].Notes)-1].CreatedAt
return iTime.After(*jTime)
func (d SortableDiscussions) Less(i, j int) bool {
var iTime, jTime *time.Time
if d.SortBy == SortByOriginalComment {
iTime = d.Discussions[i].Notes[0].CreatedAt
jTime = d.Discussions[j].Notes[0].CreatedAt
return iTime.Before(*jTime)
} else { // SortByLatestReply
iTime = d.Discussions[i].Notes[len(d.Discussions[i].Notes)-1].CreatedAt
jTime = d.Discussions[j].Notes[len(d.Discussions[j].Notes)-1].CreatedAt
return iTime.After(*jTime)
}
}

func (n SortableDiscussions) Swap(i, j int) {
n[i], n[j] = n[j], n[i]
func (d SortableDiscussions) Swap(i, j int) {
d.Discussions[i], d.Discussions[j] = d.Discussions[j], d.Discussions[i]
}

type DiscussionsLister interface {
Expand Down Expand Up @@ -115,8 +134,14 @@ func (a discussionsListerService) ServeHTTP(w http.ResponseWriter, r *http.Reque
return
}

sortedLinkedDiscussions := SortableDiscussions(linkedDiscussions)
sortedUnlinkedDiscussions := SortableDiscussions(unlinkedDiscussions)
sortedLinkedDiscussions := SortableDiscussions{
Discussions: linkedDiscussions,
SortBy: request.SortBy,
}
sortedUnlinkedDiscussions := SortableDiscussions{
Discussions: unlinkedDiscussions,
SortBy: request.SortBy,
}

sort.Sort(sortedLinkedDiscussions)
sort.Sort(sortedUnlinkedDiscussions)
Expand Down
55 changes: 44 additions & 11 deletions cmd/app/list_discussions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,14 @@ func (f fakeDiscussionsLister) ListMergeRequestDiscussions(pid interface{}, merg
if err != nil {
return nil, nil, err
}
now := time.Now()
newer := now.Add(time.Second * 100)

timePointers := make([]*time.Time, 6)
timePointers[0] = new(time.Time)
*timePointers[0] = time.Now()
for i := 1; i < len(timePointers); i++ {
timePointers[i] = new(time.Time)
*timePointers[i] = timePointers[i-1].Add(time.Second * 100)
}

type Author struct {
ID int `json:"id"`
Expand All @@ -35,8 +41,18 @@ func (f fakeDiscussionsLister) ListMergeRequestDiscussions(pid interface{}, merg
}

testListDiscussionsResponse := []*gitlab.Discussion{
{Notes: []*gitlab.Note{{CreatedAt: &now, Type: "DiffNote", Author: Author{Username: "hcramer"}}}},
{Notes: []*gitlab.Note{{CreatedAt: &newer, Type: "DiffNote", Author: Author{Username: "hcramer2"}}}},
{Notes: []*gitlab.Note{
{CreatedAt: timePointers[0], Type: "DiffNote", Author: Author{Username: "hcramer0"}},
{CreatedAt: timePointers[4], Type: "DiffNote", Author: Author{Username: "hcramer1"}},
}},
{Notes: []*gitlab.Note{
{CreatedAt: timePointers[2], Type: "DiffNote", Author: Author{Username: "hcramer2"}},
{CreatedAt: timePointers[3], Type: "DiffNote", Author: Author{Username: "hcramer3"}},
}},
{Notes: []*gitlab.Note{
{CreatedAt: timePointers[1], Type: "DiffNote", Author: Author{Username: "hcramer4"}},
{CreatedAt: timePointers[5], Type: "DiffNote", Author: Author{Username: "hcramer5"}},
}},
}
return testListDiscussionsResponse, resp, err
}
Expand Down Expand Up @@ -66,8 +82,23 @@ func getDiscussionsList(t *testing.T, svc http.Handler, request *http.Request) D
}

func TestListDiscussions(t *testing.T) {
t.Run("Returns sorted discussions", func(t *testing.T) {
request := makeRequest(t, http.MethodPost, "/mr/discussions/list", DiscussionsRequest{Blacklist: []string{}})
t.Run("Returns discussions sorted by latest reply", func(t *testing.T) {
request := makeRequest(t, http.MethodPost, "/mr/discussions/list", DiscussionsRequest{Blacklist: []string{}, SortBy: "latest_reply"})
svc := middleware(
discussionsListerService{testProjectData, fakeDiscussionsLister{}},
withMr(testProjectData, fakeMergeRequestLister{}),
withPayloadValidation(methodToPayload{http.MethodPost: newPayload[DiscussionsRequest]}),
withMethodCheck(http.MethodPost),
)
data := getDiscussionsList(t, svc, request)
assert(t, data.Message, "Discussions retrieved")
assert(t, data.Discussions[0].Notes[0].Author.Username, "hcramer4") /* Sorting applied */
assert(t, data.Discussions[1].Notes[0].Author.Username, "hcramer0")
assert(t, data.Discussions[2].Notes[0].Author.Username, "hcramer2")
})

t.Run("Returns discussions sorted by original comment", func(t *testing.T) {
request := makeRequest(t, http.MethodPost, "/mr/discussions/list", DiscussionsRequest{Blacklist: []string{}, SortBy: "original_comment"})
svc := middleware(
discussionsListerService{testProjectData, fakeDiscussionsLister{}},
withMr(testProjectData, fakeMergeRequestLister{}),
Expand All @@ -76,12 +107,13 @@ func TestListDiscussions(t *testing.T) {
)
data := getDiscussionsList(t, svc, request)
assert(t, data.Message, "Discussions retrieved")
assert(t, data.Discussions[0].Notes[0].Author.Username, "hcramer2") /* Sorting applied */
assert(t, data.Discussions[1].Notes[0].Author.Username, "hcramer")
assert(t, data.Discussions[0].Notes[0].Author.Username, "hcramer0") /* Sorting applied */
assert(t, data.Discussions[1].Notes[0].Author.Username, "hcramer4")
assert(t, data.Discussions[2].Notes[0].Author.Username, "hcramer2")
})

t.Run("Uses blacklist to filter unwanted authors", func(t *testing.T) {
request := makeRequest(t, http.MethodPost, "/mr/discussions/list", DiscussionsRequest{Blacklist: []string{"hcramer"}})
request := makeRequest(t, http.MethodPost, "/mr/discussions/list", DiscussionsRequest{Blacklist: []string{"hcramer0"}, SortBy: "latest_reply"})
svc := middleware(
discussionsListerService{testProjectData, fakeDiscussionsLister{}},
withMr(testProjectData, fakeMergeRequestLister{}),
Expand All @@ -90,8 +122,9 @@ func TestListDiscussions(t *testing.T) {
)
data := getDiscussionsList(t, svc, request)
assert(t, data.SuccessResponse.Message, "Discussions retrieved")
assert(t, len(data.Discussions), 1)
assert(t, data.Discussions[0].Notes[0].Author.Username, "hcramer2")
assert(t, len(data.Discussions), 2)
assert(t, data.Discussions[0].Notes[0].Author.Username, "hcramer4")
assert(t, data.Discussions[1].Notes[0].Author.Username, "hcramer2")
})
t.Run("Handles errors from Gitlab client", func(t *testing.T) {
request := makeRequest(t, http.MethodPost, "/mr/discussions/list", DiscussionsRequest{Blacklist: []string{}})
Expand Down
Loading

0 comments on commit 495e64c

Please sign in to comment.