diff --git a/.github/workflows/build-docker-image.yml b/.github/workflows/build-docker-image.yml index 11c0f2f3..b0615209 100644 --- a/.github/workflows/build-docker-image.yml +++ b/.github/workflows/build-docker-image.yml @@ -405,151 +405,6 @@ jobs: cache-from: type=registry,ref=whyour/qinglong:cache-debian cache-to: type=registry,ref=whyour/qinglong:cache-debian,mode=max - build-alpine310: - if: ${{ github.ref_name == 'master' }} - needs: build-static - runs-on: ubuntu-22.04 - permissions: - packages: write - contents: read - steps: - - uses: actions/checkout@v6 - - uses: actions/download-artifact@v7 - with: - name: qinglong-static-${{ github.sha }} - path: static/ - - uses: pnpm/action-setup@v6 - with: - version: "8.3.1" - - uses: actions/setup-node@v6 - with: - node-version: "24" - cache: "pnpm" - cache-dependency-path: pnpm-lock.yaml - - - name: Read version from version.yaml - id: version - run: | - VERSION=$(grep '^version:' version.yaml | awk '{print $2}') - echo "version=$VERSION" >> $GITHUB_OUTPUT - - - name: Setup timezone - run: sudo timedatectl set-timezone Asia/Shanghai - - - name: Login to DockerHub - uses: docker/login-action@v4 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Login to GHCR - uses: docker/login-action@v4 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Set up QEMU - uses: docker/setup-qemu-action@v4 - with: - cache-image: false - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Build and push (Alpine Python 3.10) - uses: docker/build-push-action@v7 - with: - build-args: | - QL_MAINTAINER=${{ github.repository_owner }} - QL_BRANCH=${{ github.ref_name }} - SOURCE_COMMIT=${{ github.sha }} - network: host - platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x,linux/386 - context: . - file: ./docker/Dockerfile.310 - push: true - provenance: mode=max - sbom: true - tags: | - whyour/qinglong:python3.10 - whyour/qinglong:${{ steps.version.outputs.version }}-python3.10 - cache-from: type=registry,ref=whyour/qinglong:cache-alpine-python3.10 - cache-to: type=registry,ref=whyour/qinglong:cache-alpine-python3.10,mode=max - - build-debian310: - if: ${{ github.ref_name == 'master' }} - needs: build-static - runs-on: ubuntu-22.04 - permissions: - packages: write - contents: read - steps: - - uses: actions/checkout@v6 - - uses: actions/download-artifact@v7 - with: - name: qinglong-static-${{ github.sha }} - path: static/ - - uses: pnpm/action-setup@v6 - with: - version: "8.3.1" - - uses: actions/setup-node@v6 - with: - node-version: "24" - cache: "pnpm" - cache-dependency-path: pnpm-lock.yaml - - - name: Read version from version.yaml - id: version - run: | - VERSION=$(grep '^version:' version.yaml | awk '{print $2}') - echo "version=$VERSION" >> $GITHUB_OUTPUT - - - name: Setup timezone - run: sudo timedatectl set-timezone Asia/Shanghai - - - name: Login to DockerHub - uses: docker/login-action@v4 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Login to GHCR - uses: docker/login-action@v4 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Set up QEMU - uses: docker/setup-qemu-action@v4 - with: - cache-image: false - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Build and push (Debian Python 3.10) - uses: docker/build-push-action@v7 - with: - build-args: | - QL_MAINTAINER=${{ github.repository_owner }} - QL_BRANCH=${{ github.ref_name }} - SOURCE_COMMIT=${{ github.sha }} - network: host - # Keep s390x on Debian: npm can hang under QEMU with Alpine (nodejs/docker-node#1973). - platforms: linux/amd64,linux/arm64,linux/ppc64le,linux/s390x - context: . - file: ./docker/Dockerfile.debian310 - push: true - provenance: mode=max - sbom: true - tags: | - whyour/qinglong:debian-python3.10 - whyour/qinglong:${{ steps.version.outputs.version }}-debian-python3.10 - cache-from: type=registry,ref=whyour/qinglong:cache-debian-python3.10 - cache-to: type=registry,ref=whyour/qinglong:cache-debian-python3.10,mode=max - # One unmodified amd64 package for migration acceptance only. This does not # publish bundles or advance development/formal channel indexes. build-npm-migration-bundle: @@ -616,7 +471,7 @@ jobs: publish: if: ${{ github.repository == 'whyour/qinglong' && github.ref == 'refs/heads/master' }} - needs: [build-alpine, build-debian, build-alpine310, build-debian310, verify-npm-package] + needs: [build-alpine, build-debian, verify-npm-package] runs-on: ubuntu-latest permissions: contents: read @@ -652,7 +507,7 @@ jobs: jq -e --arg version "$version" '. == $version' "$RUNNER_TEMP/npm-version.json" > /dev/null echo "::notice::$name@$version is already published; skipping npm publication for this image rebuild." elif jq -e '.error.code == "E404"' "$RUNNER_TEMP/npm-version.json" > /dev/null; then - npm publish "$archive" --ignore-scripts --access public --registry=https://registry.npmjs.org + npm publish "./$archive" --ignore-scripts --access public --registry=https://registry.npmjs.org else echo '::error::Could not check the published npm version; refusing to publish.' exit 1 diff --git a/.github/workflows/release-readiness.yml b/.github/workflows/release-readiness.yml index cf7a2535..9c120a37 100644 --- a/.github/workflows/release-readiness.yml +++ b/.github/workflows/release-readiness.yml @@ -70,14 +70,6 @@ jobs: file: docker/Dockerfile.debian cache: debian platforms: linux/amd64,linux/arm64,linux/ppc64le,linux/s390x - - image: alpine-python3.10 - file: docker/Dockerfile.310 - cache: alpine-python3.10 - platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x,linux/386 - - image: debian-python3.10 - file: docker/Dockerfile.debian310 - cache: debian-python3.10 - platforms: linux/amd64,linux/arm64,linux/ppc64le,linux/s390x steps: - uses: actions/checkout@v6 with: diff --git a/docs/releases/2.24.0.md b/docs/releases/2.24.0.md new file mode 100644 index 00000000..ab81ab6d --- /dev/null +++ b/docs/releases/2.24.0.md @@ -0,0 +1,23 @@ +# 青龙 2.24.0 + +## 新增功能 + +- Node.js 原生部署支持 Python venv 隔离环境。Python 依赖可使用包名、Git URL,以及位于脚本或订阅仓库中的 requirements 文件和 pyproject.toml;拉取订阅不会自动安装仓库声明的依赖。 +- 新增通知审计日志,便于查看通知发送结果和失败原因。 +- 提供经过平台校验的升级包,支持在线暂存、离线安装及失败回退。升级过程保留账号、配置、环境变量、任务和脚本等数据。 + +## 修复与优化 + +- 默认 Alpine 与 Debian 镜像统一使用 Node.js 24;SQLite 依赖升级至 1.1.4。ARM64 升级包使用原生构建环境。 +- 修复额外调度规则校验、单实例任务运行期间的新触发排队、订阅同步、Python 依赖安装与脚本发现等问题。 +- 修复系统日志清理时活跃日志文件被移除、页面加载时序和升级流程中的异常情况,并补齐相关中英文提示。 +- 独立远程 CLI 更新至 0.1.3,最低 Node.js 版本为 22.12.0。 + +## 镜像与升级提醒 + +- `2.24.0` 的 Alpine 镜像支持 amd64、arm/v6、arm/v7、arm64、ppc64le、s390x 和 386;`2.24.0-debian` 支持 amd64、arm64、ppc64le 和 s390x。Debian 暂不提供 arm/v7。 +- 2.23.0 是 Python 3.10 兼容镜像的最后一个版本;2.24.0 不再更新该变体。需要 Python 3.10 的用户请先评估迁移方案。 +- 升级前停止任务并备份完整持久化数据目录,记录原镜像摘要和启动配置。升级后检查脚本、依赖、订阅与通知;如需回退,请同时恢复与旧版本匹配的数据备份。 +- 主 npm 包 `@whyour/qinglong` 与独立远程 CLI 包 `@whyour/qinglong-cli` 均提供 `ql` 命令。在已有面板的主机上安装远程 CLI 时,使用独立 npm prefix 或 `npm exec --package=@whyour/qinglong-cli -- ql ...`,避免覆盖面板内置入口。 + +本版本以 2.23.0 为上一正式版本。开发候选的源码、npm 包与 11 个发布镜像架构已完成隔离验收;正式产物发布后仍以各目标渠道的实际构建结果为准。 diff --git a/package.json b/package.json index 53b5a2d0..01bb5d41 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@whyour/qinglong", "packageManager": "pnpm@8.3.1", - "version": "2.24.0-dev.0", + "version": "2.24.0", "description": "Timed task management platform supporting Python3, JavaScript, Shell, Typescript", "repository": { "type": "git", diff --git a/test/back/build-provenance.test.cjs b/test/back/build-provenance.test.cjs index d473f3b1..d9005615 100644 --- a/test/back/build-provenance.test.cjs +++ b/test/back/build-provenance.test.cjs @@ -51,8 +51,6 @@ test('release images receive the same-run artifact and verify it before use', () for (const name of [ 'build-alpine', 'build-debian', - 'build-alpine310', - 'build-debian310', ]) { const job = workflow.jobs[name]; assert.equal(job.needs, 'build-static'); diff --git a/test/back/mirror-status.test.cjs b/test/back/mirror-status.test.cjs index d9beff5a..31180604 100644 --- a/test/back/mirror-status.test.cjs +++ b/test/back/mirror-status.test.cjs @@ -273,8 +273,6 @@ test('Gitee workflows verify both mirrors and do not gate image publication', () for (const name of [ 'build-alpine', 'build-debian', - 'build-alpine310', - 'build-debian310', ]) { assert.equal(workflow.jobs[name].needs, 'build-static'); } diff --git a/test/back/npm-package.test.cjs b/test/back/npm-package.test.cjs index e6023506..6a0d0f35 100644 --- a/test/back/npm-package.test.cjs +++ b/test/back/npm-package.test.cjs @@ -220,7 +220,7 @@ test('npm publication consumes the exact archive whose isolated installation pas const download = workflow.jobs.publish.steps.find((step) => step.uses?.startsWith('actions/download-artifact@')); assert.equal(download.with.name, 'qinglong-npm-${{ github.sha }}'); const publication = workflow.jobs.publish.steps.find((step) => step.name === 'Publish npm package with OIDC'); - assert.match(publication.run, /npm publish "\$archive" --ignore-scripts/); + assert.match(publication.run, /npm publish "\.\/\$archive" --ignore-scripts/); assert.ok(!workflow.jobs.publish.steps.some((step) => /pnpm build/.test(step.run || ''))); }); diff --git a/test/back/npm-publication.test.cjs b/test/back/npm-publication.test.cjs index b61a10a6..9bae1213 100644 --- a/test/back/npm-publication.test.cjs +++ b/test/back/npm-publication.test.cjs @@ -12,12 +12,10 @@ const publication = workflow.jobs.publish.steps.find( (step) => step.name === 'Publish npm package with OIDC', ).run; -test('npm publication waits for every release image, including Python 3.10', () => { +test('npm publication waits for every supported release image', () => { for (const name of [ 'build-alpine', 'build-debian', - 'build-alpine310', - 'build-debian310', ]) assert.ok(workflow.jobs.publish.needs.includes(name), name); }); @@ -77,7 +75,7 @@ case 'network': console.log('upstream unavailable'); process.exit(1); assert.equal(fs.existsSync(path.join(root, 'published')), published); if (published) assert.deepEqual(JSON.parse(fs.readFileSync(path.join(root, 'published'), 'utf8')), [ - 'npm-panel/verified.tgz', '--ignore-scripts', '--access', 'public', '--registry=https://registry.npmjs.org', + './npm-panel/verified.tgz', '--ignore-scripts', '--access', 'public', '--registry=https://registry.npmjs.org', ]); }); } diff --git a/test/back/static-mirror.test.cjs b/test/back/static-mirror.test.cjs index 75085ea8..11863318 100644 --- a/test/back/static-mirror.test.cjs +++ b/test/back/static-mirror.test.cjs @@ -225,8 +225,6 @@ test('static backfill uses existing snapshots and skips all source, build and im 'verify-gitee-mirrors', 'build-alpine', 'build-debian', - 'build-alpine310', - 'build-debian310', ]) { assert.equal(workflow.jobs[name].needs, 'build-static'); assert.doesNotMatch(workflow.jobs[name].if || '', /always\(/); diff --git a/version.yaml b/version.yaml index dfd071a7..84bdbe42 100644 --- a/version.yaml +++ b/version.yaml @@ -1,9 +1,12 @@ -version: 2.24.0-dev.0 -changeLogLink: https://github.com/whyour/qinglong/blob/develop/docs/releases/2.24.0-dev.0.md -publishTime: "2026-10-25 19:22:54" +version: 2.24.0 +changeLogLink: https://github.com/whyour/qinglong/blob/v2.24.0/docs/releases/2.24.0.md +publishTime: "2026-10-29 02:14:58" changeLog: | - 1. 开发候选 2.24.0-dev.0,尚未正式发布;以 2.23.0 为上一正式版本 - 2. Alpine 与 Debian 镜像统一使用 Node.js 24,升级 sqlite3 至 1.1.4 - 3. Alpine 保留 arm/v6 和 arm/v7;Debian 暂不提供 arm/v7 镜像 - 4. ARM64 升级包在原生 runner 构建,避免 x64 QEMU 下的归档异常 - 5. 升级前备份完整数据,并在目标设备验证脚本、依赖和通知 + 1. Alpine 与 Debian 默认镜像统一使用 Node.js 24,SQLite 依赖升级至 1.1.4 + 2. 新增 Node.js 原生部署的 Python venv 隔离支持,以及 Python Git URL、requirements、pyproject 依赖源 + 3. 新增通知审计日志,完善通知失败记录与配置提示 + 4. 升级包按平台构建并校验;支持在线暂存、离线安装、失败回退及保留数据迁移 + 5. 修复任务调度、额外规则、依赖安装、脚本发现和订阅同步等问题 + 6. 独立远程 CLI 更新至 0.1.3,最低 Node.js 版本为 22.12.0 + 7. Alpine 保留 arm/v6 和 arm/v7;Debian 暂不提供 arm/v7,Python 3.10 兼容镜像停止更新 + 8. 升级前备份完整数据,并在目标设备验证脚本、依赖、订阅和通知