def upload(upload_settings: settings.Settings, dists: List[str]) -> None: dists = commands._find_dists(dists) # Determine if the user has passed in pre-signed distributions signatures = {os.path.basename(d): d for d in dists if d.endswith(".asc")} uploads = [i for i in dists if not i.endswith(".asc")] upload_settings.check_repository_url() repository_url = cast(str, upload_settings.repository_config["repository"]) print(f"Uploading distributions to {repository_url}") packages_to_upload = [ _make_package(filename, signatures, upload_settings) for filename in uploads ] repository = upload_settings.create_repository() uploaded_packages = [] for package in packages_to_upload: skip_message = " Skipping {} because it appears to already exist".format( package.basefilename) # Note: The skip_existing check *needs* to be first, because otherwise # we're going to generate extra HTTP requests against a hardcoded # URL for no reason. if upload_settings.skip_existing and repository.package_is_uploaded( package): print(skip_message) continue resp = repository.upload(package) # Bug 92. If we get a redirect we should abort because something seems # funky. The behaviour is not well defined and redirects being issued # by PyPI should never happen in reality. This should catch malicious # redirects as well. if resp.is_redirect: raise exceptions.RedirectDetected.from_args( repository_url, resp.headers["location"], ) if skip_upload(resp, upload_settings.skip_existing, package): print(skip_message) continue utils.check_status_code(resp, upload_settings.verbose) uploaded_packages.append(package) release_urls = repository.release_urls(uploaded_packages) if release_urls: print("\nView at:") for url in release_urls: print(url) # Bug 28. Try to silence a ResourceWarning by clearing the connection # pool. repository.close()
def publish_pypi(target, args): """ Build and publish the target on a pypi repository """ config = Configuration(args) assert config.has_pypi_auth(), "Missing PyPi authentication" # Build the project setup = target.check_path("setup.py") logger.info(f"Building Python project using {setup}") sandbox.run_setup(setup, ["clean", "sdist", "bdist_wheel"]) # Check some files were produced dist = target.check_path("dist") build = glob.glob(f"{dist}/*") assert len(build) > 0, "No built files found" logger.info("Will upload {}".format(", ".join(map(os.path.basename, build)))) # Use default repository repository = args.repository or DEFAULT_REPOSITORY logger.info(f"Will upload on {repository}") # Upload it through twine upload_settings = Settings( username=config.pypi["username"], password=config.pypi["password"], repository_url=repository, verbose=True, disable_progress_bar=False, ) twine_upload(upload_settings, build) logger.info("PyPi publication finished.")
def handle(self) -> int: from twine.settings import Settings from twine.commands.upload import upload distributions: list[Path] = [] with tempfile.TemporaryDirectory() as tmpdir: for project in self.app.repository.projects(): if not project.is_python_project: continue self.line(f'Build <info>{project.dist_name()}</info>') backend = Pep517BuildBackend( project.pyproject_toml.value()['build-system'] ['build-backend'], project.directory, Path(tmpdir)) sdist = backend.build_sdist() self.line(f' <comment>{sdist.name}</comment>') wheel = backend.build_wheel() self.line(f' <comment>{wheel.name}</comment>') distributions += [sdist, wheel] if not self.option("dry"): kwargs = { option.name.replace('-', '_'): self.option(option.name) for option in self.options } kwargs['repository_name'] = kwargs.pop('repository') settings = Settings(**kwargs) upload(settings, [str(d) for d in distributions]) return 0
def prepare(self): super().prepare() self.shell = True self.pypi_repository = self.get_config("pypi_repository") self.pypirc_path = os.path.expanduser(self.config.get("config_file")) self.twine_settings = Settings( config_file=self.pypirc_path, repository_name=self.pypi_repository, sign=self.get_config("sign"), identity=self.get_config("identity"), sign_with=self.get_config("sign_with"), )
def upload_component(component_path, repo="pypi", username=None, password=None): """Upload a given component to pypi The pypi username and password must either be specified in a ~/.pypirc file or in environment variables PYPI_USER and PYPI_PASS """ if username is None: username = input("Enter your username [%s]: " % repo) if password is None: password = getpass( ("Enter your password [%s]: " % repo).encode('utf-8')) distpath = os.path.join(component_path, 'dist', '*') distpath = os.path.realpath(os.path.abspath(distpath)) dists = glob.glob(distpath) repo_name = repo repo_url = None if "://" in repo_name: repo_url = repo repo_name = None try: #Invoke upload this way since subprocess call of twine cli has cross platform issues settings = Settings(username=username, password=password, repository_name=repo_name, repository_url=repo_url) upload(settings, dists) except requests.exceptions.HTTPError as exc: code = exc.response.status_code if repo_name is None: repo_name = repo_url msg = "Unknown response from server" if code == 409 or code == 400: msg = "Package already exists" raise ExternalError("PyPI repository '%s'" % repo_name, "HTTP status %d: %s" % (code, msg))
def pypi(package, dry_run): """Deploys build artifacts (python packages to PyPI) Deployment is only allowed for packages in which the visibility is "public". This check prevents publishing of private resources to the (public) PyPI webserver. """ if dry_run: logger.warn("!!!! DRY RUN MODE !!!!") logger.warn("Nothing is being deployed to server") # determine project visibility public = os.environ["CI_PROJECT_VISIBILITY"] == "public" if not public: raise RuntimeError( "The repository %s is not public - a package " "deriving from it therefore, CANNOT be published to PyPI. " "You must follow the relevant software disclosure procedures " 'and set this repository to "public" before trying again.' % os.environ["CI_PROJECT_PATH"]) from twine.settings import Settings from ..constants import CACERT settings = Settings( username=os.environ["PYPIUSER"], password=os.environ["PYPIPASS"], skip_existing=True, cacert=CACERT, ) if not dry_run: from twine.commands.upload import upload for k in package: logger.info("Deploying python package %s to PyPI", k) upload(settings, [k]) logger.info("%s: Deployed to PyPI - OK", k)
def register(register_settings: settings.Settings, package: str) -> None: repository_url = cast(str, register_settings.repository_config["repository"]) print(f"Registering package to {repository_url}") repository = register_settings.create_repository() if not os.path.exists(package): raise exceptions.PackageNotFound( f'"{package}" does not exist on the file system.') resp = repository.register( package_file.PackageFile.from_filename(package, register_settings.comment)) repository.close() if resp.is_redirect: raise exceptions.RedirectDetected.from_args( repository_url, resp.headers["location"], ) resp.raise_for_status()
def store_settings(self, config: dict) -> Settings: credential_kwargs = super()._transform_key_to_credential_kwargs( config["azure"]["keyvault_keys"][current_filename(__file__)]) return Settings(**credential_kwargs)