|
|
|
name: Release
|
|
|
|
on:
|
|
|
|
workflow_call:
|
|
|
|
inputs:
|
|
|
|
source:
|
|
|
|
required: false
|
|
|
|
default: ''
|
|
|
|
type: string
|
|
|
|
target:
|
|
|
|
required: false
|
|
|
|
default: ''
|
|
|
|
type: string
|
|
|
|
version:
|
|
|
|
required: false
|
|
|
|
default: ''
|
|
|
|
type: string
|
|
|
|
prerelease:
|
|
|
|
required: false
|
|
|
|
default: true
|
|
|
|
type: boolean
|
|
|
|
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: Upload artifacts
|
|
|
|
if: github.event_name != 'workflow_dispatch'
|
|
|
|
uses: actions/upload-artifact@v4
|
|
|
|
with:
|
|
|
|
name: build-pypi
|
|
|
|
path: |
|
|
|
|
dist/*
|
|
|
|
compression-level: 0
|
|
|
|
|
|
|
|
- name: Publish to PyPI
|
|
|
|
if: github.event_name == 'workflow_dispatch'
|
|
|
|
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/*
|