Release #7
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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@v4 | |
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: | | |
make doc | |
sed '/### /Q' Changelog.md >> ./CHANGELOG | |
echo '### ${{ env.version }}' >> ./CHANGELOG | |
python ./devscripts/make_changelog.py -vv -c >> ./CHANGELOG | |
echo >> ./CHANGELOG | |
grep -Poz '(?s)### \d+\.\d+\.\d+.+' 'Changelog.md' | head -n -1 >> ./CHANGELOG | |
cat ./CHANGELOG > Changelog.md | |
- 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 :ci run dl" | |
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 | |
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 | |
- uses: actions/setup-python@v4 | |
with: | |
python-version: "3.10" | |
- name: Install Requirements | |
run: | | |
sudo apt -y install pandoc man | |
python -m pip install -U pip setuptools wheel twine | |
python -m pip install -U -r requirements.txt | |
- 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/make_lazy_extractors.py | |
sed -i -E "s/(name=')[^']+(', # package name)/\1${{ env.pypi_project }}\2/" setup.py | |
- name: Build | |
run: | | |
rm -rf dist/* | |
make pypi-files | |
python devscripts/set-variant.py pip -M "You installed yt-dlp with pip or using the wheel from PyPi; Use that to update" | |
python setup.py sdist bdist_wheel | |
- 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@v3 | |
- uses: actions/setup-python@v4 | |
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%20should%20I%20download%3F-white.svg?style=for-the-badge)]' \ | |
'(https://github.com/${{ github.repository }}#installation "Installation instructions") ' \ | |
'[![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") ' \ | |
'[![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") ' \ | |
'[![Discord](https://img.shields.io/discord/807245652072857610?color=blue&labelColor=555555&label=&logo=discord&style=for-the-badge)]' \ | |
'(https://discord.gg/H5MNcFW63r "Discord") ' \ | |
${{ env.target_repo == 'yt-dlp/yt-dlp' && '\ | |
"[![Nightly](https://img.shields.io/badge/Get%20nightly%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/Get%20master%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 are 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/* |