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