Skip to content

Commit 3ad1add

Browse files
committed
hbd!
0 parents  commit 3ad1add

File tree

8 files changed

+377
-0
lines changed

8 files changed

+377
-0
lines changed

.github/code_of_conduct.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Architect Code of Conduct
2+
3+
We are strongly committed to ensuring the Architect community, and the various online and offline spaces in which its members congregate and collaborate, are safe, positive, inclusive, constructive, and welcoming environments.
4+
5+
As such, the Architect project adheres to the [OpenJS Foundation Code of Conduct](https://github.com/openjs-foundation/cross-project-council/blob/master/CODE_OF_CONDUCT.md), which itself adheres to the [Contributor Covenant](https://www.contributor-covenant.org).
6+
7+
Lack of familiarity with this or the OpenJS Foundation Codes of Conduct, or the Contributor covenant, is not an excuse for non-adherence.
8+
9+
10+
# Reporting
11+
If you are the subject of any behavior prohibited by this Code of Conduct, or observe someone who is, please contact an Architect team member immediately.
12+
13+
If you know an Architect team member, you may wish to contact them personally (and you should); but if not, please [contact us via email](mailto:[email protected]).
14+
15+
If possible, please attempt to collect any relevant information and evidence, including links, screenshots, or other recordings of any incident.
16+
17+
Reports will be handled with the utmost care, confidence, and sensitivity towards the individual(s) reporting.
18+
19+
20+
# Enforcement
21+
Should incidents arise, upon adjudication those found to be in violation of this Code of Conduct may be immediately expelled from the Architect community, including events, forums, chat workspaces, code repositories, and any other place where Architect community members collaborate.

.github/contributing.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Contributing
2+
3+
## First: go read the [Architect Code of Conduct](/.github/code_of_conduct.md)
4+
5+
### Agreement to the Architect Code of Conduct
6+
By participating in and contributing to the Architect community — including, but not limited to its open source projects, any related online venues such as GitHub, Slack, and in-person events, etc. — you agree to the [Architect Code of Conduct](/.github/code_of_conduct.md).
7+
8+
Lack of familiarity with this Code of Conduct is not an excuse for not adhering to it.

.github/pull_request_template.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
## Thank you for helping out! ✨
2+
3+
### We really appreciate your commitment to improving Architect
4+
5+
To maintain a high standard of quality in our releases, before merging every pull request we ask that you've completed the following:
6+
7+
- [ ] Forked the repo and created your branch from `master`
8+
- [ ] Made sure tests pass (run `npm it` from the repo root)
9+
- [ ] Expanded test coverage related to your changes:
10+
- [ ] Added and/or updated unit tests (if appropriate)
11+
- [ ] Added and/or updated integration tests (if appropriate)
12+
- [ ] Updated relevant documentation:
13+
- [ ] Internal to this repo (e.g. `readme.md`, help docs, inline docs & comments, etc.)
14+
- [ ] [Architect docs (arc.codes)](https://github.com/architect/arc.codes)
15+
- [ ] Summarized your changes in `changelog.md`
16+
- [ ] Linked to any related issues, PRs, etc. below that may relate to, consume, or necessitate these changes
17+
18+
Please also be sure to completed the CLA (if you haven't already).
19+
20+
Learn more about [contributing to Architect here](https://arc.codes/intro/community).
21+
22+
Thanks again!

.github/workflows/build.yml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
name: Node CI
2+
3+
# Push tests pushes; PR tests merges
4+
on: [ push, pull_request ]
5+
6+
defaults:
7+
run:
8+
shell: bash
9+
10+
jobs:
11+
12+
# Test the build
13+
build:
14+
# Setup
15+
runs-on: ${{ matrix.os }}
16+
strategy:
17+
matrix:
18+
node-version: [ 14.x, 16.x ]
19+
os: [ windows-latest, ubuntu-latest, macOS-latest ]
20+
21+
# Go
22+
steps:
23+
- name: Check out repo
24+
uses: actions/checkout@v2
25+
26+
- name: Set up Node.js
27+
uses: actions/setup-node@v2
28+
with:
29+
node-version: ${{ matrix.node-version }}
30+
31+
- name: Env
32+
run: |
33+
echo "Event name: ${{ github.event_name }}"
34+
echo "Git ref: ${{ github.ref }}"
35+
echo "GH actor: ${{ github.actor }}"
36+
echo "SHA: ${{ github.sha }}"
37+
VER=`node --version`; echo "Node ver: $VER"
38+
VER=`npm --version`; echo "npm ver: $VER"
39+
40+
- name: Install
41+
run: npm install
42+
43+
- name: Test
44+
run: npm test
45+
env:
46+
CI: true
47+
48+
# ----- Only git tag testing + package publishing beyond this point ----- #
49+
50+
# Publish to package registries
51+
publish:
52+
# Setup
53+
needs: build
54+
if: startsWith(github.ref, 'refs/tags/v')
55+
runs-on: ubuntu-latest
56+
57+
# Go
58+
steps:
59+
- name: Check out repo
60+
uses: actions/checkout@v2
61+
62+
- name: Set up Node.js
63+
uses: actions/setup-node@v2
64+
with:
65+
node-version: 14
66+
registry-url: https://registry.npmjs.org/
67+
68+
# Publish to npm
69+
- name: Publish @RC to npm
70+
if: contains(github.ref, 'RC')
71+
run: npm publish --tag RC
72+
env:
73+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
74+
75+
- name: Publish @latest to npm
76+
if: contains(github.ref, 'RC') == false #'!contains()'' doesn't work lol
77+
run: npm publish
78+
env:
79+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package-lock=false

package.json

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"name": "@architect/plugin-lambda-invoker",
3+
"version": "0.0.0",
4+
"description": "Interactively invoke Lambdas in Architect Sandbox with arbitrary events",
5+
"main": "src/index.js",
6+
"scripts": {
7+
"test": "npm run lint",
8+
"lint": "eslint . --fix"
9+
},
10+
"engines": {
11+
"node": ">=14"
12+
},
13+
"files": [
14+
"src/*"
15+
],
16+
"repository": {
17+
"type": "git",
18+
"url": "git+https://github.com/architect/plugin-lambda-invoker.git"
19+
},
20+
"license": "Apache-2.0",
21+
"bugs": {
22+
"url": "https://github.com/architect/plugin-lambda-invoker/issues"
23+
},
24+
"homepage": "https://github.com/architect/plugin-lambda-invoker#readme",
25+
"dependencies": {
26+
"@architect/utils": "^3.0.4",
27+
"enquirer": "^2.3.6"
28+
},
29+
"devDependencies": {
30+
"@architect/eslint-config": "^2.0.1",
31+
"eslint": "^8.11.0"
32+
},
33+
"eslintConfig": {
34+
"extends": "@architect/eslint-config"
35+
},
36+
"keywords": [
37+
"arc",
38+
"architect",
39+
"plugin",
40+
"lambda"
41+
]
42+
}

readme.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
[<img src="https://assets.arc.codes/[email protected]" width=500>](https://www.npmjs.com/package/@architect/architect/plugin-lambda-invoker)
2+
3+
## [`@architect/architect/plugin-lambda-invoker`](https://www.npmjs.com/package/@architect/architect/plugin-lambda-invoker)
4+
5+
> Interactively invoke Lambdas in Architect Sandbox with arbitrary events
6+
7+
[![GitHub CI status](https://github.com/architect/architect/plugin-lambda-invoker/workflows/Node%20CI/badge.svg)](https://github.com/architect/architect/plugin-lambda-invoker/actions?query=workflow%3A%22Node+CI%22)
8+
9+
10+
## Install
11+
12+
Into your existing Architect project:
13+
14+
```sh
15+
npm i @architect/architect/plugin-lambda-invoker --save-dev
16+
```
17+
18+
Add the following to your Architect project manifest (usually `app.arc`):
19+
20+
```arc
21+
@plugins
22+
architect/architect/plugin-lambda-invoker
23+
```
24+
25+
26+
## Usage
27+
28+
While Sandbox is running, type `i` in your terminal to bring up the Lambda invocation menu. Then select the Lambda you'd like to invoke.
29+
30+
By default, this plugin will populate your menu with all `@events`, `@queues`, `@scheduled`, and `@tables-streams`; you can limit this menu (or expand it with additional pragmas) by adding the following setting to a `pref[erence]s.arc` file:
31+
32+
```arc
33+
@sandbox
34+
invoker http scheduled # This would populate @http + @scheduled Lambdas, and ignore all others
35+
```
36+
37+
> Tip: you can navigate the invocation menu by typing numbers (zero-indexed)!
38+
39+
40+
### Invocation mocks
41+
42+
By default, Lambdas are invokved with an empty payload (`{}`); if you'd like to invoke your Lambdas with arbitrary payloads, create a file containing invocation mocks.
43+
44+
Invocation mock files live in your root with one of these filenames: `sandbox-invoke-mocks.json` or `sandbox-invoke-mocks.js`. These files should be structured like so:
45+
46+
Assuming this project manifest:
47+
48+
```arc
49+
@events
50+
background-task
51+
52+
@queues
53+
analytics
54+
55+
@scheduled
56+
backup-database
57+
```
58+
59+
If you wanted to add one or more mocks to each of the three Lambdas above, create the following `sandbox-invoke-mocks.js` (or equivalent JSON) file with the format of `[pragmaName][lambdaName][mockName]`:
60+
61+
```js
62+
module.exports = {
63+
events: {
64+
'background-task': {
65+
'my-first-mock': { /* payload */ },
66+
'another-mock': { /* payload */ },
67+
}
68+
},
69+
queues: {
70+
analytics: {
71+
'one-more-mock': { /* payload */ },
72+
'just-a-mock': { /* payload */ },
73+
}
74+
},
75+
scheduled: {
76+
'backup-database': {
77+
'a-mock-for-this': { /* payload */ },
78+
'the-last-mock': { /* payload */ },
79+
}
80+
},
81+
}
82+
```
83+
84+
> Tip: when using `sandbox-invoke-mocks.js`, you can dynamically (synchronously) generate mocks on startup

src/index.js

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
let { join } = require('path')
2+
let { existsSync, readFileSync } = require('fs')
3+
let { updater } = require('@architect/utils')
4+
let { prompt } = require('enquirer')
5+
let colors = require('ansi-colors')
6+
let update = updater('Invoker')
7+
8+
module.exports = {
9+
sandbox: {
10+
start: async ({ inventory: { inv }, invoke }) => {
11+
update.status(`Event invoker started, select an event to invoke by pressing 'i'`)
12+
let { cwd, preferences } = inv._project
13+
let jsonMocks = join(cwd, 'sandbox-invoke-mocks.json')
14+
let jsMocks = join(cwd, 'sandbox-invoke-mocks.js')
15+
16+
let pragmas = [ 'events', 'queues', 'scheduled', 'tables-streams' ]
17+
let prefs = preferences?.sandbox?.invoker
18+
if (prefs) {
19+
if (Array.isArray(prefs)) pragmas = prefs
20+
else if (typeof prefs === 'string') pragmas = [ prefs ]
21+
else throw Error('Invalid @architect/plugin-lambda-invoker plugin preferences')
22+
}
23+
24+
// Build out the availble event list
25+
let events = {}
26+
pragmas.forEach(pragma => {
27+
if (inv[pragma]) inv[pragma].forEach(({ name }) => {
28+
events[`@${pragma} ${name}`] = { pragma, name }
29+
})
30+
})
31+
// Add a cancel option should one desire
32+
events.cancel = ''
33+
34+
process.stdin.on('data', async function eventInvokeListener (input) {
35+
input = String(input)
36+
// Reset Enquirer's styles
37+
let options = {
38+
prefix: colors.white(colors.symbols.question),
39+
styles: {
40+
em: colors.cyan, // Clear underlines
41+
danger: colors.red,
42+
strong: colors.white,
43+
}
44+
}
45+
if (input === 'i') {
46+
if (Object.keys(events).length === 1) {
47+
let none = 'No Lambdas found to invoke'
48+
if (pragmas.length) update.status(none, `Using the following pragmas: @${pragmas.join(', @')}`)
49+
else update.status(none)
50+
return
51+
}
52+
53+
let payload = {}
54+
let mocks
55+
let mockName = 'empty'
56+
57+
// Load invocation mocks
58+
if (existsSync(jsonMocks)) {
59+
mocks = JSON.parse(readFileSync(jsonMocks))
60+
}
61+
else if (existsSync(jsMocks)) {
62+
// Make sure changes to mocks are always reflected
63+
delete require.cache[require.resolve(jsMocks)]
64+
// eslint-disable-next-line
65+
mocks = require(jsMocks)
66+
}
67+
68+
let { lambda } = await prompt({
69+
type: 'select',
70+
name: 'lambda',
71+
numbered: true,
72+
message: 'Which event do you want to invoke?',
73+
hint: '\nYou can use numbers to change your selection',
74+
choices: Object.keys(events),
75+
}, options)
76+
if (lambda === 'cancel') return end()
77+
let { pragma, name } = events[lambda]
78+
79+
// Present options for mocks (if any)
80+
if (mocks?.[pragma]?.[name]) {
81+
let selection = await prompt({
82+
type: 'select',
83+
name: 'mock',
84+
numbered: true,
85+
message: 'Which mock do you want to invoke?',
86+
choices: [ ...Object.keys(mocks[pragma][name]), 'empty' ],
87+
}, options)
88+
mockName = selection.mock
89+
payload = mocks[pragma][name][mockName] || {}
90+
}
91+
92+
// Wrap it up and invoke!
93+
let msg = `Invoking @${pragma} ${name}`
94+
msg += ` with ${mockName === 'empty' ? 'empty' : `'${mockName}'`} payload`
95+
update.status(msg)
96+
await invoke({ pragma, name, payload })
97+
end()
98+
}
99+
})
100+
},
101+
end: async () => {
102+
// Only remove our listener; removing Enquirer causes funky behavior
103+
process.stdin.rawListeners('data').forEach(fn => {
104+
if (fn.name === 'eventInvokeListener') {
105+
process.stdin.removeListener('data', fn)
106+
}
107+
})
108+
end()
109+
}
110+
}
111+
}
112+
113+
// Necessary per Enquirer #326
114+
function end () {
115+
if (process.stdin.isTTY) {
116+
process.stdin.setRawMode(true)
117+
process.stdin.setEncoding('utf8')
118+
process.stdin.resume()
119+
}
120+
}

0 commit comments

Comments
 (0)