model-eol 0.2.4 → 0.4.0
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/README.md +117 -22
- package/action.yml +124 -9
- package/bot/bot.mjs +1371 -0
- package/bot/lib/common.mjs +122 -0
- package/bot/lib/config.mjs +1 -0
- package/bot/lib/eval.mjs +103 -0
- package/bot/lib/feeds.mjs +48 -0
- package/bot/lib/git.mjs +131 -0
- package/bot/lib/github.mjs +187 -0
- package/bot.yml.example +145 -0
- package/check.mjs +151 -17
- package/feeds/amazon.json +1 -1
- package/feeds/anthropic.json +1 -1
- package/feeds/google.json +88 -5
- package/feeds/openai.json +11 -26
- package/lib/config.mjs +258 -0
- package/lib/feeds.mjs +38 -4
- package/lib/glob.mjs +35 -0
- package/lib/plan.mjs +27 -8
- package/lib/reports.mjs +24 -7
- package/lib/scanner.mjs +247 -70
- package/package.json +8 -4
- package/schema/model-eol.bot-config.schema.json +73 -8
- package/schema/model-eol.inventory.schema.json +21 -0
- package/schema/model-eol.plan.schema.json +22 -0
package/README.md
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
# model-eol
|
|
2
2
|
|
|
3
3
|

|
|
4
|
+
[](https://github.com/marketplace/actions/model-eol-check)
|
|
4
5
|

|
|
6
|
+
[](https://github.com/thossullivan/model-eol/actions/workflows/feed-refresh.yml)
|
|
5
7
|

|
|
6
8
|

|
|
7
9
|

|
|
8
10
|

|
|
9
11
|
|
|
10
12
|
**A machine-readable deprecation feed format for AI models, plus the reference
|
|
11
|
-
tooling that turns it into a Dependabot for models.**
|
|
13
|
+
tooling that turns it into a Dependabot for models.**
|
|
12
14
|
|
|
13
15
|

|
|
14
16
|
|
|
@@ -31,14 +33,15 @@ second, so the existing trackers can converge instead of each scraping alone.
|
|
|
31
33
|
replacement, `distributions` for per-channel lifecycles, and publisher `policy`
|
|
32
34
|
floors. Small enough that a provider could serve it at
|
|
33
35
|
`/.well-known/model-eol.json` in an afternoon.
|
|
34
|
-
- **`feeds/`** - <!-- feeds-status -->Amazon (4 entries), Anthropic (29 entries), Google (
|
|
36
|
+
- **`feeds/`** - <!-- feeds-status -->Amazon (4 entries), Anthropic (29 entries), Google (86 entries) and OpenAI (194 entries), generated from the providers' live deprecation pages plus the AWS Bedrock and Google Vertex AI lifecycle pages, feed data generated 2026-08-18<!-- /feeds-status -->. Every
|
|
35
37
|
dated entry carries a source URL.
|
|
36
38
|
- **`check.mjs`** - zero-dependency CLI: CI gate, PR diff gate, inventory, CycloneDX
|
|
37
39
|
ML-BOM export, retirement schedule, alerts and badges, migration plan/apply.
|
|
38
40
|
- **`refresh/`** - regenerates the feeds from provider pages, models endpoints, and
|
|
39
41
|
distributor lifecycle pages, with a semantic diff for human review.
|
|
40
42
|
- **`bot/`** - the Dependabot part: a cron GitHub workflow that maintains one
|
|
41
|
-
migration PR or issue per retiring model
|
|
43
|
+
migration PR or issue per retiring model, published as the `model-eol-bot`
|
|
44
|
+
binary in the same npm package.
|
|
42
45
|
- **`scripts/feed-changelog.mjs`** - the feeds' git history as Atom/markdown, so
|
|
43
46
|
"model retirements as they are announced" is a feed you can subscribe to.
|
|
44
47
|
|
|
@@ -101,6 +104,11 @@ PRs to trigger checks), and provider API keys enter the picture in exactly two
|
|
|
101
104
|
optional places: your own eval hook command, and the feed-refresh models-endpoint
|
|
102
105
|
coverage.
|
|
103
106
|
|
|
107
|
+
Both command-line binaries ship in one zero-dependency npm artifact. The test
|
|
108
|
+
suite packs that artifact, installs it into an empty consumer directory with the
|
|
109
|
+
network disabled, and runs both bins; it also fails if runtime, development,
|
|
110
|
+
peer, or optional npm dependencies are introduced.
|
|
111
|
+
|
|
104
112
|
## Use it as a GitHub Action
|
|
105
113
|
|
|
106
114
|
The same gate as a composite action - no npm install, feeds bundled, pinned to
|
|
@@ -122,9 +130,69 @@ That is the PR gate: fail only when *this* change adds a model that is retired
|
|
|
122
130
|
or retiring within the threshold. Add `via: aws-bedrock` (or `azure-ai-foundry`)
|
|
123
131
|
to judge by a distributor's clock. The copy-paste version with both gates - PR
|
|
124
132
|
diff plus a weekly full-repository check - is
|
|
125
|
-
[`examples/workflows/model-eol.yml`](examples/workflows/model-eol.yml)
|
|
126
|
-
|
|
127
|
-
|
|
133
|
+
[`examples/workflows/model-eol.yml`](examples/workflows/model-eol.yml). The
|
|
134
|
+
Action also exposes `inventory`, `schedule`, `alert`, and `plan`. Use
|
|
135
|
+
`format: cyclonedx` for an ML-BOM, or `output-file` to retain any report as a
|
|
136
|
+
workflow artifact while keeping the same output in the job log.
|
|
137
|
+
|
|
138
|
+
## One repository policy
|
|
139
|
+
|
|
140
|
+
The CLI, Action, and bot all discover a strict `.model-eol.json` at the target
|
|
141
|
+
Git repository root. CLI flags or Action inputs override configured values, and
|
|
142
|
+
`--config FILE` selects an explicit policy when auto-discovery is ambiguous:
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"days": 90,
|
|
147
|
+
"scope": "direct",
|
|
148
|
+
"via": null,
|
|
149
|
+
"ignore": {
|
|
150
|
+
"models": ["o3-deep-research"],
|
|
151
|
+
"paths": ["test/fixtures/**", "vendor"]
|
|
152
|
+
},
|
|
153
|
+
"issues": { "enabled": true },
|
|
154
|
+
"eval": { "command": "npm test" }
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Unknown keys and invalid values fail closed. A canonical model ID or any alias
|
|
159
|
+
in `ignore.models` suppresses the whole alias family; `ignore.paths` uses
|
|
160
|
+
repo-relative `*`, `**`, and `?` globs and excludes matching files before scan
|
|
161
|
+
coverage limits are counted. With no config the CLI keeps its historical
|
|
162
|
+
`scope: all`; once a config exists, omitted values use the shared bot defaults
|
|
163
|
+
(`days: 90`, `scope: direct`, and the publisher clock). The complete contract is
|
|
164
|
+
[`schema/model-eol.bot-config.schema.json`](schema/model-eol.bot-config.schema.json).
|
|
165
|
+
|
|
166
|
+
Mixed-provider monorepos can keep those top-level values as repository defaults,
|
|
167
|
+
then apply path policies and a lifecycle channel per reference:
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"days": 90,
|
|
172
|
+
"scope": "direct",
|
|
173
|
+
"overrides": [
|
|
174
|
+
{ "paths": ["services/**"], "scope": "all" },
|
|
175
|
+
{ "paths": ["services/bedrock/**"], "days": 180, "via": "aws-bedrock" }
|
|
176
|
+
],
|
|
177
|
+
"routes": [
|
|
178
|
+
{ "paths": ["services/vertex/**"], "via": "vertex-ai" },
|
|
179
|
+
{
|
|
180
|
+
"paths": ["services/bedrock/**"],
|
|
181
|
+
"match": "chat-prod",
|
|
182
|
+
"model": "claude-3-7-sonnet-20250219",
|
|
183
|
+
"via": "aws-bedrock"
|
|
184
|
+
}
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Matching overrides apply in order: later scalar values win and ignore lists are
|
|
190
|
+
additive. The last matching route wins. Exact `match`/`model` pairs resolve a
|
|
191
|
+
repository deployment alias without making cloud or gateway references patchable.
|
|
192
|
+
Explicit CLI flags and Action inputs still take precedence. JSON inventory and
|
|
193
|
+
plan output records each reference's effective threshold, scope, requested
|
|
194
|
+
channel, and matching rule indexes, so a Bedrock service and a direct publisher
|
|
195
|
+
call in the same repository do not silently share one global clock.
|
|
128
196
|
|
|
129
197
|
## Same weights, different clocks
|
|
130
198
|
|
|
@@ -133,9 +201,9 @@ this is wrong in both directions: o3-deep-research died at OpenAI on July 23 but
|
|
|
133
201
|
lives on Azure AI Foundry until December 26; claude-opus-4-1 retires at Anthropic on
|
|
134
202
|
August 5 but lives on Amazon Bedrock until January 8, 2027. `distributions` in the
|
|
135
203
|
spec carries these per-channel clocks, `--via <distributor>` judges your repo by the
|
|
136
|
-
channel you actually call, and the
|
|
137
|
-
current from
|
|
138
|
-
for the same migration, not as a destination.
|
|
204
|
+
channel you actually call, and the distributor refresh keeps Bedrock and Vertex
|
|
205
|
+
clocks current from their lifecycle pages. Treat a distributor's later date as
|
|
206
|
+
runway for the same migration, not as a destination.
|
|
139
207
|
|
|
140
208
|
## Policy floors - a planning floor from absence
|
|
141
209
|
|
|
@@ -166,33 +234,58 @@ stay visible without generating false alarms.
|
|
|
166
234
|
The scanner covers code and configuration files with [`CODE_EXT`](lib/scanner.mjs)
|
|
167
235
|
as the source of truth - Python, TypeScript/JavaScript, JSON/YAML/TOML, shell,
|
|
168
236
|
Ruby, Go, Java, C#, Rust, C/C++, PHP, Swift, Kotlin, Terraform, SQL, Scala, and
|
|
169
|
-
Objective-C
|
|
170
|
-
|
|
237
|
+
Objective-C, including `.baml` sources. Publisher-compatible BAML provider/model
|
|
238
|
+
pairs are eligible plan targets; generated BAML clients and conservative
|
|
239
|
+
`DO NOT EDIT`/`@generated` sources are skipped. Model-eol's own JSON reports are
|
|
240
|
+
also skipped on reruns, while third-party CycloneDX files remain scannable unless
|
|
241
|
+
they carry explicit model-eol generator provenance. Terraform files (`.tf`,
|
|
242
|
+
`.tfvars`) are scanned while `.terraform` directories stay excluded.
|
|
171
243
|
|
|
172
244
|
## The bot
|
|
173
245
|
|
|
174
246
|
Copy `bot.yml.example` to `.github/workflows/model-eol-bot.yml` for a weekly run
|
|
175
247
|
that maintains exactly one labelled migration PR per retiring model (full feed
|
|
176
248
|
context in the body, never auto-merged) and one issue per finding that needs a
|
|
177
|
-
human.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
249
|
+
human. The workflow resolves `model-eol@0` from npm once and reuses that exact
|
|
250
|
+
version across its plan, read-only evaluation, and write-token publication jobs;
|
|
251
|
+
consumer repositories do not copy `check.mjs` or the `bot/` source directory.
|
|
252
|
+
Dismissals are respected, reintroduced retired models create fresh work, and
|
|
253
|
+
bot-owned PRs/issues close when their finding disappears. Preview everything with
|
|
254
|
+
no GitHub calls and without adding a project dependency:
|
|
181
255
|
|
|
182
256
|
```sh
|
|
183
|
-
|
|
257
|
+
npx --yes --package=model-eol@0 model-eol-bot --dry-run --target-dir . --repo OWNER/REPO
|
|
184
258
|
```
|
|
185
259
|
|
|
260
|
+
The workflow honors configured `days`, `scope`, and `via` values; without a config
|
|
261
|
+
it uses the bot defaults of 90 days and direct references. `eval.command` also
|
|
262
|
+
comes from the config unless the `MODEL_EOL_EVAL_COMMAND` repository variable is
|
|
263
|
+
set as an explicit workflow override. Each patchable model is applied in an
|
|
264
|
+
isolated checkout and evaluated independently with its own old/new IDs, timeout,
|
|
265
|
+
bounded report, and explicitly allowed environment. The content-bound result
|
|
266
|
+
manifest is also pinned to the evaluated Git commit, letting passing migrations
|
|
267
|
+
proceed while a failing peer remains blocked without publishing against a newer,
|
|
268
|
+
unevaluated default branch.
|
|
269
|
+
|
|
270
|
+
On its first actionable run, the bot creates the `model-eol` label. If repository
|
|
271
|
+
policy prevents label creation or assignment, it fails closed rather than publish
|
|
272
|
+
work whose ownership cannot be authenticated. Existing work is trusted only when
|
|
273
|
+
the label, metadata, deterministic branch, repository, base, and Git lease agree.
|
|
274
|
+
For HTTPS remotes—including private repositories—the bot passes `GITHUB_TOKEN` to
|
|
275
|
+
temporary Git processes as a host-scoped authorization header and never places it
|
|
276
|
+
in a remote URL.
|
|
277
|
+
|
|
186
278
|
Two operational notes the hard way teaches: PRs created with `GITHUB_TOKEN` do not
|
|
187
279
|
trigger `pull_request` workflows (use a fine-grained PAT or GitHub App token when
|
|
188
|
-
checks must run
|
|
189
|
-
|
|
280
|
+
checks must run, stored as the optional `MODEL_EOL_BOT_TOKEN` secret), and the
|
|
281
|
+
workflow splits privileges—provider keys live only in the read-only evaluation
|
|
282
|
+
job, while write tokens live only in the reconciliation job.
|
|
190
283
|
|
|
191
284
|
## Keeping the feeds honest
|
|
192
285
|
|
|
193
286
|
```sh
|
|
194
287
|
node refresh/refresh.mjs --check # semantic diff vs live pages; exit 3 = PR-worthy
|
|
195
|
-
node refresh/refresh.mjs --distributor aws-bedrock
|
|
288
|
+
node refresh/refresh.mjs --distributor aws-bedrock,vertex-ai # distributor lifecycle clocks
|
|
196
289
|
node scripts/feed-changelog.mjs # feeds' git history as an Atom feed
|
|
197
290
|
```
|
|
198
291
|
|
|
@@ -226,8 +319,9 @@ move any of us can make here.
|
|
|
226
319
|
|
|
227
320
|
- Feeds refresh automatically: the weekly feed-refresh workflow is live in this
|
|
228
321
|
repo (parse failures fail the run; material changes become a reviewed PR), and
|
|
229
|
-
CI runs the full suite on every push and PR. The bot workflow
|
|
230
|
-
`bot.yml.example
|
|
322
|
+
CI runs the full suite on every push and PR. The copy-ready bot workflow ships
|
|
323
|
+
as `bot.yml.example` and consumes the published package rather than local copies
|
|
324
|
+
of the tooling.
|
|
231
325
|
- Current-model entries (and therefore policy-floor horizons) populate only when
|
|
232
326
|
refresh runs with provider API keys for the models endpoints.
|
|
233
327
|
- The checker matches known IDs only - it will not discover models absent from the
|
|
@@ -237,7 +331,8 @@ move any of us can make here.
|
|
|
237
331
|
lifecycle fetcher is not built yet.
|
|
238
332
|
- On npm as [`model-eol`](https://www.npmjs.com/package/model-eol). Material feed
|
|
239
333
|
changes republish automatically as patch versions (trusted publishing with
|
|
240
|
-
provenance),
|
|
334
|
+
provenance), while manual code releases require an explicit stable version, so
|
|
335
|
+
`npx model-eol` always checks against current dates.
|
|
241
336
|
- Not yet: feed signing, gateway route resolvers.
|
|
242
337
|
|
|
243
338
|
## Contributing
|
package/action.yml
CHANGED
|
@@ -5,7 +5,7 @@ branding:
|
|
|
5
5
|
color: 'red'
|
|
6
6
|
inputs:
|
|
7
7
|
command:
|
|
8
|
-
description: 'Command to run: check, inventory, or
|
|
8
|
+
description: 'Command to run: check, inventory, schedule, alert, or plan'
|
|
9
9
|
required: false
|
|
10
10
|
default: 'check'
|
|
11
11
|
paths:
|
|
@@ -13,35 +13,56 @@ inputs:
|
|
|
13
13
|
required: false
|
|
14
14
|
default: '.'
|
|
15
15
|
days:
|
|
16
|
-
description: 'Fail when a model retires within this many days'
|
|
16
|
+
description: 'Fail when a model retires within this many days (defaults to CLI or repository config)'
|
|
17
17
|
required: false
|
|
18
|
-
default: '
|
|
18
|
+
default: ''
|
|
19
19
|
via:
|
|
20
20
|
description: 'Judge lifecycles by a distributor clock (e.g. azure-ai-foundry, aws-bedrock) instead of the publisher''s'
|
|
21
21
|
required: false
|
|
22
22
|
default: ''
|
|
23
23
|
scope:
|
|
24
|
-
description: 'Check scope: all tracked model IDs, or direct to leave cloud/gateway refs as inventory hints'
|
|
24
|
+
description: 'Check scope: all tracked model IDs, or direct to leave cloud/gateway refs as inventory hints (defaults to CLI or repository config)'
|
|
25
25
|
required: false
|
|
26
|
-
default: '
|
|
26
|
+
default: ''
|
|
27
27
|
changed:
|
|
28
28
|
description: 'Base ref for the PR gate: check only lines added relative to this ref (requires fetch-depth: 0)'
|
|
29
29
|
required: false
|
|
30
30
|
default: ''
|
|
31
31
|
format:
|
|
32
|
-
description: '
|
|
32
|
+
description: 'Output format: json, cyclonedx, or text for inventory; github, markdown, badge, or json for alert. Defaults to json for inventory and github for alert.'
|
|
33
33
|
required: false
|
|
34
|
-
default: '
|
|
34
|
+
default: ''
|
|
35
35
|
feeds:
|
|
36
36
|
description: 'Directory of model-eol feeds (defaults to the feeds bundled with the action)'
|
|
37
37
|
required: false
|
|
38
38
|
default: ''
|
|
39
|
+
config:
|
|
40
|
+
description: 'Path to a model-eol JSON config (defaults to repository config discovery)'
|
|
41
|
+
required: false
|
|
42
|
+
default: ''
|
|
43
|
+
include-docs:
|
|
44
|
+
description: 'Scan documentation files in addition to the default source and config files'
|
|
45
|
+
required: false
|
|
46
|
+
default: 'false'
|
|
47
|
+
allow-incomplete:
|
|
48
|
+
description: 'Allow check and plan to continue when scan coverage is incomplete'
|
|
49
|
+
required: false
|
|
50
|
+
default: 'false'
|
|
51
|
+
json:
|
|
52
|
+
description: 'Emit JSON for check, inventory, schedule, or alert'
|
|
53
|
+
required: false
|
|
54
|
+
default: 'false'
|
|
55
|
+
output-file:
|
|
56
|
+
description: 'Optional path that receives an exact copy of stdout while stdout remains visible in the Actions log'
|
|
57
|
+
required: false
|
|
58
|
+
default: ''
|
|
39
59
|
runs:
|
|
40
60
|
using: 'composite'
|
|
41
61
|
steps:
|
|
42
62
|
- name: model-eol check
|
|
43
63
|
shell: bash
|
|
44
64
|
env:
|
|
65
|
+
MODEL_EOL_ACTION_PATH: ${{ github.action_path }}
|
|
45
66
|
MODEL_EOL_COMMAND: ${{ inputs.command }}
|
|
46
67
|
MODEL_EOL_PATHS: ${{ inputs.paths }}
|
|
47
68
|
MODEL_EOL_DAYS: ${{ inputs.days }}
|
|
@@ -50,7 +71,14 @@ runs:
|
|
|
50
71
|
MODEL_EOL_SCOPE: ${{ inputs.scope }}
|
|
51
72
|
MODEL_EOL_FORMAT: ${{ inputs.format }}
|
|
52
73
|
MODEL_EOL_FEEDS: ${{ inputs.feeds }}
|
|
74
|
+
MODEL_EOL_CONFIG: ${{ inputs.config }}
|
|
75
|
+
MODEL_EOL_INCLUDE_DOCS: ${{ inputs['include-docs'] }}
|
|
76
|
+
MODEL_EOL_ALLOW_INCOMPLETE: ${{ inputs['allow-incomplete'] }}
|
|
77
|
+
MODEL_EOL_JSON: ${{ inputs.json }}
|
|
78
|
+
MODEL_EOL_OUTPUT_FILE: ${{ inputs['output-file'] }}
|
|
53
79
|
run: |
|
|
80
|
+
set -euo pipefail
|
|
81
|
+
|
|
54
82
|
split_model_eol_paths() {
|
|
55
83
|
PATH_ARGS=()
|
|
56
84
|
if [[ "$MODEL_EOL_PATHS" == *$'\n'* ]]; then
|
|
@@ -62,10 +90,97 @@ runs:
|
|
|
62
90
|
fi
|
|
63
91
|
}
|
|
64
92
|
split_model_eol_paths
|
|
65
|
-
|
|
93
|
+
|
|
94
|
+
case "$MODEL_EOL_COMMAND" in
|
|
95
|
+
check|inventory|schedule|alert|plan) ;;
|
|
96
|
+
*)
|
|
97
|
+
echo "model-eol action: command must be check, inventory, schedule, alert, or plan" >&2
|
|
98
|
+
exit 2
|
|
99
|
+
;;
|
|
100
|
+
esac
|
|
101
|
+
if [ -n "$MODEL_EOL_CHANGED" ] && [ "$MODEL_EOL_COMMAND" != 'check' ]; then
|
|
102
|
+
echo "model-eol action: changed is only supported by the check command" >&2
|
|
103
|
+
exit 2
|
|
104
|
+
fi
|
|
105
|
+
if [ -n "$MODEL_EOL_FORMAT" ] && [ "$MODEL_EOL_COMMAND" != 'inventory' ] && [ "$MODEL_EOL_COMMAND" != 'alert' ]; then
|
|
106
|
+
echo "model-eol action: format is only supported by the inventory and alert commands" >&2
|
|
107
|
+
exit 2
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
ARGS=("$MODEL_EOL_COMMAND" "${PATH_ARGS[@]}")
|
|
111
|
+
if [ -n "$MODEL_EOL_DAYS" ]; then ARGS+=(--days "$MODEL_EOL_DAYS"); fi
|
|
66
112
|
if [ -n "$MODEL_EOL_VIA" ]; then ARGS+=(--via "$MODEL_EOL_VIA"); fi
|
|
67
113
|
if [ -n "$MODEL_EOL_CHANGED" ]; then ARGS+=(--changed "$MODEL_EOL_CHANGED"); fi
|
|
68
114
|
if [ -n "$MODEL_EOL_SCOPE" ]; then ARGS+=(--scope "$MODEL_EOL_SCOPE"); fi
|
|
69
115
|
if [ -n "$MODEL_EOL_FORMAT" ]; then ARGS+=(--format "$MODEL_EOL_FORMAT"); fi
|
|
70
116
|
if [ -n "$MODEL_EOL_FEEDS" ]; then ARGS+=(--feeds "$MODEL_EOL_FEEDS"); fi
|
|
71
|
-
|
|
117
|
+
if [ -n "$MODEL_EOL_CONFIG" ]; then ARGS+=(--config "$MODEL_EOL_CONFIG"); fi
|
|
118
|
+
|
|
119
|
+
append_boolean_flag() {
|
|
120
|
+
local value="$1"
|
|
121
|
+
local flag="$2"
|
|
122
|
+
local input_name="$3"
|
|
123
|
+
case "$value" in
|
|
124
|
+
true) ARGS+=("$flag") ;;
|
|
125
|
+
false|'') ;;
|
|
126
|
+
*)
|
|
127
|
+
echo "model-eol action: $input_name must be true or false" >&2
|
|
128
|
+
exit 2
|
|
129
|
+
;;
|
|
130
|
+
esac
|
|
131
|
+
}
|
|
132
|
+
append_boolean_flag "$MODEL_EOL_INCLUDE_DOCS" --include-docs include-docs
|
|
133
|
+
case "$MODEL_EOL_ALLOW_INCOMPLETE" in
|
|
134
|
+
true)
|
|
135
|
+
if [ "$MODEL_EOL_COMMAND" != 'check' ] && [ "$MODEL_EOL_COMMAND" != 'plan' ]; then
|
|
136
|
+
echo "model-eol action: allow-incomplete is only supported by the check and plan commands" >&2
|
|
137
|
+
exit 2
|
|
138
|
+
fi
|
|
139
|
+
ARGS+=(--allow-incomplete)
|
|
140
|
+
;;
|
|
141
|
+
false|'') ;;
|
|
142
|
+
*)
|
|
143
|
+
echo "model-eol action: allow-incomplete must be true or false" >&2
|
|
144
|
+
exit 2
|
|
145
|
+
;;
|
|
146
|
+
esac
|
|
147
|
+
case "$MODEL_EOL_JSON" in
|
|
148
|
+
true)
|
|
149
|
+
if [ "$MODEL_EOL_COMMAND" = 'plan' ]; then
|
|
150
|
+
echo "model-eol action: json is only supported by the check, inventory, schedule, and alert commands" >&2
|
|
151
|
+
exit 2
|
|
152
|
+
fi
|
|
153
|
+
ARGS+=(--json)
|
|
154
|
+
;;
|
|
155
|
+
false|'') ;;
|
|
156
|
+
*)
|
|
157
|
+
echo "model-eol action: json must be true or false" >&2
|
|
158
|
+
exit 2
|
|
159
|
+
;;
|
|
160
|
+
esac
|
|
161
|
+
|
|
162
|
+
if [ -z "$MODEL_EOL_OUTPUT_FILE" ]; then
|
|
163
|
+
exec node "$MODEL_EOL_ACTION_PATH/check.mjs" "${ARGS[@]}"
|
|
164
|
+
fi
|
|
165
|
+
if [ -d "$MODEL_EOL_OUTPUT_FILE" ]; then
|
|
166
|
+
echo "model-eol action: output-file must name a file, not a directory" >&2
|
|
167
|
+
exit 2
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
OUTPUT_TEMP="$(mktemp "${RUNNER_TEMP:-${TMPDIR:-/tmp}}/model-eol-output.XXXXXX")"
|
|
171
|
+
trap 'rm -f "$OUTPUT_TEMP"' EXIT
|
|
172
|
+
set +e
|
|
173
|
+
node "$MODEL_EOL_ACTION_PATH/check.mjs" "${ARGS[@]}" | tee "$OUTPUT_TEMP"
|
|
174
|
+
PIPE_STATUSES=("${PIPESTATUS[@]}")
|
|
175
|
+
CLI_STATUS="${PIPE_STATUSES[0]}"
|
|
176
|
+
TEE_STATUS="${PIPE_STATUSES[1]}"
|
|
177
|
+
COPY_STATUS=0
|
|
178
|
+
if [ "$TEE_STATUS" -eq 0 ]; then
|
|
179
|
+
cp -- "$OUTPUT_TEMP" "$MODEL_EOL_OUTPUT_FILE"
|
|
180
|
+
COPY_STATUS=$?
|
|
181
|
+
fi
|
|
182
|
+
|
|
183
|
+
FINAL_STATUS="$CLI_STATUS"
|
|
184
|
+
if [ "$FINAL_STATUS" -eq 0 ] && [ "$TEE_STATUS" -ne 0 ]; then FINAL_STATUS="$TEE_STATUS"; fi
|
|
185
|
+
if [ "$FINAL_STATUS" -eq 0 ] && [ "$COPY_STATUS" -ne 0 ]; then FINAL_STATUS="$COPY_STATUS"; fi
|
|
186
|
+
exit "$FINAL_STATUS"
|