aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt6
-rw-r--r--config/versiondef.h.in4
-rw-r--r--runtime/doc/api.txt1
-rw-r--r--runtime/doc/msgpack_rpc.txt3
-rwxr-xr-xscripts/release.sh2
-rw-r--r--src/nvim/api/private/helpers.c13
-rw-r--r--test/functional/api/compatibility_spec.lua65
-rw-r--r--test/functional/eval/api_functions_spec.lua3
-rw-r--r--test/functional/eval/msgpack_functions_spec.lua2
-rw-r--r--test/functional/fixtures/api-info/0.mpackbin0 -> 7873 bytes
10 files changed, 96 insertions, 3 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4aa6a2de32..3b139025d7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -65,6 +65,12 @@ set(NVIM_VERSION_MINOR 1)
set(NVIM_VERSION_PATCH 6)
set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers
+# Neovim API version. When changing the API, bump CURRENT if
+# PRERELEASE is false, and set PRERELEASE as true
+set(NVIM_API_CURRENT 1)
+set(NVIM_API_COMPATIBILITY 0)
+set(NVIM_API_PRERELEASE true)
+
file(TO_CMAKE_PATH ${CMAKE_CURRENT_LIST_DIR}/.git FORCED_GIT_DIR)
include(GetGitRevisionDescription)
get_git_head_revision(GIT_REFSPEC NVIM_VERSION_COMMIT)
diff --git a/config/versiondef.h.in b/config/versiondef.h.in
index c91bb29c90..465d90b674 100644
--- a/config/versiondef.h.in
+++ b/config/versiondef.h.in
@@ -7,6 +7,10 @@
#define NVIM_VERSION_PRERELEASE "@NVIM_VERSION_PRERELEASE@"
#cmakedefine NVIM_VERSION_MEDIUM "@NVIM_VERSION_MEDIUM@"
+#define NVIM_API_CURRENT @NVIM_API_CURRENT@
+#define NVIM_API_COMPATIBILITY @NVIM_API_COMPATIBILITY@
+#cmakedefine NVIM_API_PRERELEASE
+
#define NVIM_VERSION_CFLAGS "@NVIM_VERSION_CFLAGS@"
#define NVIM_VERSION_BUILD_TYPE "@NVIM_VERSION_BUILD_TYPE@"
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index c3d7fdb35b..dd48a0c2a5 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -51,6 +51,7 @@ Tabpage -> enum value kObjectTypeTabpage
Nvim exposes metadata about the API as a Dictionary with the following keys:
+api_level API version compatibility information
functions calling signature of the API functions
types The custom handle types defined by Nvim
error_types The possible kinds of errors an API function can exit with.
diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt
index b3fed9e756..bfd4100f15 100644
--- a/runtime/doc/msgpack_rpc.txt
+++ b/runtime/doc/msgpack_rpc.txt
@@ -168,6 +168,9 @@ API metadata object ~
API clients exist to hide msgpack-rpc details. The API metadata object
contains information that makes this task easier (see also |rpc-types|):
+ - The "api_level" key contais API compatibility information. The "current"
+ key holds the API version supported Neovim. The "compatibility" key holds
+ the oldest supported API version.
- The "functions" key contains a list of metadata objects for individual
functions.
- Each function metadata object has |rpc-types| information about the return
diff --git a/scripts/release.sh b/scripts/release.sh
index 5a5b5a6498..0dd840074a 100755
--- a/scripts/release.sh
+++ b/scripts/release.sh
@@ -5,6 +5,7 @@
# Steps:
# Create the "release" commit:
# - CMakeLists.txt: Unset NVIM_VERSION_PRERELEASE
+# - CMakeLists.txt: Unset NVIM_API_PRERELEASE
# - Tag the commit.
# Create the "version bump" commit:
# - CMakeLists.txt: Set NVIM_VERSION_PRERELEASE to "-dev"
@@ -46,6 +47,7 @@ __BUMP_MSG="version bump"
echo "Most recent tag: ${__LAST_TAG}"
echo "Release version: ${__VERSION}"
$__sed -i.bk 's/(NVIM_VERSION_PRERELEASE) "-dev"/\1 ""/' CMakeLists.txt
+$__sed -i.bk 's/(NVIM_API_PRERELEASE) true/\1 false/' CMakeLists.txt
echo "Building changelog since ${__LAST_TAG}..."
__CHANGELOG="$(./scripts/git-log-pretty-since.sh "$__LAST_TAG" 'vim-patch:\S')"
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index c0ee735d1a..7fda2802c8 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -20,6 +20,7 @@
#include "nvim/option_defs.h"
#include "nvim/eval/typval_encode.h"
#include "nvim/lib/kvec.h"
+#include "auto/versiondef.h"
/// Helper structure for vim_to_object
typedef struct {
@@ -766,6 +767,7 @@ Dictionary api_metadata(void)
init_function_metadata(&metadata);
init_error_type_metadata(&metadata);
init_type_metadata(&metadata);
+ init_api_level_metadata(&metadata);
}
return copy_object(DICTIONARY_OBJ(metadata)).data.dictionary;
@@ -825,6 +827,17 @@ static void init_type_metadata(Dictionary *metadata)
PUT(*metadata, "types", DICTIONARY_OBJ(types));
}
+static void init_api_level_metadata(Dictionary *metadata)
+{
+ Dictionary version = ARRAY_DICT_INIT;
+ PUT(version, "current", INTEGER_OBJ(NVIM_API_CURRENT));
+ PUT(version, "compatibility", INTEGER_OBJ(NVIM_API_COMPATIBILITY));
+#ifdef NVIM_API_PRERELEASE
+ PUT(version, "prerelease", BOOLEAN_OBJ(true));
+#endif
+
+ PUT(*metadata, "api_level", DICTIONARY_OBJ(version));
+}
/// Creates a deep clone of an object
Object copy_object(Object obj)
diff --git a/test/functional/api/compatibility_spec.lua b/test/functional/api/compatibility_spec.lua
new file mode 100644
index 0000000000..e0fc625b46
--- /dev/null
+++ b/test/functional/api/compatibility_spec.lua
@@ -0,0 +1,65 @@
+
+local helpers = require('test.functional.helpers')(after_each)
+local lfs = require('lfs')
+local mpack = require('mpack')
+local clear, eq, neq = helpers.clear, helpers.eq, helpers.neq
+
+local read_mpack_file = function(fname)
+ local fd = io.open(fname, 'rb')
+ local data = fd:read('*a')
+ fd:close()
+ local unpack = mpack.Unpacker()
+ return unpack(data)
+end
+
+-- ignore metadata in API function spec
+local remove_function_metadata = function(fspec)
+ fspec['can_fail'] = nil
+ fspec['async'] = nil
+ fspec['method'] = nil
+ fspec['since'] = nil
+ fspec['deprecated_since'] = nil
+ fspec['receives_channel_id'] = nil
+ for idx,_ in ipairs(fspec['parameters']) do
+ fspec['parameters'][idx][2] = ''
+ end
+end
+
+clear()
+local api_level = helpers.call('api_info')['api_level']
+
+describe('api compatibility', function()
+ before_each(clear)
+
+ it("version metadata is sane", function()
+ local info = helpers.call('api_info')
+ local current = info['api_level']['current']
+ local compatibility = info['api_level']['compatibility']
+ neq(current, nil)
+ neq(compatibility, nil)
+ assert(current >= compatibility)
+ end)
+
+ for ver = api_level['compatibility'], api_level['current'] do
+ local path = 'test/functional/fixtures/api-info/' .. tostring(ver) .. '.mpack'
+ it('are backwards compatible with api level '..ver, function()
+ if lfs.attributes(path,"mode") ~= "file" then
+ pending("No fixture found, skipping test")
+ return
+ end
+
+ local old_api = read_mpack_file(path)
+ local api = helpers.call('api_info')
+
+ for _, fspec in ipairs(old_api['functions']) do
+ remove_function_metadata(fspec)
+ for _, fspec_new in ipairs(api['functions']) do
+ if fspec['name'] == fspec_new['name'] then
+ remove_function_metadata(fspec_new)
+ eq(fspec, fspec_new)
+ end
+ end
+ end
+ end)
+ end
+end)
diff --git a/test/functional/eval/api_functions_spec.lua b/test/functional/eval/api_functions_spec.lua
index 2ef67e7808..5345c9782d 100644
--- a/test/functional/eval/api_functions_spec.lua
+++ b/test/functional/eval/api_functions_spec.lua
@@ -106,7 +106,7 @@ describe('api functions', function()
it('have metadata accessible with api_info()', function()
local api_keys = eval("sort(keys(api_info()))")
- eq({'error_types', 'functions', 'types'}, api_keys)
+ eq({'api_level', 'error_types', 'functions', 'types'}, api_keys)
end)
it('are highlighted by vim.vim syntax file', function()
@@ -144,5 +144,4 @@ describe('api functions', function()
]])
screen:detach()
end)
-
end)
diff --git a/test/functional/eval/msgpack_functions_spec.lua b/test/functional/eval/msgpack_functions_spec.lua
index 5b87b05652..ae7e1b5609 100644
--- a/test/functional/eval/msgpack_functions_spec.lua
+++ b/test/functional/eval/msgpack_functions_spec.lua
@@ -460,7 +460,7 @@ describe('msgpackparse() function', function()
eval(cmd)
eval(cmd) -- do it again (try to force segfault)
local api_info = eval(cmd) -- do it again
- eq({'error_types', 'functions', 'types'}, api_info)
+ eq({'api_level', 'error_types', 'functions', 'types'}, api_info)
end)
it('fails when called with no arguments', function()
diff --git a/test/functional/fixtures/api-info/0.mpack b/test/functional/fixtures/api-info/0.mpack
new file mode 100644
index 0000000000..75b236a3c1
--- /dev/null
+++ b/test/functional/fixtures/api-info/0.mpack
Binary files differ