workpeg 0.4.3__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {workpeg-0.4.3/src/workpeg.egg-info → workpeg-0.5.0}/PKG-INFO +1 -1
- {workpeg-0.4.3 → workpeg-0.5.0}/pyproject.toml +1 -1
- workpeg-0.5.0/src/workpeg/cli.py +373 -0
- {workpeg-0.4.3 → workpeg-0.5.0/src/workpeg.egg-info}/PKG-INFO +1 -1
- {workpeg-0.4.3 → workpeg-0.5.0}/tests/test_cli.py +35 -15
- {workpeg-0.4.3 → workpeg-0.5.0}/tests/test_create_new.py +4 -5
- workpeg-0.4.3/src/workpeg/cli.py +0 -118
- {workpeg-0.4.3 → workpeg-0.5.0}/LICENSE +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/MANIFEST.in +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/README.md +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/setup.cfg +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg/__init__.py +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg/build.py +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg/config.py +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg/context.py +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg/create_new.py +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg/run.py +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg/runtime.py +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg/submit.py +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg/templates/__init__.py +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg/templates/functions/Dockerfile +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg/templates/functions/LICENSE +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg/templates/functions/README.md +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg/templates/functions/app/__init__.py +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg/templates/functions/app/main.py +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg/templates/functions/requirements.txt +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg/utils.py +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg.egg-info/SOURCES.txt +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg.egg-info/dependency_links.txt +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg.egg-info/entry_points.txt +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg.egg-info/requires.txt +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/src/workpeg.egg-info/top_level.txt +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/tests/test_build.py +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/tests/test_context.py +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/tests/test_run.py +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/tests/test_runtime.py +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/tests/test_submit.py +0 -0
- {workpeg-0.4.3 → workpeg-0.5.0}/tests/test_utils.py +0 -0
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from workpeg import build, create_new, run, runtime, submit
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
from importlib.metadata import version
|
|
8
|
+
__version__ = version("workpeg")
|
|
9
|
+
except Exception:
|
|
10
|
+
__version__ = "unknown"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
14
|
+
p = argparse.ArgumentParser(
|
|
15
|
+
prog="workpeg",
|
|
16
|
+
description=(
|
|
17
|
+
"Workpeg CLI\n\n"
|
|
18
|
+
"Build, run, and deploy Workpeg workloads."
|
|
19
|
+
),
|
|
20
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
21
|
+
epilog=(
|
|
22
|
+
"Examples:\n"
|
|
23
|
+
" workpeg function new hello\n"
|
|
24
|
+
" workpeg function build\n"
|
|
25
|
+
" workpeg function run --with docker\n"
|
|
26
|
+
"\n"
|
|
27
|
+
"Use 'workpeg <namespace> --help' for more information.\n"
|
|
28
|
+
),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
p.add_argument(
|
|
32
|
+
"-v",
|
|
33
|
+
"--version",
|
|
34
|
+
action="version",
|
|
35
|
+
version=f"workpeg {__version__}",
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
root_sub = p.add_subparsers(
|
|
39
|
+
dest="namespace",
|
|
40
|
+
metavar="{function}",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
#
|
|
44
|
+
# FUNCTION NAMESPACE
|
|
45
|
+
#
|
|
46
|
+
function_p = root_sub.add_parser(
|
|
47
|
+
"function",
|
|
48
|
+
help="Manage Workpeg Functions",
|
|
49
|
+
description=(
|
|
50
|
+
"Manage Workpeg Functions.\n\n"
|
|
51
|
+
"Functions are portable execution units that run\n"
|
|
52
|
+
"inside isolated runtimes such as Docker and\n"
|
|
53
|
+
"future Firecracker microVM runtimes."
|
|
54
|
+
),
|
|
55
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
56
|
+
epilog=(
|
|
57
|
+
"Examples:\n"
|
|
58
|
+
" workpeg function new hello\n"
|
|
59
|
+
" workpeg function build\n"
|
|
60
|
+
" workpeg function run --with docker\n"
|
|
61
|
+
" workpeg function runtime --server\n"
|
|
62
|
+
" workpeg function submit hello:1.0.0\n"
|
|
63
|
+
),
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
function_p.set_defaults(_namespace_parser=function_p)
|
|
67
|
+
|
|
68
|
+
function_sub = function_p.add_subparsers(
|
|
69
|
+
dest="command",
|
|
70
|
+
metavar="{new,build,run,runtime,submit}",
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
#
|
|
74
|
+
# FUNCTION NEW
|
|
75
|
+
#
|
|
76
|
+
new_p = function_sub.add_parser(
|
|
77
|
+
"new",
|
|
78
|
+
help="Create a new function project",
|
|
79
|
+
description=(
|
|
80
|
+
"Create a new Workpeg Function project scaffold.\n\n"
|
|
81
|
+
"Generated structure includes:\n"
|
|
82
|
+
" - app/main.py\n"
|
|
83
|
+
" - workpeg.json\n"
|
|
84
|
+
" - Dockerfile\n"
|
|
85
|
+
" - tests/\n"
|
|
86
|
+
),
|
|
87
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
88
|
+
epilog=(
|
|
89
|
+
"Examples:\n"
|
|
90
|
+
" workpeg function new hello\n"
|
|
91
|
+
" workpeg function new hello --force\n"
|
|
92
|
+
),
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
new_p.add_argument(
|
|
96
|
+
"path",
|
|
97
|
+
help="Directory path for the new function project",
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
new_p.add_argument(
|
|
101
|
+
"--force",
|
|
102
|
+
action="store_true",
|
|
103
|
+
help="Overwrite existing files if the directory already exists",
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
new_p.set_defaults(_handler="function.new")
|
|
107
|
+
|
|
108
|
+
#
|
|
109
|
+
# FUNCTION RUNTIME
|
|
110
|
+
#
|
|
111
|
+
runtime_p = function_sub.add_parser(
|
|
112
|
+
"runtime",
|
|
113
|
+
help="Run the raw function runtime",
|
|
114
|
+
description=(
|
|
115
|
+
"Run the low-level Workpeg runtime.\n\n"
|
|
116
|
+
"Default mode:\n"
|
|
117
|
+
" Reads a single invocation from stdin.\n\n"
|
|
118
|
+
"Server mode:\n"
|
|
119
|
+
" Starts a persistent HTTP runtime."
|
|
120
|
+
),
|
|
121
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
122
|
+
epilog=(
|
|
123
|
+
"Examples:\n"
|
|
124
|
+
" echo '{\"context\": {}, \"payload\": {}}' | \\\n"
|
|
125
|
+
" workpeg function runtime\n\n"
|
|
126
|
+
" workpeg function runtime --server\n"
|
|
127
|
+
),
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
runtime_p.add_argument(
|
|
131
|
+
"--server",
|
|
132
|
+
action="store_true",
|
|
133
|
+
help="Run as a persistent HTTP server",
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
runtime_p.set_defaults(_handler="function.runtime")
|
|
137
|
+
|
|
138
|
+
#
|
|
139
|
+
# FUNCTION BUILD
|
|
140
|
+
#
|
|
141
|
+
build_p = function_sub.add_parser(
|
|
142
|
+
"build",
|
|
143
|
+
help="Build the function Docker image",
|
|
144
|
+
description=(
|
|
145
|
+
"Build a Docker image for the current function project."
|
|
146
|
+
),
|
|
147
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
148
|
+
epilog=(
|
|
149
|
+
"Examples:\n"
|
|
150
|
+
" workpeg function build\n"
|
|
151
|
+
" workpeg function build --tag my-image\n"
|
|
152
|
+
),
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
build_p.add_argument(
|
|
156
|
+
"--path",
|
|
157
|
+
default=".",
|
|
158
|
+
help="Path to the function project (default: current directory)",
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
build_p.add_argument(
|
|
162
|
+
"--tag",
|
|
163
|
+
default=None,
|
|
164
|
+
help="Custom Docker image tag",
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
build_p.set_defaults(_handler="function.build")
|
|
168
|
+
|
|
169
|
+
#
|
|
170
|
+
# FUNCTION RUN
|
|
171
|
+
#
|
|
172
|
+
run_p = function_sub.add_parser(
|
|
173
|
+
"run",
|
|
174
|
+
help="Run the function using a configured runtime",
|
|
175
|
+
description=(
|
|
176
|
+
"Run a Workpeg Function locally.\n\n"
|
|
177
|
+
"Docker runtime:\n"
|
|
178
|
+
" Starts a warm containerized runtime.\n\n"
|
|
179
|
+
"Cracker runtime:\n"
|
|
180
|
+
" Reserved for future Firecracker microVM support."
|
|
181
|
+
),
|
|
182
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
183
|
+
epilog=(
|
|
184
|
+
"Examples:\n"
|
|
185
|
+
" workpeg function run --with docker\n"
|
|
186
|
+
" workpeg function run --network workpeg_net\n"
|
|
187
|
+
" workpeg function run --name fn-hello\n"
|
|
188
|
+
" workpeg function run --no-expose\n"
|
|
189
|
+
),
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
run_p.add_argument(
|
|
193
|
+
"--with",
|
|
194
|
+
dest="with_runtime",
|
|
195
|
+
choices=["docker", "cracker"],
|
|
196
|
+
help="Runtime backend to use",
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
run_p.add_argument(
|
|
200
|
+
"--path",
|
|
201
|
+
default=".",
|
|
202
|
+
help="Path to the function project",
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
run_p.add_argument(
|
|
206
|
+
"--no-build",
|
|
207
|
+
action="store_true",
|
|
208
|
+
help="Skip Docker image build step",
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
run_p.add_argument(
|
|
212
|
+
"--network",
|
|
213
|
+
default=None,
|
|
214
|
+
help="Docker network to attach the container to",
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
run_p.add_argument(
|
|
218
|
+
"--name",
|
|
219
|
+
default=None,
|
|
220
|
+
help="Container name",
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
run_p.add_argument(
|
|
224
|
+
"--no-expose",
|
|
225
|
+
action="store_true",
|
|
226
|
+
help="Do not expose the runtime port to the host",
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
run_p.set_defaults(_handler="function.run")
|
|
230
|
+
|
|
231
|
+
#
|
|
232
|
+
# FUNCTION SUBMIT
|
|
233
|
+
#
|
|
234
|
+
submit_p = function_sub.add_parser(
|
|
235
|
+
"submit",
|
|
236
|
+
help="Submit a function bundle",
|
|
237
|
+
description=(
|
|
238
|
+
"Package and upload a Workpeg Function to the registry."
|
|
239
|
+
),
|
|
240
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
241
|
+
epilog=(
|
|
242
|
+
"Examples:\n"
|
|
243
|
+
" workpeg function submit hello:1.0.0\n"
|
|
244
|
+
" workpeg function submit hello:1.0.0 --timeout 30\n"
|
|
245
|
+
),
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
submit_p.add_argument(
|
|
249
|
+
"ref",
|
|
250
|
+
help="Function reference in format <name>:<version>",
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
submit_p.add_argument(
|
|
254
|
+
"--api",
|
|
255
|
+
default=None,
|
|
256
|
+
help="Override Workpeg registry API base URL",
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
submit_p.add_argument(
|
|
260
|
+
"--path",
|
|
261
|
+
default=None,
|
|
262
|
+
help="Path to the function project",
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
submit_p.add_argument(
|
|
266
|
+
"--timeout",
|
|
267
|
+
type=int,
|
|
268
|
+
default=None,
|
|
269
|
+
help="HTTP request timeout in seconds",
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
submit_p.set_defaults(_handler="function.submit")
|
|
273
|
+
|
|
274
|
+
return p
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def main(argv=None) -> None:
|
|
278
|
+
argv = argv if argv is not None else sys.argv[1:]
|
|
279
|
+
parser = build_parser()
|
|
280
|
+
|
|
281
|
+
if not argv:
|
|
282
|
+
parser.print_help()
|
|
283
|
+
return
|
|
284
|
+
|
|
285
|
+
args = parser.parse_args(argv)
|
|
286
|
+
|
|
287
|
+
if not hasattr(args, "_handler"):
|
|
288
|
+
parser.print_help()
|
|
289
|
+
return
|
|
290
|
+
|
|
291
|
+
#
|
|
292
|
+
# function new
|
|
293
|
+
#
|
|
294
|
+
if args._handler == "function.new":
|
|
295
|
+
try:
|
|
296
|
+
out = create_new.create_new_project(
|
|
297
|
+
args.path,
|
|
298
|
+
force=args.force,
|
|
299
|
+
)
|
|
300
|
+
print(str(out))
|
|
301
|
+
except create_new.TemplateError as e:
|
|
302
|
+
print(f"ERROR: {e}", file=sys.stderr)
|
|
303
|
+
raise SystemExit(2)
|
|
304
|
+
return
|
|
305
|
+
|
|
306
|
+
#
|
|
307
|
+
# function runtime
|
|
308
|
+
#
|
|
309
|
+
if args._handler == "function.runtime":
|
|
310
|
+
runtime_argv = []
|
|
311
|
+
|
|
312
|
+
if args.server:
|
|
313
|
+
runtime_argv.append("--server")
|
|
314
|
+
|
|
315
|
+
runtime.main(runtime_argv)
|
|
316
|
+
return
|
|
317
|
+
|
|
318
|
+
#
|
|
319
|
+
# function submit
|
|
320
|
+
#
|
|
321
|
+
if args._handler == "function.submit":
|
|
322
|
+
submit_argv = [args.ref]
|
|
323
|
+
|
|
324
|
+
if args.api:
|
|
325
|
+
submit_argv += ["--api", args.api]
|
|
326
|
+
|
|
327
|
+
if args.path:
|
|
328
|
+
submit_argv += ["--path", args.path]
|
|
329
|
+
|
|
330
|
+
if args.timeout is not None:
|
|
331
|
+
submit_argv += ["--timeout", str(args.timeout)]
|
|
332
|
+
|
|
333
|
+
submit.main(submit_argv)
|
|
334
|
+
return
|
|
335
|
+
|
|
336
|
+
#
|
|
337
|
+
# function build
|
|
338
|
+
#
|
|
339
|
+
if args._handler == "function.build":
|
|
340
|
+
image = build.build_image(
|
|
341
|
+
path=args.path,
|
|
342
|
+
tag=args.tag,
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
print(image)
|
|
346
|
+
return
|
|
347
|
+
|
|
348
|
+
#
|
|
349
|
+
# function run
|
|
350
|
+
#
|
|
351
|
+
if args._handler == "function.run":
|
|
352
|
+
run_argv = []
|
|
353
|
+
|
|
354
|
+
if args.with_runtime:
|
|
355
|
+
run_argv += ["--with", args.with_runtime]
|
|
356
|
+
|
|
357
|
+
if args.path:
|
|
358
|
+
run_argv += ["--path", args.path]
|
|
359
|
+
|
|
360
|
+
if args.no_build:
|
|
361
|
+
run_argv.append("--no-build")
|
|
362
|
+
|
|
363
|
+
if args.network:
|
|
364
|
+
run_argv += ["--network", args.network]
|
|
365
|
+
|
|
366
|
+
if args.name:
|
|
367
|
+
run_argv += ["--name", args.name]
|
|
368
|
+
|
|
369
|
+
if args.no_expose:
|
|
370
|
+
run_argv.append("--no-expose")
|
|
371
|
+
|
|
372
|
+
run.main(run_argv)
|
|
373
|
+
return
|
|
@@ -3,11 +3,20 @@ import pytest
|
|
|
3
3
|
from workpeg import cli
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
def test_cli_no_args_prints_help(
|
|
6
|
+
def test_cli_no_args_prints_help(capsys):
|
|
7
7
|
cli.main([])
|
|
8
8
|
|
|
9
9
|
captured = capsys.readouterr()
|
|
10
10
|
assert "usage: workpeg" in captured.out
|
|
11
|
+
assert "function" in captured.out
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_cli_function_no_args_prints_help(capsys):
|
|
15
|
+
cli.main(["function"])
|
|
16
|
+
|
|
17
|
+
captured = capsys.readouterr()
|
|
18
|
+
assert "usage: workpeg" in captured.out
|
|
19
|
+
assert "function" in captured.out
|
|
11
20
|
|
|
12
21
|
|
|
13
22
|
def test_cli_version_long(capsys):
|
|
@@ -28,34 +37,34 @@ def test_cli_version_short(capsys):
|
|
|
28
37
|
assert captured.out.strip().startswith("workpeg ")
|
|
29
38
|
|
|
30
39
|
|
|
31
|
-
def
|
|
40
|
+
def test_cli_function_new_success(monkeypatch, capsys):
|
|
32
41
|
monkeypatch.setattr(
|
|
33
42
|
cli.create_new,
|
|
34
43
|
"create_new_project",
|
|
35
44
|
lambda path, force=False: "/tmp/output",
|
|
36
45
|
)
|
|
37
46
|
|
|
38
|
-
cli.main(["
|
|
47
|
+
cli.main(["function", "new", "foo"])
|
|
39
48
|
|
|
40
49
|
out = capsys.readouterr().out.strip()
|
|
41
50
|
assert out == "/tmp/output"
|
|
42
51
|
|
|
43
52
|
|
|
44
|
-
def
|
|
53
|
+
def test_cli_function_new_template_error(monkeypatch, capsys):
|
|
45
54
|
def fake_create(path, force=False):
|
|
46
55
|
raise cli.create_new.TemplateError("boom")
|
|
47
56
|
|
|
48
57
|
monkeypatch.setattr(cli.create_new, "create_new_project", fake_create)
|
|
49
58
|
|
|
50
59
|
with pytest.raises(SystemExit) as exc:
|
|
51
|
-
cli.main(["
|
|
60
|
+
cli.main(["function", "new", "foo"])
|
|
52
61
|
|
|
53
62
|
assert exc.value.code == 2
|
|
54
63
|
err = capsys.readouterr().err
|
|
55
64
|
assert "ERROR: boom" in err
|
|
56
65
|
|
|
57
66
|
|
|
58
|
-
def
|
|
67
|
+
def test_cli_function_runtime_default(monkeypatch):
|
|
59
68
|
called = {}
|
|
60
69
|
|
|
61
70
|
def fake_runtime_main(argv):
|
|
@@ -63,11 +72,11 @@ def test_cli_runtime_default(monkeypatch):
|
|
|
63
72
|
|
|
64
73
|
monkeypatch.setattr(cli.runtime, "main", fake_runtime_main)
|
|
65
74
|
|
|
66
|
-
cli.main(["runtime"])
|
|
75
|
+
cli.main(["function", "runtime"])
|
|
67
76
|
assert called["argv"] == []
|
|
68
77
|
|
|
69
78
|
|
|
70
|
-
def
|
|
79
|
+
def test_cli_function_runtime_server(monkeypatch):
|
|
71
80
|
called = {}
|
|
72
81
|
|
|
73
82
|
def fake_runtime_main(argv):
|
|
@@ -75,11 +84,11 @@ def test_cli_runtime_server(monkeypatch):
|
|
|
75
84
|
|
|
76
85
|
monkeypatch.setattr(cli.runtime, "main", fake_runtime_main)
|
|
77
86
|
|
|
78
|
-
cli.main(["runtime", "--server"])
|
|
87
|
+
cli.main(["function", "runtime", "--server"])
|
|
79
88
|
assert called["argv"] == ["--server"]
|
|
80
89
|
|
|
81
90
|
|
|
82
|
-
def
|
|
91
|
+
def test_cli_function_submit(monkeypatch):
|
|
83
92
|
called = {}
|
|
84
93
|
|
|
85
94
|
def fake_submit_main(argv):
|
|
@@ -88,6 +97,7 @@ def test_cli_submit(monkeypatch):
|
|
|
88
97
|
monkeypatch.setattr(cli.submit, "main", fake_submit_main)
|
|
89
98
|
|
|
90
99
|
cli.main([
|
|
100
|
+
"function",
|
|
91
101
|
"submit",
|
|
92
102
|
"fn_echo:1.0.0",
|
|
93
103
|
"--api", "https://repo.workpeg.com",
|
|
@@ -103,20 +113,20 @@ def test_cli_submit(monkeypatch):
|
|
|
103
113
|
]
|
|
104
114
|
|
|
105
115
|
|
|
106
|
-
def
|
|
116
|
+
def test_cli_function_build(monkeypatch, capsys):
|
|
107
117
|
monkeypatch.setattr(
|
|
108
118
|
cli.build,
|
|
109
119
|
"build_image",
|
|
110
120
|
lambda path=".", tag=None: "built-image",
|
|
111
121
|
)
|
|
112
122
|
|
|
113
|
-
cli.main(["build"])
|
|
123
|
+
cli.main(["function", "build"])
|
|
114
124
|
|
|
115
125
|
out = capsys.readouterr().out.strip()
|
|
116
126
|
assert out == "built-image"
|
|
117
127
|
|
|
118
128
|
|
|
119
|
-
def
|
|
129
|
+
def test_cli_function_build_with_args(monkeypatch, capsys):
|
|
120
130
|
called = {}
|
|
121
131
|
|
|
122
132
|
def fake_build_image(path=".", tag=None):
|
|
@@ -126,14 +136,19 @@ def test_cli_build_with_args(monkeypatch, capsys):
|
|
|
126
136
|
|
|
127
137
|
monkeypatch.setattr(cli.build, "build_image", fake_build_image)
|
|
128
138
|
|
|
129
|
-
cli.main([
|
|
139
|
+
cli.main([
|
|
140
|
+
"function",
|
|
141
|
+
"build",
|
|
142
|
+
"--path", "/tmp/demo",
|
|
143
|
+
"--tag", "custom-image",
|
|
144
|
+
])
|
|
130
145
|
|
|
131
146
|
assert called == {"path": "/tmp/demo", "tag": "custom-image"}
|
|
132
147
|
out = capsys.readouterr().out.strip()
|
|
133
148
|
assert out == "custom-image"
|
|
134
149
|
|
|
135
150
|
|
|
136
|
-
def
|
|
151
|
+
def test_cli_function_run(monkeypatch):
|
|
137
152
|
called = {}
|
|
138
153
|
|
|
139
154
|
def fake_run_main(argv):
|
|
@@ -142,11 +157,14 @@ def test_cli_run(monkeypatch):
|
|
|
142
157
|
monkeypatch.setattr(cli.run, "main", fake_run_main)
|
|
143
158
|
|
|
144
159
|
cli.main([
|
|
160
|
+
"function",
|
|
145
161
|
"run",
|
|
146
162
|
"--with", "docker",
|
|
147
163
|
"--path", "/tmp/demo",
|
|
148
164
|
"--no-build",
|
|
149
165
|
"--network", "workpeg_net",
|
|
166
|
+
"--name", "foo",
|
|
167
|
+
"--no-expose",
|
|
150
168
|
])
|
|
151
169
|
|
|
152
170
|
assert called["argv"] == [
|
|
@@ -154,4 +172,6 @@ def test_cli_run(monkeypatch):
|
|
|
154
172
|
"--path", "/tmp/demo",
|
|
155
173
|
"--no-build",
|
|
156
174
|
"--network", "workpeg_net",
|
|
175
|
+
"--name", "foo",
|
|
176
|
+
"--no-expose",
|
|
157
177
|
]
|
|
@@ -6,7 +6,7 @@ def test_create_new_copies_template(tmp_path):
|
|
|
6
6
|
project_dir = tmp_path / "my-func"
|
|
7
7
|
|
|
8
8
|
result = subprocess.run(
|
|
9
|
-
["workpeg", "
|
|
9
|
+
["workpeg", "function", "new", str(project_dir)],
|
|
10
10
|
text=True,
|
|
11
11
|
capture_output=True,
|
|
12
12
|
cwd=tmp_path,
|
|
@@ -19,8 +19,7 @@ def test_create_new_copies_template(tmp_path):
|
|
|
19
19
|
assert (project_dir / "app" / "main.py").exists()
|
|
20
20
|
|
|
21
21
|
template_pkg = "workpeg.templates.functions.app"
|
|
22
|
-
template_main = pkg_resources.files(
|
|
23
|
-
template_pkg).joinpath("main.py").read_text()
|
|
22
|
+
template_main = pkg_resources.files(template_pkg).joinpath("main.py").read_text()
|
|
24
23
|
|
|
25
24
|
created_main = (project_dir / "app" / "main.py").read_text()
|
|
26
25
|
assert created_main == template_main
|
|
@@ -33,7 +32,7 @@ def test_create_new_refuses_overwrite_without_force(tmp_path):
|
|
|
33
32
|
(project_dir / "app" / "main.py").write_text("existing")
|
|
34
33
|
|
|
35
34
|
result = subprocess.run(
|
|
36
|
-
["workpeg", "
|
|
35
|
+
["workpeg", "function", "new", str(project_dir)],
|
|
37
36
|
text=True,
|
|
38
37
|
capture_output=True,
|
|
39
38
|
cwd=tmp_path,
|
|
@@ -50,7 +49,7 @@ def test_create_new_overwrites_with_force(tmp_path):
|
|
|
50
49
|
(project_dir / "app" / "main.py").write_text("existing")
|
|
51
50
|
|
|
52
51
|
result = subprocess.run(
|
|
53
|
-
["workpeg", "
|
|
52
|
+
["workpeg", "function", "new", str(project_dir), "--force"],
|
|
54
53
|
text=True,
|
|
55
54
|
capture_output=True,
|
|
56
55
|
cwd=tmp_path,
|
workpeg-0.4.3/src/workpeg/cli.py
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import argparse
|
|
2
|
-
import sys
|
|
3
|
-
|
|
4
|
-
from workpeg import create_new, runtime, submit, build, run
|
|
5
|
-
|
|
6
|
-
try:
|
|
7
|
-
from importlib.metadata import version
|
|
8
|
-
__version__ = version("workpeg")
|
|
9
|
-
except Exception:
|
|
10
|
-
__version__ = "unknown"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def build_parser() -> argparse.ArgumentParser:
|
|
14
|
-
p = argparse.ArgumentParser(
|
|
15
|
-
prog="workpeg",
|
|
16
|
-
description="Workpeg CLI",
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
# version flag
|
|
20
|
-
p.add_argument(
|
|
21
|
-
"-v", "--version",
|
|
22
|
-
action="version",
|
|
23
|
-
version=f"workpeg {__version__}",
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
# IMPORTANT: no required=True
|
|
27
|
-
sub = p.add_subparsers(dest="command")
|
|
28
|
-
|
|
29
|
-
# submit
|
|
30
|
-
submit_p = sub.add_parser("submit", help="Submit a function bundle")
|
|
31
|
-
submit_p.add_argument("ref")
|
|
32
|
-
submit_p.add_argument("--api", default=None)
|
|
33
|
-
submit_p.add_argument("--path", default=None)
|
|
34
|
-
submit_p.add_argument("--timeout", type=int, default=None)
|
|
35
|
-
submit_p.set_defaults(_handler="submit")
|
|
36
|
-
|
|
37
|
-
# new-function
|
|
38
|
-
new_p = sub.add_parser("new-function", help="Create a new function project from template")
|
|
39
|
-
new_p.add_argument("path")
|
|
40
|
-
new_p.add_argument("--force", action="store_true")
|
|
41
|
-
new_p.set_defaults(_handler="new-function")
|
|
42
|
-
|
|
43
|
-
# runtime
|
|
44
|
-
runtime_p = sub.add_parser("runtime", help="Run the function runtime")
|
|
45
|
-
runtime_p.add_argument("--server", action="store_true")
|
|
46
|
-
runtime_p.set_defaults(_handler="runtime")
|
|
47
|
-
|
|
48
|
-
# build
|
|
49
|
-
build_p = sub.add_parser("build", help="Build the function docker image")
|
|
50
|
-
build_p.add_argument("--path", default=".")
|
|
51
|
-
build_p.add_argument("--tag", default=None)
|
|
52
|
-
build_p.set_defaults(_handler="build")
|
|
53
|
-
|
|
54
|
-
# run
|
|
55
|
-
run_p = sub.add_parser("run", help="Run the function using a configured runtime")
|
|
56
|
-
run_p.add_argument("--with", dest="with_runtime", choices=["docker", "cracker"])
|
|
57
|
-
run_p.add_argument("--path", default=".")
|
|
58
|
-
run_p.add_argument("--no-build", action="store_true")
|
|
59
|
-
run_p.add_argument("--network", default=None)
|
|
60
|
-
run_p.set_defaults(_handler="run")
|
|
61
|
-
|
|
62
|
-
return p
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def main(argv=None) -> None:
|
|
66
|
-
argv = argv if argv is not None else sys.argv[1:]
|
|
67
|
-
parser = build_parser()
|
|
68
|
-
|
|
69
|
-
if not argv:
|
|
70
|
-
parser.print_help()
|
|
71
|
-
return
|
|
72
|
-
|
|
73
|
-
args = parser.parse_args(argv)
|
|
74
|
-
|
|
75
|
-
if args._handler == "new-function":
|
|
76
|
-
try:
|
|
77
|
-
out = create_new.create_new_project(args.path, force=args.force)
|
|
78
|
-
print(str(out))
|
|
79
|
-
except create_new.TemplateError as e:
|
|
80
|
-
print(f"ERROR: {e}", file=sys.stderr)
|
|
81
|
-
raise SystemExit(2)
|
|
82
|
-
return
|
|
83
|
-
|
|
84
|
-
if args._handler == "runtime":
|
|
85
|
-
runtime_argv = []
|
|
86
|
-
if args.server:
|
|
87
|
-
runtime_argv.append("--server")
|
|
88
|
-
runtime.main(runtime_argv)
|
|
89
|
-
return
|
|
90
|
-
|
|
91
|
-
if args._handler == "submit":
|
|
92
|
-
submit_argv = [args.ref]
|
|
93
|
-
if args.api:
|
|
94
|
-
submit_argv += ["--api", args.api]
|
|
95
|
-
if args.path:
|
|
96
|
-
submit_argv += ["--path", args.path]
|
|
97
|
-
if args.timeout is not None:
|
|
98
|
-
submit_argv += ["--timeout", str(args.timeout)]
|
|
99
|
-
submit.main(submit_argv)
|
|
100
|
-
return
|
|
101
|
-
|
|
102
|
-
if args._handler == "build":
|
|
103
|
-
image = build.build_image(path=args.path, tag=args.tag)
|
|
104
|
-
print(image)
|
|
105
|
-
return
|
|
106
|
-
|
|
107
|
-
if args._handler == "run":
|
|
108
|
-
run_argv = []
|
|
109
|
-
if args.with_runtime:
|
|
110
|
-
run_argv += ["--with", args.with_runtime]
|
|
111
|
-
if args.path:
|
|
112
|
-
run_argv += ["--path", args.path]
|
|
113
|
-
if args.no_build:
|
|
114
|
-
run_argv.append("--no-build")
|
|
115
|
-
if args.network:
|
|
116
|
-
run_argv += ["--network", args.network]
|
|
117
|
-
run.main(run_argv)
|
|
118
|
-
return
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|