123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- name: Release
- on:
- workflow_call:
- inputs:
- prerelease:
- required: false
- default: true
- type: boolean
- source:
- required: false
- default: ''
- type: string
- target:
- required: false
- default: ''
- type: string
- version:
- required: false
- default: ''
- type: string
- workflow_dispatch:
- inputs:
- source:
- description: |
- SOURCE of this release's updates:
- channel, repo, tag, or channel/repo@tag
- (default: <current_repo>)
- required: false
- default: ''
- type: string
- target:
- description: |
- TARGET to publish this release to:
- channel, tag, or channel@tag
- (default: <source> if writable else <current_repo>[@source_tag])
- required: false
- default: ''
- type: string
- version:
- description: |
- VERSION: yyyy.mm.dd[.rev] or rev
- (default: auto-generated)
- required: false
- default: ''
- type: string
- prerelease:
- description: Pre-release
- default: false
- type: boolean
- permissions:
- contents: read
- jobs:
- prepare:
- permissions:
- contents: write
- runs-on: ubuntu-latest
- outputs:
- channel: ${{ steps.setup_variables.outputs.channel }}
- version: ${{ steps.setup_variables.outputs.version }}
- target_repo: ${{ steps.setup_variables.outputs.target_repo }}
- target_repo_token: ${{ steps.setup_variables.outputs.target_repo_token }}
- target_tag: ${{ steps.setup_variables.outputs.target_tag }}
- pypi_project: ${{ steps.setup_variables.outputs.pypi_project }}
- pypi_suffix: ${{ steps.setup_variables.outputs.pypi_suffix }}
- head_sha: ${{ steps.get_target.outputs.head_sha }}
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0
- - uses: actions/setup-python@v5
- with:
- python-version: "3.10"
- - name: Process inputs
- id: process_inputs
- run: |
- cat << EOF
- ::group::Inputs
- prerelease=${{ inputs.prerelease }}
- source=${{ inputs.source }}
- target=${{ inputs.target }}
- version=${{ inputs.version }}
- ::endgroup::
- EOF
- IFS='@' read -r source_repo source_tag <<<"${{ inputs.source }}"
- IFS='@' read -r target_repo target_tag <<<"${{ inputs.target }}"
- cat << EOF >> "$GITHUB_OUTPUT"
- source_repo=${source_repo}
- source_tag=${source_tag}
- target_repo=${target_repo}
- target_tag=${target_tag}
- EOF
- - name: Setup variables
- id: setup_variables
- env:
- source_repo: ${{ steps.process_inputs.outputs.source_repo }}
- source_tag: ${{ steps.process_inputs.outputs.source_tag }}
- target_repo: ${{ steps.process_inputs.outputs.target_repo }}
- target_tag: ${{ steps.process_inputs.outputs.target_tag }}
- run: |
- # unholy bash monstrosity (sincere apologies)
- fallback_token () {
- if ${{ !secrets.ARCHIVE_REPO_TOKEN }}; then
- echo "::error::Repository access secret ${target_repo_token^^} not found"
- exit 1
- fi
- target_repo_token=ARCHIVE_REPO_TOKEN
- return 0
- }
- source_is_channel=0
- [[ "${source_repo}" == 'stable' ]] && source_repo='yt-dlp/yt-dlp'
- if [[ -z "${source_repo}" ]]; then
- source_repo='${{ github.repository }}'
- elif [[ '${{ vars[format('{0}_archive_repo', env.source_repo)] }}' ]]; then
- source_is_channel=1
- source_channel='${{ vars[format('{0}_archive_repo', env.source_repo)] }}'
- elif [[ -z "${source_tag}" && "${source_repo}" != */* ]]; then
- source_tag="${source_repo}"
- source_repo='${{ github.repository }}'
- fi
- resolved_source="${source_repo}"
- if [[ "${source_tag}" ]]; then
- resolved_source="${resolved_source}@${source_tag}"
- elif [[ "${source_repo}" == 'yt-dlp/yt-dlp' ]]; then
- resolved_source='stable'
- fi
- revision="${{ (inputs.prerelease || !vars.PUSH_VERSION_COMMIT) && '$(date -u +"%H%M%S")' || '' }}"
- version="$(
- python devscripts/update-version.py \
- -c "${resolved_source}" -r "${{ github.repository }}" ${{ inputs.version || '$revision' }} | \
- grep -Po "version=\K\d+\.\d+\.\d+(\.\d+)?")"
- if [[ "${target_repo}" ]]; then
- if [[ -z "${target_tag}" ]]; then
- if [[ '${{ vars[format('{0}_archive_repo', env.target_repo)] }}' ]]; then
- target_tag="${source_tag:-${version}}"
- else
- target_tag="${target_repo}"
- target_repo='${{ github.repository }}'
- fi
- fi
- if [[ "${target_repo}" != '${{ github.repository}}' ]]; then
- target_repo='${{ vars[format('{0}_archive_repo', env.target_repo)] }}'
- target_repo_token='${{ env.target_repo }}_archive_repo_token'
- ${{ !!secrets[format('{0}_archive_repo_token', env.target_repo)] }} || fallback_token
- pypi_project='${{ vars[format('{0}_pypi_project', env.target_repo)] }}'
- pypi_suffix='${{ vars[format('{0}_pypi_suffix', env.target_repo)] }}'
- fi
- else
- target_tag="${source_tag:-${version}}"
- if ((source_is_channel)); then
- target_repo="${source_channel}"
- target_repo_token='${{ env.source_repo }}_archive_repo_token'
- ${{ !!secrets[format('{0}_archive_repo_token', env.source_repo)] }} || fallback_token
- pypi_project='${{ vars[format('{0}_pypi_project', env.source_repo)] }}'
- pypi_suffix='${{ vars[format('{0}_pypi_suffix', env.source_repo)] }}'
- else
- target_repo='${{ github.repository }}'
- fi
- fi
- if [[ "${target_repo}" == '${{ github.repository }}' ]] && ${{ !inputs.prerelease }}; then
- pypi_project='${{ vars.PYPI_PROJECT }}'
- fi
- echo "::group::Output variables"
- cat << EOF | tee -a "$GITHUB_OUTPUT"
- channel=${resolved_source}
- version=${version}
- target_repo=${target_repo}
- target_repo_token=${target_repo_token}
- target_tag=${target_tag}
- pypi_project=${pypi_project}
- pypi_suffix=${pypi_suffix}
- EOF
- echo "::endgroup::"
- - name: Update documentation
- env:
- version: ${{ steps.setup_variables.outputs.version }}
- target_repo: ${{ steps.setup_variables.outputs.target_repo }}
- if: |
- !inputs.prerelease && env.target_repo == github.repository
- run: |
- python devscripts/update_changelog.py -vv
- make doc
- - name: Push to release
- id: push_release
- env:
- version: ${{ steps.setup_variables.outputs.version }}
- target_repo: ${{ steps.setup_variables.outputs.target_repo }}
- if: |
- !inputs.prerelease && env.target_repo == github.repository
- run: |
- git config --global user.name "github-actions[bot]"
- git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
- git add -u
- git commit -m "Release ${{ env.version }}" \
- -m "Created by: ${{ github.event.sender.login }}" -m ":ci skip all"
- git push origin --force ${{ github.event.ref }}:release
- - name: Get target commitish
- id: get_target
- run: |
- echo "head_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- - name: Update master
- env:
- target_repo: ${{ steps.setup_variables.outputs.target_repo }}
- if: |
- vars.PUSH_VERSION_COMMIT != '' && !inputs.prerelease && env.target_repo == github.repository
- run: git push origin ${{ github.event.ref }}
- build:
- needs: prepare
- uses: ./.github/workflows/build.yml
- with:
- version: ${{ needs.prepare.outputs.version }}
- channel: ${{ needs.prepare.outputs.channel }}
- origin: ${{ needs.prepare.outputs.target_repo }}
- permissions:
- contents: read
- packages: write # For package cache
- actions: write # For cleaning up cache
- secrets:
- GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }}
- publish_pypi:
- needs: [prepare, build]
- if: ${{ needs.prepare.outputs.pypi_project }}
- runs-on: ubuntu-latest
- permissions:
- id-token: write # mandatory for trusted publishing
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0
- - uses: actions/setup-python@v5
- with:
- python-version: "3.10"
- - name: Install Requirements
- run: |
- sudo apt -y install pandoc man
- python devscripts/install_deps.py -o --include build
- - name: Prepare
- env:
- version: ${{ needs.prepare.outputs.version }}
- suffix: ${{ needs.prepare.outputs.pypi_suffix }}
- channel: ${{ needs.prepare.outputs.channel }}
- target_repo: ${{ needs.prepare.outputs.target_repo }}
- pypi_project: ${{ needs.prepare.outputs.pypi_project }}
- run: |
- python devscripts/update-version.py -c "${{ env.channel }}" -r "${{ env.target_repo }}" -s "${{ env.suffix }}" "${{ env.version }}"
- python devscripts/update_changelog.py -vv
- python devscripts/make_lazy_extractors.py
- sed -i -E '0,/(name = ")[^"]+(")/s//\1${{ env.pypi_project }}\2/' pyproject.toml
- - name: Build
- run: |
- rm -rf dist/*
- make pypi-files
- printf '%s\n\n' \
- 'Official repository: <https://github.com/yt-dlp/yt-dlp>' \
- '**PS**: Some links in this document will not work since this is a copy of the README.md from Github' > ./README.md.new
- cat ./README.md >> ./README.md.new && mv -f ./README.md.new ./README.md
- python devscripts/set-variant.py pip -M "You installed yt-dlp with pip or using the wheel from PyPi; Use that to update"
- make clean-cache
- python -m build --no-isolation .
- - name: Publish to PyPI
- uses: pypa/gh-action-pypi-publish@release/v1
- with:
- verbose: true
- publish:
- needs: [prepare, build]
- permissions:
- contents: write
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0
- - uses: actions/download-artifact@v4
- with:
- path: artifact
- pattern: build-*
- merge-multiple: true
- - uses: actions/setup-python@v5
- with:
- python-version: "3.10"
- - name: Generate release notes
- env:
- head_sha: ${{ needs.prepare.outputs.head_sha }}
- target_repo: ${{ needs.prepare.outputs.target_repo }}
- target_tag: ${{ needs.prepare.outputs.target_tag }}
- run: |
- printf '%s' \
- '[![Installation](https://img.shields.io/badge/-Which%20file%20to%20download%3F-white.svg?style=for-the-badge)]' \
- '(https://github.com/${{ github.repository }}#installation "Installation instructions") ' \
- '[![Discord](https://img.shields.io/discord/807245652072857610?color=blue&labelColor=555555&label=&logo=discord&style=for-the-badge)]' \
- '(https://discord.gg/H5MNcFW63r "Discord") ' \
- '[![Donate](https://img.shields.io/badge/_-Donate-red.svg?logo=githubsponsors&labelColor=555555&style=for-the-badge)]' \
- '(https://github.com/yt-dlp/yt-dlp/blob/master/Collaborators.md#collaborators "Donate") ' \
- '[![Documentation](https://img.shields.io/badge/-Docs-brightgreen.svg?style=for-the-badge&logo=GitBook&labelColor=555555)]' \
- '(https://github.com/${{ github.repository }}' \
- '${{ env.target_repo == github.repository && format('/tree/{0}', env.target_tag) || '' }}#readme "Documentation") ' \
- ${{ env.target_repo == 'yt-dlp/yt-dlp' && '\
- "[![Nightly](https://img.shields.io/badge/Nightly%20builds-purple.svg?style=for-the-badge)]" \
- "(https://github.com/yt-dlp/yt-dlp-nightly-builds/releases/latest \"Nightly builds\") " \
- "[![Master](https://img.shields.io/badge/Master%20builds-lightblue.svg?style=for-the-badge)]" \
- "(https://github.com/yt-dlp/yt-dlp-master-builds/releases/latest \"Master builds\")"' || '' }} > ./RELEASE_NOTES
- printf '\n\n' >> ./RELEASE_NOTES
- cat >> ./RELEASE_NOTES << EOF
- #### A description of the various files is in the [README](https://github.com/${{ github.repository }}#release-files)
- ---
- $(python ./devscripts/make_changelog.py -vv --collapsible)
- EOF
- printf '%s\n\n' '**This is a pre-release build**' >> ./PRERELEASE_NOTES
- cat ./RELEASE_NOTES >> ./PRERELEASE_NOTES
- printf '%s\n\n' 'Generated from: https://github.com/${{ github.repository }}/commit/${{ env.head_sha }}' >> ./ARCHIVE_NOTES
- cat ./RELEASE_NOTES >> ./ARCHIVE_NOTES
- - name: Publish to archive repo
- env:
- GH_TOKEN: ${{ secrets[needs.prepare.outputs.target_repo_token] }}
- GH_REPO: ${{ needs.prepare.outputs.target_repo }}
- version: ${{ needs.prepare.outputs.version }}
- channel: ${{ needs.prepare.outputs.channel }}
- if: |
- inputs.prerelease && env.GH_TOKEN != '' && env.GH_REPO != '' && env.GH_REPO != github.repository
- run: |
- title="${{ startswith(env.GH_REPO, 'yt-dlp/') && 'yt-dlp ' || '' }}${{ env.channel }}"
- gh release create \
- --notes-file ARCHIVE_NOTES \
- --title "${title} ${{ env.version }}" \
- ${{ env.version }} \
- artifact/*
- - name: Prune old release
- env:
- GH_TOKEN: ${{ github.token }}
- version: ${{ needs.prepare.outputs.version }}
- target_repo: ${{ needs.prepare.outputs.target_repo }}
- target_tag: ${{ needs.prepare.outputs.target_tag }}
- if: |
- env.target_repo == github.repository && env.target_tag != env.version
- run: |
- gh release delete --yes --cleanup-tag "${{ env.target_tag }}" || true
- git tag --delete "${{ env.target_tag }}" || true
- sleep 5 # Enough time to cover deletion race condition
- - name: Publish release
- env:
- GH_TOKEN: ${{ github.token }}
- version: ${{ needs.prepare.outputs.version }}
- target_repo: ${{ needs.prepare.outputs.target_repo }}
- target_tag: ${{ needs.prepare.outputs.target_tag }}
- head_sha: ${{ needs.prepare.outputs.head_sha }}
- if: |
- env.target_repo == github.repository
- run: |
- title="${{ github.repository == 'yt-dlp/yt-dlp' && 'yt-dlp ' || '' }}"
- title+="${{ env.target_tag != env.version && format('{0} ', env.target_tag) || '' }}"
- gh release create \
- --notes-file ${{ inputs.prerelease && 'PRERELEASE_NOTES' || 'RELEASE_NOTES' }} \
- --target ${{ env.head_sha }} \
- --title "${title}${{ env.version }}" \
- ${{ inputs.prerelease && '--prerelease' || '' }} \
- ${{ env.target_tag }} \
- artifact/*
|