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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
coverage/
node_modules/
package-lock.json
.kiro
7 changes: 7 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

---

## [6.0.0 - 6.0.1] 2025-11-28

- node >= 22
- native test runner

---

## [5.0.0] 2024-09-24

- Updated deps and node > 20
Expand Down
16 changes: 5 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@architect/env",
"version": "6.0.0",
"version": "6.0.1",
"description": "Manage your Architect app's environment variables",
"main": "src/index.js",
"bin": {
Expand All @@ -9,8 +9,8 @@
"scripts": {
"test": "npm run lint && npm run coverage",
"test:nolint": "npm run coverage",
"test:unit": "cross-env tape 'test/**/*-tests.js'",
"coverage": "nyc --reporter=lcov --reporter=text npm run test:unit",
"test:unit": "node --test 'test/**/*-tests.js'",
"coverage": "node --test --experimental-test-coverage 'test/**/*-tests.js'",
"lint": "eslint . --fix",
"rc": "npm version prerelease --preid RC"
},
Expand All @@ -33,19 +33,13 @@
"dependencies": {
"@architect/inventory": "~6.0.0",
"@architect/parser": "~8.0.1",
"@architect/utils": "~6.0.0",
"@architect/utils": "~6.0.1",
"@aws-lite/client": "^0.23.2",
"@aws-lite/ssm": "^0.2.3",
"dotenv": "~17.2.3"
},
"devDependencies": {
"@architect/eslint-config": "~3.0.0",
"cross-env": "~10.1.0",
"eslint": "~9.39.1",
"nyc": "~17.1.0",
"proxyquire": "~2.1.3",
"sinon": "~21.0.0",
"tap-arc": "^1.2.2",
"tape": "^5.7.5"
"eslint": "~9.39.1"
}
}
77 changes: 34 additions & 43 deletions test/_add-remove-tests.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* let test = require('tape')
let sinon = require('sinon')
/* const { test, mock } = require('node:test')
const assert = require('node:assert')
let AWS = require('aws-sdk')
let aws = require('aws-sdk-mock')
aws.setSDKInstance(AWS)
Expand All @@ -12,77 +12,72 @@ let params = { inventory: { inv: {
aws: { region: 'us-west-2' },
} }, update }

test('Add should error on invalid environment', t => {
t.plan(1)
test('Add should error on invalid environment', () => {
let item = {
action: 'add',
env: 'idk',
name: 'foo',
value: 'bar',
}
addRemove({ ...params, ...item }, function done (err) {
if (err) t.match(err.message, /Invalid environment/, 'Errored on invalid environment')
else t.fail('Expected invalid environment error')
if (err) assert.match(err.message, /Invalid environment/, 'Errored on invalid environment')
else assert.fail('Expected invalid environment error')
})
})

test('Remove should error on invalid environment', t => {
t.plan(1)
test('Remove should error on invalid environment', () => {
let item = {
action: 'remove',
env: 'idk',
name: 'foo',
value: 'bar',
}
addRemove({ ...params, ...item }, function done (err) {
if (err) t.match(err.message, /Invalid environment/, 'Errored on invalid environment')
else t.fail('Expected invalid environment error')
if (err) assert.match(err.message, /Invalid environment/, 'Errored on invalid environment')
else assert.fail('Expected invalid environment error')
})
})

test('Adding should callback with error on invalid name', t => {
t.plan(1)
test('Adding should callback with error on invalid name', () => {
let item = {
action: 'add',
env: 'testing',
name: '$idk',
value: 'bar',
}
addRemove({ ...params, ...item }, function done (err) {
if (err) t.match(err.message, /Invalid name/, 'Errored on invalid name')
else t.fail('Expected invalid name error')
if (err) assert.match(err.message, /Invalid name/, 'Errored on invalid name')
else assert.fail('Expected invalid name error')
})
})

test('Remove should callback with error on invalid name', t => {
t.plan(1)
test('Remove should callback with error on invalid name', () => {
let item = {
action: 'remove',
env: 'testing',
name: '$idk',
value: 'bar',
}
addRemove({ ...params, ...item }, function done (err) {
if (err) t.match(err.message, /Invalid name/, 'Errored on invalid name')
else t.fail('Expected invalid name error')
if (err) assert.match(err.message, /Invalid name/, 'Errored on invalid name')
else assert.fail('Expected invalid name error')
})
})

test('Add should error on missing value', t => {
t.plan(1)
test('Add should error on missing value', () => {
let item = {
action: 'add',
env: 'testing',
name: 'foo',
}
addRemove({ ...params, ...item }, function done (err) {
if (err) t.match(err.message, /Invalid value/, 'Errored on invalid value')
else t.fail('Expected invalid value error')
if (err) assert.match(err.message, /Invalid value/, 'Errored on invalid value')
else assert.fail('Expected invalid value error')
})
})

test('Add should treat all provided values as valid', t => {
let fake = sinon.fake.yields()
test('Add should treat all provided values as valid', () => {
let fake = mock.fn((params, callback) => callback())
aws.mock('SSM', 'putParameter', fake)
let valids = [
'http://foo.com/?bar=baz',
Expand All @@ -92,7 +87,6 @@ test('Add should treat all provided values as valid', t => {
'[${foo}]',
'(%)^{}idk!',
]
t.plan(valids.length)
series(valids.map(value => {
return callback => {
let item = {
Expand All @@ -102,21 +96,20 @@ test('Add should treat all provided values as valid', t => {
value
}
addRemove({ ...params, ...item }, function done (err) {
if (err) t.fail(err, 'Errored on valid values')
if (err) assert.fail(err, 'Errored on valid values')
else {
t.pass('No error returned')
assert.ok(true, 'No error returned')
callback()
}
})
}
}))
sinon.restore()
mock.restoreAll()
aws.restore('SSM')
})

test('Adding should callback with error if SSM errors', t => {
t.plan(1)
let fake = sinon.fake.yields({ boom: true })
test('Adding should callback with error if SSM errors', () => {
let fake = mock.fn((params, callback) => callback({ boom: true }))
aws.mock('SSM', 'putParameter', fake)
let item = {
action: 'add',
Expand All @@ -125,40 +118,38 @@ test('Adding should callback with error if SSM errors', t => {
value: 'bar',
}
addRemove({ ...params, ...item }, function done (err) {
if (err) t.ok(err, 'Errored on SSM issue')
else t.fail('Expected SSM error')
if (err) assert.ok(err, 'Errored on SSM issue')
else assert.fail('Expected SSM error')
})
aws.restore('SSM')
})

test('Remove should callback with error if SSM errors', t => {
t.plan(1)
let fake = sinon.fake.yields({ boom: true })
test('Remove should callback with error if SSM errors', () => {
let fake = mock.fn((params, callback) => callback({ boom: true }))
aws.mock('SSM', 'deleteParameter', fake)
let item = {
action: 'remove',
env: 'testing',
name: 'foo',
}
addRemove({ ...params, ...item }, function done (err) {
if (err) t.ok(err, 'Errored on SSM issue')
else t.fail('Expected SSM error')
if (err) assert.ok(err, 'Errored on SSM issue')
else assert.fail('Expected SSM error')
})
aws.restore('SSM')
})

test('Remove should not callback with error if parameter is not found', t => {
t.plan(1)
let fake = sinon.fake.yields({ code: 'ParameterNotFound' })
test('Remove should not callback with error if parameter is not found', () => {
let fake = mock.fn((params, callback) => callback({ code: 'ParameterNotFound' }))
aws.mock('SSM', 'deleteParameter', fake)
let item = {
action: 'remove',
env: 'testing',
name: 'foo',
}
addRemove({ ...params, ...item }, function done (err) {
if (err) t.fail('Should not have errored')
else t.pass(`No error returned`)
if (err) assert.fail('Should not have errored')
else assert.ok(true, 'No error returned')
})
aws.restore('SSM')
})
Expand Down
37 changes: 17 additions & 20 deletions test/_all-tests.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* let test = require('tape')
let sinon = require('sinon')
/* const { test, mock } = require('node:test')
const assert = require('node:assert')
let AWS = require('aws-sdk')
let aws = require('aws-sdk-mock')
aws.setSDKInstance(AWS)
Expand All @@ -12,38 +12,35 @@ let params = { inventory: { inv: {
aws: { region: 'us-west-2' },
} }, update }

test('getEnv should callback with error if SSM errors', t => {
t.plan(1)
let fake = sinon.fake.yields({ boom: true })
test('getEnv should callback with error if SSM errors', () => {
let fake = mock.fn((query, callback) => callback({ boom: true }))
aws.mock('SSM', 'getParametersByPath', fake)
getEnv(params, function done (err) {
if (err) t.ok(err, 'got an error when SSM explodes')
else t.fail('no error returned when SSM explodes')
if (err) assert.ok(err, 'got an error when SSM explodes')
else assert.fail('no error returned when SSM explodes')
aws.restore('SSM')
})
})

test('getEnv should return massaged data from SSM', t => {
t.plan(1)
let fake = sinon.fake.yields(null, {
test('getEnv should return massaged data from SSM', () => {
let fake = mock.fn((query, callback) => callback(null, {
Parameters: [ { Name: 'ssm/fakeappname/testing/key', Value: 'value' } ]
})
}))
aws.mock('SSM', 'getParametersByPath', fake)
getEnv(params, function done (err, results) {
if (err) {
t.fail('unexpected error callback when ssm returns proper data')
assert.fail('unexpected error callback when ssm returns proper data')
console.log(err)
}
else t.deepEqual(results, [ { app: 'appname', env: 'testing', name: 'key', value: 'value' } ], 'got expected format for SSM env vars')
else assert.deepStrictEqual(results, [ { app: 'appname', env: 'testing', name: 'key', value: 'value' } ], 'got expected format for SSM env vars')
aws.restore('SSM')
})
})

test('getEnv should be able to handle paginated data from SSM', t => {
t.plan(2)
let fake = sinon.fake(function (query, callback) {
test('getEnv should be able to handle paginated data from SSM', () => {
let fake = mock.fn(function (query, callback) {
// Only on the first call, provide a next token.
if (fake.callCount == 1) {
if (fake.mock.callCount() === 1) {
callback(null, {
Parameters: [ { Name: 'ssm/fakeappname/testing/key', Value: 'value' } ],
NextToken: 'yep'
Expand All @@ -56,12 +53,12 @@ test('getEnv should be able to handle paginated data from SSM', t => {
aws.mock('SSM', 'getParametersByPath', fake)
getEnv(params, function done (err, results) {
if (err) {
t.fail('unexpected error')
assert.fail('unexpected error')
console.log(err)
}
else {
t.equals(fake.callCount, 2, 'SSM.getParametersByPath called twice when next token is present')
t.equals(results.length, 2, 'returned results from both pages')
assert.strictEqual(fake.mock.callCount(), 2, 'SSM.getParametersByPath called twice when next token is present')
assert.strictEqual(results.length, 2, 'returned results from both pages')
}
aws.restore('SSM')
})
Expand Down
20 changes: 10 additions & 10 deletions test/_write-tests.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
let test = require('tape')
let sinon = require('sinon')
const { test, mock } = require('node:test')
const assert = require('node:assert')
let write = require('../src/_write')
let fs = require('fs')
let { updater } = require('@architect/utils')
let update = updater('Env')
let params = { appname: 'fakeappname', update }

test('_write should write out env vars to a .arc-env file', t => {
t.plan(2)
test('_write should write out env vars to a .arc-env file', () => {
process.env.ARC_TESTING = true
let fake = sinon.fake.returns()
sinon.replace(fs, 'writeFileSync', fake)
let fake = mock.fn()
mock.method(fs, 'writeFileSync', fake)
write({ envVars: [
{ env: 'testing', name: 'one', value: '1' },
{ env: 'staging', name: 'two', value: '2' },
Expand All @@ -22,8 +21,8 @@ test('_write should write out env vars to a .arc-env file', t => {
{ env: 'production', name: 'dee', value: 'dee1.23' },
{ env: 'production', name: 'eee', value: '1.23eee' },
], ...params } )
let args = fake.args
let file = args[0][1].split('\n').slice(1).join('\n') // Lop off the comment at the top of the block
let calls = fake.mock.calls
let file = calls[0].arguments[1].split('\n').slice(1).join('\n') // Lop off the comment at the top of the block
let contents = `@env
testing
one 1
Expand All @@ -41,6 +40,7 @@ production
eee 1.23eee
`
delete process.env.ARC_TESTING
t.ok(args[0][0].endsWith('preferences.arc'), 'wrote to a file that ends in preferences.arc')
t.equal(file, contents, 'All env vars were placed correctly in the preferences file')
assert.ok(calls[0].arguments[0].endsWith('preferences.arc'), 'wrote to a file that ends in preferences.arc')
assert.strictEqual(file, contents, 'All env vars were placed correctly in the preferences file')
mock.restoreAll()
})
Loading