mirror of
https://github.com/hykilpikonna/hyfetch.git
synced 2026-06-21 14:39:57 -05:00
377 lines
12 KiB
YAML
377 lines
12 KiB
YAML
name: Release
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- "[0-9]*.[0-9]*.[0-9]*"
|
|
- "v[0-9]*.[0-9]*.[0-9]*"
|
|
workflow_dispatch:
|
|
inputs:
|
|
tag:
|
|
description: "Existing release tag to publish, such as 2.1.1 or v2.1.1"
|
|
required: true
|
|
type: string
|
|
source_ref:
|
|
description: "Ref to build/publish from. Leave empty to use the release tag; set to master/a branch for recovery fixes."
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
create_github_release:
|
|
description: "Create or complete the GitHub Release"
|
|
required: true
|
|
default: true
|
|
type: boolean
|
|
publish_pypi:
|
|
description: "Publish the Python distributions to PyPI"
|
|
required: true
|
|
default: true
|
|
type: boolean
|
|
publish_npm:
|
|
description: "Publish package.json to npm"
|
|
required: true
|
|
default: true
|
|
type: boolean
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
concurrency:
|
|
group: release-${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
metadata:
|
|
name: Validate release metadata
|
|
runs-on: ubuntu-22.04
|
|
outputs:
|
|
tag: ${{ steps.metadata.outputs.tag }}
|
|
source_ref: ${{ steps.release-refs.outputs.source_ref }}
|
|
version: ${{ steps.metadata.outputs.version }}
|
|
python_package: ${{ steps.metadata.outputs.python_package }}
|
|
npm_package: ${{ steps.metadata.outputs.npm_package }}
|
|
steps:
|
|
- name: Resolve release refs
|
|
id: release-refs
|
|
run: |
|
|
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
|
echo "tag=${{ inputs.tag }}" >> "$GITHUB_OUTPUT"
|
|
if [[ -n "${{ inputs.source_ref }}" ]]; then
|
|
echo "source_ref=${{ inputs.source_ref }}" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "source_ref=${{ inputs.tag }}" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
else
|
|
echo "tag=${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
|
|
echo "source_ref=${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
ref: ${{ steps.release-refs.outputs.source_ref }}
|
|
|
|
- name: Validate checked-in versions
|
|
id: metadata
|
|
run: python3 tools/release.py metadata --tag "${{ steps.release-refs.outputs.tag }}"
|
|
|
|
release-state:
|
|
name: Check completed release stages
|
|
runs-on: ubuntu-22.04
|
|
needs: metadata
|
|
outputs:
|
|
pypi_exists: ${{ steps.state.outputs.pypi_exists }}
|
|
npm_exists: ${{ steps.state.outputs.npm_exists }}
|
|
github_release_exists: ${{ steps.state.outputs.github_release_exists }}
|
|
github_release_complete: ${{ steps.state.outputs.github_release_complete }}
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
ref: ${{ needs.metadata.outputs.source_ref }}
|
|
|
|
- name: Query registries and GitHub Release
|
|
id: state
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
python3 tools/release.py state \
|
|
--tag "${{ needs.metadata.outputs.tag }}" \
|
|
--version "${{ needs.metadata.outputs.version }}" \
|
|
--python-package "${{ needs.metadata.outputs.python_package }}" \
|
|
--npm-package "${{ needs.metadata.outputs.npm_package }}" \
|
|
--repo "${{ github.repository }}"
|
|
|
|
- name: Summarize release state
|
|
run: |
|
|
{
|
|
echo "## Release state"
|
|
echo
|
|
echo "| Stage | Already complete |"
|
|
echo "| --- | --- |"
|
|
echo "| PyPI | ${{ steps.state.outputs.pypi_exists }} |"
|
|
echo "| npm | ${{ steps.state.outputs.npm_exists }} |"
|
|
echo "| GitHub Release assets | ${{ steps.state.outputs.github_release_complete }} |"
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
preflight:
|
|
name: Preflight release stages
|
|
runs-on: ubuntu-22.04
|
|
needs:
|
|
- metadata
|
|
- release-state
|
|
steps:
|
|
- name: Verify pending publish stages
|
|
env:
|
|
CREATE_GITHUB_RELEASE: ${{ github.event_name != 'workflow_dispatch' || inputs.create_github_release }}
|
|
PUBLISH_PYPI: ${{ github.event_name != 'workflow_dispatch' || inputs.publish_pypi }}
|
|
PUBLISH_NPM: ${{ github.event_name != 'workflow_dispatch' || inputs.publish_npm }}
|
|
run: |
|
|
pending=()
|
|
skipped=()
|
|
|
|
if [[ "$CREATE_GITHUB_RELEASE" == "true" ]]; then
|
|
if [[ "${{ needs.release-state.outputs.github_release_complete }}" == "true" ]]; then
|
|
skipped+=("GitHub Release")
|
|
else
|
|
pending+=("GitHub Release")
|
|
fi
|
|
fi
|
|
|
|
if [[ "$PUBLISH_PYPI" == "true" ]]; then
|
|
if [[ "${{ needs.release-state.outputs.pypi_exists }}" == "true" ]]; then
|
|
skipped+=("PyPI")
|
|
else
|
|
pending+=("PyPI")
|
|
fi
|
|
fi
|
|
|
|
if [[ "$PUBLISH_NPM" == "true" ]]; then
|
|
if [[ "${{ needs.release-state.outputs.npm_exists }}" == "true" ]]; then
|
|
skipped+=("npm")
|
|
else
|
|
pending+=("npm")
|
|
fi
|
|
fi
|
|
|
|
{
|
|
echo "## Preflight"
|
|
echo
|
|
if ((${#pending[@]})); then
|
|
printf 'Pending stages: %s\n\n' "$(IFS=', '; echo "${pending[*]}")"
|
|
else
|
|
echo "No pending stages."
|
|
echo
|
|
fi
|
|
if ((${#skipped[@]})); then
|
|
printf 'Already complete: %s\n\n' "$(IFS=', '; echo "${skipped[*]}")"
|
|
fi
|
|
echo "PyPI and npm publishing use trusted publishing/OIDC; no registry secrets are required."
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
build-python-dist:
|
|
name: Build Python distributions
|
|
runs-on: ubuntu-22.04
|
|
needs:
|
|
- metadata
|
|
- release-state
|
|
- preflight
|
|
if: >-
|
|
${{
|
|
always()
|
|
&& needs.preflight.result == 'success'
|
|
&& (
|
|
(
|
|
(github.event_name != 'workflow_dispatch' || inputs.publish_pypi)
|
|
&& needs.release-state.outputs.pypi_exists != 'true'
|
|
)
|
|
|| (
|
|
(github.event_name != 'workflow_dispatch' || inputs.create_github_release)
|
|
&& needs.release-state.outputs.github_release_complete != 'true'
|
|
)
|
|
)
|
|
}}
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
ref: ${{ needs.metadata.outputs.source_ref }}
|
|
|
|
- uses: actions/setup-python@v6
|
|
with:
|
|
python-version: "3.13"
|
|
|
|
- name: Install build dependencies
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y help2man libarchive-tools shellcheck unzip wget zip
|
|
python -m pip install --upgrade pip
|
|
python -m pip install build twine
|
|
|
|
- name: Build and check distributions
|
|
run: tools/build_pkg.sh
|
|
|
|
- name: Upload distribution artifact
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: python-dist-${{ needs.metadata.outputs.version }}
|
|
path: dist/*
|
|
if-no-files-found: error
|
|
|
|
github-release:
|
|
name: Create GitHub Release
|
|
runs-on: ubuntu-22.04
|
|
needs:
|
|
- metadata
|
|
- release-state
|
|
- preflight
|
|
- build-python-dist
|
|
permissions:
|
|
contents: write
|
|
if: >-
|
|
${{
|
|
always()
|
|
&& needs.preflight.result == 'success'
|
|
&& needs.build-python-dist.result == 'success'
|
|
&& (github.event_name != 'workflow_dispatch' || inputs.create_github_release)
|
|
&& needs.release-state.outputs.github_release_complete != 'true'
|
|
}}
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
ref: ${{ needs.metadata.outputs.source_ref }}
|
|
|
|
- uses: actions/download-artifact@v8
|
|
with:
|
|
name: python-dist-${{ needs.metadata.outputs.version }}
|
|
path: dist
|
|
|
|
- name: Write release notes
|
|
run: |
|
|
python3 tools/release.py changelog \
|
|
--version "${{ needs.metadata.outputs.version }}" \
|
|
--output RELEASE_NOTES.md
|
|
|
|
- name: Create or update release metadata
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
GH_REPO: ${{ github.repository }}
|
|
TAG: ${{ needs.metadata.outputs.tag }}
|
|
VERSION: ${{ needs.metadata.outputs.version }}
|
|
run: |
|
|
if gh release view "$TAG" >/dev/null 2>&1; then
|
|
echo "GitHub Release $TAG already exists."
|
|
gh release edit "$TAG" \
|
|
--title "$VERSION" \
|
|
--notes-file RELEASE_NOTES.md
|
|
else
|
|
gh release create "$TAG" \
|
|
--verify-tag \
|
|
--title "$VERSION" \
|
|
--notes-file RELEASE_NOTES.md
|
|
fi
|
|
|
|
- name: Upload missing release assets
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
GH_REPO: ${{ github.repository }}
|
|
TAG: ${{ needs.metadata.outputs.tag }}
|
|
run: |
|
|
mapfile -t existing_assets < <(gh release view "$TAG" --json assets --jq '.assets[].name')
|
|
missing_assets=()
|
|
|
|
for file in dist/*; do
|
|
name="$(basename "$file")"
|
|
found=false
|
|
for existing in "${existing_assets[@]}"; do
|
|
if [[ "$existing" == "$name" ]]; then
|
|
found=true
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [[ "$found" == "false" ]]; then
|
|
missing_assets+=("$file")
|
|
fi
|
|
done
|
|
|
|
if ((${#missing_assets[@]} == 0)); then
|
|
echo "All release assets are already uploaded."
|
|
else
|
|
gh release upload "$TAG" "${missing_assets[@]}"
|
|
fi
|
|
|
|
publish-pypi:
|
|
name: Publish to PyPI
|
|
runs-on: ubuntu-22.04
|
|
permissions:
|
|
contents: read
|
|
id-token: write
|
|
needs:
|
|
- metadata
|
|
- release-state
|
|
- preflight
|
|
- build-python-dist
|
|
if: >-
|
|
${{
|
|
always()
|
|
&& needs.preflight.result == 'success'
|
|
&& needs.build-python-dist.result == 'success'
|
|
&& (github.event_name != 'workflow_dispatch' || inputs.publish_pypi)
|
|
&& needs.release-state.outputs.pypi_exists != 'true'
|
|
}}
|
|
steps:
|
|
- uses: actions/download-artifact@v8
|
|
with:
|
|
name: python-dist-${{ needs.metadata.outputs.version }}
|
|
path: dist
|
|
|
|
- name: Publish distributions
|
|
uses: pypa/gh-action-pypi-publish@v1.14.0
|
|
with:
|
|
packages-dir: dist
|
|
skip-existing: true
|
|
|
|
publish-npm:
|
|
name: Publish to npm
|
|
runs-on: ubuntu-22.04
|
|
permissions:
|
|
contents: read
|
|
id-token: write
|
|
needs:
|
|
- metadata
|
|
- release-state
|
|
- preflight
|
|
if: >-
|
|
${{
|
|
always()
|
|
&& needs.preflight.result == 'success'
|
|
&& (github.event_name != 'workflow_dispatch' || inputs.publish_npm)
|
|
&& needs.release-state.outputs.npm_exists != 'true'
|
|
}}
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
ref: ${{ needs.metadata.outputs.source_ref }}
|
|
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: "24"
|
|
package-manager-cache: false
|
|
|
|
- name: Use npm with trusted publishing support
|
|
run: npm install -g npm@11
|
|
|
|
- name: Confirm npm version is still unpublished
|
|
id: npm-state
|
|
env:
|
|
NPM_PACKAGE: ${{ needs.metadata.outputs.npm_package }}
|
|
VERSION: ${{ needs.metadata.outputs.version }}
|
|
run: |
|
|
if npm view "$NPM_PACKAGE@$VERSION" version --registry https://registry.npmjs.org >/dev/null 2>&1; then
|
|
echo "$NPM_PACKAGE@$VERSION is already published; skipping."
|
|
echo "exists=true" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
echo "exists=false" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Publish package
|
|
if: steps.npm-state.outputs.exists != 'true'
|
|
run: npm publish --provenance
|