Skip to content
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
26 changes: 26 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,32 @@ jobs:
- name: Test
run: nix develop ".#${{ matrix.shell }}" -c make test

# The real gh, glab, tea, and fj, and real Gitea and Forgejo servers
integration:
name: Integration
if: github.event_name != 'schedule'
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install Nix
uses: cachix/install-nix-action@448cde739abec1eaf0646249e3d25bb8d9bc7702 # v31.11.2
with:
extra_nix_config: |
extra-substituters = https://nix-community.cachix.org
extra-trusted-public-keys = nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=
- name: Show versions
run: >-
nix develop .#integration -c sh -c
'nvim --version | head -1; gh --version | head -1; glab --version; tea --version; fj version;
gitea --version; forgejo --version'
- name: Test
env:
# A missing CLI or server fails its cases, and does not skip them
CMP_GIT_INTEGRATION_REQUIRE: 1
run: nix develop .#integration -c make test-integration

# Shared runners are noisy, so a failed comparison is a warning to read in the job summary, not a failed check
bench:
name: Benchmarks
Expand Down
54 changes: 47 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@ To load the default shell when you enter the repository:
2. Install direnv and hook it into your shell.
3. In the repository, run `direnv allow`.

The flake has three shells. Each shell also has StyLua, Selene, lua-language-server, make, and git.
The flake has four shells. Each shell also has StyLua, Selene, lua-language-server, make, and git.

| Shell | Neovim | Command |
| ------------- | -------------------------------------------------------- | --------------------------- |
| `default` | The stable release in the locked nixpkgs | `nix develop` |
| `nvim-0_12_0` | 0.12.0, the minimum supported version | `nix develop .#nvim-0_12_0` |
| `nightly` | The nightly build in the locked `neovim-nightly-overlay` | `nix develop .#nightly` |
| `integration` | The stable release, with the CLIs and the servers | `nix develop .#integration` |

The `integration` shell also has curl, `gh`, `glab`, `tea`, `fj`, and the `gitea` and `forgejo` servers. nixpkgs marks
`forgejo` as broken on `aarch64-darwin`, so the shell has no `forgejo` there.

The nightly builds are in the nix-community binary cache. Without this cache, Nix builds Neovim from source. To use
the cache, add these lines to your Nix config:
Expand All @@ -41,8 +45,9 @@ extra-trusted-public-keys = nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq

| Target | Action |
| ------------------------------ | --------------------------------------------------------------------------------------------------- |
| `make test` | Runs all tests. |
| `make test` | Runs all tests, except the tests in `tests/integration/`. |
| `make test-file FILE=<path>` | Runs one test file. |
| `make test-integration` | Runs the tests in `tests/integration/`. Use the `integration` shell. |
| `make format` | Formats `lua/`, `tests/`, and `benchmarks/` with StyLua. |
| `make format-check` | Checks the formatting. |
| `make lint` | Lints `lua/`, `tests/`, and `benchmarks/` with Selene. Warnings fail the target. |
Expand All @@ -63,8 +68,9 @@ that version.

## Tests

The tests use [mini.test](https://github.com/nvim-mini/mini.nvim/blob/main/readmes/mini-test.md). The files in
`tests/` mirror the modules in `lua/cmp_git/`. mini.test collects the files that match `tests/**/test_*.lua`.
The tests use [mini.test](https://github.com/nvim-mini/mini.nvim/blob/main/readmes/mini-test.md). The files in `tests/`
mirror the modules in `lua/cmp_git/`. mini.test collects the files that match `tests/**/test_*.lua`. `make test`
collects the files outside `tests/integration/`, and `make test-integration` collects the files in it.

- `tests/minimal_init.lua` adds the repository and mini.nvim to `runtimepath`.
- `tests/helpers.lua` has the expectations, the fakes, and the hooks for each case.
Expand All @@ -73,13 +79,18 @@ Start each test file with `local T = helpers.new_set()`. The hooks of this set i

- They capture `vim.notify`, so log messages do not print. To read the messages, call `helpers.flush()`, and then
read `helpers.notifications`.
- They unset `GITHUB_API_TOKEN` and `GITLAB_TOKEN`.
- They unset `GITHUB_API_TOKEN`, `GITLAB_TOKEN`, `GITEA_TOKEN`, and `FORGEJO_TOKEN`.
- They unset `XDG_CONFIG_HOME`, `XDG_DATA_HOME`, and `APPDATA`, and set `HOME` to a temporary directory. Thus the
tea logins and the `fj` tokens of your user do not apply.
- They isolate git from your user config and your system config.
- They set `XDG_CACHE_HOME` to a temporary directory, so that the cache of the GitHub and GitLab items is empty.
- They set `XDG_CACHE_HOME` to a temporary directory, so that the cache of the items is empty.
- They clear the tea logins that the Gitea source read.
- They restore the cwd, the buffers, and the values that `helpers.stub` replaced.
- They delete the directories from `helpers.tempdir` and `helpers.git_repo`.

Do not use the network in tests. Use fake runners and fake adapters in place of `gh`, `glab`, and `curl`.
Do not use the network in tests. Use fake runners and fake adapters in place of `gh`, `glab`, `tea`, and `curl`.
`helpers.fake_commands` puts fake commands on `PATH` for one case. `tests/sources/fake_gitea_api.lua` has a fake curl
and a fake tea for the Gitea and Forgejo sources.

To run one test file:

Expand All @@ -104,6 +115,30 @@ nix develop .#nightly --no-write-lock-file \
--override-input neovim-nightly-overlay "github:nix-community/neovim-nightly-overlay/$rev" -c make test
```

### Integration tests

The tests in `tests/integration/` run the real CLIs. They do not use the network either:

- `gh` and `glab` send their requests to a fake HTTP server in the Neovim of the tests. `integration.http_server` starts
it, and `integration.use_gh` and `integration.use_glab` give the CLIs an isolated config for it. The canned GraphQL
answers for `gh` must match the queries of the locked `gh` version.
- tea, the `fj` token, and curl send their requests to real `gitea` and `forgejo` servers on `127.0.0.1`.
`integration.forge("gitea")` gives a server for the test file. The first case that calls `start` starts it, and
`stop` in `post_once` ends it. `integration.use_tea` and `integration.use_fj` give the CLIs a login for the server.

Each server starts in a temporary directory, with a free port, SQLite, and seed data: the admin `root`, the
repositories `root/public` and the private `root/private`, and the collaborator `ada`. The start time of each server
goes to the notes of the case. The log of the server goes to the notes of a case that fails.

To run the integration tests:

```sh
nix develop .#integration -c make test-integration
```

A case skips when a binary that it needs is not on `PATH`. With `CMP_GIT_INTEGRATION_REQUIRE=1`, as in CI, a missing
binary fails the case. The Forgejo server cases always skip on `aarch64-darwin`.

## Benchmarks

The benchmarks in `benchmarks/` measure the two costs that users feel: the work that runs while they type, and the time
Expand Down Expand Up @@ -170,6 +205,7 @@ has these jobs:
| `Neovim 0.12.0` | `make test` in the `nvim-0_12_0` shell | Yes |
| `Nightly cache` | `scripts/nightly-cache.sh check` (the locked nightly Neovim is in the cache for each system) | Yes |
| `Neovim nightly` | `make test` with the newest `neovim-nightly-overlay` commit that is in the cache, not the locked revision | No |
| `Integration` | `make test-integration` in the `integration` shell, with `CMP_GIT_INTEGRATION_REQUIRE=1` | Yes |
| `Benchmarks` | Pull requests only. `scripts/bench-compare.sh` against the base branch, with the report in the job summary | No |

A weekly schedule (Monday 06:00 UTC) runs only the nightly job. GitHub disables scheduled workflows after 60 days
Expand Down Expand Up @@ -201,6 +237,10 @@ changes that you pushed to the branch.

To check the locked nightly Neovim on your computer, run `scripts/nightly-cache.sh check`.

A nixpkgs update can also change the versions of `gh`, `glab`, `tea`, `fj`, `gitea`, and `forgejo`. If the
`Integration` job then fails, run `nix develop .#integration -c make test-integration` on the Dependabot branch. Then
fix the code or the canned answers of the fake server.

Dependabot does not change the Neovim 0.12.0 pin in `flake.nix`.

### Update mini.nvim
Expand Down
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ MINI_DIR := deps/mini.nvim
LUA_PATHS := lua plugin tests benchmarks
REF ?= main

.PHONY: test-deps test test-file bench bench-compare format format-check lint typecheck ci
.PHONY: test-deps test test-integration test-file bench bench-compare format format-check lint typecheck ci

test-deps:
@if [ ! -d "$(MINI_DIR)/.git" ]; then \
Expand All @@ -20,9 +20,15 @@ test-deps:
git -C "$(MINI_DIR)" checkout --detach "$(MINI_VERSION)"; \
fi

# Runs the files in tests/ without tests/integration/
test: test-deps
$(NVIM) --headless --noplugin -u tests/minimal_init.lua -c "lua MiniTest.run()"

# Runs the files in tests/integration/. They need the CLIs and the servers of `nix develop .#integration`.
test-integration: test-deps
TEST_SUITE=integration $(NVIM) --headless --noplugin -u tests/minimal_init.lua -c "lua MiniTest.run()"

# Also runs a file in tests/integration/
test-file: test-deps
@test -n "$(FILE)" || (printf '%s\n' 'Usage: make test-file FILE=tests/**/test_*.lua' >&2; exit 2)
TEST_FILE="$(FILE)" $(NVIM) --headless --noplugin -u tests/minimal_init.lua \
Expand Down
81 changes: 75 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,22 @@ Git source for [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp) and [Sagh
| Mentions | @ |
| Merge Requests | ! |

| Gitea and Forgejo | Trigger |
| ----------------- | ------- |
| Issues | # |
| Mentions | @ |
| Pull Requests | #, ! |

## Requirements

- Neovim >= 0.12
- git (>= 2.31 to find trailer keys in history)
- curl (>= 7.55)
- [GitHub CLI](https://cli.github.com/) (optional, cmp-git uses curl if it is not available)
- [GitLab CLI](https://gitlab.com/gitlab-org/cli) (optional, cmp-git uses curl if it is not available)
- [tea](https://gitea.com/gitea/tea) >= 0.12.0 (optional, for Gitea, cmp-git uses curl if it is not available)
- [forgejo-cli](https://codeberg.org/forgejo-contrib/forgejo-cli) (`fj`) (optional, for Forgejo, cmp-git reads the
token of `fj` and sends it with curl)

### GitHub private repositories

Expand All @@ -43,6 +52,21 @@ Git source for [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp) and [Sagh
`GITLAB_TOKEN` environment variable to the token.
- `GitLab CLI`: Run [glab auth login](https://glab.readthedocs.io/en/latest/auth/login.html).

### Gitea private repositories

- `curl`: Generate an access token in Settings > Applications on the server, with the `read:issue` and
`read:repository` scopes. Set the `GITEA_TOKEN` environment variable to the token.
- `tea`: Run `tea login add` for the server. cmp-git uses the login whose URL is the host of the remote.

### Forgejo private repositories

- `curl`: Generate an access token in Settings > Applications on the server, with the `read:issue` and
`read:repository` scopes. Set the `FORGEJO_TOKEN` environment variable to the token.
- `forgejo-cli`: Run `fj auth login` or `fj auth add-token` for the server. cmp-git reads the token that `fj` keeps for
the host.

Without a token, `@` shows no Gitea and Forgejo mentions, also in a public repository. The assignees API needs a token.

## Installation

[vim-plug](https://github.com/junegunn/vim-plug)
Expand Down Expand Up @@ -135,7 +159,7 @@ require("cmp_git").setup({
enableRemoteUrlRewrites = false, -- enable git url rewrites, see https://git-scm.com/docs/git-config#Documentation/git-config.txt-urlltbasegtinsteadOf
ssh_aliases = {}, -- SSH host aliases and their real hosts, such as { ["github-work"] = "github.com" }
cache = {
ttl = 300, -- seconds after which a request also gets the GitHub and GitLab items again in the background
ttl = 300, -- seconds after which a request also gets the items again in the background
},
git = {
commits = {
Expand Down Expand Up @@ -217,6 +241,46 @@ require("cmp_git").setup({
format = format.gitlab.merge_requests,
},
},
gitea = {
hosts = {}, -- list of private instances of gitea, with the port and the path prefix if any, such as "example.com/gitea"
issues = {
limit = 50, -- the servers give at most 50 items
state = "open", -- open, closed, all
sort_by = sort.gitea.issues,
format = format.gitea.issues,
},
mentions = {
limit = 100,
sort_by = sort.gitea.mentions,
format = format.gitea.mentions,
},
pull_requests = {
limit = 50, -- the servers give at most 50 items
state = "open", -- open, closed, all
sort_by = sort.gitea.pull_requests,
format = format.gitea.pull_requests,
},
},
forgejo = {
hosts = {}, -- list of private instances of forgejo, with the port and the path prefix if any
issues = {
limit = 50, -- the servers give at most 50 items
state = "open", -- open, closed, all
sort_by = sort.forgejo.issues,
format = format.forgejo.issues,
},
mentions = {
limit = 100,
sort_by = sort.forgejo.mentions,
format = format.forgejo.mentions,
},
pull_requests = {
limit = 50, -- the servers give at most 50 items
state = "open", -- open, closed, all
sort_by = sort.forgejo.pull_requests,
format = format.forgejo.pull_requests,
},
},
trigger_actions = {
{
pattern = [[^[[:alnum:]-]\+]],
Expand All @@ -233,15 +297,20 @@ require("cmp_git").setup({
},
{
trigger_character = "#",
actions = { "gitlab_issues", "github_issues_and_change_requests" },
actions = {
"gitlab_issues",
"github_issues_and_change_requests",
"gitea_issues_and_change_requests",
"forgejo_issues_and_change_requests",
},
},
{
trigger_character = "@",
actions = { "gitlab_mentions", "github_mentions" },
actions = { "gitlab_mentions", "github_mentions", "gitea_mentions", "forgejo_mentions" },
},
{
trigger_character = "!",
actions = { "gitlab_change_requests" },
actions = { "gitlab_change_requests", "gitea_change_requests", "forgejo_change_requests" },
},
},
}
Expand All @@ -255,8 +324,8 @@ require("cmp_git").setup({
- [Format and sort items](docs/configuration.md#format-and-sort-items)
- [Filetypes](docs/configuration.md#filetypes)
- [Remotes and SSH aliases](docs/configuration.md#remotes-and-ssh-aliases)
- [GitHub CLI, GitLab CLI, and curl](docs/configuration.md#github-cli-gitlab-cli-and-curl)
- [Hosted GitHub and GitLab instances](docs/configuration.md#hosted-github-and-gitlab-instances)
- [CLIs, tokens, and curl](docs/configuration.md#clis-tokens-and-curl)
- [Hosted instances](docs/configuration.md#hosted-instances)
- [Cache](docs/configuration.md#cache), and the `:CmpGitClearCache` command
- [Troubleshooting](docs/configuration.md#troubleshooting)

Expand Down
4 changes: 2 additions & 2 deletions benchmarks/cases/e2e.lua
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ local REQUESTS = {
github_mentions = { row = 3, line = "See @", trigger_character = "@" },
}

---Remove the cached GitHub and GitLab items from memory and from disk. Revisions before the disk cache have no cache
---Remove the cached items of the providers from memory and from disk. Revisions before the disk cache have no cache
---module, and a new source is cold there.
local function clear_cache()
local ok, cache = pcall(require, "cmp_git.cache")
Expand Down Expand Up @@ -95,7 +95,7 @@ for _, name in ipairs({
table.insert(cases, request_case(name, "cold"))
table.insert(cases, request_case(name, "warm"))
end
-- Only the GitHub and GitLab items have cache files
-- Only the items of the providers have cache files, not the commits and the trailers
for _, name in ipairs({ "github_issues_and_prs", "github_mentions" }) do
table.insert(cases, request_case(name, "disk"))
end
Expand Down
Loading
Loading