@voxgig/sdkgen 1.3.18 → 1.3.19
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.
- package/dist/cmp/Deploy.js +16 -16
- package/dist/cmp/Deploy.js.map +1 -1
- package/dist/cmp/ReadmeTop.js +13 -11
- package/dist/cmp/ReadmeTop.js.map +1 -1
- package/dist/helpers/naming.d.ts +3 -1
- package/dist/helpers/naming.js +65 -0
- package/dist/helpers/naming.js.map +1 -1
- package/dist/helpers/serverVars.d.ts +10 -0
- package/dist/helpers/serverVars.js +87 -0
- package/dist/helpers/serverVars.js.map +1 -0
- package/dist/sdkgen.d.ts +3 -2
- package/dist/sdkgen.js +6 -1
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/project/.sdk/model/target/go-cli.aontu +2 -2
- package/project/.sdk/src/cmp/csharp/TestEntity_csharp.ts +22 -15
- package/project/.sdk/src/cmp/go/Config_go.ts +10 -1
- package/project/.sdk/src/cmp/go-cli/Main_go-cli.ts +54 -35
- package/project/.sdk/src/cmp/go-cli/fragment/main.fragment.go +7 -7
- package/project/.sdk/src/cmp/go-cli/fragment/words.fragment.go +21 -18
- package/project/.sdk/src/cmp/js/Config_js.ts +11 -0
- package/project/.sdk/src/cmp/js/fragment/Config.fragment.js +2 -2
- package/project/.sdk/src/cmp/js/fragment/Direct.test.fragment.js +4 -0
- package/project/.sdk/src/cmp/lua/Config_lua.ts +10 -1
- package/project/.sdk/src/cmp/php/Config_php.ts +13 -2
- package/project/.sdk/src/cmp/py/Config_py.ts +10 -1
- package/project/.sdk/src/cmp/rb/Config_rb.ts +12 -1
- package/project/.sdk/src/cmp/rust/TestEntity_rust.ts +25 -18
- package/project/.sdk/src/cmp/swift/EntityTypes_swift.ts +10 -3
- package/project/.sdk/src/cmp/ts/Config_ts.ts +11 -0
- package/project/.sdk/src/cmp/ts/fragment/Config.fragment.ts +2 -2
- package/project/.sdk/src/cmp/ts/fragment/Direct.test.fragment.ts +4 -0
- package/project/.sdk/tm/csharp/Makefile +6 -6
- package/project/.sdk/tm/dart/Makefile +3 -3
- package/project/.sdk/tm/go/Makefile +6 -6
- package/project/.sdk/tm/go/test/primary_utility_test.go +5 -0
- package/project/.sdk/tm/go/utility/make_options.go +48 -0
- package/project/.sdk/tm/java/Makefile +6 -6
- package/project/.sdk/tm/js/Makefile +6 -6
- package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +39 -1
- package/project/.sdk/tm/js/test/utility/PrimaryUtility.test.js +5 -0
- package/project/.sdk/tm/kotlin/Makefile +6 -6
- package/project/.sdk/tm/lua/Makefile +7 -7
- package/project/.sdk/tm/lua/feature/test_feature.lua +29 -1
- package/project/.sdk/tm/lua/test/primary_utility_test.lua +4 -0
- package/project/.sdk/tm/lua/utility/make_options.lua +39 -0
- package/project/.sdk/tm/perl/Makefile +6 -6
- package/project/.sdk/tm/php/Makefile +6 -6
- package/project/.sdk/tm/php/feature/TestFeature.php +30 -2
- package/project/.sdk/tm/php/test/PrimaryUtilityTest.php +5 -0
- package/project/.sdk/tm/php/utility/MakeOptions.php +44 -0
- package/project/.sdk/tm/py/Makefile +6 -6
- package/project/.sdk/tm/py/test/test_primary_utility.py +5 -0
- package/project/.sdk/tm/py/utility/make_options.py +42 -0
- package/project/.sdk/tm/rb/Makefile +6 -6
- package/project/.sdk/tm/rb/test/primary_utility_test.rb +4 -0
- package/project/.sdk/tm/rb/utility/make_options.rb +37 -0
- package/project/.sdk/tm/rust/Makefile +6 -6
- package/project/.sdk/tm/swift/Makefile +6 -6
- package/project/.sdk/tm/ts/Makefile +6 -6
- package/project/.sdk/tm/ts/src/utility/MakeOptionsUtility.ts +39 -1
- package/project/.sdk/tm/ts/test/utility/PrimaryUtility.test.ts +4 -0
- package/src/cmp/Deploy.ts +16 -16
- package/src/cmp/ReadmeTop.ts +13 -11
- package/src/helpers/naming.ts +71 -0
- package/src/helpers/serverVars.ts +105 -0
- package/src/sdkgen.ts +6 -1
|
@@ -587,6 +587,10 @@ class PrimaryUtilityTest extends TestCase
|
|
|
587
587
|
{
|
|
588
588
|
$calls = [];
|
|
589
589
|
$live_client = new ProjectNameSDK([
|
|
590
|
+
// Concrete base: a live construction must satisfy any server
|
|
591
|
+
// variables a templated base URL declares; a literal base
|
|
592
|
+
// sidesteps the requirement.
|
|
593
|
+
'base' => 'http://localhost:8080',
|
|
590
594
|
'system' => [
|
|
591
595
|
'fetch' => function (string $url, array $fetchdef) use (&$calls) {
|
|
592
596
|
$calls[] = ['url' => $url, 'init' => $fetchdef];
|
|
@@ -614,6 +618,7 @@ class PrimaryUtilityTest extends TestCase
|
|
|
614
618
|
public function test_fetcher_blocked_test_mode(): void
|
|
615
619
|
{
|
|
616
620
|
$blocked_client = new ProjectNameSDK([
|
|
621
|
+
'base' => 'http://localhost:8080',
|
|
617
622
|
'system' => [
|
|
618
623
|
'fetch' => function (string $url, array $fetchdef) {
|
|
619
624
|
return [[], null];
|
|
@@ -88,6 +88,11 @@ class ProjectNameMakeOptions
|
|
|
88
88
|
'system' => (object)[],
|
|
89
89
|
'test' => ['active' => false, 'entity' => ['`$OPEN`' => true]],
|
|
90
90
|
'clean' => ['keys' => 'key,token,id'],
|
|
91
|
+
// Server-variable values for a templated base URL (OpenAPI server
|
|
92
|
+
// variables): {name} placeholders in 'base' are substituted from
|
|
93
|
+
// this map at construction. Spec defaults arrive via the generated
|
|
94
|
+
// config; user values override them.
|
|
95
|
+
'server' => ['`$CHILD`' => ''],
|
|
91
96
|
];
|
|
92
97
|
|
|
93
98
|
// Empty [] would be treated as a list and clobber the map under merge;
|
|
@@ -101,6 +106,45 @@ class ProjectNameMakeOptions
|
|
|
101
106
|
$opts = [];
|
|
102
107
|
}
|
|
103
108
|
|
|
109
|
+
// Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
|
|
110
|
+
// Every placeholder must resolve to a non-empty value: from
|
|
111
|
+
// $options['server'] (user), else the config default. A placeholder
|
|
112
|
+
// that resolves to '' is a construction ERROR in live mode — the URL
|
|
113
|
+
// cannot work — but in test mode substitutes the deterministic value
|
|
114
|
+
// "test-<name>" so offline tests need no configuration.
|
|
115
|
+
$base = $opts['base'] ?? null;
|
|
116
|
+
if (is_string($base) && strpos($base, '{') !== false) {
|
|
117
|
+
$testmode =
|
|
118
|
+
\Voxgig\Struct\Struct::getpath($opts, 'test.active') === true
|
|
119
|
+
|| \Voxgig\Struct\Struct::getpath($opts, 'feature.test.active') === true;
|
|
120
|
+
$server = is_array($opts['server'] ?? null) ? $opts['server'] : [];
|
|
121
|
+
$sdkname = \Voxgig\Struct\Struct::getpath($config, 'main.name');
|
|
122
|
+
if (!is_string($sdkname) || $sdkname === '') {
|
|
123
|
+
$sdkname = 'SDK';
|
|
124
|
+
}
|
|
125
|
+
$opts['base'] = preg_replace_callback(
|
|
126
|
+
'/\{([A-Za-z0-9_]+)\}/',
|
|
127
|
+
function ($m) use ($server, $testmode, $sdkname, $base) {
|
|
128
|
+
$name = $m[1];
|
|
129
|
+
$val = $server[$name] ?? '';
|
|
130
|
+
if (!is_string($val)) {
|
|
131
|
+
$val = '';
|
|
132
|
+
}
|
|
133
|
+
if ($val === '') {
|
|
134
|
+
if ($testmode) {
|
|
135
|
+
return 'test-' . $name;
|
|
136
|
+
}
|
|
137
|
+
throw new \InvalidArgumentException(
|
|
138
|
+
$sdkname . ": the server variable '" . $name . "' is required: " .
|
|
139
|
+
"the API base URL is '" . $base . "' — pass " .
|
|
140
|
+
"['server' => ['" . $name . "' => '...']] in the SDK options");
|
|
141
|
+
}
|
|
142
|
+
return $val;
|
|
143
|
+
},
|
|
144
|
+
$base
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
104
148
|
if ($sys_fetch) {
|
|
105
149
|
if (!is_array($opts['system'] ?? null)) {
|
|
106
150
|
$opts['system'] = [];
|
|
@@ -10,16 +10,16 @@ clean:
|
|
|
10
10
|
find . -name __pycache__ -exec rm -rf {} + 2>/dev/null; true
|
|
11
11
|
|
|
12
12
|
# --- Release: publish to PyPI ---------------------------------------------
|
|
13
|
-
# Publish this package to PyPI, then tag py/vX.Y.Z. Run headless under the
|
|
13
|
+
# Publish this package to PyPI, then tag py/vX.Y.Z. Run headless under the boru
|
|
14
14
|
# key vault, which injects the PyPI + GitHub tokens as environment variables
|
|
15
15
|
# (never written to disk or argv):
|
|
16
|
-
#
|
|
17
|
-
#
|
|
16
|
+
# boru vault exec --for=pypi=<alias> --for=github=<alias> -- make publish
|
|
17
|
+
# boru `--dry-run` injects a filler token we detect to rehearse: builds the dist
|
|
18
18
|
# but performs no upload, tag, or push. set -e + tag-last: a failed upload never
|
|
19
19
|
# leaves a tag behind. Needs python `build` + `twine` (pip install build twine).
|
|
20
20
|
VERSION := $(shell sed -nE 's/^version *= *"([^"]+)".*/\1/p' pyproject.toml | head -1)
|
|
21
21
|
TAG := py/v$(VERSION)
|
|
22
|
-
|
|
22
|
+
BORU_DRY_RUN_FILLER := BORU-DRY-RUN-FILLER-NOT-A-REAL-SECRET
|
|
23
23
|
publish: test
|
|
24
24
|
@if git rev-parse -q --verify "refs/tags/$(TAG)" >/dev/null; then \
|
|
25
25
|
echo "tag $(TAG) already exists — bump pyproject.toml version first"; exit 1; fi
|
|
@@ -27,8 +27,8 @@ publish: test
|
|
|
27
27
|
token="$${GITHUB_TOKEN:-$$GH_TOKEN}"; \
|
|
28
28
|
rm -rf dist; \
|
|
29
29
|
python3 -m build; \
|
|
30
|
-
if [ "$$token" = "$(
|
|
31
|
-
echo "[dry-run]
|
|
30
|
+
if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ] || [ "$$TWINE_PASSWORD" = "$(BORU_DRY_RUN_FILLER)" ]; then \
|
|
31
|
+
echo "[dry-run] boru filler token detected: built the dist; would upload to PyPI and tag $(TAG); nothing pushed."; \
|
|
32
32
|
exit 0; \
|
|
33
33
|
fi; \
|
|
34
34
|
python3 -m twine upload dist/*; \
|
|
@@ -468,6 +468,10 @@ class TestPrimaryUtility:
|
|
|
468
468
|
return {"status": 200, "statusText": "OK"}, None
|
|
469
469
|
|
|
470
470
|
live_client = ProjectNameSDK({
|
|
471
|
+
# Concrete base: a live construction must satisfy any server
|
|
472
|
+
# variables a templated base URL declares; a literal base
|
|
473
|
+
# sidesteps the requirement.
|
|
474
|
+
"base": "http://localhost:8080",
|
|
471
475
|
"system": {
|
|
472
476
|
"fetch": mock_fetch,
|
|
473
477
|
},
|
|
@@ -490,6 +494,7 @@ class TestPrimaryUtility:
|
|
|
490
494
|
return {}, None
|
|
491
495
|
|
|
492
496
|
blocked_client = ProjectNameSDK({
|
|
497
|
+
"base": "http://localhost:8080",
|
|
493
498
|
"system": {
|
|
494
499
|
"fetch": mock_fetch,
|
|
495
500
|
},
|
|
@@ -84,6 +84,13 @@ def make_options_util(ctx):
|
|
|
84
84
|
"clean": {
|
|
85
85
|
"keys": "key,token,id",
|
|
86
86
|
},
|
|
87
|
+
# Server-variable values for a templated base URL (OpenAPI server
|
|
88
|
+
# variables): {name} placeholders in "base" are substituted from this
|
|
89
|
+
# map at construction. Spec defaults arrive via the generated config;
|
|
90
|
+
# user values override them.
|
|
91
|
+
"server": {
|
|
92
|
+
"`$CHILD`": "",
|
|
93
|
+
},
|
|
87
94
|
}
|
|
88
95
|
|
|
89
96
|
# Preserve system.fetch before merge/validate.
|
|
@@ -95,6 +102,41 @@ def make_options_util(ctx):
|
|
|
95
102
|
validated = {}
|
|
96
103
|
opts = validated
|
|
97
104
|
|
|
105
|
+
# Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
|
|
106
|
+
# Every placeholder must resolve to a non-empty value: from
|
|
107
|
+
# options["server"] (user), else the config default. A placeholder that
|
|
108
|
+
# resolves to "" is a construction ERROR in live mode — the URL cannot
|
|
109
|
+
# work — but in test mode substitutes the deterministic value
|
|
110
|
+
# "test-<name>" so offline tests need no configuration.
|
|
111
|
+
base = opts.get("base")
|
|
112
|
+
if isinstance(base, str) and "{" in base:
|
|
113
|
+
import re as _re
|
|
114
|
+
testmode = (
|
|
115
|
+
vs.getpath(opts, "test.active") is True
|
|
116
|
+
or vs.getpath(opts, "feature.test.active") is True
|
|
117
|
+
)
|
|
118
|
+
server = opts.get("server") if isinstance(opts.get("server"), dict) else {}
|
|
119
|
+
sdkname = "SDK"
|
|
120
|
+
if isinstance(config, dict):
|
|
121
|
+
mn = vs.getpath(config, "main.name")
|
|
122
|
+
if isinstance(mn, str) and mn != "":
|
|
123
|
+
sdkname = mn
|
|
124
|
+
|
|
125
|
+
def _sub(m):
|
|
126
|
+
name = m.group(1)
|
|
127
|
+
val = server.get(name)
|
|
128
|
+
val = val if isinstance(val, str) else ""
|
|
129
|
+
if val == "":
|
|
130
|
+
if testmode:
|
|
131
|
+
return "test-" + name
|
|
132
|
+
raise ValueError(
|
|
133
|
+
sdkname + ": the server variable '" + name + "' is required: "
|
|
134
|
+
"the API base URL is '" + base + "' — pass "
|
|
135
|
+
'{"server": {"' + name + '": "..."}} in the SDK options')
|
|
136
|
+
return val
|
|
137
|
+
|
|
138
|
+
opts["base"] = _re.sub(r"\{([A-Za-z0-9_]+)\}", _sub, base)
|
|
139
|
+
|
|
98
140
|
# Restore system.fetch.
|
|
99
141
|
if sys_fetch is not None:
|
|
100
142
|
if isinstance(opts.get("system"), dict):
|
|
@@ -13,14 +13,14 @@ clean:
|
|
|
13
13
|
|
|
14
14
|
# --- Release: publish to RubyGems -----------------------------------------
|
|
15
15
|
# Build the gem and push it to RubyGems, then tag rb/vX.Y.Z. Run headless under
|
|
16
|
-
# the
|
|
16
|
+
# the boru key vault, which injects GEM_HOST_API_KEY + the GitHub token (never on
|
|
17
17
|
# disk or argv):
|
|
18
|
-
#
|
|
19
|
-
#
|
|
18
|
+
# boru vault exec --for=gem=<alias> --for=github=<alias> -- make publish
|
|
19
|
+
# boru `--dry-run` injects a filler token we detect to rehearse (build only, no
|
|
20
20
|
# push/tag). set -e + tag-last: a failed push never leaves a tag behind.
|
|
21
21
|
VERSION := $(shell sed -nE 's/.*\.version *= *"([^"]+)".*/\1/p' *.gemspec | head -1)
|
|
22
22
|
TAG := rb/v$(VERSION)
|
|
23
|
-
|
|
23
|
+
BORU_DRY_RUN_FILLER := BORU-DRY-RUN-FILLER-NOT-A-REAL-SECRET
|
|
24
24
|
publish: test
|
|
25
25
|
@if git rev-parse -q --verify "refs/tags/$(TAG)" >/dev/null; then \
|
|
26
26
|
echo "tag $(TAG) already exists — bump the gemspec version first"; exit 1; fi
|
|
@@ -28,8 +28,8 @@ publish: test
|
|
|
28
28
|
token="$${GITHUB_TOKEN:-$$GH_TOKEN}"; \
|
|
29
29
|
rm -f *.gem; \
|
|
30
30
|
gem build *.gemspec; \
|
|
31
|
-
if [ "$$token" = "$(
|
|
32
|
-
echo "[dry-run]
|
|
31
|
+
if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ] || [ "$$GEM_HOST_API_KEY" = "$(BORU_DRY_RUN_FILLER)" ]; then \
|
|
32
|
+
echo "[dry-run] boru filler token detected: built the gem; would push to RubyGems and tag $(TAG); nothing pushed."; \
|
|
33
33
|
exit 0; \
|
|
34
34
|
fi; \
|
|
35
35
|
gem push *.gem; \
|
|
@@ -176,6 +176,9 @@ class PrimaryUtilityTest < Minitest::Test
|
|
|
176
176
|
def test_fetcher_live
|
|
177
177
|
calls = []
|
|
178
178
|
live_client = ProjectNameSDK.new({
|
|
179
|
+
# Concrete base: a live construction must satisfy any server variables
|
|
180
|
+
# a templated base URL declares; a literal base sidesteps the requirement.
|
|
181
|
+
"base" => "http://localhost:8080",
|
|
179
182
|
"system" => {
|
|
180
183
|
"fetch" => ->(url, fetchdef) {
|
|
181
184
|
calls << { "url" => url, "init" => fetchdef }
|
|
@@ -199,6 +202,7 @@ class PrimaryUtilityTest < Minitest::Test
|
|
|
199
202
|
|
|
200
203
|
def test_fetcher_blocked_test_mode
|
|
201
204
|
blocked_client = ProjectNameSDK.new({
|
|
205
|
+
"base" => "http://localhost:8080",
|
|
202
206
|
"system" => {
|
|
203
207
|
"fetch" => ->(url, fetchdef) {
|
|
204
208
|
return {}, nil
|
|
@@ -52,6 +52,11 @@ module ProjectNameUtilities
|
|
|
52
52
|
"system" => {},
|
|
53
53
|
"test" => { "active" => false, "entity" => { "`$OPEN`" => true } },
|
|
54
54
|
"clean" => { "keys" => "key,token,id" },
|
|
55
|
+
# Server-variable values for a templated base URL (OpenAPI server
|
|
56
|
+
# variables): {name} placeholders in "base" are substituted from this
|
|
57
|
+
# map at construction. Spec defaults arrive via the generated config;
|
|
58
|
+
# user values override them.
|
|
59
|
+
"server" => { "`$CHILD`" => "" },
|
|
55
60
|
}
|
|
56
61
|
|
|
57
62
|
sys_fetch = VoxgigStruct.getpath(opts, "system.fetch")
|
|
@@ -60,6 +65,38 @@ module ProjectNameUtilities
|
|
|
60
65
|
validated = VoxgigStruct.validate(merged, optspec)
|
|
61
66
|
opts = validated.is_a?(Hash) ? validated : {}
|
|
62
67
|
|
|
68
|
+
# Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
|
|
69
|
+
# Every placeholder must resolve to a non-empty value: from
|
|
70
|
+
# options["server"] (user), else the config default. A placeholder that
|
|
71
|
+
# resolves to "" is a construction ERROR in live mode — the URL cannot
|
|
72
|
+
# work — but in test mode substitutes the deterministic value
|
|
73
|
+
# "test-<name>" so offline tests need no configuration.
|
|
74
|
+
base = opts["base"]
|
|
75
|
+
if base.is_a?(String) && base.include?("{")
|
|
76
|
+
testmode = VoxgigStruct.getpath(opts, "test.active") == true ||
|
|
77
|
+
VoxgigStruct.getpath(opts, "feature.test.active") == true
|
|
78
|
+
server = opts["server"].is_a?(Hash) ? opts["server"] : {}
|
|
79
|
+
sdkname = VoxgigStruct.getpath(config, "main.name")
|
|
80
|
+
sdkname = "SDK" unless sdkname.is_a?(String) && !sdkname.empty?
|
|
81
|
+
opts["base"] = base.gsub(/\{([A-Za-z0-9_]+)\}/) do
|
|
82
|
+
name = Regexp.last_match(1)
|
|
83
|
+
val = server[name]
|
|
84
|
+
val = "" unless val.is_a?(String)
|
|
85
|
+
if val.empty?
|
|
86
|
+
if testmode
|
|
87
|
+
"test-#{name}"
|
|
88
|
+
else
|
|
89
|
+
raise ArgumentError,
|
|
90
|
+
"#{sdkname}: the server variable '#{name}' is required: " \
|
|
91
|
+
"the API base URL is '#{base}' — pass " \
|
|
92
|
+
"{ \"server\" => { \"#{name}\" => \"...\" } } in the SDK options"
|
|
93
|
+
end
|
|
94
|
+
else
|
|
95
|
+
val
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
63
100
|
if sys_fetch
|
|
64
101
|
opts["system"] = {} unless opts["system"].is_a?(Hash)
|
|
65
102
|
opts["system"]["fetch"] = sys_fetch
|
|
@@ -13,21 +13,21 @@ clean:
|
|
|
13
13
|
# The crates.io registry entry is declared in the model with
|
|
14
14
|
# state: 'pending' — a real deploy publishes the git tag rust/vX.Y.Z only;
|
|
15
15
|
# `cargo publish` starts when the registry state flips to 'active'. Run
|
|
16
|
-
# headless under the
|
|
16
|
+
# headless under the boru key vault, which injects the GitHub token so
|
|
17
17
|
# nothing lands on disk or argv:
|
|
18
|
-
#
|
|
19
|
-
#
|
|
18
|
+
# boru vault exec --for=github=<alias> -- make publish
|
|
19
|
+
# boru `--dry-run` injects a filler token we detect to rehearse (no tag/push).
|
|
20
20
|
# set -e + tag-last: a failed push never leaves a tag behind.
|
|
21
21
|
VERSION := $(shell cat VERSION)
|
|
22
22
|
TAG := rust/v$(VERSION)
|
|
23
|
-
|
|
23
|
+
BORU_DRY_RUN_FILLER := BORU-DRY-RUN-FILLER-NOT-A-REAL-SECRET
|
|
24
24
|
publish:
|
|
25
25
|
@if git rev-parse -q --verify "refs/tags/$(TAG)" >/dev/null; then \
|
|
26
26
|
echo "tag $(TAG) already exists — bump VERSION first"; exit 1; fi
|
|
27
27
|
@set -e; \
|
|
28
28
|
token="$${GITHUB_TOKEN:-$$GH_TOKEN}"; \
|
|
29
|
-
if [ "$$token" = "$(
|
|
30
|
-
echo "[dry-run]
|
|
29
|
+
if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ]; then \
|
|
30
|
+
echo "[dry-run] boru filler token detected: would tag $(TAG); nothing pushed."; \
|
|
31
31
|
exit 0; \
|
|
32
32
|
fi; \
|
|
33
33
|
git tag -a "$(TAG)" -m "rust v$(VERSION)"; \
|
|
@@ -13,21 +13,21 @@ clean:
|
|
|
13
13
|
# --- Release: tag for the SwiftPM registry ---------------------------------
|
|
14
14
|
# SwiftPM has no upload step - publishing IS the git tag. Publication is
|
|
15
15
|
# pending (see model/target/swift.aontu publish block); publishing a version
|
|
16
|
-
# currently means pushing the tag swift/vX.Y.Z. Run headless under the
|
|
16
|
+
# currently means pushing the tag swift/vX.Y.Z. Run headless under the boru key
|
|
17
17
|
# vault, which injects the GitHub token so nothing lands on disk or argv:
|
|
18
|
-
#
|
|
19
|
-
#
|
|
18
|
+
# boru vault exec --for=github=<alias> -- make publish
|
|
19
|
+
# boru `--dry-run` injects a filler token we detect to rehearse (no tag/push).
|
|
20
20
|
# set -e + tag-last: a failed push never leaves a tag behind.
|
|
21
21
|
VERSION := $(shell cat VERSION)
|
|
22
22
|
TAG := swift/v$(VERSION)
|
|
23
|
-
|
|
23
|
+
BORU_DRY_RUN_FILLER := BORU-DRY-RUN-FILLER-NOT-A-REAL-SECRET
|
|
24
24
|
publish: test
|
|
25
25
|
@if git rev-parse -q --verify "refs/tags/$(TAG)" >/dev/null; then \
|
|
26
26
|
echo "tag $(TAG) already exists - bump VERSION first"; exit 1; fi
|
|
27
27
|
@set -e; \
|
|
28
28
|
token="$${GITHUB_TOKEN:-$$GH_TOKEN}"; \
|
|
29
|
-
if [ "$$token" = "$(
|
|
30
|
-
echo "[dry-run]
|
|
29
|
+
if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ]; then \
|
|
30
|
+
echo "[dry-run] boru filler token detected: would tag $(TAG); nothing pushed."; \
|
|
31
31
|
exit 0; \
|
|
32
32
|
fi; \
|
|
33
33
|
git tag -a "$(TAG)" -m "swift v$(VERSION)"; \
|
|
@@ -17,22 +17,22 @@ clean:
|
|
|
17
17
|
|
|
18
18
|
# --- Release: publish to npm ----------------------------------------------
|
|
19
19
|
# Compile, then publish this package to npm and tag ts/vX.Y.Z. Run headless
|
|
20
|
-
# under the
|
|
20
|
+
# under the boru key vault, which injects the npm auth token + the GitHub token
|
|
21
21
|
# (never on disk or argv):
|
|
22
|
-
#
|
|
23
|
-
#
|
|
22
|
+
# boru vault exec --for=npm=<alias> --for=github=<alias> -- make publish
|
|
23
|
+
# boru `--dry-run` injects a filler token we detect to rehearse (build only, no
|
|
24
24
|
# publish/tag). set -e + tag-last: a failed publish never leaves a tag behind.
|
|
25
25
|
SHELL := /bin/bash
|
|
26
26
|
VERSION := $(shell node -p "require('./package.json').version")
|
|
27
27
|
TAG := ts/v$(VERSION)
|
|
28
|
-
|
|
28
|
+
BORU_DRY_RUN_FILLER := BORU-DRY-RUN-FILLER-NOT-A-REAL-SECRET
|
|
29
29
|
publish: test
|
|
30
30
|
@if git rev-parse -q --verify "refs/tags/$(TAG)" >/dev/null; then \
|
|
31
31
|
echo "tag $(TAG) already exists — bump package.json version first"; exit 1; fi
|
|
32
32
|
@set -e; \
|
|
33
33
|
token="$${GITHUB_TOKEN:-$$GH_TOKEN}"; \
|
|
34
|
-
if [ "$$token" = "$(
|
|
35
|
-
echo "[dry-run]
|
|
34
|
+
if [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ]; then \
|
|
35
|
+
echo "[dry-run] boru filler token detected: would publish to npm and tag $(TAG); nothing pushed."; \
|
|
36
36
|
exit 0; \
|
|
37
37
|
fi; \
|
|
38
38
|
npm stage publish --access public --registry https://registry.npmjs.org; \
|
|
@@ -82,16 +82,54 @@ function makeOptions(ctx: Context) {
|
|
|
82
82
|
},
|
|
83
83
|
clean: {
|
|
84
84
|
keys: 'key,token,id'
|
|
85
|
+
},
|
|
86
|
+
// Server-variable values for a templated base URL (OpenAPI server
|
|
87
|
+
// variables): `{name}` placeholders in `base` are substituted from
|
|
88
|
+
// this map at construction. Spec defaults arrive via the generated
|
|
89
|
+
// Config; user values override them.
|
|
90
|
+
server: {
|
|
91
|
+
'`$CHILD`': ''
|
|
85
92
|
}
|
|
86
93
|
}
|
|
87
94
|
|
|
88
95
|
// JavaScript specific option values.
|
|
89
96
|
optspec.system.fetch = opts.system?.fetch || global.fetch
|
|
90
97
|
|
|
91
|
-
|
|
98
|
+
// Clone the config side before merging: `config` is a module-level
|
|
99
|
+
// singleton in ts/js, and merge would otherwise use its nested maps as
|
|
100
|
+
// merge TARGETS — one instance's options (server, headers, ...) would
|
|
101
|
+
// contaminate every instance constructed after it.
|
|
102
|
+
opts = merge([{}, struct.clone(cfgopts), opts])
|
|
92
103
|
|
|
93
104
|
opts = validate(opts, optspec)
|
|
94
105
|
|
|
106
|
+
// Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
|
|
107
|
+
// Every placeholder must resolve to a non-empty value: from
|
|
108
|
+
// options.server (user), else the Config default. A placeholder that
|
|
109
|
+
// resolves to '' is a construction ERROR in live mode — the URL cannot
|
|
110
|
+
// work — but in test mode substitutes the deterministic value
|
|
111
|
+
// `test-<name>` so offline tests need no configuration.
|
|
112
|
+
if ('string' === typeof opts.base && opts.base.includes('{')) {
|
|
113
|
+
const testmode = true === opts.test.active ||
|
|
114
|
+
true === (opts.feature && opts.feature.test && opts.feature.test.active)
|
|
115
|
+
const server = opts.server || {}
|
|
116
|
+
opts.base = opts.base.replace(/\{([A-Za-z0-9_]+)\}/g,
|
|
117
|
+
(_m: string, name: string) => {
|
|
118
|
+
let val = server[name]
|
|
119
|
+
val = 'string' === typeof val ? val : ''
|
|
120
|
+
if ('' === val) {
|
|
121
|
+
if (testmode) {
|
|
122
|
+
return 'test-' + name
|
|
123
|
+
}
|
|
124
|
+
throw new Error(
|
|
125
|
+
`${config?.main?.name || 'SDK'}: the server variable '${name}' is required: ` +
|
|
126
|
+
`the API base URL is '${opts.base}' — pass { server: { ${name}: '...' } } ` +
|
|
127
|
+
`in the SDK options`)
|
|
128
|
+
}
|
|
129
|
+
return val
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
|
|
95
133
|
// Resolve the feature add-order: an explicit array order (above) wins;
|
|
96
134
|
// otherwise order the map test-first, then the remaining names sorted, so
|
|
97
135
|
// the outcome is deterministic and `test` is always the base transport.
|
|
@@ -229,6 +229,8 @@ describe('PrimaryUtility', async () => {
|
|
|
229
229
|
body: 'present',
|
|
230
230
|
})
|
|
231
231
|
const reqClient = new (SDK as any)({
|
|
232
|
+
// Concrete base: a live construction must satisfy any server variables a templated base URL declares; a literal base sidesteps the requirement.
|
|
233
|
+
base: 'http://localhost:8080',
|
|
232
234
|
system: { fetch: mockFetch }
|
|
233
235
|
})
|
|
234
236
|
const reqUtility = reqClient.utility()
|
|
@@ -410,6 +412,7 @@ describe('PrimaryUtility', async () => {
|
|
|
410
412
|
test('fetcher-live', async () => {
|
|
411
413
|
const calls: any[] = []
|
|
412
414
|
const liveClient = new (SDK as any)({
|
|
415
|
+
base: 'http://localhost:8080',
|
|
413
416
|
system: {
|
|
414
417
|
fetch: async (url: string, init: any) => {
|
|
415
418
|
calls.push({ url, init })
|
|
@@ -431,6 +434,7 @@ describe('PrimaryUtility', async () => {
|
|
|
431
434
|
|
|
432
435
|
test('fetcher-blocked-test-mode', async () => {
|
|
433
436
|
const blockedClient = new (SDK as any)({
|
|
437
|
+
base: 'http://localhost:8080',
|
|
434
438
|
system: { fetch: async () => ({}) }
|
|
435
439
|
})
|
|
436
440
|
blockedClient._mode = 'test'
|
package/src/cmp/Deploy.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
// `publish` sections (see model/sdkgen.aontu):
|
|
11
11
|
//
|
|
12
12
|
// publish.tag — git release tag `<prefix>/vX.Y.Z`; every port has
|
|
13
|
-
// one, pushed with a token from the
|
|
13
|
+
// one, pushed with a token from the boru key vault
|
|
14
14
|
// (--for recipe + alias, default github/github).
|
|
15
15
|
// publish.registry — package registry details (name, url, vault
|
|
16
16
|
// credential recipe or raw env mapping) plus a
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
// Follows the voxgig/struct root Makefile conventions: per-target deploy
|
|
26
26
|
// targets, deliberately no all-targets real deploy (each upload is
|
|
27
27
|
// irreversible), and an everything-at-once DRY run leaning on
|
|
28
|
-
// `
|
|
28
|
+
// `boru vault exec --dry-run` filler-token cooperation in each target's
|
|
29
29
|
// publish recipe.
|
|
30
30
|
const Deploy = cmp(function Deploy(props: any) {
|
|
31
31
|
const { ctx$ } = props
|
|
@@ -76,7 +76,7 @@ function aliasVarName(name: string): string {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
|
|
79
|
-
// The
|
|
79
|
+
// The boru vault exec argument string for a target: `--for=<recipe>=<alias>`
|
|
80
80
|
// flags where a preset recipe exists, or a raw `'alias=ENV_VAR,...'`
|
|
81
81
|
// mapping when any credential lacks a preset (e.g. luarocks). The github
|
|
82
82
|
// token for the tag push is always included.
|
|
@@ -142,10 +142,10 @@ function makeDeployMakefile(model: any, targets: any[]): string {
|
|
|
142
142
|
return `
|
|
143
143
|
deploy-${t.name}:
|
|
144
144
|
\t@echo "deploy-${t.name}: tag-only port — publishing the git tag."
|
|
145
|
-
\
|
|
145
|
+
\tboru vault exec ${ghArgs} -- $(MAKE) tag-push-${t.name}
|
|
146
146
|
|
|
147
147
|
deploy-dry-${t.name}:
|
|
148
|
-
\
|
|
148
|
+
\tboru vault exec --dry-run ${ghArgs} -- $(MAKE) tag-push-${t.name}
|
|
149
149
|
${tagPushRecipe(t.name, 'tag-only port')}
|
|
150
150
|
`
|
|
151
151
|
}
|
|
@@ -157,20 +157,20 @@ ${tagPushRecipe(t.name, 'tag-only port')}
|
|
|
157
157
|
return `
|
|
158
158
|
deploy-${t.name}:
|
|
159
159
|
\t@echo "deploy-${t.name}: ${reg.name} publication is pending — publishing the git tag only."
|
|
160
|
-
\
|
|
160
|
+
\tboru vault exec ${ghArgs} -- $(MAKE) tag-push-${t.name}
|
|
161
161
|
|
|
162
162
|
deploy-dry-${t.name}:
|
|
163
|
-
\
|
|
163
|
+
\tboru vault exec --dry-run ${ghArgs} -- $(MAKE) tag-push-${t.name}
|
|
164
164
|
${tagPushRecipe(t.name, reg.name + ' publication pending — tag-only deploy')}
|
|
165
165
|
`
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
return `
|
|
169
169
|
deploy-${t.name}:
|
|
170
|
-
\
|
|
170
|
+
\tboru vault exec ${args} -- $(MAKE) -C ${t.name} publish
|
|
171
171
|
|
|
172
172
|
deploy-dry-${t.name}:
|
|
173
|
-
\
|
|
173
|
+
\tboru vault exec --dry-run ${args} -- $(MAKE) -C ${t.name} publish
|
|
174
174
|
`
|
|
175
175
|
}).join('')
|
|
176
176
|
|
|
@@ -183,7 +183,7 @@ deploy-dry-${t.name}:
|
|
|
183
183
|
#
|
|
184
184
|
# Every port gets a git release tag <target>/vX.Y.Z. Ports with an ACTIVE
|
|
185
185
|
# registry also publish a package there. Credentials are injected at exec
|
|
186
|
-
# time by the
|
|
186
|
+
# time by the boru key vault (https://github.com/boru-lang/boru) — never
|
|
187
187
|
# stored on disk or passed on the command line.
|
|
188
188
|
#
|
|
189
189
|
# Publication state (from the model):
|
|
@@ -194,7 +194,7 @@ ${summary}
|
|
|
194
194
|
# registry upload is irreversible); while a
|
|
195
195
|
# registry is pending this publishes the
|
|
196
196
|
# port's git tag only
|
|
197
|
-
# make deploy-dry rehearse EVERY target:
|
|
197
|
+
# make deploy-dry rehearse EVERY target: boru --dry-run
|
|
198
198
|
# injects a filler token that each publish
|
|
199
199
|
# recipe detects, so build + test run in full
|
|
200
200
|
# but nothing is uploaded and no tag is cut
|
|
@@ -207,7 +207,7 @@ ${varLines}
|
|
|
207
207
|
|
|
208
208
|
# Lockstep SDK version, read from the canonical ts manifest.
|
|
209
209
|
VERSION := $(shell node -p "require('./ts/package.json').version" 2>/dev/null || echo 0.0.0)
|
|
210
|
-
|
|
210
|
+
BORU_DRY_RUN_FILLER := BORU-DRY-RUN-FILLER-NOT-A-REAL-SECRET
|
|
211
211
|
|
|
212
212
|
TARGETS := ${targets.map((t: any) => t.name).join(' ')}
|
|
213
213
|
|
|
@@ -233,7 +233,7 @@ ${deployRules}`
|
|
|
233
233
|
|
|
234
234
|
|
|
235
235
|
|
|
236
|
-
// The root-level tag creation + push recipe for a target:
|
|
236
|
+
// The root-level tag creation + push recipe for a target: boru --dry-run
|
|
237
237
|
// filler cooperation, idempotent tag creation, token-authenticated https
|
|
238
238
|
// push (works from an ssh-remote clone without ssh keys).
|
|
239
239
|
function tagPushRecipe(name: string, note: string): string {
|
|
@@ -241,9 +241,9 @@ function tagPushRecipe(name: string, note: string): string {
|
|
|
241
241
|
tag-push-${name}:
|
|
242
242
|
\t@set -e; tag="${name}/v$(VERSION)"; \\
|
|
243
243
|
\ttoken="\$\${GITHUB_TOKEN:-$$GH_TOKEN}"; \\
|
|
244
|
-
\tif [ "$$token" = "$(
|
|
245
|
-
\t echo "[dry-run]
|
|
246
|
-
\tif [ -z "$$token" ]; then echo "tag-push-${name}: no GITHUB_TOKEN in env — run via make deploy-${name} (
|
|
244
|
+
\tif [ "$$token" = "$(BORU_DRY_RUN_FILLER)" ]; then \\
|
|
245
|
+
\t echo "[dry-run] boru filler token detected: would create (if missing) and push tag $$tag; nothing pushed."; exit 0; fi; \\
|
|
246
|
+
\tif [ -z "$$token" ]; then echo "tag-push-${name}: no GITHUB_TOKEN in env — run via make deploy-${name} (boru vault exec)"; exit 1; fi; \\
|
|
247
247
|
\tif git rev-parse -q --verify "refs/tags/$$tag" >/dev/null; then \\
|
|
248
248
|
\t echo "tag $$tag already exists — pushing existing tag"; \\
|
|
249
249
|
\telse git tag -a "$$tag" -m "Release $$tag"; fi; \\
|
package/src/cmp/ReadmeTop.ts
CHANGED
|
@@ -549,28 +549,30 @@ Pass custom features via the \`extend\` option at construction time.
|
|
|
549
549
|
`)
|
|
550
550
|
}
|
|
551
551
|
|
|
552
|
-
// 13. Upstream API —
|
|
552
|
+
// 13. Upstream API — always disclose the OpenAPI origin and where the
|
|
553
|
+
// spec(s) live; contact/servers links come from the OpenAPI info block.
|
|
553
554
|
const upstreamUrl = (info.contact && info.contact.url)
|
|
554
555
|
|| (info.servers && info.servers[0] && info.servers[0].url)
|
|
555
556
|
|| homepage
|
|
556
|
-
|
|
557
|
-
Content(`## Upstream API
|
|
557
|
+
Content(`## Upstream API
|
|
558
558
|
|
|
559
559
|
This SDK is generated from the upstream OpenAPI specification. It is an
|
|
560
560
|
unofficial client and is not affiliated with the API provider.
|
|
561
561
|
|
|
562
|
+
The OpenAPI spec(s) this SDK was generated from are kept in the
|
|
563
|
+
[\`.sdk/def/\`](.sdk/def/) folder.
|
|
564
|
+
|
|
562
565
|
`)
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
`)
|
|
566
|
-
}
|
|
567
|
-
if (docsUrl && docsUrl !== upstreamUrl) {
|
|
568
|
-
Content(`- Documentation: [${docsUrl}](${docsUrl})
|
|
566
|
+
if (upstreamUrl) {
|
|
567
|
+
Content(`- Upstream API: [${upstreamUrl}](${upstreamUrl})
|
|
569
568
|
`)
|
|
570
|
-
|
|
571
|
-
|
|
569
|
+
}
|
|
570
|
+
if (docsUrl && docsUrl !== upstreamUrl) {
|
|
571
|
+
Content(`- Documentation: [${docsUrl}](${docsUrl})
|
|
572
572
|
`)
|
|
573
573
|
}
|
|
574
|
+
Content(`
|
|
575
|
+
`)
|
|
574
576
|
|
|
575
577
|
// 13b. Security
|
|
576
578
|
Content(`## Security
|