再见
This commit is contained in:
1 parent
f3b0cf5d3a
commit
54016abac5
382 files changed
+2
-188190
No files matched your search
@@ -1,140 +0,0 @@
|
||||
name: "报告 Bug"
|
||||
description: "代码出现了非预期的问题、崩溃或报错"
|
||||
title: "[Bug]: "
|
||||
labels: ["type: bug", "status: needs info"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
请提供尽可能详细的信息,帮助我们快速定位和修复问题。
|
||||
- type: input
|
||||
id: confirm-unique
|
||||
attributes:
|
||||
label: 确认唯一性
|
||||
description: 请输入:我已确认没有相同问题出现
|
||||
placeholder: 我已确认没有相同问题出现
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: standard-operation
|
||||
attributes:
|
||||
label: 这是标准操作流程下出现的问题吗?
|
||||
description: 确认你是按照正常方式使用,而不是非常规操作
|
||||
options:
|
||||
- 是,标准操作
|
||||
- 否,非标准操作
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: code-issue-confirm
|
||||
attributes:
|
||||
label: 你确认这真的是我们的代码导致的吗?
|
||||
description: 请仔细思考,排除网络、系统、第三方服务等外部因素
|
||||
options:
|
||||
- 是,确认是代码问题
|
||||
- 不确定
|
||||
- 否,可能是其他原因
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: pre-check
|
||||
attributes:
|
||||
label: 基础确认
|
||||
options:
|
||||
- label: 我使用的是最新版本
|
||||
required: true
|
||||
- label: 我已阅读过相关文档
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: platform
|
||||
attributes:
|
||||
label: 使用平台
|
||||
description: 选择出现问题的平台
|
||||
options:
|
||||
- Windows
|
||||
- macOS
|
||||
- Linux
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: severity
|
||||
attributes:
|
||||
label: 问题严重程度
|
||||
description: 这个问题对你的使用造成了多大影响?
|
||||
options:
|
||||
- 严重崩溃或数据丢失(无法使用)
|
||||
- 核心功能受影响(在下一个常规发布中必须修复)
|
||||
- 边缘场景或轻微问题(等待空闲时修复)
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: 问题描述
|
||||
description: 清晰描述你遇到的问题,包括实际发生了什么
|
||||
placeholder: 例如:当我点击发送按钮时,应用程序崩溃并显示白屏
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: 复现步骤
|
||||
description: 提供详细的操作步骤,让我们能够重现这个问题
|
||||
placeholder: |
|
||||
1. 打开应用并登录账号
|
||||
2. 进入聊天页面
|
||||
3. 点击发送按钮
|
||||
4. 观察到应用崩溃
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected-behavior
|
||||
attributes:
|
||||
label: 预期行为
|
||||
description: 描述你期望的正确行为应该是什么样的
|
||||
placeholder: 例如:点击发送按钮后,消息应该正常发送并显示在聊天窗口中
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: actual-behavior
|
||||
attributes:
|
||||
label: 实际行为
|
||||
description: 描述实际发生的错误行为
|
||||
placeholder: 例如:点击后应用直接崩溃,显示白屏
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: 错误日志或截图
|
||||
description: 粘贴控制台错误信息、崩溃日志,或拖入截图
|
||||
placeholder: 请粘贴完整的错误堆栈信息
|
||||
render: shell
|
||||
- type: input
|
||||
id: os
|
||||
attributes:
|
||||
label: 操作系统版本
|
||||
description: 例如:Windows 11 24H2、macOS 15.0、Ubuntu 24.04
|
||||
placeholder: Windows 11 24H2
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: app-version
|
||||
attributes:
|
||||
label: 应用版本
|
||||
description: 在关于页面或设置中查看版本号
|
||||
placeholder: v1.2.3
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: architecture
|
||||
attributes:
|
||||
label: 系统架构
|
||||
description: 例如:x64、arm64
|
||||
placeholder: x64
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: 补充信息
|
||||
description: 其他可能有助于定位问题的信息
|
||||
placeholder: 例如:这个问题是在某次更新后开始出现的,或者只在特定网络环境下出现
|
||||
@@ -1 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
@@ -1,75 +0,0 @@
|
||||
name: "文档反馈"
|
||||
description: "文档存在错别字、描述不清晰或缺少必要的示例"
|
||||
title: "[Docs]: "
|
||||
labels: ["type: docs"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
优秀的文档和代码一样重要。感谢你帮助我们完善文档!
|
||||
- type: input
|
||||
id: confirm-unique
|
||||
attributes:
|
||||
label: 确认唯一性
|
||||
description: 请输入:我已确认没有相同问题出现
|
||||
placeholder: 我已确认没有相同问题出现
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: doc-type
|
||||
attributes:
|
||||
label: 文档类型
|
||||
description: 问题出现在哪类文档中?
|
||||
options:
|
||||
- README 或项目说明
|
||||
- 安装部署文档
|
||||
- 使用教程
|
||||
- API 文档
|
||||
- 开发者文档
|
||||
- 其他
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: doc-link
|
||||
attributes:
|
||||
label: 文档位置
|
||||
description: 提供文档的 URL 或文件路径
|
||||
placeholder: 例如:docs/installation.md 或 https://github.com/xxx/xxx/wiki/xxx
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: issue-type
|
||||
attributes:
|
||||
label: 问题类型
|
||||
description: 文档存在什么问题?
|
||||
options:
|
||||
- 错别字或语法错误
|
||||
- 内容过时或不准确
|
||||
- 描述不清晰或有歧义
|
||||
- 缺少必要的示例代码
|
||||
- 缺少重要的说明或警告
|
||||
- 链接失效或错误
|
||||
- 其他
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: issue-desc
|
||||
attributes:
|
||||
label: 问题描述
|
||||
description: 详细说明文档中存在的问题
|
||||
placeholder: 例如:第 3 步中的命令拼写错误,应该是 "npm install" 而不是 "npm instal"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: suggestion
|
||||
attributes:
|
||||
label: 修改建议
|
||||
description: 你认为应该如何修改?
|
||||
placeholder: 例如:建议将"安装依赖"部分补充完整的命令示例,并说明不同操作系统的差异
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: 补充说明
|
||||
description: 其他需要补充的信息
|
||||
@@ -1,92 +0,0 @@
|
||||
name: "功能与体验优化"
|
||||
description: "对现有的功能逻辑进行优化,或改进用户体验"
|
||||
title: "[Enhancement]: "
|
||||
labels: ["type: enhancement"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
持续优化是项目进步的动力!请告诉我们哪个现有功能可以做得更好。
|
||||
- type: input
|
||||
id: confirm-unique
|
||||
attributes:
|
||||
label: 确认唯一性
|
||||
description: 请输入:我已确认没有相同问题出现
|
||||
placeholder: 我已确认没有相同问题出现
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: confirm-beneficial
|
||||
attributes:
|
||||
label: 确认有益性
|
||||
description: 请输入:我确认这真的对应用有益
|
||||
placeholder: 我确认这真的对应用有益
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: pre-check
|
||||
attributes:
|
||||
label: 提交前确认
|
||||
options:
|
||||
- label: 这是对现有功能的改进,而不是全新功能
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: category
|
||||
attributes:
|
||||
label: 优化类别
|
||||
description: 这个优化主要属于哪个方面?
|
||||
options:
|
||||
- 性能优化(速度、内存、资源占用)
|
||||
- 交互体验(操作流程、界面布局)
|
||||
- 视觉设计(样式、动画、美观度)
|
||||
- 易用性(降低使用门槛、减少操作步骤)
|
||||
- 稳定性(减少崩溃、提高可靠性)
|
||||
- 其他
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: target
|
||||
attributes:
|
||||
label: 目标功能或模块
|
||||
description: 你希望优化的具体功能或页面是哪个?
|
||||
placeholder: 例如:聊天页面的消息加载、设置页面的布局、文件上传功能
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: current-behavior
|
||||
attributes:
|
||||
label: 当前表现
|
||||
description: 描述当前功能的不足之处或存在的问题
|
||||
placeholder: 例如:消息列表滚动时会出现明显卡顿,加载 100 条消息需要 3 秒
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: improvement
|
||||
attributes:
|
||||
label: 优化建议
|
||||
description: 详细说明你的优化方案和预期效果
|
||||
placeholder: 例如:建议使用虚拟滚动技术,只渲染可见区域的消息,预计可将加载时间缩短到 0.5 秒以内
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: benefits
|
||||
attributes:
|
||||
label: 优化收益
|
||||
description: 这个优化会带来什么具体好处?
|
||||
placeholder: 例如:提升 80% 的加载速度、减少 50% 的内存占用、降低用户操作步骤从 5 步到 2 步
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: impact
|
||||
attributes:
|
||||
label: 影响范围
|
||||
description: 这个优化会影响哪些用户或场景?
|
||||
placeholder: 例如:所有用户在查看历史消息时都会受益,尤其是群聊消息较多的场景
|
||||
- type: checkboxes
|
||||
id: contribution
|
||||
attributes:
|
||||
label: 参与贡献
|
||||
options:
|
||||
- label: 我愿意提交 Pull Request 来实现这个优化
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,85 +0,0 @@
|
||||
name: "全新功能请求"
|
||||
description: "提议一个目前项目中完全没有的新特性"
|
||||
title: "[Feature]: "
|
||||
labels: ["type: feature"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
感谢你为项目提供新想法!详细的需求描述能极大提高该功能被采纳的几率。
|
||||
- type: input
|
||||
id: confirm-unique
|
||||
attributes:
|
||||
label: 确认唯一性
|
||||
description: 请输入:我已确认没有相同问题出现
|
||||
placeholder: 我已确认没有相同问题出现
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: confirm-useful
|
||||
attributes:
|
||||
label: 确认实用性
|
||||
description: 请输入:我认为这会对大部分人都有用
|
||||
placeholder: 我认为这会对大部分人都有用
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: pre-check
|
||||
attributes:
|
||||
label: 提交前确认
|
||||
options:
|
||||
- label: 这是一个全新的功能,而不是对现有功能的改进
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: priority
|
||||
attributes:
|
||||
label: 功能优先级
|
||||
description: 你认为这个功能有多重要?
|
||||
options:
|
||||
- 高优先级(核心功能缺失,严重影响使用体验)
|
||||
- 中优先级(有助于提升使用体验)
|
||||
- 低优先级(锦上添花的功能)
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: 问题或痛点
|
||||
description: 【为什么需要】你现在做某件事遇到了什么困难?缺少什么能力?
|
||||
placeholder: 例如:目前无法批量导出聊天记录,每次只能手动复制单条消息,处理 100 条消息需要半小时
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: solution
|
||||
attributes:
|
||||
label: 期望的解决方案
|
||||
description: 【怎么实现】详细描述功能的操作流程、界面位置、可选参数等
|
||||
placeholder: 例如:在聊天窗口右键菜单添加"导出记录",点击后弹窗可选时间范围、导出格式(TXT/JSON)、筛选用户,最后保存到本地
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: use-case
|
||||
attributes:
|
||||
label: 使用场景
|
||||
description: 【什么时候用】你会在哪些具体情况下使用这个功能?
|
||||
placeholder: 例如:每周五整理工作讨论记录;保存客户沟通记录作为合同依据;备份重要群聊内容
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: 替代方案
|
||||
description: 你目前使用什么临时方案?或者有没有考虑过其他实现方式?
|
||||
placeholder: 例如:目前只能手动截图或逐条复制粘贴
|
||||
- type: textarea
|
||||
id: reference
|
||||
attributes:
|
||||
label: 参考示例
|
||||
description: 其他应用中是否有类似功能可以参考?
|
||||
placeholder: 例如:微信的聊天记录导出功能、Telegram 的导出数据功能
|
||||
- type: checkboxes
|
||||
id: contribution
|
||||
attributes:
|
||||
label: 参与贡献
|
||||
options:
|
||||
- label: 我愿意提交 Pull Request 来实现这个功能
|
||||
@@ -1,77 +0,0 @@
|
||||
name: "使用答疑"
|
||||
description: "关于如何配置、如何使用项目的求助"
|
||||
title: "[Question]: "
|
||||
labels: ["type: question"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
在提问之前,请确保你已经仔细阅读过我们的官方文档。
|
||||
- type: input
|
||||
id: confirm-unique
|
||||
attributes:
|
||||
label: 确认唯一性
|
||||
description: 请输入:我已确认没有相同问题出现
|
||||
placeholder: 我已确认没有相同问题出现
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: pre-check
|
||||
attributes:
|
||||
label: 提交前确认
|
||||
options:
|
||||
- label: 我已阅读过相关文档
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: question-type
|
||||
attributes:
|
||||
label: 问题类型
|
||||
description: 你的问题属于哪个方面?
|
||||
options:
|
||||
- 安装部署问题
|
||||
- 配置相关问题
|
||||
- 功能使用问题
|
||||
- API 调用问题
|
||||
- 错误排查问题
|
||||
- 其他
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: question
|
||||
attributes:
|
||||
label: 问题描述
|
||||
description: 清晰描述你遇到的问题或疑问
|
||||
placeholder: 例如:我在 Windows 系统上安装后无法启动应用,双击图标没有任何反应
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: attempts
|
||||
attributes:
|
||||
label: 已尝试的方法
|
||||
description: 你已经尝试过哪些解决方法?
|
||||
placeholder: 例如:我尝试过重新安装、以管理员身份运行、关闭防火墙,但问题依然存在
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: 运行环境
|
||||
description: 提供你的系统环境信息
|
||||
placeholder: |
|
||||
操作系统:Windows 11
|
||||
应用版本:v1.2.3
|
||||
系统架构:x64
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: code-snippet
|
||||
attributes:
|
||||
label: 相关配置或代码
|
||||
description: 如果涉及配置或代码问题,请粘贴相关内容
|
||||
placeholder: 粘贴你的配置文件或代码片段
|
||||
render: javascript
|
||||
- type: textarea
|
||||
id: screenshots
|
||||
attributes:
|
||||
label: 截图或日志
|
||||
description: 如有必要,请提供截图或错误日志
|
||||
@@ -1,7 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
target-branch: "dev"
|
||||
@@ -1,237 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
retry_cmd() {
|
||||
local attempts="$1"
|
||||
local delay_seconds="$2"
|
||||
shift 2
|
||||
|
||||
local i
|
||||
local exit_code
|
||||
for ((i = 1; i <= attempts; i++)); do
|
||||
if "$@"; then
|
||||
return 0
|
||||
fi
|
||||
exit_code=$?
|
||||
if [ "$i" -lt "$attempts" ]; then
|
||||
echo "Command failed (attempt $i/$attempts, exit=$exit_code): $*" >&2
|
||||
echo "Retrying in ${delay_seconds}s..." >&2
|
||||
sleep "$delay_seconds"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Command failed after $attempts attempts: $*" >&2
|
||||
return "$exit_code"
|
||||
}
|
||||
|
||||
capture_cmd_with_retry() {
|
||||
local result_var="$1"
|
||||
local attempts="$2"
|
||||
local delay_seconds="$3"
|
||||
shift 3
|
||||
|
||||
local i
|
||||
local output=""
|
||||
local exit_code=1
|
||||
for ((i = 1; i <= attempts; i++)); do
|
||||
if output="$("$@" 2>/dev/null)"; then
|
||||
printf -v "$result_var" "%s" "$output"
|
||||
return 0
|
||||
fi
|
||||
exit_code=$?
|
||||
if [ "$i" -lt "$attempts" ]; then
|
||||
echo "Capture command failed (attempt $i/$attempts, exit=$exit_code): $*" >&2
|
||||
echo "Retrying in ${delay_seconds}s..." >&2
|
||||
sleep "$delay_seconds"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Capture command failed after $attempts attempts: $*" >&2
|
||||
return "$exit_code"
|
||||
}
|
||||
|
||||
wait_for_release_id() {
|
||||
local repo="$1"
|
||||
local tag="$2"
|
||||
local attempts="${3:-12}"
|
||||
local delay_seconds="${4:-2}"
|
||||
|
||||
local i
|
||||
local release_id
|
||||
local release_api_url
|
||||
for ((i = 1; i <= attempts; i++)); do
|
||||
release_id="$(gh api "repos/$repo/releases/tags/$tag" --jq '.id' 2>/dev/null || true)"
|
||||
if [[ "$release_id" =~ ^[0-9]+$ ]]; then
|
||||
echo "$release_id"
|
||||
return 0
|
||||
fi
|
||||
|
||||
release_id="$(gh release view "$tag" --repo "$repo" --json databaseId --jq '.databaseId // empty' 2>/dev/null || true)"
|
||||
if [[ "$release_id" =~ ^[0-9]+$ ]]; then
|
||||
echo "$release_id"
|
||||
return 0
|
||||
fi
|
||||
|
||||
release_api_url="$(gh release view "$tag" --repo "$repo" --json apiUrl --jq '.apiUrl // empty' 2>/dev/null || true)"
|
||||
if [[ "$release_api_url" =~ /releases/([0-9]+)$ ]]; then
|
||||
echo "${BASH_REMATCH[1]}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "$i" -lt "$attempts" ]; then
|
||||
echo "Release id for tag '$tag' is not ready yet (attempt $i/$attempts), retrying in ${delay_seconds}s..." >&2
|
||||
sleep "$delay_seconds"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Unable to fetch release id for tag '$tag' after $attempts attempts." >&2
|
||||
gh release view "$tag" --repo "$repo" --json databaseId,id,isDraft,isPrerelease,url 2>/dev/null || true
|
||||
gh api "repos/$repo/releases/tags/$tag" --jq '{draft: .draft, prerelease: .prerelease, url: .html_url}' 2>/dev/null || true
|
||||
return 1
|
||||
}
|
||||
|
||||
settle_release_state() {
|
||||
local repo="$1"
|
||||
local release_id="$2"
|
||||
local tag="$3"
|
||||
local attempts="${4:-12}"
|
||||
local delay_seconds="${5:-2}"
|
||||
local endpoint="repos/$repo/releases/tags/$tag"
|
||||
|
||||
local i
|
||||
local draft_state
|
||||
local prerelease_state
|
||||
for ((i = 1; i <= attempts; i++)); do
|
||||
gh release edit "$tag" --repo "$repo" --draft=false --prerelease >/dev/null 2>&1 || true
|
||||
gh api --method PATCH "repos/$repo/releases/$release_id" -F draft=false -F prerelease=true >/dev/null 2>&1 || true
|
||||
draft_state="$(gh api "$endpoint" --jq '.draft' 2>/dev/null || gh release view "$tag" --repo "$repo" --json isDraft --jq '.isDraft' 2>/dev/null || echo true)"
|
||||
prerelease_state="$(gh api "$endpoint" --jq '.prerelease' 2>/dev/null || gh release view "$tag" --repo "$repo" --json isPrerelease --jq '.isPrerelease' 2>/dev/null || echo false)"
|
||||
if [ "$draft_state" = "false" ] && [ "$prerelease_state" = "true" ]; then
|
||||
return 0
|
||||
fi
|
||||
if [ "$i" -lt "$attempts" ]; then
|
||||
echo "Release '$tag' state not settled yet (attempt $i/$attempts), retrying in ${delay_seconds}s..." >&2
|
||||
sleep "$delay_seconds"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Failed to settle release state for tag '$tag'." >&2
|
||||
gh release view "$tag" --repo "$repo" --json isDraft,isPrerelease,url 2>/dev/null || true
|
||||
gh api "$endpoint" --jq '{draft: .draft, prerelease: .prerelease, url: .html_url}' 2>/dev/null || true
|
||||
return 1
|
||||
}
|
||||
|
||||
print_release_state() {
|
||||
local repo="$1"
|
||||
local tag="$2"
|
||||
|
||||
gh api "repos/$repo/releases/tags/$tag" --jq '{isDraft: .draft, isPrerelease: .prerelease, url: .html_url}' 2>/dev/null \
|
||||
|| gh release view "$tag" --repo "$repo" --json isDraft,isPrerelease,url --jq '{isDraft: .isDraft, isPrerelease: .isPrerelease, url: .url}'
|
||||
}
|
||||
|
||||
wait_for_release_absent() {
|
||||
local repo="$1"
|
||||
local tag="$2"
|
||||
local attempts="${3:-12}"
|
||||
local delay_seconds="${4:-2}"
|
||||
|
||||
local i
|
||||
for ((i = 1; i <= attempts; i++)); do
|
||||
if gh release view "$tag" --repo "$repo" >/dev/null 2>&1; then
|
||||
if [ "$i" -lt "$attempts" ]; then
|
||||
echo "Release '$tag' still exists (attempt $i/$attempts), waiting ${delay_seconds}s..." >&2
|
||||
sleep "$delay_seconds"
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
return 0
|
||||
done
|
||||
|
||||
echo "Release '$tag' still exists after waiting." >&2
|
||||
gh release view "$tag" --repo "$repo" --json url,isDraft,isPrerelease 2>/dev/null || true
|
||||
return 1
|
||||
}
|
||||
|
||||
wait_for_git_tag_absent() {
|
||||
local repo="$1"
|
||||
local tag="$2"
|
||||
local attempts="${3:-12}"
|
||||
local delay_seconds="${4:-2}"
|
||||
|
||||
local i
|
||||
for ((i = 1; i <= attempts; i++)); do
|
||||
if gh api "repos/$repo/git/ref/tags/$tag" >/dev/null 2>&1; then
|
||||
if [ "$i" -lt "$attempts" ]; then
|
||||
echo "Git tag '$tag' still exists (attempt $i/$attempts), waiting ${delay_seconds}s..." >&2
|
||||
sleep "$delay_seconds"
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
return 0
|
||||
done
|
||||
|
||||
echo "Git tag '$tag' still exists after waiting." >&2
|
||||
gh api "repos/$repo/git/ref/tags/$tag" --jq '{ref: .ref, object: .object.sha}' 2>/dev/null || true
|
||||
return 1
|
||||
}
|
||||
|
||||
recreate_fixed_prerelease() {
|
||||
local repo="$1"
|
||||
local tag="$2"
|
||||
local target_branch="$3"
|
||||
local release_title="$4"
|
||||
local release_notes="$5"
|
||||
|
||||
if gh release view "$tag" --repo "$repo" >/dev/null 2>&1; then
|
||||
retry_cmd 5 3 gh release delete "$tag" --repo "$repo" --yes --cleanup-tag
|
||||
fi
|
||||
|
||||
wait_for_release_absent "$repo" "$tag" 12 2
|
||||
|
||||
if gh api "repos/$repo/git/ref/tags/$tag" >/dev/null 2>&1; then
|
||||
retry_cmd 5 2 gh api --method DELETE "repos/$repo/git/refs/tags/$tag"
|
||||
fi
|
||||
|
||||
wait_for_git_tag_absent "$repo" "$tag" 12 2
|
||||
|
||||
local created="false"
|
||||
local i
|
||||
for ((i = 1; i <= 6; i++)); do
|
||||
if gh release create "$tag" --repo "$repo" --title "$release_title" --notes "$release_notes" --prerelease --target "$target_branch"; then
|
||||
created="true"
|
||||
break
|
||||
fi
|
||||
if gh release view "$tag" --repo "$repo" >/dev/null 2>&1; then
|
||||
echo "Release '$tag' appears to exist after create failure; continue to settle state." >&2
|
||||
created="true"
|
||||
break
|
||||
fi
|
||||
if [ "$i" -lt 6 ]; then
|
||||
echo "Create release '$tag' failed (attempt $i/6), retrying in 3s..." >&2
|
||||
sleep 3
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$created" != "true" ]; then
|
||||
echo "Failed to create release '$tag'." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local release_id
|
||||
release_id="$(wait_for_release_id "$repo" "$tag" 12 2)"
|
||||
settle_release_state "$repo" "$release_id" "$tag" 12 2
|
||||
}
|
||||
|
||||
upload_release_assets_with_retry() {
|
||||
local repo="$1"
|
||||
local tag="$2"
|
||||
shift 2
|
||||
|
||||
if [ "$#" -eq 0 ]; then
|
||||
echo "No release assets provided for upload." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
wait_for_release_id "$repo" "$tag" 12 2 >/dev/null
|
||||
retry_cmd 5 3 gh release upload "$tag" "$@" --repo "$repo" --clobber
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
name: Anti-Spam
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened, edited]
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
check-spam:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check for spam
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const issue = context.payload.issue;
|
||||
const title = (issue.title || '').toLowerCase();
|
||||
const body = (issue.body || '').toLowerCase();
|
||||
const text = title + ' ' + body;
|
||||
|
||||
// 博彩/赌球类
|
||||
const gamblingPatterns = [
|
||||
/世界杯.*买球/, /买球.*世界杯/,
|
||||
/世界杯.*下注/, /世界杯.*竞猜/,
|
||||
/世界杯.*投注/, /世界杯.*押注/,
|
||||
/世界杯.*彩票/, /世界杯.*平台/,
|
||||
/世界杯.*app/, /世界杯.*软件/,
|
||||
/世界杯.*网站/, /世界杯.*网址/,
|
||||
/足球.*买球/, /买球.*足球/,
|
||||
/足球.*投注/, /足球.*押注/,
|
||||
/足球.*竞猜/, /足球.*平台/,
|
||||
/篮球.*买球/, /篮球.*投注/,
|
||||
/体育.*投注/, /体育.*竞猜/,
|
||||
/体育.*买球/, /体育.*押注/,
|
||||
/赌球/, /赌博.*网站/, /赌博.*平台/,
|
||||
/博彩/, /博彩.*网站/, /博彩.*平台/,
|
||||
/正规.*买球/, /官方.*买球/,
|
||||
/买球.*网站/, /买球.*app/,
|
||||
/买球.*软件/, /买球.*网址/,
|
||||
/买球.*平台/, /买球.*技巧/,
|
||||
/投注.*网站/, /投注.*平台/,
|
||||
/押注.*网站/, /押注.*平台/,
|
||||
/竞猜.*网站/, /竞猜.*平台/,
|
||||
/彩票.*网站/, /彩票.*平台/,
|
||||
/欧洲杯.*买球/, /欧冠.*买球/,
|
||||
/nba.*买球/, /nba.*投注/,
|
||||
];
|
||||
|
||||
// 色情/交友类
|
||||
const adultPatterns = [
|
||||
/约炮/, /一夜情/, /外围/,
|
||||
/包养/, /援交/, /陪聊/,
|
||||
/成人.*网站/, /成人.*视频/,
|
||||
/av.*网站/, /黄色.*网站/,
|
||||
];
|
||||
|
||||
// 贷款/金融诈骗类
|
||||
const financePatterns = [
|
||||
/秒到账.*贷款/, /无抵押.*贷款/,
|
||||
/征信.*贷款/, /黑户.*贷款/,
|
||||
/快速.*放款/, /私人.*放贷/,
|
||||
/刷单/, /兼职.*日入/, /兼职.*月入/,
|
||||
/网赚/, /躺赚/, /被动收入.*平台/,
|
||||
/虚拟货币.*投资/, /usdt.*投资/,
|
||||
/炒币.*平台/, /数字货币.*平台/,
|
||||
];
|
||||
|
||||
// 垃圾推广类
|
||||
const spamPromoPatterns = [
|
||||
/代刷/, /粉丝.*购买/, /涨粉/,
|
||||
/seo.*优化/, /快速排名/,
|
||||
/微商/, /代理.*招募/,
|
||||
];
|
||||
|
||||
// 账号特征检测(新账号 + 无 contribution)
|
||||
const allPatterns = [
|
||||
...gamblingPatterns,
|
||||
...adultPatterns,
|
||||
...financePatterns,
|
||||
...spamPromoPatterns,
|
||||
];
|
||||
|
||||
const isSpam = allPatterns.some(pattern => pattern.test(text));
|
||||
|
||||
// 额外检测:标题超短且含可疑关键词(常见于批量刷单)
|
||||
const suspiciousShort = title.length < 10 && /(买球|投注|博彩|赌博|下注|押注)/.test(title);
|
||||
|
||||
if (isSpam || suspiciousShort) {
|
||||
// 确保 spam label 存在
|
||||
try {
|
||||
await github.rest.issues.createLabel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
name: 'spam',
|
||||
color: 'e4e669',
|
||||
description: 'Spam issue'
|
||||
});
|
||||
} catch (e) {
|
||||
// label 已存在,忽略
|
||||
}
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
body: '此 issue 已被自动识别为垃圾内容并关闭。\n\nThis issue has been automatically identified as spam and closed.'
|
||||
});
|
||||
|
||||
await github.rest.issues.addLabels({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
labels: ['spam']
|
||||
});
|
||||
|
||||
await github.rest.issues.update({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
state: 'closed',
|
||||
state_reason: 'not_planned'
|
||||
});
|
||||
|
||||
await github.rest.issues.lock({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
lock_reason: 'spam'
|
||||
});
|
||||
|
||||
console.log(`Closed spam issue #${issue.number}: ${issue.title}`);
|
||||
}
|
||||
@@ -1,389 +0,0 @@
|
||||
name: Dev Daily
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# GitHub Actions schedule uses UTC. 16:00 UTC = 北京时间次日 00:00
|
||||
- cron: "0 16 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: dev-nightly-fixed-release
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
||||
FIXED_DEV_TAG: nightly-dev
|
||||
TARGET_BRANCH: dev
|
||||
ELECTRON_BUILDER_BINARIES_MIRROR: https://github.com/electron-userland/electron-builder-binaries/releases/download/
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
dev_version: ${{ steps.meta.outputs.dev_version }}
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ env.TARGET_BRANCH }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 24
|
||||
cache: "npm"
|
||||
|
||||
- name: Generate daily dev version
|
||||
id: meta
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
YEAR_2="$(TZ=Asia/Shanghai date +%y)"
|
||||
MONTH="$(TZ=Asia/Shanghai date +%-m)"
|
||||
DAY="$(TZ=Asia/Shanghai date +%-d)"
|
||||
DEV_VERSION="${YEAR_2}.${MONTH}.${DAY}"
|
||||
echo "dev_version=$DEV_VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "Dev version: $DEV_VERSION"
|
||||
|
||||
- name: Recreate fixed prerelease
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source .github/scripts/release-utils.sh
|
||||
recreate_fixed_prerelease "$GITHUB_REPOSITORY" "$FIXED_DEV_TAG" "$TARGET_BRANCH" "Daily Dev Build" "开发版发布页"
|
||||
|
||||
dev-mac-arm64:
|
||||
needs: prepare
|
||||
runs-on: macos-14
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ env.TARGET_BRANCH }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 24
|
||||
cache: "npm"
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Ensure mac key helpers are executable
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
for file in \
|
||||
resources/key/macos/universal/xkey_helper \
|
||||
resources/key/macos/universal/image_scan_helper \
|
||||
resources/key/macos/universal/xkey_helper_macos \
|
||||
resources/key/macos/universal/libwx_key.dylib
|
||||
do
|
||||
if [ -f "$file" ]; then
|
||||
chmod +x "$file"
|
||||
ls -l "$file"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Set dev version
|
||||
shell: bash
|
||||
run: npm version "${{ needs.prepare.outputs.dev_version }}" --no-git-tag-version --allow-same-version
|
||||
|
||||
- name: Build Frontend & Type Check
|
||||
shell: bash
|
||||
run: |
|
||||
npx tsc
|
||||
npx vite build
|
||||
|
||||
- name: Package macOS arm64 dev artifacts
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
export ELECTRON_BUILDER_BINARIES_MIRROR="https://github.com/electron-userland/electron-builder-binaries/releases/download/"
|
||||
echo "Using ELECTRON_BUILDER_BINARIES_MIRROR=$ELECTRON_BUILDER_BINARIES_MIRROR"
|
||||
if ! npx electron-builder --mac dmg zip --arm64 --publish never '--config.publish.channel=dev' '--config.artifactName=${productName}-dev-arm64.${ext}'; then
|
||||
echo "::warning::DMG packaging failed (hdiutil instability on runner). Retrying with ZIP only."
|
||||
npx electron-builder --mac zip --arm64 --publish never '--config.publish.channel=dev' '--config.artifactName=${productName}-dev-arm64.${ext}'
|
||||
fi
|
||||
|
||||
- name: Upload macOS arm64 assets to fixed release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source .github/scripts/release-utils.sh
|
||||
assets=()
|
||||
while IFS= read -r file; do
|
||||
assets+=("$file")
|
||||
done < <(find release -maxdepth 1 -type f | sort)
|
||||
if [ "${#assets[@]}" -eq 0 ]; then
|
||||
echo "No release files found in ./release"
|
||||
exit 1
|
||||
fi
|
||||
upload_release_assets_with_retry "$GITHUB_REPOSITORY" "$FIXED_DEV_TAG" "${assets[@]}"
|
||||
|
||||
dev-linux:
|
||||
needs: prepare
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ env.TARGET_BRANCH }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 24
|
||||
cache: "npm"
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Set dev version
|
||||
shell: bash
|
||||
run: npm version "${{ needs.prepare.outputs.dev_version }}" --no-git-tag-version --allow-same-version
|
||||
|
||||
- name: Build Frontend & Type Check
|
||||
shell: bash
|
||||
run: |
|
||||
npx tsc
|
||||
npx vite build
|
||||
|
||||
- name: Package Linux dev artifacts
|
||||
run: |
|
||||
npx electron-builder --linux --publish never '--config.publish.channel=dev' '--config.artifactName=${productName}-dev-linux.${ext}'
|
||||
|
||||
- name: Upload Linux assets to fixed release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source .github/scripts/release-utils.sh
|
||||
assets=()
|
||||
while IFS= read -r file; do
|
||||
assets+=("$file")
|
||||
done < <(find release -maxdepth 1 -type f | sort)
|
||||
if [ "${#assets[@]}" -eq 0 ]; then
|
||||
echo "No release files found in ./release"
|
||||
exit 1
|
||||
fi
|
||||
upload_release_assets_with_retry "$GITHUB_REPOSITORY" "$FIXED_DEV_TAG" "${assets[@]}"
|
||||
|
||||
dev-win-x64:
|
||||
needs: prepare
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ env.TARGET_BRANCH }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 24
|
||||
cache: "npm"
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Set dev version
|
||||
shell: bash
|
||||
run: npm version "${{ needs.prepare.outputs.dev_version }}" --no-git-tag-version --allow-same-version
|
||||
|
||||
- name: Build Frontend & Type Check
|
||||
shell: bash
|
||||
run: |
|
||||
npx tsc
|
||||
npx vite build
|
||||
|
||||
- name: Package Windows x64 dev artifacts
|
||||
run: |
|
||||
npx electron-builder --win nsis --x64 --publish never '--config.publish.channel=dev' '--config.artifactName=${productName}-dev-x64-Setup.${ext}'
|
||||
|
||||
- name: Upload Windows x64 assets to fixed release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source .github/scripts/release-utils.sh
|
||||
assets=()
|
||||
while IFS= read -r file; do
|
||||
assets+=("$file")
|
||||
done < <(find release -maxdepth 1 -type f | sort)
|
||||
if [ "${#assets[@]}" -eq 0 ]; then
|
||||
echo "No release files found in ./release"
|
||||
exit 1
|
||||
fi
|
||||
upload_release_assets_with_retry "$GITHUB_REPOSITORY" "$FIXED_DEV_TAG" "${assets[@]}"
|
||||
|
||||
dev-win-arm64:
|
||||
needs: prepare
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ env.TARGET_BRANCH }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 24
|
||||
cache: "npm"
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Set dev version
|
||||
shell: bash
|
||||
run: npm version "${{ needs.prepare.outputs.dev_version }}" --no-git-tag-version --allow-same-version
|
||||
|
||||
- name: Build Frontend & Type Check
|
||||
shell: bash
|
||||
run: |
|
||||
npx tsc
|
||||
npx vite build
|
||||
|
||||
- name: Package Windows arm64 dev artifacts
|
||||
run: |
|
||||
npx electron-builder --win nsis --arm64 --publish never '--config.publish.channel=dev-arm64' '--config.artifactName=${productName}-dev-arm64-Setup.${ext}'
|
||||
|
||||
- name: Upload Windows arm64 assets to fixed release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source .github/scripts/release-utils.sh
|
||||
assets=()
|
||||
while IFS= read -r file; do
|
||||
assets+=("$file")
|
||||
done < <(find release -maxdepth 1 -type f | sort)
|
||||
if [ "${#assets[@]}" -eq 0 ]; then
|
||||
echo "No release files found in ./release"
|
||||
exit 1
|
||||
fi
|
||||
upload_release_assets_with_retry "$GITHUB_REPOSITORY" "$FIXED_DEV_TAG" "${assets[@]}"
|
||||
|
||||
update-dev-release-notes:
|
||||
needs:
|
||||
- prepare
|
||||
- dev-mac-arm64
|
||||
- dev-linux
|
||||
- dev-win-x64
|
||||
- dev-win-arm64
|
||||
if: always() && needs.prepare.result == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ env.TARGET_BRANCH }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Update fixed dev release notes
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
TAG="${FIXED_DEV_TAG:-}"
|
||||
if [ -z "$TAG" ]; then
|
||||
echo "FIXED_DEV_TAG is empty, abort."
|
||||
exit 1
|
||||
fi
|
||||
REPO="$GITHUB_REPOSITORY"
|
||||
RELEASE_PAGE="https://github.com/$REPO/releases/tag/$TAG"
|
||||
echo "Using release tag: $TAG"
|
||||
|
||||
if ! gh api "repos/$REPO/releases/tags/$TAG" >/dev/null 2>&1; then
|
||||
echo "Release $TAG not found, skip notes update."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ASSETS_JSON="$(gh api "repos/$REPO/releases/tags/$TAG")"
|
||||
|
||||
pick_asset() {
|
||||
local pattern="$1"
|
||||
echo "$ASSETS_JSON" | jq -r --arg p "$pattern" '[.assets[].name | select(test($p))][0] // ""'
|
||||
}
|
||||
|
||||
WINDOWS_ASSET="$(pick_asset "dev-x64-Setup[.]exe$")"
|
||||
WINDOWS_ARM64_ASSET="$(pick_asset "dev-arm64-Setup[.]exe$")"
|
||||
MAC_ASSET="$(pick_asset "dev-arm64[.]dmg$")"
|
||||
if [ -z "$MAC_ASSET" ]; then
|
||||
MAC_ASSET="$(pick_asset "dev-arm64[.]zip$")"
|
||||
fi
|
||||
LINUX_TAR_ASSET="$(pick_asset "dev-linux[.]tar[.]gz$")"
|
||||
LINUX_APPIMAGE_ASSET="$(pick_asset "dev-linux[.]AppImage$")"
|
||||
|
||||
build_link() {
|
||||
local name="$1"
|
||||
if [ -n "$name" ]; then
|
||||
echo "https://github.com/$REPO/releases/download/$TAG/$name"
|
||||
fi
|
||||
}
|
||||
|
||||
WINDOWS_URL="$(build_link "$WINDOWS_ASSET")"
|
||||
WINDOWS_ARM64_URL="$(build_link "$WINDOWS_ARM64_ASSET")"
|
||||
MAC_URL="$(build_link "$MAC_ASSET")"
|
||||
LINUX_TAR_URL="$(build_link "$LINUX_TAR_ASSET")"
|
||||
LINUX_APPIMAGE_URL="$(build_link "$LINUX_APPIMAGE_ASSET")"
|
||||
|
||||
cat > dev_release_notes.md <<EOF
|
||||
## Daily Dev Build
|
||||
- 该发布页为 **开发版**。
|
||||
- 当前构建版本:\`${{ needs.prepare.outputs.dev_version }}\`
|
||||
- 此版本为每日构建的开发版,包含最新的功能和修复,但可能不够稳定,仅推荐用于测试和验证。
|
||||
|
||||
## 下载
|
||||
- Windows x64: [点击下载](${WINDOWS_URL:-$RELEASE_PAGE})
|
||||
- Windows arm64: [点击下载](${WINDOWS_ARM64_URL:-$RELEASE_PAGE})
|
||||
- macOS(Apple Silicon): [点击下载](${MAC_URL:-$RELEASE_PAGE})
|
||||
- Linux (.tar.gz): [点击下载](${LINUX_TAR_URL:-$RELEASE_PAGE})
|
||||
- Linux (.AppImage): [点击下载](${LINUX_APPIMAGE_URL:-$RELEASE_PAGE})
|
||||
|
||||
## macOS 安装提示
|
||||
- 如果被系统提示已损坏,你需要在终端执行以下命令去除隔离标记:
|
||||
- \`xattr -dr com.apple.quarantine "/Applications/WeFlow.app"\`
|
||||
- 执行后重新打开 WeFlow。
|
||||
|
||||
## 说明
|
||||
- 该发布页的同名资源会被后续构建覆盖,请勿将其视作长期归档版本。
|
||||
- 如某个平台资源暂未生成,请进入[发布页]($RELEASE_PAGE)查看最新状态
|
||||
EOF
|
||||
|
||||
update_release_notes() {
|
||||
local attempts=5
|
||||
local delay_seconds=2
|
||||
local i
|
||||
for ((i=1; i<=attempts; i++)); do
|
||||
if gh release edit "$TAG" --repo "$REPO" --title "Daily Dev Build" --notes-file dev_release_notes.md --prerelease >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
if [ "$i" -lt "$attempts" ]; then
|
||||
echo "Release update failed (attempt $i/$attempts), retry in ${delay_seconds}s..."
|
||||
sleep "$delay_seconds"
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
update_release_notes
|
||||
source .github/scripts/release-utils.sh
|
||||
RELEASE_REST_ID="$(wait_for_release_id "$REPO" "$TAG" 12 2)"
|
||||
settle_release_state "$REPO" "$RELEASE_REST_ID" "$TAG" 12 2
|
||||
print_release_state "$REPO" "$TAG"
|
||||
@@ -1,84 +0,0 @@
|
||||
name: Issue Auto Assign
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened, edited, reopened]
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
assign-by-platform:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Assign issue by selected platform
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
ASSIGNEE_WINDOWS: ${{ vars.ISSUE_ASSIGNEE_WINDOWS }}
|
||||
ASSIGNEE_MACOS: ${{ vars.ISSUE_ASSIGNEE_MACOS }}
|
||||
ASSIGNEE_LINUX: ${{ vars.ISSUE_ASSIGNEE_LINUX || 'H3CoF6' }}
|
||||
with:
|
||||
script: |
|
||||
const issue = context.payload.issue;
|
||||
if (!issue) {
|
||||
core.info("No issue payload.");
|
||||
return;
|
||||
}
|
||||
|
||||
const labels = (issue.labels || []).map((l) => l.name);
|
||||
if (!labels.includes("type: bug")) {
|
||||
core.info("Skip non-bug issue.");
|
||||
return;
|
||||
}
|
||||
|
||||
const body = issue.body || "";
|
||||
const match = body.match(/###\s*(?:使用平台|平台|Platform)\s*\r?\n+([^\r\n]+)/i);
|
||||
if (!match) {
|
||||
core.info("No platform field found in issue body.");
|
||||
return;
|
||||
}
|
||||
|
||||
const rawPlatform = match[1].trim().toLowerCase();
|
||||
let platformKey = null;
|
||||
if (rawPlatform.includes("windows")) platformKey = "windows";
|
||||
if (rawPlatform.includes("macos")) platformKey = "macos";
|
||||
if (rawPlatform.includes("linux")) platformKey = "linux";
|
||||
|
||||
if (!platformKey) {
|
||||
core.info(`Unrecognized platform value: ${rawPlatform}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const parseAssignees = (value) =>
|
||||
(value || "")
|
||||
.split(",")
|
||||
.map((v) => v.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
const assigneeMap = {
|
||||
windows: parseAssignees(process.env.ASSIGNEE_WINDOWS),
|
||||
macos: parseAssignees(process.env.ASSIGNEE_MACOS),
|
||||
linux: parseAssignees(process.env.ASSIGNEE_LINUX),
|
||||
};
|
||||
|
||||
const candidates = assigneeMap[platformKey] || [];
|
||||
if (candidates.length === 0) {
|
||||
core.info(`No assignee configured for platform: ${platformKey}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const existing = new Set((issue.assignees || []).map((a) => a.login));
|
||||
const toAdd = candidates.filter((u) => !existing.has(u));
|
||||
if (toAdd.length === 0) {
|
||||
core.info("All configured assignees already assigned.");
|
||||
return;
|
||||
}
|
||||
|
||||
await github.rest.issues.addAssignees({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: issue.number,
|
||||
assignees: toAdd,
|
||||
});
|
||||
|
||||
core.info(`Assigned issue #${issue.number} to: ${toAdd.join(", ")}`);
|
||||
@@ -1,432 +0,0 @@
|
||||
name: Preview Nightly
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# GitHub Actions schedule uses UTC. 16:00 UTC = 北京时间次日 00:00
|
||||
- cron: "0 16 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: preview-nightly-fixed-release
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
||||
FIXED_PREVIEW_TAG: nightly-preview
|
||||
TARGET_BRANCH: main
|
||||
ELECTRON_BUILDER_BINARIES_MIRROR: https://github.com/electron-userland/electron-builder-binaries/releases/download/
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
should_build: ${{ steps.meta.outputs.should_build }}
|
||||
preview_version: ${{ steps.meta.outputs.preview_version }}
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ env.TARGET_BRANCH }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 24
|
||||
cache: "npm"
|
||||
|
||||
- name: Decide whether to build and generate preview version
|
||||
id: meta
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
git fetch origin main --depth=1
|
||||
COMMITS_24H="$(git rev-list --count --since='24 hours ago' origin/main)"
|
||||
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||
SHOULD_BUILD=true
|
||||
elif [ "$COMMITS_24H" -gt 0 ]; then
|
||||
SHOULD_BUILD=true
|
||||
else
|
||||
SHOULD_BUILD=false
|
||||
fi
|
||||
|
||||
YEAR_2="$(TZ=Asia/Shanghai date +%y)"
|
||||
YEARLY_RUN_COUNT=1
|
||||
LAST_VERSION="$(gh release view "$FIXED_PREVIEW_TAG" --repo "$GITHUB_REPOSITORY" --json body --jq '.body' 2>/dev/null | grep -Eo '0\.[0-9]{2}\.[0-9]+' | head -n 1 || true)"
|
||||
if [[ "$LAST_VERSION" =~ ^0\.([0-9]{2})\.([0-9]+)$ ]]; then
|
||||
LAST_YEAR="${BASH_REMATCH[1]}"
|
||||
LAST_COUNT="${BASH_REMATCH[2]}"
|
||||
if [ "$LAST_YEAR" = "$YEAR_2" ]; then
|
||||
YEARLY_RUN_COUNT=$((LAST_COUNT + 1))
|
||||
fi
|
||||
fi
|
||||
|
||||
PREVIEW_VERSION="0.${YEAR_2}.${YEARLY_RUN_COUNT}"
|
||||
|
||||
echo "should_build=$SHOULD_BUILD" >> "$GITHUB_OUTPUT"
|
||||
echo "preview_version=$PREVIEW_VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "Preview version: $PREVIEW_VERSION (commits in last 24h on main: $COMMITS_24H, yearly count: $YEARLY_RUN_COUNT)"
|
||||
|
||||
- name: Recreate fixed preview prerelease
|
||||
if: steps.meta.outputs.should_build == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source .github/scripts/release-utils.sh
|
||||
recreate_fixed_prerelease "$GITHUB_REPOSITORY" "$FIXED_PREVIEW_TAG" "$TARGET_BRANCH" "Preview Nightly Build" "预览版发布页"
|
||||
|
||||
preview-mac-arm64:
|
||||
needs: prepare
|
||||
if: needs.prepare.outputs.should_build == 'true'
|
||||
runs-on: macos-14
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ env.TARGET_BRANCH }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 24
|
||||
cache: "npm"
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Ensure mac key helpers are executable
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
for file in \
|
||||
resources/key/macos/universal/xkey_helper \
|
||||
resources/key/macos/universal/image_scan_helper \
|
||||
resources/key/macos/universal/xkey_helper_macos \
|
||||
resources/key/macos/universal/libwx_key.dylib
|
||||
do
|
||||
if [ -f "$file" ]; then
|
||||
chmod +x "$file"
|
||||
ls -l "$file"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Set preview version
|
||||
shell: bash
|
||||
run: npm version "${{ needs.prepare.outputs.preview_version }}" --no-git-tag-version --allow-same-version
|
||||
|
||||
- name: Build Frontend & Type Check
|
||||
shell: bash
|
||||
run: |
|
||||
npx tsc
|
||||
npx vite build
|
||||
|
||||
- name: Package macOS arm64 preview artifacts
|
||||
env:
|
||||
CSC_IDENTITY_AUTO_DISCOVERY: "false"
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
export ELECTRON_BUILDER_BINARIES_MIRROR="https://github.com/electron-userland/electron-builder-binaries/releases/download/"
|
||||
echo "Using ELECTRON_BUILDER_BINARIES_MIRROR=$ELECTRON_BUILDER_BINARIES_MIRROR"
|
||||
if ! npx electron-builder --mac dmg zip --arm64 --publish never '--config.publish.channel=preview' '--config.artifactName=${productName}-preview-arm64.${ext}'; then
|
||||
echo "::warning::DMG packaging failed (hdiutil instability on runner). Retrying with ZIP only."
|
||||
npx electron-builder --mac zip --arm64 --publish never '--config.publish.channel=preview' '--config.artifactName=${productName}-preview-arm64.${ext}'
|
||||
fi
|
||||
|
||||
- name: Upload macOS arm64 assets to fixed preview release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source .github/scripts/release-utils.sh
|
||||
assets=()
|
||||
while IFS= read -r file; do
|
||||
assets+=("$file")
|
||||
done < <(find release -maxdepth 1 -type f | sort)
|
||||
if [ "${#assets[@]}" -eq 0 ]; then
|
||||
echo "No release files found in ./release"
|
||||
exit 1
|
||||
fi
|
||||
upload_release_assets_with_retry "$GITHUB_REPOSITORY" "$FIXED_PREVIEW_TAG" "${assets[@]}"
|
||||
|
||||
preview-linux:
|
||||
needs: prepare
|
||||
if: needs.prepare.outputs.should_build == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ env.TARGET_BRANCH }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 24
|
||||
cache: "npm"
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Set preview version
|
||||
shell: bash
|
||||
run: npm version "${{ needs.prepare.outputs.preview_version }}" --no-git-tag-version --allow-same-version
|
||||
|
||||
- name: Build Frontend & Type Check
|
||||
shell: bash
|
||||
run: |
|
||||
npx tsc
|
||||
npx vite build
|
||||
|
||||
- name: Package Linux preview artifacts
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
npx electron-builder --linux --publish never '--config.publish.channel=preview' '--config.artifactName=${productName}-preview-linux.${ext}'
|
||||
|
||||
- name: Upload Linux assets to fixed preview release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source .github/scripts/release-utils.sh
|
||||
assets=()
|
||||
while IFS= read -r file; do
|
||||
assets+=("$file")
|
||||
done < <(find release -maxdepth 1 -type f | sort)
|
||||
if [ "${#assets[@]}" -eq 0 ]; then
|
||||
echo "No release files found in ./release"
|
||||
exit 1
|
||||
fi
|
||||
upload_release_assets_with_retry "$GITHUB_REPOSITORY" "$FIXED_PREVIEW_TAG" "${assets[@]}"
|
||||
|
||||
preview-win-x64:
|
||||
needs: prepare
|
||||
if: needs.prepare.outputs.should_build == 'true'
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ env.TARGET_BRANCH }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 24
|
||||
cache: "npm"
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Set preview version
|
||||
shell: bash
|
||||
run: npm version "${{ needs.prepare.outputs.preview_version }}" --no-git-tag-version --allow-same-version
|
||||
|
||||
- name: Build Frontend & Type Check
|
||||
shell: bash
|
||||
run: |
|
||||
npx tsc
|
||||
npx vite build
|
||||
|
||||
- name: Package Windows x64 preview artifacts
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
npx electron-builder --win nsis --x64 --publish never '--config.publish.channel=preview' '--config.artifactName=${productName}-preview-x64-Setup.${ext}'
|
||||
|
||||
- name: Upload Windows x64 assets to fixed preview release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source .github/scripts/release-utils.sh
|
||||
assets=()
|
||||
while IFS= read -r file; do
|
||||
assets+=("$file")
|
||||
done < <(find release -maxdepth 1 -type f | sort)
|
||||
if [ "${#assets[@]}" -eq 0 ]; then
|
||||
echo "No release files found in ./release"
|
||||
exit 1
|
||||
fi
|
||||
upload_release_assets_with_retry "$GITHUB_REPOSITORY" "$FIXED_PREVIEW_TAG" "${assets[@]}"
|
||||
|
||||
preview-win-arm64:
|
||||
needs: prepare
|
||||
if: needs.prepare.outputs.should_build == 'true'
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ env.TARGET_BRANCH }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 24
|
||||
cache: "npm"
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Set preview version
|
||||
shell: bash
|
||||
run: npm version "${{ needs.prepare.outputs.preview_version }}" --no-git-tag-version --allow-same-version
|
||||
|
||||
- name: Build Frontend & Type Check
|
||||
shell: bash
|
||||
run: |
|
||||
npx tsc
|
||||
npx vite build
|
||||
|
||||
- name: Package Windows arm64 preview artifacts
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
npx electron-builder --win nsis --arm64 --publish never '--config.publish.channel=preview-arm64' '--config.artifactName=${productName}-preview-arm64-Setup.${ext}'
|
||||
|
||||
- name: Upload Windows arm64 assets to fixed preview release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source .github/scripts/release-utils.sh
|
||||
assets=()
|
||||
while IFS= read -r file; do
|
||||
assets+=("$file")
|
||||
done < <(find release -maxdepth 1 -type f | sort)
|
||||
if [ "${#assets[@]}" -eq 0 ]; then
|
||||
echo "No release files found in ./release"
|
||||
exit 1
|
||||
fi
|
||||
upload_release_assets_with_retry "$GITHUB_REPOSITORY" "$FIXED_PREVIEW_TAG" "${assets[@]}"
|
||||
|
||||
update-preview-release-notes:
|
||||
needs:
|
||||
- prepare
|
||||
- preview-mac-arm64
|
||||
- preview-linux
|
||||
- preview-win-x64
|
||||
- preview-win-arm64
|
||||
if: needs.prepare.outputs.should_build == 'true' && always()
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ env.TARGET_BRANCH }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Update preview release notes
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
TAG="${FIXED_PREVIEW_TAG:-}"
|
||||
if [ -z "$TAG" ]; then
|
||||
echo "FIXED_PREVIEW_TAG is empty, abort."
|
||||
exit 1
|
||||
fi
|
||||
CURRENT_PREVIEW_VERSION="${{ needs.prepare.outputs.preview_version }}"
|
||||
REPO="$GITHUB_REPOSITORY"
|
||||
RELEASE_PAGE="https://github.com/$REPO/releases/tag/$TAG"
|
||||
echo "Using release tag: $TAG"
|
||||
|
||||
if ! gh api "repos/$REPO/releases/tags/$TAG" >/dev/null 2>&1; then
|
||||
echo "Release $TAG not found (possibly all publish jobs failed), skip notes update."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ASSETS_JSON="$(gh api "repos/$REPO/releases/tags/$TAG")"
|
||||
|
||||
pick_asset() {
|
||||
local pattern="$1"
|
||||
echo "$ASSETS_JSON" | jq -r --arg p "$pattern" '[.assets[].name | select(test($p))][0] // ""'
|
||||
}
|
||||
|
||||
WINDOWS_ASSET="$(pick_asset "x64.*[.]exe$")"
|
||||
if [ -z "$WINDOWS_ASSET" ]; then
|
||||
WINDOWS_ASSET="$(echo "$ASSETS_JSON" | jq -r '[.assets[].name | select(test("[.]exe$")) | select(test("arm64") | not)][0] // ""')"
|
||||
fi
|
||||
WINDOWS_ARM64_ASSET="$(pick_asset "arm64.*[.]exe$")"
|
||||
MAC_ASSET="$(pick_asset "[.]dmg$")"
|
||||
if [ -z "$MAC_ASSET" ]; then
|
||||
MAC_ASSET="$(pick_asset "[.]zip$")"
|
||||
fi
|
||||
LINUX_TAR_ASSET="$(pick_asset "[.]tar[.]gz$")"
|
||||
LINUX_APPIMAGE_ASSET="$(pick_asset "[.]AppImage$")"
|
||||
|
||||
build_link() {
|
||||
local name="$1"
|
||||
if [ -n "$name" ]; then
|
||||
echo "https://github.com/$REPO/releases/download/$TAG/$name"
|
||||
fi
|
||||
}
|
||||
|
||||
WINDOWS_URL="$(build_link "$WINDOWS_ASSET")"
|
||||
WINDOWS_ARM64_URL="$(build_link "$WINDOWS_ARM64_ASSET")"
|
||||
MAC_URL="$(build_link "$MAC_ASSET")"
|
||||
LINUX_TAR_URL="$(build_link "$LINUX_TAR_ASSET")"
|
||||
LINUX_APPIMAGE_URL="$(build_link "$LINUX_APPIMAGE_ASSET")"
|
||||
|
||||
cat > preview_release_notes.md <<EOF
|
||||
## Preview Nightly 说明
|
||||
- 该版本为 **预览版**,用于提前体验即将发布的功能与修复。
|
||||
- 可能包含尚未完全稳定的改动,不建议长期使用
|
||||
- 当前版本号:\`$CURRENT_PREVIEW_VERSION\`
|
||||
|
||||
## 下载
|
||||
- Windows x64: [点击下载](${WINDOWS_URL:-$RELEASE_PAGE})
|
||||
- Windows arm64: [点击下载](${WINDOWS_ARM64_URL:-$RELEASE_PAGE})
|
||||
- macOS(Apple Silicon): [点击下载](${MAC_URL:-$RELEASE_PAGE})
|
||||
- Linux (.tar.gz): [点击下载](${LINUX_TAR_URL:-$RELEASE_PAGE})
|
||||
- Linux (.AppImage): [点击下载](${LINUX_APPIMAGE_URL:-$RELEASE_PAGE})
|
||||
|
||||
## macOS 安装提示
|
||||
- 如果被系统提示已损坏,你需要在终端执行以下命令去除隔离标记:
|
||||
- \`xattr -dr com.apple.quarantine "/Applications/WeFlow.app"\`
|
||||
- 执行后重新打开 WeFlow。
|
||||
|
||||
> 如某个平台链接暂未生成,请前往[发布页]($RELEASE_PAGE)查看最新资源
|
||||
EOF
|
||||
|
||||
update_release_notes() {
|
||||
local attempts=5
|
||||
local delay_seconds=2
|
||||
local i
|
||||
for ((i=1; i<=attempts; i++)); do
|
||||
if gh release edit "$TAG" --repo "$REPO" --title "Preview Nightly Build" --notes-file preview_release_notes.md --prerelease >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
if [ "$i" -lt "$attempts" ]; then
|
||||
echo "Release update failed (attempt $i/$attempts), retry in ${delay_seconds}s..."
|
||||
sleep "$delay_seconds"
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
update_release_notes
|
||||
source .github/scripts/release-utils.sh
|
||||
RELEASE_REST_ID="$(wait_for_release_id "$REPO" "$TAG" 12 2)"
|
||||
settle_release_state "$REPO" "$RELEASE_REST_ID" "$TAG" 12 2
|
||||
print_release_state "$REPO" "$TAG"
|
||||
@@ -1,391 +0,0 @@
|
||||
name: Build and Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
||||
ELECTRON_BUILDER_BINARIES_MIRROR: https://github.com/electron-userland/electron-builder-binaries/releases/download/
|
||||
|
||||
jobs:
|
||||
release-mac-arm64:
|
||||
runs-on: macos-14
|
||||
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 24
|
||||
cache: "npm"
|
||||
- name: Install Dependencies
|
||||
run: npm install --ignore-scripts
|
||||
|
||||
- name: Ensure mac key helpers are executable
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
for file in \
|
||||
resources/key/macos/universal/xkey_helper \
|
||||
resources/key/macos/universal/image_scan_helper \
|
||||
resources/key/macos/universal/xkey_helper_macos \
|
||||
resources/key/macos/universal/libwx_key.dylib
|
||||
do
|
||||
if [ -f "$file" ]; then
|
||||
chmod +x "$file"
|
||||
ls -l "$file"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Sync version with tag
|
||||
shell: bash
|
||||
run: |
|
||||
VERSION=${GITHUB_REF_NAME#v}
|
||||
echo "Syncing package.json version to $VERSION"
|
||||
node -e "const fs=require('fs');const p=JSON.parse(fs.readFileSync('package.json','utf8'));p.version='$VERSION';fs.writeFileSync('package.json',JSON.stringify(p,null,2)+'\n')"
|
||||
|
||||
- name: Build Frontend & Type Check
|
||||
shell: bash
|
||||
run: |
|
||||
npx tsc
|
||||
npx vite build
|
||||
|
||||
- name: Package and Publish macOS arm64 (unsigned DMG + ZIP)
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CSC_IDENTITY_AUTO_DISCOVERY: "false"
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
export ELECTRON_BUILDER_BINARIES_MIRROR="https://github.com/electron-userland/electron-builder-binaries/releases/download/"
|
||||
echo "Using ELECTRON_BUILDER_BINARIES_MIRROR=$ELECTRON_BUILDER_BINARIES_MIRROR"
|
||||
if ! npx electron-builder --mac dmg zip --arm64 --publish always '--config.npmRebuild=false' '--config.publish.owner=${{ github.repository_owner }}' '--config.publish.repo=${{ github.event.repository.name }}'; then
|
||||
echo "::warning::DMG packaging failed (hdiutil instability on runner). Retrying with ZIP only."
|
||||
npx electron-builder --mac zip --arm64 --publish always '--config.npmRebuild=false' '--config.publish.owner=${{ github.repository_owner }}' '--config.publish.repo=${{ github.event.repository.name }}'
|
||||
fi
|
||||
|
||||
- name: Inject minimumVersion into latest yml
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source .github/scripts/release-utils.sh
|
||||
TAG=${GITHUB_REF_NAME}
|
||||
REPO=${{ github.repository }}
|
||||
MINIMUM_VERSION="4.1.7"
|
||||
wait_for_release_id "$REPO" "$TAG" 12 2 >/dev/null
|
||||
for YML_FILE in latest-mac.yml latest-arm64-mac.yml; do
|
||||
if ! retry_cmd 5 3 gh release download "$TAG" --repo "$REPO" --pattern "$YML_FILE" --output "/tmp/$YML_FILE"; then
|
||||
echo "Skip $YML_FILE because download failed after retries."
|
||||
continue
|
||||
fi
|
||||
if ! grep -q 'minimumVersion' "/tmp/$YML_FILE"; then
|
||||
echo "minimumVersion: $MINIMUM_VERSION" >> "/tmp/$YML_FILE"
|
||||
fi
|
||||
retry_cmd 5 3 gh release upload "$TAG" --repo "$REPO" "/tmp/$YML_FILE" --clobber
|
||||
done
|
||||
|
||||
release-linux:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 24
|
||||
cache: "npm"
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Ensure linux key helper is executable
|
||||
shell: bash
|
||||
run: |
|
||||
[ -f "resources/key/linux/x64/xkey_helper" ] && chmod +x "resources/key/linux/x64/xkey_helper" || echo "File not found"
|
||||
|
||||
- name: Sync version with tag
|
||||
shell: bash
|
||||
run: |
|
||||
VERSION=${GITHUB_REF_NAME#v}
|
||||
echo "Syncing package.json version to $VERSION"
|
||||
node -e "const fs=require('fs');const p=JSON.parse(fs.readFileSync('package.json','utf8'));p.version='$VERSION';fs.writeFileSync('package.json',JSON.stringify(p,null,2)+'\n')"
|
||||
|
||||
- name: Build Frontend & Type Check
|
||||
shell: bash
|
||||
run: |
|
||||
npx tsc
|
||||
npx vite build
|
||||
|
||||
- name: Package and Publish Linux
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
npx electron-builder --linux --publish always '--config.publish.owner=${{ github.repository_owner }}' '--config.publish.repo=${{ github.event.repository.name }}'
|
||||
|
||||
- name: Inject minimumVersion into latest yml
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source .github/scripts/release-utils.sh
|
||||
TAG=${GITHUB_REF_NAME}
|
||||
REPO=${{ github.repository }}
|
||||
MINIMUM_VERSION="4.1.7"
|
||||
wait_for_release_id "$REPO" "$TAG" 12 2 >/dev/null
|
||||
retry_cmd 5 3 gh release download "$TAG" --repo "$REPO" --pattern "latest-linux.yml" --output "/tmp/latest-linux.yml" || true
|
||||
if [ -f /tmp/latest-linux.yml ] && ! grep -q 'minimumVersion' /tmp/latest-linux.yml; then
|
||||
echo "minimumVersion: $MINIMUM_VERSION" >> /tmp/latest-linux.yml
|
||||
retry_cmd 5 3 gh release upload "$TAG" --repo "$REPO" /tmp/latest-linux.yml --clobber
|
||||
fi
|
||||
|
||||
release:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 24
|
||||
cache: 'npm'
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Sync version with tag
|
||||
shell: bash
|
||||
run: |
|
||||
VERSION=${GITHUB_REF_NAME#v}
|
||||
echo "Syncing package.json version to $VERSION"
|
||||
node -e "const fs=require('fs');const p=JSON.parse(fs.readFileSync('package.json','utf8'));p.version='$VERSION';fs.writeFileSync('package.json',JSON.stringify(p,null,2)+'\n')"
|
||||
|
||||
- name: Build Frontend & Type Check
|
||||
shell: bash
|
||||
run: |
|
||||
npx tsc
|
||||
npx vite build
|
||||
|
||||
- name: Package and Publish
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
npx electron-builder --win nsis --x64 --publish always '--config.publish.owner=${{ github.repository_owner }}' '--config.publish.repo=${{ github.event.repository.name }}' '--config.artifactName=${productName}-${version}-x64-Setup.${ext}'
|
||||
|
||||
- name: Inject minimumVersion into latest yml
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source .github/scripts/release-utils.sh
|
||||
TAG=${GITHUB_REF_NAME}
|
||||
REPO=${{ github.repository }}
|
||||
MINIMUM_VERSION="4.1.7"
|
||||
wait_for_release_id "$REPO" "$TAG" 12 2 >/dev/null
|
||||
retry_cmd 5 3 gh release download "$TAG" --repo "$REPO" --pattern "latest.yml" --output "/tmp/latest.yml" || true
|
||||
if [ -f /tmp/latest.yml ] && ! grep -q 'minimumVersion' /tmp/latest.yml; then
|
||||
echo "minimumVersion: $MINIMUM_VERSION" >> /tmp/latest.yml
|
||||
retry_cmd 5 3 gh release upload "$TAG" --repo "$REPO" /tmp/latest.yml --clobber
|
||||
fi
|
||||
|
||||
release-windows-arm64:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 24
|
||||
cache: 'npm'
|
||||
- name: Install Dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Sync version with tag
|
||||
shell: bash
|
||||
run: |
|
||||
VERSION=${GITHUB_REF_NAME#v}
|
||||
echo "Syncing package.json version to $VERSION"
|
||||
node -e "const fs=require('fs');const p=JSON.parse(fs.readFileSync('package.json','utf8'));p.version='$VERSION';fs.writeFileSync('package.json',JSON.stringify(p,null,2)+'\n')"
|
||||
|
||||
- name: Build Frontend & Type Check
|
||||
shell: bash
|
||||
run: |
|
||||
npx tsc
|
||||
npx vite build
|
||||
|
||||
- name: Package and Publish Windows arm64
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
npx electron-builder --win nsis --arm64 --publish always '--config.publish.owner=${{ github.repository_owner }}' '--config.publish.repo=${{ github.event.repository.name }}' '--config.publish.channel=latest-arm64' '--config.artifactName=${productName}-${version}-arm64-Setup.${ext}'
|
||||
|
||||
- name: Inject minimumVersion into latest yml
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source .github/scripts/release-utils.sh
|
||||
TAG=${GITHUB_REF_NAME}
|
||||
REPO=${{ github.repository }}
|
||||
MINIMUM_VERSION="4.1.7"
|
||||
wait_for_release_id "$REPO" "$TAG" 12 2 >/dev/null
|
||||
retry_cmd 5 3 gh release download "$TAG" --repo "$REPO" --pattern "latest-arm64.yml" --output "/tmp/latest-arm64.yml" || true
|
||||
if [ -f /tmp/latest-arm64.yml ] && ! grep -q 'minimumVersion' /tmp/latest-arm64.yml; then
|
||||
echo "minimumVersion: $MINIMUM_VERSION" >> /tmp/latest-arm64.yml
|
||||
retry_cmd 5 3 gh release upload "$TAG" --repo "$REPO" /tmp/latest-arm64.yml --clobber
|
||||
fi
|
||||
|
||||
update-release-notes:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- release-mac-arm64
|
||||
- release-linux
|
||||
- release
|
||||
- release-windows-arm64
|
||||
|
||||
steps:
|
||||
- name: Check out git repository
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Generate release notes with platform download links
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source .github/scripts/release-utils.sh
|
||||
|
||||
TAG="$GITHUB_REF_NAME"
|
||||
REPO="$GITHUB_REPOSITORY"
|
||||
RELEASE_PAGE="https://github.com/$REPO/releases/tag/$TAG"
|
||||
wait_for_release_id "$REPO" "$TAG" 12 2 >/dev/null
|
||||
|
||||
capture_cmd_with_retry ASSETS_JSON 8 3 gh release view "$TAG" --repo "$REPO" --json assets
|
||||
|
||||
pick_asset() {
|
||||
local pattern="$1"
|
||||
echo "$ASSETS_JSON" | jq -r --arg p "$pattern" '[.assets[].name | select(test($p))][0] // ""'
|
||||
}
|
||||
|
||||
WINDOWS_ASSET="$(echo "$ASSETS_JSON" | jq -r '[.assets[].name | select(test("x64.*\\.exe$"))][0] // ""')"
|
||||
if [ -z "$WINDOWS_ASSET" ]; then
|
||||
WINDOWS_ASSET="$(echo "$ASSETS_JSON" | jq -r '[.assets[].name | select(test("\\.exe$")) | select(test("arm64") | not)][0] // ""')"
|
||||
fi
|
||||
WINDOWS_ARM64_ASSET="$(echo "$ASSETS_JSON" | jq -r '[.assets[].name | select(test("arm64.*\\.exe$"))][0] // ""')"
|
||||
MAC_ASSET="$(pick_asset "\\.dmg$")"
|
||||
if [ -z "$MAC_ASSET" ]; then
|
||||
MAC_ASSET="$(pick_asset "arm64\\.zip$")"
|
||||
fi
|
||||
LINUX_TAR_ASSET="$(pick_asset "\\.tar\\.gz$")"
|
||||
LINUX_APPIMAGE_ASSET="$(pick_asset "\\.AppImage$")"
|
||||
|
||||
build_link() {
|
||||
local name="$1"
|
||||
if [ -n "$name" ]; then
|
||||
echo "https://github.com/$REPO/releases/download/$TAG/$name"
|
||||
fi
|
||||
}
|
||||
|
||||
WINDOWS_URL="$(build_link "$WINDOWS_ASSET")"
|
||||
WINDOWS_ARM64_URL="$(build_link "$WINDOWS_ARM64_ASSET")"
|
||||
MAC_URL="$(build_link "$MAC_ASSET")"
|
||||
LINUX_TAR_URL="$(build_link "$LINUX_TAR_ASSET")"
|
||||
LINUX_APPIMAGE_URL="$(build_link "$LINUX_APPIMAGE_ASSET")"
|
||||
|
||||
cat > release_notes.md <<EOF
|
||||
## 更新日志
|
||||
修复了一些已知问题
|
||||
|
||||
## 查看更多日志/获取最新动态
|
||||
[点击加入 Telegram 频道](https://t.me/weflow_cc)
|
||||
|
||||
## 下载
|
||||
- Windows x64(Win10+): [点击下载](${WINDOWS_URL:-$RELEASE_PAGE})
|
||||
- Windows arm64: [点击下载](${WINDOWS_ARM64_URL:-$RELEASE_PAGE})
|
||||
- macOS(M系列芯片): [点击下载](${MAC_URL:-$RELEASE_PAGE})
|
||||
- Linux (.tar.gz): [点击下载](${LINUX_TAR_URL:-$RELEASE_PAGE})
|
||||
- Linux (.AppImage): [点击下载](${LINUX_APPIMAGE_URL:-$RELEASE_PAGE})
|
||||
|
||||
## macOS 安装提示
|
||||
- 如果被系统提示已损坏,你需要在终端执行以下命令去除隔离标记:
|
||||
- \`xattr -dr com.apple.quarantine "/Applications/WeFlow.app"\`
|
||||
- 执行后重新打开 WeFlow。
|
||||
|
||||
> 如果某个平台链接暂时未生成,可进入[完整发布页]($RELEASE_PAGE)查看全部资源
|
||||
EOF
|
||||
|
||||
retry_cmd 5 3 gh release edit "$TAG" --repo "$REPO" --notes-file release_notes.md
|
||||
|
||||
deploy-aur:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [release-linux]
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
steps:
|
||||
- name: Check AUR credentials
|
||||
id: aur-credentials
|
||||
shell: bash
|
||||
env:
|
||||
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||
run: |
|
||||
if [ -z "${AUR_SSH_PRIVATE_KEY}" ]; then
|
||||
echo "::notice::AUR_SSH_PRIVATE_KEY is not configured; skipping AUR publish."
|
||||
echo "enabled=false" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "enabled=true" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Checkout code
|
||||
if: steps.aur-credentials.outputs.enabled == 'true'
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Update PKGBUILD version
|
||||
if: steps.aur-credentials.outputs.enabled == 'true'
|
||||
run: |
|
||||
NEW_VER=$(echo "${{ github.ref_name }}" | sed 's/^v//')
|
||||
sed -i "s/^pkgver=.*/pkgver=${NEW_VER}/" resources/installer/linux/PKGBUILD
|
||||
sed -i "s/^pkgrel=.*/pkgrel=1/" resources/installer/linux/PKGBUILD
|
||||
|
||||
- name: Publish AUR package
|
||||
if: steps.aur-credentials.outputs.enabled == 'true'
|
||||
uses: KSXGitHub/github-actions-deploy-aur@master
|
||||
with:
|
||||
pkgname: weflow
|
||||
pkgbuild: resources/installer/linux/PKGBUILD
|
||||
updpkgsums: true
|
||||
assets: |
|
||||
resources/installer/linux/weflow.desktop
|
||||
resources/installer/linux/icon.png
|
||||
resources/installer/linux/.gitignore
|
||||
|
||||
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||
commit_username: H3CoF6
|
||||
commit_email: h3cof6@gmail.com
|
||||
ssh_keyscan_types: ed25519
|
||||
Reference in new issue
Block a user