Skip to content

fix: 修复 gmqtt 挂载导致 gmqttd 丢失,并发布离线镜像包 #16

fix: 修复 gmqtt 挂载导致 gmqttd 丢失,并发布离线镜像包

fix: 修复 gmqtt 挂载导致 gmqttd 丢失,并发布离线镜像包 #16

Workflow file for this run

name: Release — Build & Publish Installers
on:
push:
tags:
- 'v*.*.*' # 正式版本:v1.2.0
- 'v*.*.*.*' # 子版本:v1.1.13.6
workflow_dispatch:
inputs:
version:
description: "版本号(如 v1.2.0)"
required: true
type: string
push_latest:
description: "同时更新 latest 标签"
required: false
default: true
type: boolean
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
env:
REGISTRY: registry.cn-hangzhou.aliyuncs.com/thingspanel
jobs:
# ── 确定版本号 ──────────────────────────────────────────────────────────────
prepare:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- id: version
name: Resolve version
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
VERSION="${{ inputs.version }}"
else
VERSION="${GITHUB_REF_NAME}"
fi
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "Version: ${VERSION}"
# ── 验证 docker-compose.yml 语法 ───────────────────────────────────────────
validate:
runs-on: ubuntu-latest
needs: prepare
steps:
- uses: actions/checkout@v4
- name: Create test .env
run: |
cat > .env << 'EOF'
POSTGRES_PASSWORD=test_pg_pass
REDIS_PASSWORD=test_redis_pass
AUTH_SECRET=test_auth_secret_minimum_32_chars_long
TP_VERSION=${{ needs.prepare.outputs.version }}
TP_VUE_VERSION=${{ needs.prepare.outputs.version }}
TP_BACKEND_VERSION=${{ needs.prepare.outputs.version }}
TP_GMQTT_VERSION=v1.1.6
TP_REDIS_VERSION=6.2.7
TP_MODBUS_VERSION=v1.0.6.1
TP_HTTP_ADAPTER_VERSION=v1.0.0
TP_THINGSVIS_SERVER_VERSION=v1.0.4
TP_THINGSVIS_STUDIO_VERSION=v1.0.4
TP_TIMESCALEDB_VERSION=14
DATA_DIR=./data
HTTP_PORT=8080
MQTT_PORT=1883
MODBUS_TCP_PORT=502
MODBUS_RTU_PORT=503
TZ=Asia/Shanghai
TP_LOG_LEVEL=error
EOF
- name: Validate docker-compose syntax
run: docker compose config --quiet
- name: Check script syntax (bash)
run: |
bash -n install.sh
bash -n upgrade.sh
bash -n uninstall.sh
# ── 构建 Windows 安装包 ─────────────────────────────────────────────────────
# ── 镜像推送到 GHCR (可选) ──────────────────────────────────────────────────
# ── 镜像推送到 GHCR (可选) 以及打包离线镜像 ──────────────────────────────────
sync-ghcr-and-package:
runs-on: ubuntu-latest
needs: prepare
permissions:
packages: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Create .env
run: |
cat > .env << 'ENDEOF'
POSTGRES_PASSWORD=1
REDIS_PASSWORD=1
AUTH_SECRET=1
TP_VERSION=${{ needs.prepare.outputs.version }}
TP_VUE_VERSION=${{ needs.prepare.outputs.version }}
TP_BACKEND_VERSION=${{ needs.prepare.outputs.version }}
TP_GMQTT_VERSION=v1.1.6
TP_REDIS_VERSION=6.2.7
TP_MODBUS_VERSION=v1.0.6.1
TP_HTTP_ADAPTER_VERSION=v1.0.0
TP_THINGSVIS_SERVER_VERSION=v1.0.4
TP_THINGSVIS_STUDIO_VERSION=v1.0.4
TP_TIMESCALEDB_VERSION=14
DATA_DIR=./data
DOCKER_REGISTRY=registry.cn-hangzhou.aliyuncs.com
ENDEOF
- name: Use Aliyun to list images
run: |
docker compose config --images > images.txt
cat images.txt
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GHCR_TOKEN || secrets.GITHUB_TOKEN }}
- name: Pull and Push to GHCR
run: |
while read img; do
docker pull "$img"
if [[ "$img" == *"registry.cn-hangzhou.aliyuncs.com"* ]]; then
ghcr_img=$(echo "$img" | sed 's/registry.cn-hangzhou.aliyuncs.com/ghcr.io/g')
docker tag "$img" "$ghcr_img"
docker push "$ghcr_img" || echo "Failed to push $ghcr_img but continuing..."
else
echo "Skip pushing $img to GHCR (not an Aliyun registry image)"
fi
done < images.txt
- name: Package Offline Images
run: |
docker save $(cat images.txt) -o images.tar
- name: Upload images.tar artifact
uses: actions/upload-artifact@v4
with:
name: docker-images-tar
path: images.tar
retention-days: 1
build-windows:
runs-on: windows-latest
needs: [prepare, validate, sync-ghcr-and-package]
steps:
- uses: actions/checkout@v4
- name: Install Inno Setup
run: choco install innosetup --no-progress -y
- name: Create placeholder icon (if not exists)
shell: pwsh
run: |
$iconDir = "packaging\windows\assets"
if (-not (Test-Path "$iconDir\thingspanel.ico")) {
Copy-Item "$env:SystemRoot\System32\shell32.dll" "$iconDir\thingspanel.ico" -ErrorAction SilentlyContinue || $true
}
if (-not (Test-Path "$iconDir\sidebar.bmp")) {
[System.IO.File]::WriteAllBytes("$iconDir\sidebar.bmp", [byte[]]@(66,77,58,0,0,0,0,0,0,0,54,0,0,0,40,0,0,0,1,0,0,0,1,0,0,0,1,0,24,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0))
}
- name: Download images.tar artifact
uses: actions/download-artifact@v4
with:
name: docker-images-tar
path: .
- name: Build Windows installer
shell: cmd
env:
TP_VERSION: ${{ needs.prepare.outputs.version }}
run: |
mkdir dist\windows 2>nul || true
"C:\Program Files (x86)\Inno Setup 6\ISCC.exe" /DTP_VERSION=%TP_VERSION% packaging\windows\ThingsPanel-Setup.iss
- name: Upload Windows artifact
uses: actions/upload-artifact@v4
with:
name: windows-installer
path: dist/windows/ThingsPanel-Setup-*.exe
retention-days: 7
build-macos:
runs-on: macos-latest
needs: [prepare, validate, sync-ghcr-and-package]
steps:
- uses: actions/checkout@v4
- name: Create placeholder resources (if not exists)
run: |
mkdir -p packaging/macos/resources
[ -f packaging/macos/resources/welcome.html ] || echo "<html><body><h2>欢迎安装 ThingsPanel</h2></body></html>" > packaging/macos/resources/welcome.html
[ -f packaging/macos/resources/readme.html ] || echo "<html><body><h2>说明</h2><p>ThingsPanel 是一个开...</p></body></html>" > packaging/macos/resources/readme.html
[ -f packaging/macos/resources/license.html ] || echo "<html><body><h2>许可证</h2><p>Apache 2.0</p></body></html>" > packaging/macos/resources/license.html
[ -f packaging/macos/resources/conclusion.html ] || echo "<html><body><h2>安装完成</h2><p>访问 http://localhost:8080</p></body></html>" > packaging/macos/resources/conclusion.html
[ -f packaging/macos/resources/background.png ] || echo "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" | base64 -d > packaging/macos/resources/background.png
- name: Make scripts executable
run: |
chmod +x packaging/macos/build.sh
chmod +x packaging/macos/scripts/preinstall
chmod +x packaging/macos/scripts/postinstall
- name: Download images.tar artifact
uses: actions/download-artifact@v4
with:
name: docker-images-tar
path: .
- name: Build macOS installer
env:
TP_VERSION: ${{ needs.prepare.outputs.version }}
run: ./packaging/macos/build.sh
- name: Upload macOS artifact
uses: actions/upload-artifact@v4
with:
name: macos-installer
path: dist/macos/ThingsPanel-*.pkg
retention-days: 7
release:
runs-on: ubuntu-latest
needs: [prepare, build-windows, build-macos]
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Download Windows installer
uses: actions/download-artifact@v4
with:
name: windows-installer
path: dist/windows
- name: Download macOS installer
uses: actions/download-artifact@v4
with:
name: macos-installer
path: dist/macos
- name: Download offline images.tar
uses: actions/download-artifact@v4
with:
name: docker-images-tar
path: dist
- name: Generate SHA256 checksums
run: |
cd dist
touch SHA256SUMS.txt
find . -type f \( -name "*.exe" -o -name "*.pkg" -o -name "images.tar" \) | sort | while read f; do
sha256sum "$f" >> SHA256SUMS.txt
done
cat SHA256SUMS.txt
- name: Create Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.prepare.outputs.version }}
name: "ThingsPanel All-in-One ${{ needs.prepare.outputs.version }}"
body: |
## ThingsPanel All-in-One ${{ needs.prepare.outputs.version }}
### 快速安装
**Linux / macOS(推荐)**
```bash
curl -fsSL https://raw.githubusercontent.com/ThingsPanel/all-in-one-assembler/main/install.sh | sh
```
**Windows**
下载下方 `ThingsPanel-Setup-*.exe`,右键"以管理员身份运行"。
**macOS(图形界面)**
下载下方 `ThingsPanel-*.pkg`,双击安装。
### 前置要求
- Docker Desktop(Windows / macOS)或 Docker Engine(Linux)
- 内存 ≥ 2GB
### 文件说明
| 文件 | 平台 | 说明 |
|------|------|------|
| `ThingsPanel-Setup-*.exe` | Windows | Inno Setup 安装向导 |
| `ThingsPanel-*.pkg` | macOS | macOS 安装包 |
| `images.tar` | Windows/Linux/macOS | 离线 Docker 镜像包(可选,放到安装目录后会自动 `docker load`) |
| `install.sh` | Linux/macOS | 一行命令安装脚本 |
draft: false
prerelease: ${{ contains(needs.prepare.outputs.version, 'rc') || contains(needs.prepare.outputs.version, 'beta') }}
files: |
dist/windows/*.exe
dist/macos/*.pkg
dist/images.tar
dist/SHA256SUMS.txt