Compare commits

...

2 Commits

Author SHA1 Message Date
bashonly
78ec25a07a
[update] Refactor for unit testing and improved output 2023-11-12 15:48:36 -06:00
bashonly
c6092a0be2
[build] Support PyPI prereleases and trusted publishing 2023-11-12 15:28:26 -06:00
8 changed files with 62 additions and 28 deletions

View File

@ -24,4 +24,5 @@ jobs:
permissions: permissions:
contents: write contents: write
packages: write packages: write
id-token: write # mandatory for trusted publishing
secrets: inherit secrets: inherit

View File

@ -31,4 +31,5 @@ jobs:
permissions: permissions:
contents: write contents: write
packages: write packages: write
id-token: write # mandatory for trusted publishing
secrets: inherit secrets: inherit

View File

@ -63,6 +63,7 @@ jobs:
target_repo_token: ${{ steps.setup_variables.outputs.target_repo_token }} target_repo_token: ${{ steps.setup_variables.outputs.target_repo_token }}
target_tag: ${{ steps.setup_variables.outputs.target_tag }} target_tag: ${{ steps.setup_variables.outputs.target_tag }}
pypi_project: ${{ steps.setup_variables.outputs.pypi_project }} pypi_project: ${{ steps.setup_variables.outputs.pypi_project }}
pypi_suffix: ${{ steps.setup_variables.outputs.pypi_suffix }}
pypi_token: ${{ steps.setup_variables.outputs.pypi_token }} pypi_token: ${{ steps.setup_variables.outputs.pypi_token }}
head_sha: ${{ steps.get_target.outputs.head_sha }} head_sha: ${{ steps.get_target.outputs.head_sha }}
@ -151,6 +152,7 @@ jobs:
target_repo_token='${{ env.target_repo }}_archive_repo_token' target_repo_token='${{ env.target_repo }}_archive_repo_token'
${{ !!secrets[format('{0}_archive_repo_token', env.target_repo)] }} || fallback_token ${{ !!secrets[format('{0}_archive_repo_token', env.target_repo)] }} || fallback_token
pypi_project='${{ vars[format('{0}_pypi_project', env.target_repo)] }}' pypi_project='${{ vars[format('{0}_pypi_project', env.target_repo)] }}'
pypi_suffix='${{ vars[format('{0}_pypi_suffix', env.target_repo)] }}'
${{ !secrets[format('{0}_pypi_token', env.target_repo)] }} || pypi_token='${{ env.target_repo }}_pypi_token' ${{ !secrets[format('{0}_pypi_token', env.target_repo)] }} || pypi_token='${{ env.target_repo }}_pypi_token'
fi fi
else else
@ -160,6 +162,7 @@ jobs:
target_repo_token='${{ env.source_repo }}_archive_repo_token' target_repo_token='${{ env.source_repo }}_archive_repo_token'
${{ !!secrets[format('{0}_archive_repo_token', env.source_repo)] }} || fallback_token ${{ !!secrets[format('{0}_archive_repo_token', env.source_repo)] }} || fallback_token
pypi_project='${{ vars[format('{0}_pypi_project', env.source_repo)] }}' pypi_project='${{ vars[format('{0}_pypi_project', env.source_repo)] }}'
pypi_suffix='${{ vars[format('{0}_pypi_suffix', env.source_repo)] }}'
${{ !secrets[format('{0}_pypi_token', env.source_repo)] }} || pypi_token='${{ env.source_repo }}_pypi_token' ${{ !secrets[format('{0}_pypi_token', env.source_repo)] }} || pypi_token='${{ env.source_repo }}_pypi_token'
else else
target_repo='${{ github.repository }}' target_repo='${{ github.repository }}'
@ -171,10 +174,10 @@ jobs:
fi fi
if [[ -z "${pypi_token}" && "${pypi_project}" ]]; then if [[ -z "${pypi_token}" && "${pypi_project}" ]]; then
if ${{ !secrets.PYPI_TOKEN }}; then if ${{ !secrets.PYPI_TOKEN }}; then
echo "::error::No PYPI_TOKEN for use with ${pypi_project} found" pypi_token=OIDC
exit 1 else
pypi_token=PYPI_TOKEN
fi fi
pypi_token=PYPI_TOKEN
fi fi
echo "::group::Output variables" echo "::group::Output variables"
@ -185,6 +188,7 @@ jobs:
target_repo_token=${target_repo_token} target_repo_token=${target_repo_token}
target_tag=${target_tag} target_tag=${target_tag}
pypi_project=${pypi_project} pypi_project=${pypi_project}
pypi_suffix=${pypi_suffix}
pypi_token=${pypi_token} pypi_token=${pypi_token}
EOF EOF
echo "::endgroup::" echo "::endgroup::"
@ -248,6 +252,8 @@ jobs:
needs: [prepare, build] needs: [prepare, build]
if: ${{ needs.prepare.outputs.pypi_project }} if: ${{ needs.prepare.outputs.pypi_project }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
id-token: write # mandatory for trusted publishing
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -264,25 +270,38 @@ jobs:
- name: Prepare - name: Prepare
env: env:
version: ${{ needs.prepare.outputs.version }} version: ${{ needs.prepare.outputs.version }}
suffix: ${{ needs.prepare.outputs.pypi_suffix }}
channel: ${{ needs.prepare.outputs.channel }} channel: ${{ needs.prepare.outputs.channel }}
target_repo: ${{ needs.prepare.outputs.target_repo }} target_repo: ${{ needs.prepare.outputs.target_repo }}
run: |
python devscripts/update-version.py -c "${{ env.channel }}" -r "${{ env.target_repo }}" "${{ env.version }}"
python devscripts/make_lazy_extractors.py
- name: Build and publish on PyPI
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets[needs.prepare.outputs.pypi_token] }}
pypi_project: ${{ needs.prepare.outputs.pypi_project }} pypi_project: ${{ needs.prepare.outputs.pypi_project }}
run: | run: |
rm -rf dist/* 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 sed -i -E "s/(name=')[^']+(', # package name)/\1${{ env.pypi_project }}\2/" setup.py
- name: Build
run: |
rm -rf dist/*
make pypi-files 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 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 python setup.py sdist bdist_wheel
- name: Publish to PyPI via token
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets[needs.prepare.outputs.pypi_token] }}
if: |
needs.prepare.outputs.pypi_token != 'OIDC' && env.TWINE_PASSWORD
run: |
twine upload dist/* twine upload dist/*
- name: Publish to PyPI via trusted publishing
if: |
needs.prepare.outputs.pypi_token == 'OIDC'
uses: pypa/gh-action-pypi-publish@release/v1
with:
verbose: true
publish: publish:
needs: [prepare, build] needs: [prepare, build]
permissions: permissions:

View File

@ -48,6 +48,8 @@ UPDATE_HINT = None
CHANNEL = {channel!r} CHANNEL = {channel!r}
ORIGIN = {origin!r} ORIGIN = {origin!r}
_pkg_version = {package_version!r}
''' '''
if __name__ == '__main__': if __name__ == '__main__':
@ -58,6 +60,9 @@ if __name__ == '__main__':
parser.add_argument( parser.add_argument(
'-r', '--origin', default='local', '-r', '--origin', default='local',
help='Select origin/repository (default: %(default)s)') help='Select origin/repository (default: %(default)s)')
parser.add_argument(
'-s', '--suffix', default='',
help='Add an alphanumeric suffix to the package version, e.g. "dev"')
parser.add_argument( parser.add_argument(
'-o', '--output', default='yt_dlp/version.py', '-o', '--output', default='yt_dlp/version.py',
help='The output file to write to (default: %(default)s)') help='The output file to write to (default: %(default)s)')
@ -71,6 +76,7 @@ if __name__ == '__main__':
args.version if args.version and '.' in args.version args.version if args.version and '.' in args.version
else get_new_version(None, args.version)) else get_new_version(None, args.version))
write_file(args.output, VERSION_TEMPLATE.format( write_file(args.output, VERSION_TEMPLATE.format(
version=version, git_head=git_head, channel=args.channel, origin=args.origin)) version=version, git_head=git_head, channel=args.channel, origin=args.origin,
package_version=f'{version}{args.suffix}'))
print(f'version={version} ({args.channel}), head={git_head}') print(f'version={version} ({args.channel}), head={git_head}')

View File

@ -13,10 +13,11 @@ def write_file(fname, content, mode='w'):
return f.write(content) return f.write(content)
def read_version(fname='yt_dlp/version.py'): def read_version(fname='yt_dlp/version.py', varname='__version__'):
"""Get the version without importing the package""" """Get the version without importing the package"""
exec(compile(read_file(fname), fname, 'exec')) items = {}
return locals()['__version__'] exec(compile(read_file(fname), fname, 'exec'), items)
return items[varname]
def get_filename_args(has_infile=False, default_outfile=None): def get_filename_args(has_infile=False, default_outfile=None):

View File

@ -18,7 +18,7 @@ except ImportError:
from devscripts.utils import read_file, read_version from devscripts.utils import read_file, read_version
VERSION = read_version() VERSION = read_version(varname='_pkg_version')
DESCRIPTION = 'A youtube-dl fork with additional features and patches' DESCRIPTION = 'A youtube-dl fork with additional features and patches'

View File

@ -211,20 +211,24 @@ class UpdateInfo:
class Updater: class Updater:
# XXX: use class variables to simplify testing
_channel = CHANNEL
_origin = ORIGIN
def __init__(self, ydl, target: str | None = None): def __init__(self, ydl, target: str | None = None):
self.ydl = ydl self.ydl = ydl
# For backwards compat, target needs to be treated as if it could be None # For backwards compat, target needs to be treated as if it could be None
self.requested_channel, sep, self.requested_tag = (target or CHANNEL).rpartition('@') self.requested_channel, sep, self.requested_tag = (target or self._channel).rpartition('@')
# Check if requested_tag is actually the requested repo/channel # Check if requested_tag is actually the requested repo/channel
if not sep and ('/' in self.requested_tag or self.requested_tag in UPDATE_SOURCES): if not sep and ('/' in self.requested_tag or self.requested_tag in UPDATE_SOURCES):
self.requested_channel = self.requested_tag self.requested_channel = self.requested_tag
self.requested_tag: str = None # type: ignore (we set it later) self.requested_tag: str = None # type: ignore (we set it later)
elif not self.requested_channel: elif not self.requested_channel:
# User did not specify a channel, so we are requesting the default channel # User did not specify a channel, so we are requesting the default channel
self.requested_channel = CHANNEL.partition('@')[0] self.requested_channel = self._channel.partition('@')[0]
# --update should not be treated as an exact tag request even if CHANNEL has a @tag # --update should not be treated as an exact tag request even if CHANNEL has a @tag
self._exact = bool(target) and target != CHANNEL self._exact = bool(target) and target != self._channel
if not self.requested_tag: if not self.requested_tag:
# User did not specify a tag, so we request 'latest' and track that no exact tag was passed # User did not specify a tag, so we request 'latest' and track that no exact tag was passed
self.requested_tag = 'latest' self.requested_tag = 'latest'
@ -233,7 +237,7 @@ class Updater:
if '/' in self.requested_channel: if '/' in self.requested_channel:
# requested_channel is actually a repository # requested_channel is actually a repository
self.requested_repo = self.requested_channel self.requested_repo = self.requested_channel
if not self.requested_repo.startswith('yt-dlp/') and self.requested_repo != ORIGIN: if not self.requested_repo.startswith('yt-dlp/') and self.requested_repo != self._origin:
self.ydl.report_warning( self.ydl.report_warning(
f'You are switching to an {self.ydl._format_err("unofficial", "red")} executable ' f'You are switching to an {self.ydl._format_err("unofficial", "red")} executable '
f'from {self.ydl._format_err(self.requested_repo, self.ydl.Styles.EMPHASIS)}. ' f'from {self.ydl._format_err(self.requested_repo, self.ydl.Styles.EMPHASIS)}. '
@ -365,7 +369,7 @@ class Updater:
self._report_network_error(f'obtain version info ({e})', delim='; Please try again later or') self._report_network_error(f'obtain version info ({e})', delim='; Please try again later or')
return None return None
if self._exact and ORIGIN != self.requested_repo: if self._exact and self._origin != self.requested_repo:
has_update = True has_update = True
elif requested_version: elif requested_version:
if self._exact: if self._exact:
@ -377,16 +381,18 @@ class Updater:
else: else:
has_update = False has_update = False
current_label = _make_label(ORIGIN, CHANNEL.partition("@")[2] or self.current_version, self.current_version) resolved_tag = requested_version if self.requested_tag == 'latest' else self.requested_tag
current_label = _make_label(self._origin, self._channel.partition("@")[2] or self.current_version, self.current_version)
requested_label = _make_label(self.requested_repo, resolved_tag, requested_version)
latest_or_requested = f'{"Latest" if self.requested_tag == "latest" else "Requested"} version: {requested_label}'
if not has_update: if not has_update:
if _output: if _output:
self.ydl.to_screen(f'yt-dlp is up to date ({current_label})') self.ydl.to_screen(f'{latest_or_requested}\nyt-dlp is up to date ({current_label})')
return None return None
update_spec = self._download_update_spec(('latest', None) if requested_version else (None,)) update_spec = self._download_update_spec(('latest', None) if requested_version else (None,))
if not update_spec: if not update_spec:
return None return None
resolved_tag = requested_version if self.requested_tag == 'latest' else self.requested_tag
# `result_` prefixed vars == post-_process_update_spec() values # `result_` prefixed vars == post-_process_update_spec() values
result_tag = self._process_update_spec(update_spec, resolved_tag) result_tag = self._process_update_spec(update_spec, resolved_tag)
if not result_tag or result_tag == self.current_version: if not result_tag or result_tag == self.current_version:
@ -417,11 +423,9 @@ class Updater:
self.ydl.report_warning('The hash could not be found in the checksum file, skipping verification') self.ydl.report_warning('The hash could not be found in the checksum file, skipping verification')
if _output: if _output:
requested_label = _make_label(self.requested_repo, resolved_tag, requested_version)
update_label = _make_label(self.requested_repo, result_tag, result_version) update_label = _make_label(self.requested_repo, result_tag, result_version)
self.ydl.to_screen( self.ydl.to_screen(
f'Current version: {current_label}\n' f'Current version: {current_label}\n{latest_or_requested}'
+ f'{"Latest" if self.requested_tag == "latest" else "Requested"} version: {requested_label}'
+ (f'\nUpgradable to: {update_label}' if update_label != requested_label else '')) + (f'\nUpgradable to: {update_label}' if update_label != requested_label else ''))
return UpdateInfo( return UpdateInfo(

View File

@ -11,3 +11,5 @@ UPDATE_HINT = None
CHANNEL = 'stable' CHANNEL = 'stable'
ORIGIN = 'yt-dlp/yt-dlp' ORIGIN = 'yt-dlp/yt-dlp'
_pkg_version = '2023.10.13'