feat: align with upstream 1.5.9.9

This commit is contained in:
2026-09-12 18:21:11 +08:00
commit 34f0679117
805 changed files with 376275 additions and 0 deletions
+133
View File
@@ -0,0 +1,133 @@
name: 🐛 问题反馈
description: 报告VoiceHub系统中的问题或错误
title: '[Bug]: '
labels: ['bug', '需要确认']
assignees: []
body:
- type: markdown
attributes:
value: |
感谢您报告问题!请详细描述遇到的问题,这将帮助我们更快地定位和解决问题。
- type: dropdown
id: bug-type
attributes:
label: 问题类型
description: 请选择最符合的问题类型
options:
- 音乐播放相关
- 用户登录/注册
- 点歌功能
- 通知系统
- 管理员功能
- 界面显示
- 性能问题
- 其他
validations:
required: true
- type: textarea
id: bug-description
attributes:
label: 问题描述
description: 请详细描述遇到的问题
placeholder: 请清楚地描述问题的具体表现...
validations:
required: true
- type: textarea
id: steps-to-reproduce
attributes:
label: 复现步骤
description: 请提供详细的复现步骤
placeholder: |
1. 进入...
2. 点击...
3. 看到错误...
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: dropdown
id: browser
attributes:
label: 浏览器
description: 使用的浏览器类型
options:
- Chrome
- Firefox
- Safari
- Edge
- 其他
validations:
required: false
- type: input
id: browser-version
attributes:
label: 浏览器版本
description: 浏览器的具体版本号
placeholder: 例如:Chrome 120.0.0.0
validations:
required: false
- type: dropdown
id: device-type
attributes:
label: 设备类型
description: 使用的设备类型
options:
- 桌面电脑
- 笔记本电脑
- 平板电脑
- 手机
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: 附加信息
description: 任何其他有助于理解问题的信息
placeholder: 截图、错误日志、相关配置等...
validations:
required: false
- type: input
id: instance-id
attributes:
label: 实例 ID(可选)
description: 如果方便,可以提供系统实例 ID(可在管理员后台「系统状态」或浏览器控制台中查看),这能帮助开发者关联到具体的部署环境
placeholder: 例如:a807234c-cc23-45ea-ab3b-dcb604e1b7d9
validations:
required: false
- type: checkboxes
id: terms
attributes:
label: 确认事项
description: 请确认以下事项
options:
- label: 我已经搜索了现有的Issues,确认这不是重复问题
required: true
- label: 我已经尝试刷新页面或重新登录
required: false
- label: 问题可以稳定复现
required: false
+14
View File
@@ -0,0 +1,14 @@
blank_issues_enabled: true
contact_links:
- name: 📚 使用文档
url: https://docs.voicehub.lao-shui.top
about: 查看VoiceHub的使用文档和常见问题解答
- name: 💬 讨论区
url: https://github.com/laoshuikaixue/VoiceHub/discussions
about: 在讨论区提问、分享经验或参与社区讨论
- name: 🔒 安全问题私密报告
url: mailto:contact@lao-shui.top
about: 对于严重的安全漏洞,请通过邮件私密报告
- name: 📧 联系我们
url: mailto:contact@lao-shui.top
about: 如果您需要技术支持或有其他问题,可以直接联系我们
+139
View File
@@ -0,0 +1,139 @@
name: ✨ 功能建议
description: 为VoiceHub系统提出新功能或改进建议
title: '[Feature]: '
labels: ['enhancement', '功能建议']
assignees: []
body:
- type: markdown
attributes:
value: |
感谢您为VoiceHub提出功能建议!您的想法将帮助我们改进系统,为用户提供更好的体验。
- type: dropdown
id: feature-category
attributes:
label: 功能类别
description: 请选择建议功能所属的类别
options:
- 音乐播放功能
- 点歌系统
- 用户管理
- 通知系统
- 管理员工具
- 用户界面
- 数据统计
- 安全功能
- API接口
- 其他
validations:
required: true
- type: textarea
id: feature-summary
attributes:
label: 功能概述
description: 简要描述您建议的功能
placeholder: 用一两句话概括您的功能建议...
validations:
required: true
- type: textarea
id: problem-statement
attributes:
label: 问题描述
description: 描述当前存在的问题或不便之处
placeholder: 目前在使用VoiceHub时遇到了什么问题或不便?
validations:
required: false
- type: textarea
id: proposed-solution
attributes:
label: 建议方案
description: 详细描述您建议的解决方案
placeholder: |
请详细描述您的功能建议:
- 功能如何工作
- 用户如何使用
- 预期效果
validations:
required: false
- type: textarea
id: user-stories
attributes:
label: 用户场景
description: 描述用户在什么情况下会使用这个功能
placeholder: |
作为一个[用户角色],我希望[功能描述],这样我就可以[预期收益]。
例如:
- 作为学生,我希望能够预约点歌时间,这样我就可以在特定时间播放我的歌曲
- 作为管理员,我希望能够批量管理歌曲,这样我就可以更高效地维护歌曲库
validations:
required: false
- type: textarea
id: alternatives
attributes:
label: 替代方案
description: 是否考虑过其他解决方案?
placeholder: 描述您考虑过的其他可能的解决方案...
validations:
required: false
- type: dropdown
id: priority
attributes:
label: 优先级
description: 您认为这个功能的重要程度如何?
options:
- 高 - 非常重要,急需实现
- 中 - 重要,希望尽快实现
- 低 - 有了更好,不急
validations:
required: true
- type: dropdown
id: user-type
attributes:
label: 目标用户
description: 这个功能主要面向哪类用户?
options:
- 所有用户
- 普通学生用户
- 管理员
- 特定用户群体
validations:
required: true
- type: textarea
id: technical-considerations
attributes:
label: 技术考虑
description: 如果您有技术背景,可以提供一些技术实现的想法
placeholder: 实现思路、技术栈建议、性能考虑等...
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: 附加信息
description: 任何其他有助于理解功能需求的信息
placeholder: 参考资料、类似功能的例子、设计草图等...
validations:
required: false
- type: checkboxes
id: terms
attributes:
label: 确认事项
description: 请确认以下事项
options:
- label: 我已经搜索了现有的Issues,确认这不是重复建议
required: true
- label: 我愿意参与功能的讨论和测试
required: false
- label: 如果有能力,我愿意协助开发这个功能
required: false
+112
View File
@@ -0,0 +1,112 @@
name: '❓ 提问 / Question'
description: '遇到问题需要帮助?在这里提问,我们会尽快为您解答!'
title: '[Question]: '
labels: ['question', '需要帮助']
assignees: []
body:
- type: markdown
attributes:
value: |
感谢您使用 VoiceHub 校园广播点歌系统!如果您在使用过程中遇到任何问题,请填写以下信息,我们会尽快为您提供帮助。
💡 **提示**:提问前建议先查看已有的 Issues。
- type: dropdown
id: question-type
attributes:
label: '问题类型'
description: '请选择您遇到的问题类型'
options:
- '使用问题 - 不知道如何操作某个功能'
- '技术问题 - 功能无法正常工作'
- '配置问题 - 系统设置相关'
- '账户问题 - 登录、权限等'
- '音频问题 - 播放、上传相关'
- '界面问题 - 显示异常或操作困难'
- '其他问题'
validations:
required: true
- type: textarea
id: question-description
attributes:
label: '问题描述'
description: '请详细描述您遇到的问题,包括具体的操作步骤和现象'
placeholder: |
例如:
1. 我在尝试点歌时...
2. 点击"添加到播放列表"按钮后...
3. 期望的结果是...,但实际发生的是...
validations:
required: true
- type: dropdown
id: user-role
attributes:
label: '用户角色'
description: '您在系统中的角色是什么?'
options:
- '学生用户'
- '教师用户'
- '管理员'
- '超级管理员'
- '访客'
validations:
required: true
- type: input
id: environment
attributes:
label: '使用环境'
description: '请提供您的使用环境信息'
placeholder: '例如:Chrome 120, Windows 11, 移动端Safari等'
validations:
required: false
- type: textarea
id: attempted-solutions
attributes:
label: '已尝试的解决方法'
description: '请描述您已经尝试过的解决方法(如果有的话)'
placeholder: |
例如:
- 刷新了页面
- 清除了浏览器缓存
- 尝试了不同的浏览器
- 重新登录了账户
validations:
required: false
- type: dropdown
id: urgency
attributes:
label: '紧急程度'
description: '这个问题对您的使用影响有多大?'
options:
- '低 - 不影响正常使用,有时间时解决即可'
- '中 - 影响部分功能,希望尽快解决'
- '高 - 严重影响使用,需要紧急处理'
validations:
required: true
- type: textarea
id: additional-info
attributes:
label: '补充信息'
description: '任何其他可能有帮助的信息,如截图、错误信息等'
placeholder: '您可以在这里添加截图、错误截图或其他相关信息'
validations:
required: false
- type: checkboxes
id: confirmation
attributes:
label: '确认事项'
description: '请确认以下事项'
options:
- label: '我已经搜索了现有的 Issues,确认这不是重复问题'
required: true
# - label: "我已经查看了项目文档和常见问题"
# required: false
- label: '我愿意提供更多信息来帮助解决这个问题'
required: false
+149
View File
@@ -0,0 +1,149 @@
name: 🔒 安全问题报告
description: 报告VoiceHub系统中的安全漏洞或安全相关问题
title: '[Security]: '
labels: ['security', '高优先级']
assignees: []
body:
- type: markdown
attributes:
value: |
⚠️ **重要提醒**:如果您发现了严重的安全漏洞,请不要在公开的Issue中详细描述。
请发送邮件至 `contact@lao-shui.top` 。
感谢您帮助我们保护VoiceHub系统的安全!
- type: dropdown
id: security-type
attributes:
label: 安全问题类型
description: 请选择最符合的安全问题类型
options:
- 身份认证问题
- 权限控制问题
- 数据泄露风险
- 跨站脚本攻击(XSS)
- SQL注入
- 跨站请求伪造(CSRF)
- 文件上传安全
- 会话管理问题
- 密码安全
- API安全
- 其他安全问题
validations:
required: true
- type: dropdown
id: severity
attributes:
label: 严重程度
description: 请评估安全问题的严重程度
options:
- 严重 - 可能导致系统完全被攻破
- 高 - 可能导致重要数据泄露
- 中 - 可能影响部分用户或功能
- 低 - 轻微的安全改进建议
validations:
required: true
- type: textarea
id: security-summary
attributes:
label: 安全问题概述
description: 简要描述发现的安全问题(避免详细的攻击步骤)
placeholder: 简要说明发现的安全问题类型和影响范围...
validations:
required: true
- type: textarea
id: affected-components
attributes:
label: 受影响的组件
description: 列出可能受到影响的系统组件或功能模块
placeholder: |
例如:
- 用户登录模块
- 文件上传功能
- 管理员面板
- API接口
validations:
required: true
- type: textarea
id: potential-impact
attributes:
label: 潜在影响
description: 描述这个安全问题可能造成的影响
placeholder: |
可能的影响包括:
- 用户数据泄露
- 未授权访问
- 系统功能被滥用
- 其他安全风险
validations:
required: true
- type: textarea
id: reproduction-info
attributes:
label: 复现信息
description: 提供必要的复现信息(请避免详细的攻击步骤)
placeholder: |
请提供:
- 发现问题的环境
- 触发条件
- 观察到的异常行为
注意:请不要提供完整的攻击代码或详细攻击步骤
validations:
required: false
- type: textarea
id: mitigation-suggestions
attributes:
label: 缓解建议
description: 如果您有安全方面的建议,请提供
placeholder: |
可能的解决方案:
- 输入验证改进
- 权限检查加强
- 安全配置调整
- 其他安全措施
validations:
required: false
- type: dropdown
id: disclosure-timeline
attributes:
label: 披露时间线
description: 您希望的问题处理时间线
options:
- 立即处理 - 严重安全问题
- 1周内 - 重要安全问题
- 2周内 - 一般安全问题
- 1个月内 - 安全改进建议
validations:
required: true
- type: textarea
id: additional-info
attributes:
label: 附加信息
description: 其他有助于理解和解决安全问题的信息
placeholder: 相关文档、参考资料、类似案例等...
validations:
required: false
- type: checkboxes
id: security-terms
attributes:
label: 安全报告确认
description: 请确认以下事项
options:
- label: 我理解这是一个安全相关的问题报告
required: true
- label: 我已经避免在公开Issue中透露详细的攻击方法
required: true
- label: 我愿意配合安全团队进行问题验证和修复
required: true
- label: 我同意遵循负责任的安全披露原则
required: true
+125
View File
@@ -0,0 +1,125 @@
# .github/workflows/build-fpk.yml
# VoiceHub 飞牛 fnOS FPK 安装包自动构建
# 手动触发,版本号自动从 package.json 读取
name: Build VoiceHub FPK
on:
push:
branches:
- main
workflow_dispatch:
permissions:
contents: read
jobs:
build-fpk:
if: github.repository == 'laoshuikaixue/VoiceHub' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: 读取版本号 & 安装 fnpack
run: |
# 读取原始版本号
ORIGINAL_VER=$(node -p "require('./package.json').version")
echo "📦 原始版本: $ORIGINAL_VER"
# 转换为三段式版本号 (x.y.zw 格式,将第四段拼接到第三段)
FNOS_VER=$(echo "$ORIGINAL_VER" | awk -F. '{
if (NF >= 4) {
# 四段式版本号,拼接最后两段
printf "%s.%s.%s%s", $1, $2, $3, $4
} else if (NF == 3) {
# 已经是三段式,直接使用
printf "%s.%s.%s", $1, $2, $3
} else {
# 其他情况,保持原样
print $0
}
}')
echo "APP_VER=$FNOS_VER" >> "$GITHUB_ENV"
echo "📦 转换后版本: $FNOS_VER"
wget -q https://static2.fnnas.com/fnpack/fnpack-1.2.1-linux-amd64 -O /usr/local/bin/fnpack
chmod +x /usr/local/bin/fnpack
- name: 创建 FPK 目录
run: |
fnpack create voicehub --template docker
echo "📁 模板结构:"
find voicehub -type f | sort
- name: 写入 manifest & 准备图标
run: |
# 复制仓库中的 fnos 模板
cp -r fnos/* voicehub/
# 从 public 目录复制图标到构建目录
mkdir -p voicehub/app/ui/images
cp public/assets/logo.png voicehub/app/ui/images/icon-64.png
cp public/assets/logo.png voicehub/app/ui/images/icon-256.png
cp public/assets/logo.png voicehub/ICON.PNG
cp public/assets/logo.png voicehub/ICON_256.PNG
# 更新版本号
sed -i "s/^version=.*/version=${APP_VER}/" voicehub/manifest
chmod +x voicehub/cmd/main
echo "✅ manifest, cmd/main & icons 已就绪"
- name: 从仓库读取 docker-compose-prebuild-nju.yml 并写入
run: |
# 从项目根目录读取仓库内的 compose 文件
SRC_COMPOSE="docker-compose/docker-compose-prebuild-nju.yml"
# 目标路径
DST_COMPOSE="voicehub/app/docker/docker-compose.yaml"
# 创建目录
mkdir -p voicehub/app/docker
# 复制内容并进行修改:
# 1. 移除 postgres 服务的端口映射,以避免 fnOS 5432 端口冲突
# 2. 移除 voicehub 服务的代码挂载 (.:/app),避免覆盖镜像内的预构建代码导致 MODULE_NOT_FOUND
# 3. 确保容器间通过 service name 互联
# 直接使用 awk 工具更精确地过滤掉整个 volumes 块和 ports 块中我们不想要的行,或者删除空块
awk '
/^[[:space:]]+volumes:/ { in_volumes=1; print; next }
/^[[:space:]]+ports:/ { in_ports=1; print; next }
/^[[:space:]]+restart:/ { in_volumes=0; in_ports=0; print; next }
/^[[:space:]]+[a-zA-Z0-9_]+:/ { in_volumes=0; in_ports=0; print; next }
in_volumes && /^[[:space:]]+-[[:space:]]+.:\/app/ { next }
in_volumes && /^[[:space:]]+-[[:space:]]+\/app\/node_modules/ { next }
in_ports && /^[[:space:]]+-[[:space:]]+.5432:5432./ { next }
{ print }
' "$SRC_COMPOSE" > "$DST_COMPOSE.tmp"
# 清理由于上述删除可能产生的空的 volumes: 或 ports: 标签
# 使用 grep 检查下一行是否是配置项或空行
sed -E '/^[[:space:]]+volumes:[[:space:]]*$/{N;/\n[[:space:]]+-/!d}' "$DST_COMPOSE.tmp" > "$DST_COMPOSE.tmp2"
sed -E '/^[[:space:]]+ports:[[:space:]]*$/{N;/\n[[:space:]]+-/!d}' "$DST_COMPOSE.tmp2" > "$DST_COMPOSE"
rm "$DST_COMPOSE.tmp" "$DST_COMPOSE.tmp2"
echo "✅ 已处理 compose 文件:移除数据库端口暴露 & 移除应用代码挂载"
cat "$DST_COMPOSE"
- name: 最终目录 & 打包
run: |
echo "📦 FPK 结构:"
find voicehub -type f | sort
echo "---"
cd voicehub
fnpack build
ls -lh *.fpk 2>/dev/null || { echo "❌ 打包失败"; exit 1; }
mv *.fpk ../
- name: 上传 Artifact
uses: actions/upload-artifact@v7
with:
name: voicehub-fpk-${{ env.APP_VER }}
path: "*.fpk"
retention-days: 30
+222
View File
@@ -0,0 +1,222 @@
name: Build and Push Docker Image
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
inputs:
reason:
description: 'Reason for manual trigger'
required: false
default: 'Manual trigger'
env:
REGISTRY: ghcr.io
jobs:
# 阶段1:优先构建并推送 amd64 架构,立即可用
build-amd64:
if: github.repository == 'laoshuikaixue/VoiceHub' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: '0'
- name: Prepare lowercase names
id: names
run: |
echo "image-name=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
echo "actor-name=$(echo '${{ github.actor }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
- name: Extract version from package.json
id: extract-version
run: |
FULL_VERSION=$(node -p "require('./package.json').version")
MAJOR_MINOR_VERSION=$(echo "$FULL_VERSION" | sed -E 's/^([0-9]+\.[0-9]+)\.[0-9]+$/\1/')
echo "full-version=$FULL_VERSION" >> $GITHUB_OUTPUT
echo "major-minor-version=$MAJOR_MINOR_VERSION" >> $GITHUB_OUTPUT
echo "Extracted full version: $FULL_VERSION"
echo "Extracted major.minor version: $MAJOR_MINOR_VERSION"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Log in to the Container registry
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ steps.names.outputs.actor-name }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ steps.names.outputs.image-name }}
tags: |
# 正式标签 - amd64 构建完成后立即可用
type=raw,value=latest,enable={{is_default_branch}}
type=ref,event=branch
type=ref,event=pr
type=raw,value=${{ steps.extract-version.outputs.full-version }}
type=raw,value=${{ steps.extract-version.outputs.major-minor-version }}
# 架构后缀标签 - 用于后续多架构合并
type=raw,value=latest-amd64,enable={{is_default_branch}}
type=raw,value=${{ steps.extract-version.outputs.full-version }}-amd64
type=raw,value=${{ steps.extract-version.outputs.major-minor-version }}-amd64
- name: Build and push amd64 image
uses: docker/build-push-action@v7
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64
cache-from: type=gha,scope=amd64
cache-to: type=gha,mode=max,scope=amd64
# 阶段2:并行构建其余架构,各自推送带后缀的独立标签
build-other-arches:
if: github.repository == 'laoshuikaixue/VoiceHub' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
matrix:
arch:
- { platform: linux/arm64, suffix: -arm64 }
- { platform: linux/arm/v7, suffix: -armv7 }
- { platform: linux/arm/v6, suffix: -armv6 }
- { platform: linux/ppc64le, suffix: -ppc64le }
- { platform: linux/s390x, suffix: -s390x }
fail-fast: false
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: '0'
- name: Prepare lowercase names
id: names
run: |
echo "image-name=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
echo "actor-name=$(echo '${{ github.actor }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
- name: Extract version from package.json
id: extract-version
run: |
FULL_VERSION=$(node -p "require('./package.json').version")
MAJOR_MINOR_VERSION=$(echo "$FULL_VERSION" | sed -E 's/^([0-9]+\.[0-9]+)\.[0-9]+$/\1/')
echo "full-version=$FULL_VERSION" >> $GITHUB_OUTPUT
echo "major-minor-version=$MAJOR_MINOR_VERSION" >> $GITHUB_OUTPUT
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Log in to the Container registry
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ steps.names.outputs.actor-name }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ steps.names.outputs.image-name }}
tags: |
type=raw,value=latest${{ matrix.arch.suffix }},enable={{is_default_branch}}
type=raw,value=${{ steps.extract-version.outputs.full-version }}${{ matrix.arch.suffix }}
type=raw,value=${{ steps.extract-version.outputs.major-minor-version }}${{ matrix.arch.suffix }}
- name: Build and push ${{ matrix.arch.platform }} image
uses: docker/build-push-action@v7
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: ${{ matrix.arch.platform }}
cache-from: type=gha,scope=${{ matrix.arch.suffix }}
cache-to: type=gha,mode=max,scope=${{ matrix.arch.suffix }}
# 阶段3:所有架构构建完成后,合并为多架构 manifest 清单并推送正式标签
merge-manifests:
if: (github.repository == 'laoshuikaixue/VoiceHub' || github.event_name == 'workflow_dispatch') && github.event_name != 'pull_request'
runs-on: ubuntu-latest
needs: [build-amd64, build-other-arches]
permissions:
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Prepare lowercase names
id: names
run: |
echo "image-name=$(echo '${{ github.repository }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
echo "actor-name=$(echo '${{ github.actor }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
- name: Extract version from package.json
id: extract-version
run: |
FULL_VERSION=$(node -p "require('./package.json').version")
MAJOR_MINOR_VERSION=$(echo "$FULL_VERSION" | sed -E 's/^([0-9]+\.[0-9]+)\.[0-9]+$/\1/')
echo "full-version=$FULL_VERSION" >> $GITHUB_OUTPUT
echo "major-minor-version=$MAJOR_MINOR_VERSION" >> $GITHUB_OUTPUT
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Log in to the Container registry
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ steps.names.outputs.actor-name }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create and push multi-architecture manifest lists
env:
IMAGE_BASE: ${{ env.REGISTRY }}/${{ steps.names.outputs.image-name }}
FULL_VER: ${{ steps.extract-version.outputs.full-version }}
MAJOR_MINOR_VER: ${{ steps.extract-version.outputs.major-minor-version }}
run: |
# 所有架构后缀列表
ARCH_SUFFIXES=("-amd64" "-arm64" "-armv7" "-armv6" "-ppc64le" "-s390x")
# 生成指定标签的所有架构镜像参数
build_arch_args() {
local tag=$1
local args=""
for suffix in "${ARCH_SUFFIXES[@]}"; do
args="$args ${IMAGE_BASE}:${tag}${suffix}"
done
echo "$args"
}
# 合并 latest 标签(仅默认分支)
if [ "${{ github.ref == 'refs/heads/main' }}" = "true" ]; then
echo "Merging multi-arch manifest for latest tag"
docker buildx imagetools create -t "${IMAGE_BASE}:latest" $(build_arch_args "latest")
fi
# 合并完整版本号标签
echo "Merging multi-arch manifest for ${FULL_VER} tag"
docker buildx imagetools create -t "${IMAGE_BASE}:${FULL_VER}" $(build_arch_args "${FULL_VER}")
# 合并主次版本号标签
echo "Merging multi-arch manifest for ${MAJOR_MINOR_VER} tag"
docker buildx imagetools create -t "${IMAGE_BASE}:${MAJOR_MINOR_VER}" $(build_arch_args "${MAJOR_MINOR_VER}")
+79
View File
@@ -0,0 +1,79 @@
name: Build and Push PostgreSQL Docker Image
on:
push:
branches: [main]
paths:
- 'Dockerfile-postgres'
- '.github/workflows/docker-postgres.yml'
workflow_dispatch:
inputs:
reason:
description: 'Reason for manual trigger'
required: false
default: 'Manual trigger'
env:
REGISTRY: ghcr.io
jobs:
build-and-push:
if: github.repository == 'laoshuikaixue/VoiceHub' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: '0'
# 转换仓库名、用户名全小写,解决GHCR大写报错
- name: Generate lowercase image & actor name
id: lowercase
run: |
REPO_LOWER=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
ACTOR_LOWER=$(echo "${{ github.actor }}" | tr '[:upper:]' '[:lower:]')
IMAGE_FULL="${REPO_LOWER}-postgres"
echo "repo_lower=$REPO_LOWER" >> $GITHUB_OUTPUT
echo "actor_lower=$ACTOR_LOWER" >> $GITHUB_OUTPUT
echo "image_name=$IMAGE_FULL" >> $GITHUB_OUTPUT
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Log in to the Container registry
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ steps.lowercase.outputs.actor_lower }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ steps.lowercase.outputs.image_name }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=raw,value=15-alpine,enable={{is_default_branch}}
- name: Build and push PostgreSQL Docker image
id: build-and-push
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile-postgres
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v6,linux/ppc64le,linux/s390x,linux/386,linux/riscv64
cache-from: type=gha
cache-to: type=gha,mode=max
provenance: false
sbom: false
+32
View File
@@ -0,0 +1,32 @@
name: Nix CI
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
workflow_dispatch:
jobs:
nix-check:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Nix
uses: DeterminateSystems/determinate-nix-action@v3
- name: Setup Cachix binary cache
uses: cachix/cachix-action@v14
with:
name: voicehub
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- name: Run nix flake check
run: nix flake check
- name: Build voicehub (validate hashes)
run: nix build .#voicehub
+110
View File
@@ -0,0 +1,110 @@
name: 更新 Nix pnpm 依赖哈希
on:
push:
paths:
- pnpm-lock.yaml
- flake.nix
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths:
- pnpm-lock.yaml
- flake.nix
workflow_dispatch:
permissions:
contents: write
concurrency:
group: update-nix-pnpm-hash-${{ github.event_name == 'pull_request' && github.event.pull_request.head.ref || github.ref_name }}
cancel-in-progress: true
jobs:
update-hash:
name: 同步 pnpmDeps 哈希
if: github.actor != 'github-actions[bot]' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
runs-on: ubuntu-latest
env:
TARGET_BRANCH: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.ref || github.ref_name }}
CHECKOUT_REPOSITORY: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name || github.repository }}
steps:
- name: 检出触发分支
uses: actions/checkout@v4
with:
repository: ${{ env.CHECKOUT_REPOSITORY }}
ref: ${{ env.TARGET_BRANCH }}
- name: 安装 Nix
uses: DeterminateSystems/determinate-nix-action@v3
- name: 配置 Git 提交身份
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: 计算 pnpmDeps 哈希
shell: bash
run: |
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
path = Path("flake.nix")
text = path.read_text(encoding="utf-8")
marker = "pnpmDeps = pkgs.fetchPnpmDeps {"
start = text.index(marker)
key = 'hash = "'
hash_start = text.index(key, start) + len(key)
hash_end = text.index('"', hash_start)
path.write_text(text[:hash_start] + text[hash_end:], encoding="utf-8")
PY
set +e
nix build .#voicehub --no-link 2>&1 | tee nix-build.log
status="${PIPESTATUS[0]}"
set -e
if [ "$status" -eq 0 ]; then
echo "Nix 构建在空哈希下意外成功,无法提取新的 pnpmDeps 哈希。"
exit 1
fi
new_hash="$(grep -Eo 'got:[[:space:]]+sha256-[A-Za-z0-9+/=_-]+' nix-build.log | tail -n 1 | sed -E 's/got:[[:space:]]+//')"
if [ -z "$new_hash" ]; then
echo "没有在 Nix 输出中找到 got: sha256-...,请查看上方日志。"
exit 1
fi
HASH="$new_hash" python3 - <<'PY'
import os
from pathlib import Path
new_hash = os.environ["HASH"]
path = Path("flake.nix")
text = path.read_text(encoding="utf-8")
marker = "pnpmDeps = pkgs.fetchPnpmDeps {"
start = text.index(marker)
key = 'hash = "'
hash_start = text.index(key, start) + len(key)
hash_end = text.index('"', hash_start)
path.write_text(text[:hash_start] + new_hash + text[hash_end:], encoding="utf-8")
PY
echo "新的 pnpmDeps 哈希: $new_hash"
- name: 提交哈希更新
shell: bash
run: |
set -euo pipefail
if git diff --quiet -- flake.nix; then
echo "pnpmDeps 哈希已经是最新,无需提交。"
exit 0
fi
git add flake.nix
git commit -m "ci: 同步 pnpmDeps 哈希"
git push origin "HEAD:${TARGET_BRANCH}"