mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 10:45:16 -07:00
api: Nvim version, API level #5386
The API level is disconnected from the NVIM version. The API metadata holds the current API level, and the lowest backwards-compatible level supported by this instance. Release 0.1.6 will be the first release reporting the Nvim version and API level. metadata['version'] = { major: 0, minor: 1, patch: 6, prerelease: true, api_level: 1, api_compatible: 0, } The API level may remain unchanged across Neovim releases if the API has not changed. When changing the API the CMake variable NVIM_API_PRERELEASE is set to true, and NVIM_API_CURRENT/NVIM_API_COMPATIBILITY are incremented accordingly. The functional tests check the API table against fixtures of past versions of Neovim. It compares all the functions in the old table with the new one, it does ignore some metadata attributes that do not alter the function signature or were removed since 0.1.5. Currently the only fixture is 0.mpack, generated from Neovim 0.1.5 with nvim --api-info.
This commit is contained in:
parent
90bf31c742
commit
f25797f869
@ -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)
|
||||
|
@ -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@"
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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')"
|
||||
|
||||
|
@ -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)
|
||||
|
65
test/functional/api/compatibility_spec.lua
Normal file
65
test/functional/api/compatibility_spec.lua
Normal file
@ -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)
|
@ -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)
|
||||
|
@ -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()
|
||||
|
BIN
test/functional/fixtures/api-info/0.mpack
Normal file
BIN
test/functional/fixtures/api-info/0.mpack
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user