feat(s3): create bucket interactively during auth when unconfigured
Problem: when a user runs `:Pending s3 auth` with no bucket configured, auth succeeds but offers no way to create the bucket. The user must manually run `aws s3api create-bucket` and update their config. Solution: add `util.input()` coroutine-aware prompt wrapper and a `create_bucket()` flow in `s3.lua` that prompts for bucket name and region, handles the `us-east-1` LocationConstraint quirk, and logs a config snippet on success. Called automatically from `auth()` when `sync.s3.bucket` is absent.
This commit is contained in:
parent
ee75e6844e
commit
58804fcfc7
3 changed files with 303 additions and 0 deletions
241
spec/s3_spec.lua
241
spec/s3_spec.lua
|
|
@ -99,6 +99,28 @@ describe('s3', function()
|
|||
assert.truthy(msg and msg:find('authenticated'))
|
||||
end)
|
||||
|
||||
it('skips bucket creation when bucket is configured', function()
|
||||
util.system = function(args)
|
||||
if vim.tbl_contains(args, 'get-caller-identity') then
|
||||
return {
|
||||
code = 0,
|
||||
stdout = '{"Account":"123456","Arn":"arn:aws:iam::user/test"}',
|
||||
stderr = '',
|
||||
}
|
||||
end
|
||||
return { code = 0, stdout = '', stderr = '' }
|
||||
end
|
||||
local orig_input = util.input
|
||||
local input_called = false
|
||||
util.input = function()
|
||||
input_called = true
|
||||
return nil
|
||||
end
|
||||
s3.auth()
|
||||
util.input = orig_input
|
||||
assert.is_false(input_called)
|
||||
end)
|
||||
|
||||
it('detects SSO expiry', function()
|
||||
util.system = function(args)
|
||||
if vim.tbl_contains(args, 'get-caller-identity') then
|
||||
|
|
@ -133,6 +155,225 @@ describe('s3', function()
|
|||
end)
|
||||
end)
|
||||
|
||||
describe('auth bucket creation', function()
|
||||
local orig_input
|
||||
|
||||
before_each(function()
|
||||
vim.g.pending = { data_path = tmpdir .. '/tasks.json', sync = { s3 = {} } }
|
||||
config.reset()
|
||||
package.loaded['pending'] = nil
|
||||
package.loaded['pending.sync.s3'] = nil
|
||||
pending = require('pending')
|
||||
s3 = require('pending.sync.s3')
|
||||
orig_input = util.input
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
util.input = orig_input
|
||||
end)
|
||||
|
||||
it('prompts for bucket when none configured', function()
|
||||
local input_calls = {}
|
||||
util.input = function(opts)
|
||||
table.insert(input_calls, opts)
|
||||
if opts.prompt:find('bucket') then
|
||||
return 'my-bucket'
|
||||
end
|
||||
return opts.default
|
||||
end
|
||||
local create_args
|
||||
util.system = function(args)
|
||||
if vim.tbl_contains(args, 'get-caller-identity') then
|
||||
return {
|
||||
code = 0,
|
||||
stdout = '{"Account":"123","Arn":"arn:aws:iam::user/test"}',
|
||||
stderr = '',
|
||||
}
|
||||
end
|
||||
if vim.tbl_contains(args, 'configure') then
|
||||
return { code = 0, stdout = 'us-west-2\n', stderr = '' }
|
||||
end
|
||||
if vim.tbl_contains(args, 'create-bucket') then
|
||||
create_args = args
|
||||
return { code = 0, stdout = '', stderr = '' }
|
||||
end
|
||||
return { code = 0, stdout = '', stderr = '' }
|
||||
end
|
||||
local msg
|
||||
local orig_notify = vim.notify
|
||||
vim.notify = function(m)
|
||||
msg = m
|
||||
end
|
||||
s3.auth()
|
||||
vim.notify = orig_notify
|
||||
assert.equals(2, #input_calls)
|
||||
assert.is_not_nil(create_args)
|
||||
assert.truthy(vim.tbl_contains(create_args, 'my-bucket'))
|
||||
assert.truthy(msg and msg:find('bucket created'))
|
||||
end)
|
||||
|
||||
it('cancels when user provides empty bucket name', function()
|
||||
util.input = function(opts)
|
||||
if opts.prompt:find('bucket') then
|
||||
return nil
|
||||
end
|
||||
return opts.default
|
||||
end
|
||||
util.system = function(args)
|
||||
if vim.tbl_contains(args, 'get-caller-identity') then
|
||||
return {
|
||||
code = 0,
|
||||
stdout = '{"Account":"123","Arn":"arn:aws:iam::user/test"}',
|
||||
stderr = '',
|
||||
}
|
||||
end
|
||||
return { code = 0, stdout = '', stderr = '' }
|
||||
end
|
||||
local msg
|
||||
local orig_notify = vim.notify
|
||||
vim.notify = function(m)
|
||||
msg = m
|
||||
end
|
||||
s3.auth()
|
||||
vim.notify = orig_notify
|
||||
assert.truthy(msg and msg:find('cancelled'))
|
||||
end)
|
||||
|
||||
it('omits LocationConstraint for us-east-1', function()
|
||||
util.input = function(opts)
|
||||
if opts.prompt:find('bucket') then
|
||||
return 'my-bucket'
|
||||
end
|
||||
if opts.prompt:find('region') then
|
||||
return 'us-east-1'
|
||||
end
|
||||
return opts.default
|
||||
end
|
||||
local create_args
|
||||
util.system = function(args)
|
||||
if vim.tbl_contains(args, 'get-caller-identity') then
|
||||
return {
|
||||
code = 0,
|
||||
stdout = '{"Account":"123","Arn":"arn:aws:iam::user/test"}',
|
||||
stderr = '',
|
||||
}
|
||||
end
|
||||
if vim.tbl_contains(args, 'configure') then
|
||||
return { code = 0, stdout = 'us-east-1\n', stderr = '' }
|
||||
end
|
||||
if vim.tbl_contains(args, 'create-bucket') then
|
||||
create_args = args
|
||||
return { code = 0, stdout = '', stderr = '' }
|
||||
end
|
||||
return { code = 0, stdout = '', stderr = '' }
|
||||
end
|
||||
s3.auth()
|
||||
assert.is_not_nil(create_args)
|
||||
local joined = table.concat(create_args, ' ')
|
||||
assert.falsy(joined:find('LocationConstraint'))
|
||||
end)
|
||||
|
||||
it('includes LocationConstraint for non-us-east-1 regions', function()
|
||||
util.input = function(opts)
|
||||
if opts.prompt:find('bucket') then
|
||||
return 'my-bucket'
|
||||
end
|
||||
if opts.prompt:find('region') then
|
||||
return 'eu-west-1'
|
||||
end
|
||||
return opts.default
|
||||
end
|
||||
local create_args
|
||||
util.system = function(args)
|
||||
if vim.tbl_contains(args, 'get-caller-identity') then
|
||||
return {
|
||||
code = 0,
|
||||
stdout = '{"Account":"123","Arn":"arn:aws:iam::user/test"}',
|
||||
stderr = '',
|
||||
}
|
||||
end
|
||||
if vim.tbl_contains(args, 'configure') then
|
||||
return { code = 0, stdout = 'eu-west-1\n', stderr = '' }
|
||||
end
|
||||
if vim.tbl_contains(args, 'create-bucket') then
|
||||
create_args = args
|
||||
return { code = 0, stdout = '', stderr = '' }
|
||||
end
|
||||
return { code = 0, stdout = '', stderr = '' }
|
||||
end
|
||||
s3.auth()
|
||||
assert.is_not_nil(create_args)
|
||||
assert.truthy(vim.tbl_contains(create_args, 'LocationConstraint=eu-west-1'))
|
||||
end)
|
||||
|
||||
it('reports error on bucket creation failure', function()
|
||||
util.input = function(opts)
|
||||
if opts.prompt:find('bucket') then
|
||||
return 'bad-bucket'
|
||||
end
|
||||
return opts.default
|
||||
end
|
||||
util.system = function(args)
|
||||
if vim.tbl_contains(args, 'get-caller-identity') then
|
||||
return {
|
||||
code = 0,
|
||||
stdout = '{"Account":"123","Arn":"arn:aws:iam::user/test"}',
|
||||
stderr = '',
|
||||
}
|
||||
end
|
||||
if vim.tbl_contains(args, 'configure') then
|
||||
return { code = 0, stdout = 'us-east-1\n', stderr = '' }
|
||||
end
|
||||
if vim.tbl_contains(args, 'create-bucket') then
|
||||
return { code = 1, stdout = '', stderr = 'BucketAlreadyExists' }
|
||||
end
|
||||
return { code = 0, stdout = '', stderr = '' }
|
||||
end
|
||||
local msg
|
||||
local orig_notify = vim.notify
|
||||
vim.notify = function(m, level)
|
||||
if level == vim.log.levels.ERROR then
|
||||
msg = m
|
||||
end
|
||||
end
|
||||
s3.auth()
|
||||
vim.notify = orig_notify
|
||||
assert.truthy(msg and msg:find('bucket creation failed'))
|
||||
end)
|
||||
|
||||
it('defaults region to us-east-1 when aws configure returns nothing', function()
|
||||
util.input = function(opts)
|
||||
if opts.prompt:find('bucket') then
|
||||
return 'my-bucket'
|
||||
end
|
||||
return ''
|
||||
end
|
||||
local create_args
|
||||
util.system = function(args)
|
||||
if vim.tbl_contains(args, 'get-caller-identity') then
|
||||
return {
|
||||
code = 0,
|
||||
stdout = '{"Account":"123","Arn":"arn:aws:iam::user/test"}',
|
||||
stderr = '',
|
||||
}
|
||||
end
|
||||
if vim.tbl_contains(args, 'configure') then
|
||||
return { code = 1, stdout = '', stderr = '' }
|
||||
end
|
||||
if vim.tbl_contains(args, 'create-bucket') then
|
||||
create_args = args
|
||||
return { code = 0, stdout = '', stderr = '' }
|
||||
end
|
||||
return { code = 0, stdout = '', stderr = '' }
|
||||
end
|
||||
s3.auth()
|
||||
assert.is_not_nil(create_args)
|
||||
assert.truthy(vim.tbl_contains(create_args, 'us-east-1'))
|
||||
local joined = table.concat(create_args, ' ')
|
||||
assert.falsy(joined:find('LocationConstraint'))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('push', function()
|
||||
it('uploads store to S3', function()
|
||||
local s = pending.store()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue