GitLab Publish
中文 · English
VSCode 扩展:在侧边栏按环境执行发布命令,命令结束后轮询健康检查,直到健康检查返回的时间晚于发布结束时刻,判定为发布完成。
功能
- 按环境保存一套「发布命令 + 健康检查命令」,切换环境即切换整套命令。
- 发布、看输出、停止检查都在侧边栏完成,不用切到终端。
- 发布命令成功(退出码 0)后记录发布结束时刻;之后每 3 秒执行一次健康检查。
- 健康检查返回的时间晚于发布时间即判定发布完成;连续失败 20 次则停止并提示,可点【继续检查】再来一轮。
- 输出窗口显示两条命令及其输出,支持复制、清空,有新输出时自动滚到底部。
安装
- 从 VSIX 安装:扩展视图右上角
... → 从 VSIX 安装…,选择 gitlab-publish.vsix;或执行 code --install-extension gitlab-publish.vsix。
- 源码运行:
npm install && npm run compile,在 VSCode 中按 F5 启动扩展宿主。
要求 VS Code 1.85 及以上。安装后活动栏出现 GitLab 发布 图标,点击打开侧边栏(视图名「发布」)。
快速开始
- 用 VSCode 打开一个文件夹(多根工作区只使用第一个文件夹)。命令都在这个文件夹下执行。
- 点击活动栏的 GitLab 发布 图标。
- 首次使用先新增环境:点环境下拉框右侧的 +,输入名称(例如
测试、生产)。
- 点标题栏齿轮打开设置,填写当前环境的 发布命令 和 健康检查命令,点 保存。两项都必须填。
- 用下拉框切换环境,点 发布 开始。
- 发布命令结束后自动进入健康检查。想提前结束轮询点 停止健康检查;连续失败 20 次后点 继续检查 再给一轮额度。
- 手工改过
gitlab-publish.json 后,点标题栏齿轮左侧的刷新按钮重新读取,不需要重开侧边栏。
新增、切换、删除环境和保存设置前,插件都会重新读一次磁盘上的配置文件,避免覆盖手工修改。
配置
配置文件
配置保存在工作区第一个文件夹根目录的 gitlab-publish.json 中(设置面板底部显示相对路径)。文件按环境分组:
{
"currentEnvironment": "测试",
"environments": {
"测试": {
"publishCommand": "git push origin HEAD:test",
"healthCheckCommand": "(Invoke-RestMethod http://127.0.0.1:8080/api/version).deployedAt"
},
"生产": {
"publishCommand": "git push origin HEAD:main",
"healthCheckCommand": "(Invoke-RestMethod http://10.0.0.10/api/version).deployedAt"
}
}
}
| 字段 |
说明 |
currentEnvironment |
当前选中的环境名。必须存在于 environments 中,否则回退到第一个环境。 |
environments |
环境名到一组命令的映射,键就是界面上显示的环境名称。 |
publishCommand |
该环境的发布命令,PowerShell 语法。 |
healthCheckCommand |
该环境的健康检查命令,PowerShell 语法,输出需要包含时间。 |
- 文件必须是合法 JSON:不支持注释、尾逗号。
- 插件在保存、切换、新增、删除环境时会重写整个文件,只保留
currentEnvironment 和各环境的两个命令字段,手工添加的其他字段不会保留。
- 旧版配置(顶层直接是
publishCommand / healthCheckCommand)会自动归入名为 默认 的环境,命令不丢;下次保存时改写为新结构。
- 文件无法解析时,侧边栏提示错误并展开设置,但不会改动文件;修好 JSON 后点刷新按钮即可。
环境管理
| 操作 |
入口 |
说明 |
| 新增 |
环境下拉框右侧 + |
名称 1–40 个字符、不能重名;新增后自动切到该环境并展开设置。 |
| 切换 |
环境下拉框 |
立即把 currentEnvironment 写回配置文件。 |
| 删除 |
环境下拉框右侧删除按钮 |
弹窗确认,连同该环境的两个命令一起删除;删的是当前环境时切到剩下的第一个。 |
| 重新加载 |
标题栏刷新按钮(齿轮左侧) |
重新读盘刷新界面,不改文件。 |
发布或健康检查进行中时,环境下拉框、新增、删除、刷新都不可用。环境全部删完时下拉框显示「未配置环境」。
命令怎么写
- 两条命令都通过 PowerShell 执行,工作目录是工作区文件夹。Windows 用
powershell.exe,其他平台用 pwsh,以 -NoProfile -NonInteractive -ExecutionPolicy Bypass 启动,并固定以 UTF-8 读取输出。
- 命令按 PowerShell 语法写,不是 cmd 语法;需要 cmd 内置命令时用
cmd /c ...。
- 发布命令:进程退出码为 0 才继续。非 0 或无法启动时立即停止,不再执行健康检查,可以直接再点【发布】。
- 健康检查命令:插件取 stdout 的最后一行非空输出 作为时间,整行必须是时间本身(允许被引号包着),不能是 JSON、日志前缀或夹带其他文字。写到 stderr 不算。
建议让健康检查命令只输出时间:
# 接口直接返回纯文本时间
curl.exe -s http://127.0.0.1:8080/api/deployed-at
# 接口返回 JSON,只取出时间字段
(Invoke-RestMethod http://127.0.0.1:8080/api/version).deployedAt
支持的时间格式:
| 格式 |
示例 |
ISO 8601,带或不带时区,T 或空格分隔 |
2026-11-07T10:24:35Z、2026-11-07T10:24:35+08:00、2026-11-07 10:24:35 |
| 中文日期 |
2026年11月7日 10:24:35 |
| 13 位毫秒时间戳 |
1794037475000 |
| 10 位秒级时间戳 |
1794037475 |
不带时区的时间按本机时区解释,跨时区部署建议让接口返回带时区的时间。RFC 2822 形式(如 Sat, 07 Nov 2026 10:24:35 GMT)也能识别。
命令示例
# 发布:推送到对应分支
git push origin HEAD:test
# 发布:构建并同步产物
dotnet publish -c Release -o ./publish; scp -r ./publish/* deploy@10.0.0.10:/srv/app
# 健康检查:读取服务自报的部署完成时间
(Invoke-RestMethod http://127.0.0.1:8080/api/version).deployedAt
PowerShell 5.1 里 curl 是 Invoke-WebRequest 的别名。要调真正的 curl,写 curl.exe,否则 -s 之类的参数会报错。
发布过程与结果判定
- 点【发布】立即执行当前环境的发布命令,日志开头写明环境,例如
──── 10:24:31 开始发布(测试)────。
- 发布命令退出码为 0 时,用本机时钟记录发布结束时刻(日志中为
记录发布时间:2026-11-07 10:24:35)。发布命令本身不需要输出任何时间。
- 立即执行第一次健康检查,之后每 3 秒一次。
- 健康检查返回的时间严格晚于发布时间即发布完成,显示总用时;早于或等于发布时间则继续轮询。
- 健康检查退出码非 0、没有输出、时间无法解析,都计一次失败;连续失败达到 20 次时停止检查并提示,点【继续检查】可再获得 20 次额度。
- 返回了可解析时间但尚未更新(不晚于发布时间)会清零连续失败计数,不会因为「时间没变」耗尽额度。
- 检查期间点【停止健康检查】立即停止轮询,状态显示已停止;再点【发布】开始新一轮。
状态栏文案:就绪、正在执行发布命令… 已用时 mm:ss、正在发布… 已用时 mm:ss(健康检查连续失败 n/20)、发布完成(用时 mm:ss)、已停止健康检查(用时 mm:ss)、发布失败:原因、健康检查连续失败 20 次,已停止检查。
输出窗口保留最近约 50 万个字符,新输出会自动滚到底部;【复制】复制当前缓冲内容,【清空】只清界面与缓冲,不影响正在执行的命令。
常见问题
一直停在「正在发布…」:服务返回的是构建时间或提交时间,早于发布结束时刻,判据永远不成立。让接口返回部署完成时间,或换成部署动作之后落盘的时间戳。
第一次检查就报「无法从输出解析时间」:确认 stdout 最后一行只有时间本身。整段 JSON、Deployed at: ... 这类前缀都无法解析;用 (Invoke-RestMethod ...).字段 只输出时间。
时间看着对,却一直不判定完成:核对服务与本机时钟是否一致,以及时间字符串是否带时区。不带时区会按本机时区解释,差 8 小时就会一直等下去。
发布命令明明失败了,插件却继续做健康检查:插件只看进程退出码,而 PowerShell 不会自动把外部命令的退出码带到进程退出码——失败语句后面还有成功语句时,整体仍返回 0。在命令末尾补一行:
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
设置里提示 JSON 无效:gitlab-publish.json 必须是合法 JSON,不支持注释、单引号和尾逗号。修好后点标题栏刷新按钮。
提示「请先打开一个文件夹」:命令的工作目录来自工作区,需要先用 VSCode 打开文件夹,而不是单个文件。
开发
npm install
npm run compile
npm run watch # 监听编译
npm test # 状态机与配置读写测试
npm run package # 生成 gitlab-publish.vsix
English
中文 · English
The extension UI is currently in Chinese; UI labels are quoted as they appear.
A VS Code extension that runs a per-environment publish command from the sidebar, then polls a health-check command until the time it returns is later than the moment the publish command finished.
Features
- One publish command and one health-check command per environment; switching environments switches both.
- Publish, watch output, and stop checking without leaving the sidebar.
- The publish end time is recorded once the publish command succeeds (exit code 0); health checks then run every 3 seconds.
- A health check whose returned time is later than the publish end time completes the publish. After 20 consecutive failures checking stops; 继续检查 grants another round.
- The output pane shows both commands and their output, supports copy and clear, and scrolls to the bottom on new output.
Install
- From VSIX: in the Extensions view, open the
... menu → Install from VSIX… and pick gitlab-publish.vsix, or run code --install-extension gitlab-publish.vsix.
- From source: run
npm install && npm run compile, then press F5 in VS Code to launch the Extension Development Host.
Requires VS Code 1.85 or newer. After installation a GitLab 发布 icon appears in the Activity Bar; click it to open the sidebar view named 发布.
Quick start
- Open a folder in VS Code (in a multi-root workspace only the first folder is used). All commands run in that folder.
- Click the GitLab 发布 icon in the Activity Bar.
- On first use, add an environment: click + next to the environment dropdown and enter a name such as
测试 or 生产.
- Click the gear icon in the view title to open settings, fill in the publish command and health-check command for the current environment, and click 保存. Both fields are required.
- Switch environments with the dropdown and click 发布.
- After the publish command finishes, health checking starts automatically. Click 停止健康检查 to stop polling early; after 20 consecutive failures, 继续检查 grants another round.
- After editing
gitlab-publish.json by hand, click the refresh button to the left of the gear icon to reload it; no need to reopen the sidebar.
Before adding, switching, or deleting an environment, and before saving settings, the extension re-reads the config file from disk so manual edits are not overwritten.
Configuration
Config file
Configuration lives in gitlab-publish.json at the root of the first workspace folder (the settings panel shows the relative path). It is grouped by environment:
{
"currentEnvironment": "测试",
"environments": {
"测试": {
"publishCommand": "git push origin HEAD:test",
"healthCheckCommand": "(Invoke-RestMethod http://127.0.0.1:8080/api/version).deployedAt"
},
"生产": {
"publishCommand": "git push origin HEAD:main",
"healthCheckCommand": "(Invoke-RestMethod http://10.0.0.10/api/version).deployedAt"
}
}
}
| Field |
Meaning |
currentEnvironment |
Selected environment name. Must exist in environments; otherwise the first environment is used. |
environments |
Map of environment name to its command pair. The key is the name shown in the UI. |
publishCommand |
Publish command for that environment, in PowerShell syntax. |
healthCheckCommand |
Health-check command for that environment, in PowerShell syntax; its output must contain a time. |
- The file must be valid JSON: no comments, no trailing commas.
- Saving, switching, adding, or deleting an environment rewrites the whole file with only
currentEnvironment and the two command fields per environment. Extra fields you add by hand are not preserved.
- Legacy configuration (top-level
publishCommand / healthCheckCommand) is migrated into an environment named 默认 without losing the commands, and rewritten in the new shape on the next save.
- If the file cannot be parsed, the sidebar shows the error and opens settings but does not modify the file. Fix the JSON and click refresh.
Environments
| Action |
Where |
Notes |
| Add |
+ next to the dropdown |
Name must be 1–40 characters and unique. The new environment becomes current and settings open. |
| Switch |
Environment dropdown |
Writes currentEnvironment to the config file immediately. |
| Delete |
Delete button next to the dropdown |
Confirmation dialog; removes the environment and both its commands. If it was current, the first remaining environment becomes current. |
| Reload |
Refresh button in the view title (left of the gear) |
Re-reads the file and refreshes the UI without writing. |
While publishing or checking, the dropdown, add, delete, and refresh controls are disabled. With no environments left, the dropdown shows 未配置环境.
Writing commands
- Both commands run through PowerShell with the workspace folder as the working directory. On Windows the extension uses
powershell.exe; elsewhere it uses pwsh. Processes start with -NoProfile -NonInteractive -ExecutionPolicy Bypass, and output is read as UTF-8.
- Use PowerShell syntax, not cmd syntax. For cmd built-ins, call
cmd /c ....
- Publish command: the flow continues only when the process exits with code 0. A non-zero exit or a launch failure stops everything immediately; you can click 发布 again right away.
- Health-check command: the extension parses the last non-empty stdout line as the time. That whole line must be the time itself (quotes around it are fine) — not JSON, not a log prefix, not extra text. Output written to stderr is ignored.
Make the health-check command print only the time:
# Endpoint returns plain text
curl.exe -s http://127.0.0.1:8080/api/deployed-at
# Endpoint returns JSON; extract just the time field
(Invoke-RestMethod http://127.0.0.1:8080/api/version).deployedAt
Supported time formats:
| Format |
Examples |
ISO 8601, with or without time zone, T or space separated |
2026-11-07T10:24:35Z, 2026-11-07T10:24:35+08:00, 2026-11-07 10:24:35 |
| Chinese date |
2026年11月7日 10:24:35 |
| 13-digit millisecond timestamp |
1794037475000 |
| 10-digit second timestamp |
1794037475 |
Times without a time zone are interpreted in the local time zone; for cross-time-zone deployments return a zoned time. RFC 2822 strings such as Sat, 07 Nov 2026 10:24:35 GMT also parse.
Command examples
# Publish: push to the matching branch
git push origin HEAD:test
# Publish: build and sync the artifacts
dotnet publish -c Release -o ./publish; scp -r ./publish/* deploy@10.0.0.10:/srv/app
# Health check: read the deployment time reported by the service
(Invoke-RestMethod http://127.0.0.1:8080/api/version).deployedAt
In Windows PowerShell 5.1, curl is an alias for Invoke-WebRequest. To call real curl, write curl.exe; otherwise flags such as -s fail.
Publish flow and success rule
- Clicking 发布 runs the current environment's publish command. The log header names the environment, e.g.
──── 10:24:31 开始发布(测试)────.
- When the publish command exits with 0, the extension records the publish end time using the local clock (
记录发布时间:2026-11-07 10:24:35). The publish command does not need to print any time.
- The first health check runs immediately, then every 3 seconds.
- If the returned time is strictly later than the publish end time, the publish is complete and the total elapsed time is shown. Otherwise polling continues.
- A non-zero exit code, empty output, or an unparsable time counts as one failure. After 20 consecutive failures checking stops with a notice; 继续检查 grants another 20.
- A parsable time that has not advanced (not later than the publish end time) resets the consecutive-failure counter, so "time unchanged" never exhausts the budget.
- Clicking 停止健康检查 stops polling immediately and shows the stopped state. Click 发布 again to start a new run.
Status texts: 就绪, 正在执行发布命令… 已用时 mm:ss, 正在发布… 已用时 mm:ss(健康检查连续失败 n/20), 发布完成(用时 mm:ss), 已停止健康检查(用时 mm:ss), 发布失败:原因, 健康检查连续失败 20 次,已停止检查.
The output pane keeps roughly the last 500,000 characters and scrolls to the newest line. 复制 copies the current buffer; 清空 only clears the pane and buffer and does not affect a running command.
Troubleshooting
Stuck on "正在发布…": the service returns a build or commit time that predates the publish end time, so the rule never matches. Report the deployment completion time instead, or a timestamp written after deployment.
"无法从输出解析时间" on the very first check: make sure the last stdout line is only the time. A whole JSON document or a prefix such as Deployed at: ... will not parse; use (Invoke-RestMethod ...).field to print the time alone.
The time looks right but checking never completes: compare the service clock with the local clock and check whether the string carries a time zone. A zone-less time is interpreted locally, so an 8-hour offset waits forever.
A failed publish command still proceeds to health checking: the extension only looks at the process exit code, and PowerShell does not propagate an external command's exit code on its own — a successful statement after the failure makes the process exit 0. Append this line:
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
Settings report invalid JSON: gitlab-publish.json must be valid JSON — no comments, single quotes, or trailing commas. Fix it and click the refresh button in the view title.
"请先打开一个文件夹": commands run relative to the workspace, so open a folder in VS Code rather than a single file.
Development
npm install
npm run compile
npm run watch # watch mode
npm test # state machine and config tests
npm run package # produces gitlab-publish.vsix
目录 / Project layout
src/extension.ts sidebar view, environment management, messaging, config and output buffer
src/session.ts publish/health-check state machine (no vscode dependency)
src/runner.ts PowerShell process execution and output streaming
src/config.ts multi-environment config read/write, deletion, legacy migration
src/logic.ts time parsing and formatting helpers
src/webviewHtml.ts sidebar HTML template
media/ sidebar styles and interaction script
test/ state machine and config tests