]> jfr.im git - yt-dlp.git/blame - .github/workflows/release.yml
[ci] Bump `actions/setup-python` to v5
[yt-dlp.git] / .github / workflows / release.yml
CommitLineData
29cb20bd 1name: Release
c4efa0ae 2on:
1d03633c 3 workflow_call:
c4efa0ae 4 inputs:
1d03633c 5 prerelease:
6 required: false
7 default: true
8 type: boolean
9 source:
10 required: false
11 default: ''
12 type: string
13 target:
14 required: false
15 default: ''
16 type: string
c4efa0ae 17 version:
c4efa0ae 18 required: false
19 default: ''
20 type: string
1d03633c 21 workflow_dispatch:
22 inputs:
23 source:
24 description: |
25 SOURCE of this release's updates:
26 channel, repo, tag, or channel/repo@tag
27 (default: <current_repo>)
28 required: false
29 default: ''
30 type: string
31 target:
32 description: |
33 TARGET to publish this release to:
34 channel, tag, or channel@tag
35 (default: <source> if writable else <current_repo>[@source_tag])
36 required: false
37 default: ''
38 type: string
39 version:
40 description: |
41 VERSION: yyyy.mm.dd[.rev] or rev
42 (default: auto-generated)
c4efa0ae 43 required: false
44 default: ''
45 type: string
46 prerelease:
47 description: Pre-release
48 default: false
49 type: boolean
50
29cb20bd
SS
51permissions:
52 contents: read
53
54jobs:
55 prepare:
56 permissions:
57 contents: write
58 runs-on: ubuntu-latest
59 outputs:
1d03633c 60 channel: ${{ steps.setup_variables.outputs.channel }}
61 version: ${{ steps.setup_variables.outputs.version }}
62 target_repo: ${{ steps.setup_variables.outputs.target_repo }}
63 target_repo_token: ${{ steps.setup_variables.outputs.target_repo_token }}
64 target_tag: ${{ steps.setup_variables.outputs.target_tag }}
65 pypi_project: ${{ steps.setup_variables.outputs.pypi_project }}
66 pypi_suffix: ${{ steps.setup_variables.outputs.pypi_suffix }}
c4efa0ae 67 head_sha: ${{ steps.get_target.outputs.head_sha }}
29cb20bd
SS
68
69 steps:
5438593a 70 - uses: actions/checkout@v4
29cb20bd
SS
71 with:
72 fetch-depth: 0
73
b14e818b 74 - uses: actions/setup-python@v5
29cb20bd
SS
75 with:
76 python-version: "3.10"
77
1d03633c 78 - name: Process inputs
79 id: process_inputs
c4efa0ae 80 run: |
1d03633c 81 cat << EOF
82 ::group::Inputs
83 prerelease=${{ inputs.prerelease }}
84 source=${{ inputs.source }}
85 target=${{ inputs.target }}
86 version=${{ inputs.version }}
87 ::endgroup::
88 EOF
89 IFS='@' read -r source_repo source_tag <<<"${{ inputs.source }}"
90 IFS='@' read -r target_repo target_tag <<<"${{ inputs.target }}"
91 cat << EOF >> "$GITHUB_OUTPUT"
92 source_repo=${source_repo}
93 source_tag=${source_tag}
94 target_repo=${target_repo}
95 target_tag=${target_tag}
96 EOF
c4efa0ae 97
1d03633c 98 - name: Setup variables
99 id: setup_variables
100 env:
101 source_repo: ${{ steps.process_inputs.outputs.source_repo }}
102 source_tag: ${{ steps.process_inputs.outputs.source_tag }}
103 target_repo: ${{ steps.process_inputs.outputs.target_repo }}
104 target_tag: ${{ steps.process_inputs.outputs.target_tag }}
29cb20bd 105 run: |
1d03633c 106 # unholy bash monstrosity (sincere apologies)
107 fallback_token () {
108 if ${{ !secrets.ARCHIVE_REPO_TOKEN }}; then
109 echo "::error::Repository access secret ${target_repo_token^^} not found"
110 exit 1
111 fi
112 target_repo_token=ARCHIVE_REPO_TOKEN
113 return 0
114 }
115
116 source_is_channel=0
117 [[ "${source_repo}" == 'stable' ]] && source_repo='yt-dlp/yt-dlp'
118 if [[ -z "${source_repo}" ]]; then
119 source_repo='${{ github.repository }}'
120 elif [[ '${{ vars[format('{0}_archive_repo', env.source_repo)] }}' ]]; then
121 source_is_channel=1
122 source_channel='${{ vars[format('{0}_archive_repo', env.source_repo)] }}'
123 elif [[ -z "${source_tag}" && "${source_repo}" != */* ]]; then
124 source_tag="${source_repo}"
125 source_repo='${{ github.repository }}'
126 fi
127 resolved_source="${source_repo}"
128 if [[ "${source_tag}" ]]; then
129 resolved_source="${resolved_source}@${source_tag}"
130 elif [[ "${source_repo}" == 'yt-dlp/yt-dlp' ]]; then
131 resolved_source='stable'
132 fi
133
134 revision="${{ (inputs.prerelease || !vars.PUSH_VERSION_COMMIT) && '$(date -u +"%H%M%S")' || '' }}"
135 version="$(
20314dd4 136 python devscripts/update-version.py \
137 -c "${resolved_source}" -r "${{ github.repository }}" ${{ inputs.version || '$revision' }} | \
1d03633c 138 grep -Po "version=\K\d+\.\d+\.\d+(\.\d+)?")"
139
140 if [[ "${target_repo}" ]]; then
141 if [[ -z "${target_tag}" ]]; then
142 if [[ '${{ vars[format('{0}_archive_repo', env.target_repo)] }}' ]]; then
143 target_tag="${source_tag:-${version}}"
144 else
145 target_tag="${target_repo}"
146 target_repo='${{ github.repository }}'
147 fi
148 fi
149 if [[ "${target_repo}" != '${{ github.repository}}' ]]; then
150 target_repo='${{ vars[format('{0}_archive_repo', env.target_repo)] }}'
151 target_repo_token='${{ env.target_repo }}_archive_repo_token'
152 ${{ !!secrets[format('{0}_archive_repo_token', env.target_repo)] }} || fallback_token
153 pypi_project='${{ vars[format('{0}_pypi_project', env.target_repo)] }}'
154 pypi_suffix='${{ vars[format('{0}_pypi_suffix', env.target_repo)] }}'
1d03633c 155 fi
156 else
157 target_tag="${source_tag:-${version}}"
158 if ((source_is_channel)); then
159 target_repo="${source_channel}"
160 target_repo_token='${{ env.source_repo }}_archive_repo_token'
161 ${{ !!secrets[format('{0}_archive_repo_token', env.source_repo)] }} || fallback_token
162 pypi_project='${{ vars[format('{0}_pypi_project', env.source_repo)] }}'
163 pypi_suffix='${{ vars[format('{0}_pypi_suffix', env.source_repo)] }}'
1d03633c 164 else
165 target_repo='${{ github.repository }}'
166 fi
167 fi
168
169 if [[ "${target_repo}" == '${{ github.repository }}' ]] && ${{ !inputs.prerelease }}; then
170 pypi_project='${{ vars.PYPI_PROJECT }}'
171 fi
1d03633c 172
173 echo "::group::Output variables"
174 cat << EOF | tee -a "$GITHUB_OUTPUT"
175 channel=${resolved_source}
176 version=${version}
177 target_repo=${target_repo}
178 target_repo_token=${target_repo_token}
179 target_tag=${target_tag}
180 pypi_project=${pypi_project}
181 pypi_suffix=${pypi_suffix}
1d03633c 182 EOF
183 echo "::endgroup::"
29cb20bd
SS
184
185 - name: Update documentation
1d03633c 186 env:
187 version: ${{ steps.setup_variables.outputs.version }}
188 target_repo: ${{ steps.setup_variables.outputs.target_repo }}
189 if: |
190 !inputs.prerelease && env.target_repo == github.repository
29cb20bd
SS
191 run: |
192 make doc
193 sed '/### /Q' Changelog.md >> ./CHANGELOG
1d03633c 194 echo '### ${{ env.version }}' >> ./CHANGELOG
29cb20bd
SS
195 python ./devscripts/make_changelog.py -vv -c >> ./CHANGELOG
196 echo >> ./CHANGELOG
197 grep -Poz '(?s)### \d+\.\d+\.\d+.+' 'Changelog.md' | head -n -1 >> ./CHANGELOG
198 cat ./CHANGELOG > Changelog.md
199
200 - name: Push to release
201 id: push_release
1d03633c 202 env:
203 version: ${{ steps.setup_variables.outputs.version }}
204 target_repo: ${{ steps.setup_variables.outputs.target_repo }}
205 if: |
206 !inputs.prerelease && env.target_repo == github.repository
29cb20bd 207 run: |
24f82787 208 git config --global user.name "github-actions[bot]"
209 git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
29cb20bd 210 git add -u
1d03633c 211 git commit -m "Release ${{ env.version }}" \
29cb20bd
SS
212 -m "Created by: ${{ github.event.sender.login }}" -m ":ci skip all :ci run dl"
213 git push origin --force ${{ github.event.ref }}:release
c4efa0ae 214
215 - name: Get target commitish
216 id: get_target
217 run: |
29cb20bd
SS
218 echo "head_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
219
220 - name: Update master
1d03633c 221 env:
222 target_repo: ${{ steps.setup_variables.outputs.target_repo }}
223 if: |
224 vars.PUSH_VERSION_COMMIT != '' && !inputs.prerelease && env.target_repo == github.repository
29cb20bd
SS
225 run: git push origin ${{ github.event.ref }}
226
c4efa0ae 227 build:
29cb20bd 228 needs: prepare
c4efa0ae 229 uses: ./.github/workflows/build.yml
230 with:
231 version: ${{ needs.prepare.outputs.version }}
232 channel: ${{ needs.prepare.outputs.channel }}
20314dd4 233 origin: ${{ needs.prepare.outputs.target_repo }}
c4efa0ae 234 permissions:
235 contents: read
236 packages: write # For package cache
237 secrets:
238 GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }}
239
1d03633c 240 publish_pypi:
c4efa0ae 241 needs: [prepare, build]
1d03633c 242 if: ${{ needs.prepare.outputs.pypi_project }}
29cb20bd 243 runs-on: ubuntu-latest
1d03633c 244 permissions:
245 id-token: write # mandatory for trusted publishing
29cb20bd
SS
246
247 steps:
5438593a 248 - uses: actions/checkout@v4
867f637b 249 with:
250 fetch-depth: 0
b14e818b 251 - uses: actions/setup-python@v5
29cb20bd
SS
252 with:
253 python-version: "3.10"
254
255 - name: Install Requirements
256 run: |
1d03633c 257 sudo apt -y install pandoc man
b8a433aa 258 python devscripts/install_deps.py -o --include build
29cb20bd
SS
259
260 - name: Prepare
1d03633c 261 env:
262 version: ${{ needs.prepare.outputs.version }}
263 suffix: ${{ needs.prepare.outputs.pypi_suffix }}
264 channel: ${{ needs.prepare.outputs.channel }}
265 target_repo: ${{ needs.prepare.outputs.target_repo }}
266 pypi_project: ${{ needs.prepare.outputs.pypi_project }}
29cb20bd 267 run: |
1d03633c 268 python devscripts/update-version.py -c "${{ env.channel }}" -r "${{ env.target_repo }}" -s "${{ env.suffix }}" "${{ env.version }}"
29cb20bd 269 python devscripts/make_lazy_extractors.py
775cde82 270 sed -i -E '0,/(name = ")[^"]+(")/s//\1${{ env.pypi_project }}\2/' pyproject.toml
29cb20bd 271
1d03633c 272 - name: Build
29cb20bd
SS
273 run: |
274 rm -rf dist/*
55676fe4 275 make pypi-files
775cde82 276 printf '%s\n\n' \
277 'Official repository: <https://github.com/yt-dlp/yt-dlp>' \
278 '**PS**: Some links in this document will not work since this is a copy of the README.md from Github' > ./README.md.new
279 cat ./README.md >> ./README.md.new && mv -f ./README.md.new ./README.md
29cb20bd 280 python devscripts/set-variant.py pip -M "You installed yt-dlp with pip or using the wheel from PyPi; Use that to update"
775cde82 281 make clean-cache
282 python -m build --no-isolation .
29cb20bd 283
632b8ee5 284 - name: Publish to PyPI
1d03633c 285 uses: pypa/gh-action-pypi-publish@release/v1
286 with:
287 verbose: true
29cb20bd 288
29cb20bd
SS
289 publish:
290 needs: [prepare, build]
29cb20bd
SS
291 permissions:
292 contents: write
1d03633c 293 runs-on: ubuntu-latest
294
295 steps:
5438593a 296 - uses: actions/checkout@v4
1d03633c 297 with:
298 fetch-depth: 0
299 - uses: actions/download-artifact@v3
b14e818b 300 - uses: actions/setup-python@v5
1d03633c 301 with:
302 python-version: "3.10"
303
304 - name: Generate release notes
305 env:
306 head_sha: ${{ needs.prepare.outputs.head_sha }}
307 target_repo: ${{ needs.prepare.outputs.target_repo }}
308 target_tag: ${{ needs.prepare.outputs.target_tag }}
309 run: |
310 printf '%s' \
311 '[![Installation](https://img.shields.io/badge/-Which%20file%20should%20I%20download%3F-white.svg?style=for-the-badge)]' \
312 '(https://github.com/${{ github.repository }}#installation "Installation instructions") ' \
313 '[![Documentation](https://img.shields.io/badge/-Docs-brightgreen.svg?style=for-the-badge&logo=GitBook&labelColor=555555)]' \
314 '(https://github.com/${{ github.repository }}' \
315 '${{ env.target_repo == github.repository && format('/tree/{0}', env.target_tag) || '' }}#readme "Documentation") ' \
316 '[![Donate](https://img.shields.io/badge/_-Donate-red.svg?logo=githubsponsors&labelColor=555555&style=for-the-badge)]' \
317 '(https://github.com/yt-dlp/yt-dlp/blob/master/Collaborators.md#collaborators "Donate") ' \
318 '[![Discord](https://img.shields.io/discord/807245652072857610?color=blue&labelColor=555555&label=&logo=discord&style=for-the-badge)]' \
319 '(https://discord.gg/H5MNcFW63r "Discord") ' \
320 ${{ env.target_repo == 'yt-dlp/yt-dlp' && '\
321 "[![Nightly](https://img.shields.io/badge/Get%20nightly%20builds-purple.svg?style=for-the-badge)]" \
322 "(https://github.com/yt-dlp/yt-dlp-nightly-builds/releases/latest \"Nightly builds\") " \
323 "[![Master](https://img.shields.io/badge/Get%20master%20builds-lightblue.svg?style=for-the-badge)]" \
324 "(https://github.com/yt-dlp/yt-dlp-master-builds/releases/latest \"Master builds\")"' || '' }} > ./RELEASE_NOTES
325 printf '\n\n' >> ./RELEASE_NOTES
326 cat >> ./RELEASE_NOTES << EOF
327 #### A description of the various files are in the [README](https://github.com/${{ github.repository }}#release-files)
328 ---
329 $(python ./devscripts/make_changelog.py -vv --collapsible)
330 EOF
331 printf '%s\n\n' '**This is a pre-release build**' >> ./PRERELEASE_NOTES
332 cat ./RELEASE_NOTES >> ./PRERELEASE_NOTES
333 printf '%s\n\n' 'Generated from: https://github.com/${{ github.repository }}/commit/${{ env.head_sha }}' >> ./ARCHIVE_NOTES
334 cat ./RELEASE_NOTES >> ./ARCHIVE_NOTES
335
336 - name: Publish to archive repo
337 env:
338 GH_TOKEN: ${{ secrets[needs.prepare.outputs.target_repo_token] }}
339 GH_REPO: ${{ needs.prepare.outputs.target_repo }}
340 version: ${{ needs.prepare.outputs.version }}
341 channel: ${{ needs.prepare.outputs.channel }}
342 if: |
343 inputs.prerelease && env.GH_TOKEN != '' && env.GH_REPO != '' && env.GH_REPO != github.repository
344 run: |
345 title="${{ startswith(env.GH_REPO, 'yt-dlp/') && 'yt-dlp ' || '' }}${{ env.channel }}"
346 gh release create \
347 --notes-file ARCHIVE_NOTES \
348 --title "${title} ${{ env.version }}" \
349 ${{ env.version }} \
350 artifact/*
351
352 - name: Prune old release
353 env:
354 GH_TOKEN: ${{ github.token }}
355 version: ${{ needs.prepare.outputs.version }}
356 target_repo: ${{ needs.prepare.outputs.target_repo }}
357 target_tag: ${{ needs.prepare.outputs.target_tag }}
358 if: |
359 env.target_repo == github.repository && env.target_tag != env.version
360 run: |
361 gh release delete --yes --cleanup-tag "${{ env.target_tag }}" || true
362 git tag --delete "${{ env.target_tag }}" || true
363 sleep 5 # Enough time to cover deletion race condition
364
365 - name: Publish release
366 env:
367 GH_TOKEN: ${{ github.token }}
368 version: ${{ needs.prepare.outputs.version }}
369 target_repo: ${{ needs.prepare.outputs.target_repo }}
370 target_tag: ${{ needs.prepare.outputs.target_tag }}
371 head_sha: ${{ needs.prepare.outputs.head_sha }}
372 if: |
373 env.target_repo == github.repository
374 run: |
375 title="${{ github.repository == 'yt-dlp/yt-dlp' && 'yt-dlp ' || '' }}"
376 title+="${{ env.target_tag != env.version && format('{0} ', env.target_tag) || '' }}"
377 gh release create \
378 --notes-file ${{ inputs.prerelease && 'PRERELEASE_NOTES' || 'RELEASE_NOTES' }} \
379 --target ${{ env.head_sha }} \
380 --title "${title}${{ env.version }}" \
381 ${{ inputs.prerelease && '--prerelease' || '' }} \
382 ${{ env.target_tag }} \
383 artifact/*