Skip to content

Commit efc321e

Browse files
authored
Add crisis alert Telegram channel config (#91)
1 parent 8dabb39 commit efc321e

7 files changed

Lines changed: 112 additions & 6 deletions

File tree

.github/workflows/sync-cloud-run-env.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ jobs:
6161
CRISIS_ALERT_PUSH_PRIORITY: ${{ vars.CRISIS_ALERT_PUSH_PRIORITY }}
6262
CRISIS_ALERT_PUSH_TAGS: ${{ vars.CRISIS_ALERT_PUSH_TAGS }}
6363
CRISIS_ALERT_PUSH_BODY_MAX_CHARS: ${{ vars.CRISIS_ALERT_PUSH_BODY_MAX_CHARS }}
64+
CRISIS_ALERT_TELEGRAM_CHAT_IDS: ${{ vars.CRISIS_ALERT_TELEGRAM_CHAT_IDS }}
65+
CRISIS_ALERT_TELEGRAM_BOT_TOKEN_SECRET_NAME: ${{ vars.CRISIS_ALERT_TELEGRAM_BOT_TOKEN_SECRET_NAME }}
66+
CRISIS_ALERT_TELEGRAM_API_BASE_URL: ${{ vars.CRISIS_ALERT_TELEGRAM_API_BASE_URL }}
67+
CRISIS_ALERT_TELEGRAM_PARSE_MODE: ${{ vars.CRISIS_ALERT_TELEGRAM_PARSE_MODE }}
68+
CRISIS_ALERT_TELEGRAM_DISABLE_WEB_PAGE_PREVIEW: ${{ vars.CRISIS_ALERT_TELEGRAM_DISABLE_WEB_PAGE_PREVIEW }}
69+
CRISIS_ALERT_TELEGRAM_BODY_MAX_CHARS: ${{ vars.CRISIS_ALERT_TELEGRAM_BODY_MAX_CHARS }}
6470
# Strategy-owned defaults continue to come from UsEquityStrategies; this workflow only syncs platform/runtime inputs.
6571
EXECUTION_REPORT_GCS_URI: ${{ vars.EXECUTION_REPORT_GCS_URI }}
6672
IB_GATEWAY_ZONE: ${{ vars.IB_GATEWAY_ZONE }}
@@ -72,6 +78,7 @@ jobs:
7278
CRISIS_ALERT_SMS_AUTH_TOKEN: ${{ secrets.CRISIS_ALERT_SMS_AUTH_TOKEN }}
7379
CRISIS_ALERT_PUSH_APP_TOKEN: ${{ secrets.CRISIS_ALERT_PUSH_APP_TOKEN }}
7480
CRISIS_ALERT_PUSH_ACCESS_TOKEN: ${{ secrets.CRISIS_ALERT_PUSH_ACCESS_TOKEN }}
81+
CRISIS_ALERT_TELEGRAM_BOT_TOKEN: ${{ secrets.CRISIS_ALERT_TELEGRAM_BOT_TOKEN }}
7582
steps:
7683
- name: Check whether env sync is enabled
7784
id: config
@@ -366,6 +373,17 @@ jobs:
366373
shared_remove_secret_vars+=("CRISIS_ALERT_PUSH_ACCESS_TOKEN")
367374
fi
368375
376+
if [ -n "${CRISIS_ALERT_TELEGRAM_BOT_TOKEN_SECRET_NAME:-}" ]; then
377+
shared_secret_pairs+=("CRISIS_ALERT_TELEGRAM_BOT_TOKEN=${CRISIS_ALERT_TELEGRAM_BOT_TOKEN_SECRET_NAME}:latest")
378+
shared_remove_env_vars+=("CRISIS_ALERT_TELEGRAM_BOT_TOKEN")
379+
elif [ -n "${CRISIS_ALERT_TELEGRAM_BOT_TOKEN:-}" ]; then
380+
shared_env_pairs+=("CRISIS_ALERT_TELEGRAM_BOT_TOKEN=${CRISIS_ALERT_TELEGRAM_BOT_TOKEN}")
381+
shared_remove_secret_vars+=("CRISIS_ALERT_TELEGRAM_BOT_TOKEN")
382+
else
383+
shared_remove_env_vars+=("CRISIS_ALERT_TELEGRAM_BOT_TOKEN")
384+
shared_remove_secret_vars+=("CRISIS_ALERT_TELEGRAM_BOT_TOKEN")
385+
fi
386+
369387
if [ -n "${CRISIS_ALERT_CHANNELS:-}" ]; then
370388
shared_env_pairs+=("CRISIS_ALERT_CHANNELS=${CRISIS_ALERT_CHANNELS}")
371389
else
@@ -486,6 +504,36 @@ jobs:
486504
shared_remove_env_vars+=("CRISIS_ALERT_PUSH_BODY_MAX_CHARS")
487505
fi
488506
507+
if [ -n "${CRISIS_ALERT_TELEGRAM_CHAT_IDS:-}" ]; then
508+
shared_env_pairs+=("CRISIS_ALERT_TELEGRAM_CHAT_IDS=${CRISIS_ALERT_TELEGRAM_CHAT_IDS}")
509+
else
510+
shared_remove_env_vars+=("CRISIS_ALERT_TELEGRAM_CHAT_IDS")
511+
fi
512+
513+
if [ -n "${CRISIS_ALERT_TELEGRAM_API_BASE_URL:-}" ]; then
514+
shared_env_pairs+=("CRISIS_ALERT_TELEGRAM_API_BASE_URL=${CRISIS_ALERT_TELEGRAM_API_BASE_URL}")
515+
else
516+
shared_remove_env_vars+=("CRISIS_ALERT_TELEGRAM_API_BASE_URL")
517+
fi
518+
519+
if [ -n "${CRISIS_ALERT_TELEGRAM_PARSE_MODE:-}" ]; then
520+
shared_env_pairs+=("CRISIS_ALERT_TELEGRAM_PARSE_MODE=${CRISIS_ALERT_TELEGRAM_PARSE_MODE}")
521+
else
522+
shared_remove_env_vars+=("CRISIS_ALERT_TELEGRAM_PARSE_MODE")
523+
fi
524+
525+
if [ -n "${CRISIS_ALERT_TELEGRAM_DISABLE_WEB_PAGE_PREVIEW:-}" ]; then
526+
shared_env_pairs+=("CRISIS_ALERT_TELEGRAM_DISABLE_WEB_PAGE_PREVIEW=${CRISIS_ALERT_TELEGRAM_DISABLE_WEB_PAGE_PREVIEW}")
527+
else
528+
shared_remove_env_vars+=("CRISIS_ALERT_TELEGRAM_DISABLE_WEB_PAGE_PREVIEW")
529+
fi
530+
531+
if [ -n "${CRISIS_ALERT_TELEGRAM_BODY_MAX_CHARS:-}" ]; then
532+
shared_env_pairs+=("CRISIS_ALERT_TELEGRAM_BODY_MAX_CHARS=${CRISIS_ALERT_TELEGRAM_BODY_MAX_CHARS}")
533+
else
534+
shared_remove_env_vars+=("CRISIS_ALERT_TELEGRAM_BODY_MAX_CHARS")
535+
fi
536+
489537
for target_index in "${!target_services[@]}"; do
490538
cloud_run_service="${target_services[${target_index}]}"
491539
mapfile -t target_env_pairs < <(emit_target_env_pairs "${target_index}")

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,15 @@ For IBKR, keep `paper` as a single account-group entry. If you later add live ac
112112
| `TELEGRAM_TOKEN` | Yes | Telegram bot token. For Cloud Run, prefer a Secret Manager reference instead of a literal env var. |
113113
| `GLOBAL_TELEGRAM_CHAT_ID` | Yes | Telegram chat ID used by this service. |
114114
| `NOTIFY_LANG` | No | `en` (default) or `zh` |
115-
| `CRISIS_ALERT_CHANNELS` | No | Optional crisis alert channel list: `email`, `sms`, and/or `push`. |
115+
| `CRISIS_ALERT_CHANNELS` | No | Optional crisis alert channel list: `email`, `sms`, `push`, and/or `telegram`. |
116116
| `CRISIS_ALERT_EMAIL_RECIPIENTS` | No | Comma/semicolon/newline-separated email-form recipients. Use a normal mailbox for email-only delivery, or a Google Voice-associated mailbox/address to also trigger Google Voice prompts. |
117117
| `CRISIS_ALERT_EMAIL_SENDER_EMAIL` | No | Sender email address used for crisis alert email. Gmail is the default transport, but the sender naming is provider-neutral. |
118118
| `CRISIS_ALERT_EMAIL_SENDER_PASSWORD` | No | Sender SMTP password or app password. For Cloud Run, prefer `CRISIS_ALERT_EMAIL_SENDER_PASSWORD_SECRET_NAME` in env sync. |
119119
| `CRISIS_ALERT_EMAIL_SMTP_HOST` | No | Optional SMTP host override. Defaults to Gmail SMTP when unset. |
120120
| `CRISIS_ALERT_EMAIL_SMTP_PORT` | No | Optional SMTP port override. Defaults to `465` when unset. |
121121
| `CRISIS_ALERT_EMAIL_SMTP_SECURITY` | No | Optional SMTP security override: `ssl`, `starttls`, or `none`. Defaults to `ssl` when unset. |
122+
| `CRISIS_ALERT_TELEGRAM_CHAT_IDS` | No | Dedicated crisis-alert Telegram chat IDs. Separate from the strategy-cycle Telegram chat. |
123+
| `CRISIS_ALERT_TELEGRAM_BOT_TOKEN` | No | Dedicated crisis-alert Telegram bot token. For Cloud Run, prefer `CRISIS_ALERT_TELEGRAM_BOT_TOKEN_SECRET_NAME` in env sync. |
122124

123125
The selected account-group entry must provide at least:
124126

@@ -426,13 +428,15 @@ IBKR 账户
426428
| `TELEGRAM_TOKEN` || Telegram 机器人 Token。Cloud Run 上更推荐走 Secret Manager 引用,不要直接写成明文 env。 |
427429
| `GLOBAL_TELEGRAM_CHAT_ID` || 这个服务使用的 Telegram Chat ID。 |
428430
| `NOTIFY_LANG` || `en`(默认)或 `zh` |
429-
| `CRISIS_ALERT_CHANNELS` || 可选危机告警通道列表:`email``sms` 和/或 `push`|
431+
| `CRISIS_ALERT_CHANNELS` || 可选危机告警通道列表:`email``sms``push` 和/或 `telegram`|
430432
| `CRISIS_ALERT_EMAIL_RECIPIENTS` || 通知收件邮箱。普通邮箱只收邮件;关联 Google Voice 的邮箱/地址会额外触发 Google Voice 提醒。支持逗号、分号或换行分隔。 |
431433
| `CRISIS_ALERT_EMAIL_SENDER_EMAIL` || 邮件通知的发送方邮箱。默认传输走 Gmail SMTP,但命名不绑定 Gmail。 |
432434
| `CRISIS_ALERT_EMAIL_SENDER_PASSWORD` || 发送方 SMTP 密码或 app password。Cloud Run env sync 建议配置 `CRISIS_ALERT_EMAIL_SENDER_PASSWORD_SECRET_NAME`|
433435
| `CRISIS_ALERT_EMAIL_SMTP_HOST` || 可选 SMTP host 覆盖。不设置时默认 Gmail SMTP。 |
434436
| `CRISIS_ALERT_EMAIL_SMTP_PORT` || 可选 SMTP port 覆盖。不设置时默认 `465`|
435437
| `CRISIS_ALERT_EMAIL_SMTP_SECURITY` || 可选 SMTP 加密方式:`ssl``starttls``none`。不设置时默认 `ssl`|
438+
| `CRISIS_ALERT_TELEGRAM_CHAT_IDS` || 危机告警专用 Telegram chat ID,和常规策略周期 Telegram 分开。 |
439+
| `CRISIS_ALERT_TELEGRAM_BOT_TOKEN` || 危机告警专用 Telegram bot token。Cloud Run env sync 建议配置 `CRISIS_ALERT_TELEGRAM_BOT_TOKEN_SECRET_NAME`|
436440

437441
选中的账号组配置里,至少要有:
438442

requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
flask
22
gunicorn
3-
quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@2fdb7c35edf2f39c1592a7dd9319b7516276fabf
4-
us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@b626ee3e42feabbf6cd427af6faf5655ca6cd76f
3+
quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@b520bcaa216e36b94ce60c8c6a13f982de826830
4+
us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@df91828c8b521516c85512e136e724064b6b9dac
55
pandas
66
numpy
77
requests

runtime_config_support.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ class PlatformRuntimeSettings:
9696
crisis_alert_push_priority: str | None = None
9797
crisis_alert_push_tags: str | None = None
9898
crisis_alert_push_body_max_chars: str | None = None
99+
crisis_alert_telegram_chat_ids: tuple[str, ...] = ()
100+
crisis_alert_telegram_bot_token: str | None = None
101+
crisis_alert_telegram_api_base_url: str | None = None
102+
crisis_alert_telegram_parse_mode: str | None = None
103+
crisis_alert_telegram_disable_web_page_preview: str | None = None
104+
crisis_alert_telegram_body_max_chars: str | None = None
99105
runtime_target: RuntimeTarget | None = None
100106

101107

@@ -274,6 +280,24 @@ def load_platform_runtime_settings(
274280
crisis_alert_push_body_max_chars=first_non_empty(
275281
os.getenv("CRISIS_ALERT_PUSH_BODY_MAX_CHARS")
276282
),
283+
crisis_alert_telegram_chat_ids=split_env_list(
284+
os.getenv("CRISIS_ALERT_TELEGRAM_CHAT_IDS")
285+
),
286+
crisis_alert_telegram_bot_token=first_non_empty(
287+
os.getenv("CRISIS_ALERT_TELEGRAM_BOT_TOKEN")
288+
),
289+
crisis_alert_telegram_api_base_url=first_non_empty(
290+
os.getenv("CRISIS_ALERT_TELEGRAM_API_BASE_URL")
291+
),
292+
crisis_alert_telegram_parse_mode=first_non_empty(
293+
os.getenv("CRISIS_ALERT_TELEGRAM_PARSE_MODE")
294+
),
295+
crisis_alert_telegram_disable_web_page_preview=first_non_empty(
296+
os.getenv("CRISIS_ALERT_TELEGRAM_DISABLE_WEB_PAGE_PREVIEW")
297+
),
298+
crisis_alert_telegram_body_max_chars=first_non_empty(
299+
os.getenv("CRISIS_ALERT_TELEGRAM_BODY_MAX_CHARS")
300+
),
277301
runtime_target=runtime_target,
278302
)
279303

tests/conftest.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ def load_strategy_module(**env_overrides):
4646
"CRISIS_ALERT_PUSH_PRIORITY": None,
4747
"CRISIS_ALERT_PUSH_TAGS": None,
4848
"CRISIS_ALERT_PUSH_BODY_MAX_CHARS": None,
49+
"CRISIS_ALERT_TELEGRAM_CHAT_IDS": None,
50+
"CRISIS_ALERT_TELEGRAM_BOT_TOKEN": None,
51+
"CRISIS_ALERT_TELEGRAM_API_BASE_URL": None,
52+
"CRISIS_ALERT_TELEGRAM_PARSE_MODE": None,
53+
"CRISIS_ALERT_TELEGRAM_DISABLE_WEB_PAGE_PREVIEW": None,
54+
"CRISIS_ALERT_TELEGRAM_BODY_MAX_CHARS": None,
4955
}
5056
defaults.update(env_overrides)
5157
if "RUNTIME_TARGET_JSON" not in defaults:

tests/test_runtime_config_support.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@ def test_load_platform_runtime_settings_uses_minimal_group_config(monkeypatch):
161161
assert settings.crisis_alert_push_priority is None
162162
assert settings.crisis_alert_push_tags is None
163163
assert settings.crisis_alert_push_body_max_chars is None
164+
assert settings.crisis_alert_telegram_chat_ids == ()
165+
assert settings.crisis_alert_telegram_bot_token is None
166+
assert settings.crisis_alert_telegram_api_base_url is None
167+
assert settings.crisis_alert_telegram_parse_mode is None
168+
assert settings.crisis_alert_telegram_disable_web_page_preview is None
169+
assert settings.crisis_alert_telegram_body_max_chars is None
164170

165171

166172
def test_load_platform_runtime_settings_prefers_runtime_target_json(monkeypatch):
@@ -276,7 +282,7 @@ def test_load_platform_runtime_settings_reads_crisis_alert_channels_and_push_con
276282
monkeypatch.setenv("RUNTIME_TARGET_JSON", runtime_target_json(SAMPLE_STRATEGY_PROFILE))
277283
monkeypatch.setenv("ACCOUNT_GROUP", "paper")
278284
monkeypatch.setenv("IB_ACCOUNT_GROUP_CONFIG_JSON", MINIMAL_GROUP_JSON)
279-
monkeypatch.setenv("CRISIS_ALERT_CHANNELS", "email;push")
285+
monkeypatch.setenv("CRISIS_ALERT_CHANNELS", "email;push;telegram")
280286
monkeypatch.setenv("CRISIS_ALERT_PUSH_RECIPIENTS", "risk-topic; backup-topic")
281287
monkeypatch.setenv("CRISIS_ALERT_PUSH_PROVIDER", "ntfy")
282288
monkeypatch.setenv("CRISIS_ALERT_PUSH_APP_TOKEN", "app-token")
@@ -286,10 +292,16 @@ def test_load_platform_runtime_settings_reads_crisis_alert_channels_and_push_con
286292
monkeypatch.setenv("CRISIS_ALERT_PUSH_PRIORITY", "5")
287293
monkeypatch.setenv("CRISIS_ALERT_PUSH_TAGS", "warning")
288294
monkeypatch.setenv("CRISIS_ALERT_PUSH_BODY_MAX_CHARS", "300")
295+
monkeypatch.setenv("CRISIS_ALERT_TELEGRAM_CHAT_IDS", "12345; @risk_channel")
296+
monkeypatch.setenv("CRISIS_ALERT_TELEGRAM_BOT_TOKEN", "telegram-token")
297+
monkeypatch.setenv("CRISIS_ALERT_TELEGRAM_API_BASE_URL", "https://telegram.example.test")
298+
monkeypatch.setenv("CRISIS_ALERT_TELEGRAM_PARSE_MODE", "HTML")
299+
monkeypatch.setenv("CRISIS_ALERT_TELEGRAM_DISABLE_WEB_PAGE_PREVIEW", "false")
300+
monkeypatch.setenv("CRISIS_ALERT_TELEGRAM_BODY_MAX_CHARS", "900")
289301

290302
settings = load_platform_runtime_settings(project_id_resolver=lambda: "project-1")
291303

292-
assert settings.crisis_alert_channels == ("email", "push")
304+
assert settings.crisis_alert_channels == ("email", "push", "telegram")
293305
assert settings.crisis_alert_push_recipients == ("risk-topic", "backup-topic")
294306
assert settings.crisis_alert_push_provider == "ntfy"
295307
assert settings.crisis_alert_push_app_token == "app-token"
@@ -299,6 +311,12 @@ def test_load_platform_runtime_settings_reads_crisis_alert_channels_and_push_con
299311
assert settings.crisis_alert_push_priority == "5"
300312
assert settings.crisis_alert_push_tags == "warning"
301313
assert settings.crisis_alert_push_body_max_chars == "300"
314+
assert settings.crisis_alert_telegram_chat_ids == ("12345", "@risk_channel")
315+
assert settings.crisis_alert_telegram_bot_token == "telegram-token"
316+
assert settings.crisis_alert_telegram_api_base_url == "https://telegram.example.test"
317+
assert settings.crisis_alert_telegram_parse_mode == "HTML"
318+
assert settings.crisis_alert_telegram_disable_web_page_preview == "false"
319+
assert settings.crisis_alert_telegram_body_max_chars == "900"
302320

303321

304322
def test_load_platform_runtime_settings_uses_whole_share_quantity_step(monkeypatch):

tests/test_sync_cloud_run_env_workflow.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@ grep -Fq 'IBKR_STRATEGY_PLUGIN_MOUNTS_JSON: ${{ vars.IBKR_STRATEGY_PLUGIN_MOUNTS
2525
grep -Fq 'CRISIS_ALERT_CHANNELS: ${{ vars.CRISIS_ALERT_CHANNELS }}' "$workflow_file"
2626
grep -Fq 'CRISIS_ALERT_EMAIL_RECIPIENTS: ${{ vars.CRISIS_ALERT_EMAIL_RECIPIENTS }}' "$workflow_file"
2727
grep -Fq 'CRISIS_ALERT_EMAIL_SENDER_PASSWORD_SECRET_NAME: ${{ vars.CRISIS_ALERT_EMAIL_SENDER_PASSWORD_SECRET_NAME }}' "$workflow_file"
28+
grep -Fq 'CRISIS_ALERT_TELEGRAM_CHAT_IDS: ${{ vars.CRISIS_ALERT_TELEGRAM_CHAT_IDS }}' "$workflow_file"
29+
grep -Fq 'CRISIS_ALERT_TELEGRAM_BOT_TOKEN_SECRET_NAME: ${{ vars.CRISIS_ALERT_TELEGRAM_BOT_TOKEN_SECRET_NAME }}' "$workflow_file"
2830
grep -Fq 'TELEGRAM_TOKEN: ${{ secrets.TELEGRAM_TOKEN }}' "$workflow_file"
2931
grep -Fq 'CRISIS_ALERT_EMAIL_SENDER_PASSWORD: ${{ secrets.CRISIS_ALERT_EMAIL_SENDER_PASSWORD }}' "$workflow_file"
32+
grep -Fq 'CRISIS_ALERT_TELEGRAM_BOT_TOKEN: ${{ secrets.CRISIS_ALERT_TELEGRAM_BOT_TOKEN }}' "$workflow_file"
3033

3134
grep -Fq 'Skipping Cloud Run env sync because ENABLE_GITHUB_ENV_SYNC is not set to true.' "$workflow_file"
3235
grep -Fq 'scripts/build_cloud_run_env_sync_plan.py --json' "$workflow_file"
@@ -50,8 +53,11 @@ grep -Fq 'shared_remove_env_vars=(' "$workflow_file"
5053
grep -Fq 'shared_remove_secret_vars=(' "$workflow_file"
5154
grep -Fq 'shared_secret_pairs+=("TELEGRAM_TOKEN=${TELEGRAM_TOKEN_SECRET_NAME}:latest")' "$workflow_file"
5255
grep -Fq 'shared_secret_pairs+=("CRISIS_ALERT_EMAIL_SENDER_PASSWORD=${CRISIS_ALERT_EMAIL_SENDER_PASSWORD_SECRET_NAME}:latest")' "$workflow_file"
56+
grep -Fq 'shared_secret_pairs+=("CRISIS_ALERT_TELEGRAM_BOT_TOKEN=${CRISIS_ALERT_TELEGRAM_BOT_TOKEN_SECRET_NAME}:latest")' "$workflow_file"
5357
grep -Fq 'shared_env_pairs+=("CRISIS_ALERT_CHANNELS=${CRISIS_ALERT_CHANNELS}")' "$workflow_file"
5458
grep -Fq 'shared_remove_env_vars+=("CRISIS_ALERT_CHANNELS")' "$workflow_file"
59+
grep -Fq 'shared_env_pairs+=("CRISIS_ALERT_TELEGRAM_CHAT_IDS=${CRISIS_ALERT_TELEGRAM_CHAT_IDS}")' "$workflow_file"
60+
grep -Fq 'shared_remove_env_vars+=("CRISIS_ALERT_TELEGRAM_BOT_TOKEN")' "$workflow_file"
5561
grep -Fq 'mapfile -t target_env_pairs < <(emit_target_env_pairs "${target_index}")' "$workflow_file"
5662
grep -Fq 'mapfile -t target_remove_env_vars < <(emit_target_remove_env_vars "${target_index}")' "$workflow_file"
5763
grep -Fq 'env_pairs=("${target_env_pairs[@]}" "${shared_env_pairs[@]}")' "$workflow_file"

0 commit comments

Comments
 (0)