diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8fead57..ca733fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,10 +4,11 @@ on: branches: [master] pull_request: workflow_dispatch: + workflow_call: permissions: contents: read concurrency: - group: ci-${{ github.ref }} + group: ci-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: test: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..de0c2dc --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,64 @@ +name: Publish to PyPI +on: + workflow_dispatch: + inputs: + version: + description: Version to publish (must match the source) + required: true + type: string +permissions: + contents: read +concurrency: + group: pypi-release + cancel-in-progress: false +jobs: + test: + if: github.ref == 'refs/heads/master' + uses: ./.github/workflows/ci.yml + build: + needs: test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.14' + - name: Verify requested version + env: + RELEASE_VERSION: ${{ inputs.version }} + run: | + python - <<'PY' + import os, runpy + version = runpy.run_path('cloudmusic/__version__.py')['__version__'] + assert version == os.environ['RELEASE_VERSION'], 'Requested version differs from source' + PY + - run: python -m pip install build twine + - run: python -m build + - run: python -m twine check --strict dist/* + - name: Verify isolated wheel installation + env: + RELEASE_VERSION: ${{ inputs.version }} + run: | + python -m venv /tmp/cloudmusic-release + /tmp/cloudmusic-release/bin/pip install dist/*.whl + cd /tmp + /tmp/cloudmusic-release/bin/python -c "import os, cloudmusic; from importlib.metadata import version; assert cloudmusic.__version__ == version('cloudmusic') == os.environ['RELEASE_VERSION']" + - uses: actions/upload-artifact@v4 + with: + name: distributions + path: dist/ + if-no-files-found: error + publish: + needs: build + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/project/cloudmusic/ + permissions: + id-token: write + steps: + - uses: actions/download-artifact@v4 + with: + name: distributions + path: dist/ + - uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/README.md b/README.md index 479a714..d17488a 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,16 @@ 支持 Python 3.10–3.14。保留 `getMusic()`、`getPlaylist()`、`search()` 等原有调用方式。 -> 仓库维护版本为 **0.2.0**。在发布到 PyPI 之前,`pip install cloudmusic` 仍可能安装旧的 0.1.1。请按下面的源码安装方式使用当前版本。历史 HTML/PDF 文档对应 0.1.1,当前接口以本 README 为准。 +> 当前维护版本为 **0.2.0**。历史 HTML/PDF 文档对应 0.1.1,当前接口以本 README 为准。 ## 安装 +```bash +python -m pip install --upgrade cloudmusic +``` + +也可以从源码安装: + ```bash git clone https://github.com/p697/cloudmusic.git cd cloudmusic @@ -181,7 +187,12 @@ python -m pytest --live --cookie-env NETEASE_COOKIE -m live -v --tb=short - 下载默认沿用对象品质;明确传入 `level="standard"` 时会请求该品质。 - 错误不再以字符串、打印信息、`None` 或意外 `KeyError` 混合返回;请处理相应异常。 - `query.py` 内部旧 HTML 抓取函数已移除。内部模块不是稳定 API。 -- 尚未自动发布到 PyPI。 + +## 发布维护版本 + +维护者在 GitHub Actions 手动运行 `Publish to PyPI`,选择 `master` 并填写与源码一致的版本号。流程先执行跨平台 CI,再构建、检查和独立安装分发包,最后通过 PyPI Trusted Publishing 上传;无需保存长期 API token。 + +PyPI 的可信发布者配置为仓库 `p697/cloudmusic`、工作流 `release.yml`、环境 `pypi`。发布环境仅允许 `master` 分支。修改版本号后应先通过 PR 合并,再启动发布。 历史贡献参考:[PR #14](https://github.com/p697/cloudmusic/pull/14)、[PR #17](https://github.com/p697/cloudmusic/pull/17)、[PR #21](https://github.com/p697/cloudmusic/pull/21)。本轮吸收了跨平台路径和音质目录传递的修复方向;封面/标签写入功能暂未纳入。