diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..d93834d --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,69 @@ +--- +include: + - local: .gitlab-ci/versioning/gitversion.yml + - local: .gitlab-ci/git/create_tag.yml + +stages: + - build + - release + +gitversion: + extends: .versioning:gitversion + stage: .pre + tags: + - gitlab-org-docker + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when commits are pushed or merged to the default branch + +build: + stage: build + image: python:3.9.21 + tags: + - gitlab-org-docker + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when commits are pushed or merged to the default branch + needs: + - job: gitversion + artifacts: true + script: + - sed -i "s/^__version__ = .*/__version__ = \"${GitVersion_MajorMinorPatch}\"/" src/PyPiUpdater/__init__.py + - cat src/PyPiUpdater/__init__.py + - python3 -m pip install build + - python3 -m build + artifacts: + paths: + - dist/* + expire_in: 1 day + +publish: + stage: release + image: python:3.9.21 + tags: + - gitlab-org-docker + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when commits are pushed or merged to the default branch + variables: + TWINE_USERNAME: "__token__" + TWINE_PASSWORD: $TWINE_API + needs: + - job: build + artifacts: true + script: + - python3 -m pip install twine + - python3 -m twine upload dist/* + +create_tag: + extends: .git:create_tag + stage: release + tags: + - gitlab-org-docker + variables: + VERSION: $GitVersion_SemVer + TOKEN: $GITLAB_TOKEN + needs: + - job: gitversion + artifacts: true + rules: + - if: $CI_COMMIT_TAG + when: never # Do not run this job when a tag is created manually + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # Run this job when commits are pushed or merged to the default branch diff --git a/.gitlab-ci/git/create_tag.yml b/.gitlab-ci/git/create_tag.yml new file mode 100644 index 0000000..2c1afd7 --- /dev/null +++ b/.gitlab-ci/git/create_tag.yml @@ -0,0 +1,15 @@ +--- + +.git:create_tag: + image: alpine:3.21 + variables: + GIT_STRATEGY: clone + GIT_DEPTH: 0 + GIT_LFS_SKIP_SMUDGE: 1 + VERSION: '' + TOKEN: '' # Token with push privileges + script: + - apk add git + - git remote set-url origin https://oauth2:$TOKEN@$CI_SERVER_HOST/$CI_PROJECT_PATH + - git tag $VERSION + - git push origin tag $VERSION diff --git a/.gitlab-ci/versioning/gitversion.yml b/.gitlab-ci/versioning/gitversion.yml new file mode 100644 index 0000000..dbbc149 --- /dev/null +++ b/.gitlab-ci/versioning/gitversion.yml @@ -0,0 +1,31 @@ +--- +.versioning:gitversion: + image: + name: mcr.microsoft.com/dotnet/sdk:9.0 + variables: + GIT_STRATEGY: clone + GIT_DEPTH: 0 # force a deep/non-shallow fetch need by gitversion + GIT_LFS_SKIP_SMUDGE: 1 + cache: [] # caches and before / after scripts can mess things up + script: + - | + dotnet tool install --global GitVersion.Tool --version 5.* + export PATH="$PATH:/root/.dotnet/tools" + + dotnet-gitversion -output buildserver + + # We could just collect the output file gitversion.properties (with artifacts:report:dotenv: gitversion.properties as it is already in DOTENV format, + # however it contains ~33 variables which unnecessarily consumes many of the 50 max DOTENV variables of the free GitLab version. + # Limits are higher for licensed editions, see https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportsdotenv + grep 'GitVersion_LegacySemVer=' gitversion.properties >> gitversion.env + grep 'GitVersion_SemVer=' gitversion.properties >> gitversion.env + grep 'GitVersion_FullSemVer=' gitversion.properties >> gitversion.env + grep 'GitVersion_Major=' gitversion.properties >> gitversion.env + grep 'GitVersion_Minor=' gitversion.properties >> gitversion.env + grep 'GitVersion_Patch=' gitversion.properties >> gitversion.env + grep 'GitVersion_MajorMinorPatch=' gitversion.properties >> gitversion.env + grep 'GitVersion_BuildMetaData=' gitversion.properties >> gitversion.env + artifacts: + reports: + # propagates variables into the pipeline level + dotenv: gitversion.env diff --git a/.woodpecker/woodpecker_ci.yml b/.woodpecker/woodpecker_ci.yml deleted file mode 100644 index c531675..0000000 --- a/.woodpecker/woodpecker_ci.yml +++ /dev/null @@ -1,92 +0,0 @@ -steps: - - name: gitversion - depends_on: [] # nothing start emititly - when: - event: push - branch: main - image: mcr.microsoft.com/dotnet/sdk:9.0 - environment: - CI_TOKEN: - from_secret: CI_TOKEN - commands: - - git remote set-url origin https://CodeByMrFinchum:$CI_TOKEN@code.boxyfoxy.net/$CI_REPO.git - - git fetch --unshallow --tags - - apt-get update && apt-get install -y jq - - dotnet tool install --global GitVersion.Tool --version 5.* - - export PATH="$PATH:/root/.dotnet/tools" - - dotnet-gitversion -output json > version.json - - ls - - cat version.json - - | - echo "GitVersion_SemVer=$(jq -r '.SemVer' version.json)" >> gitversion.env - echo "GitVersion_LegacySemVer=$(jq -r '.LegacySemVer' version.json)" >> gitversion.env - echo "GitVersion_FullSemVer=$(jq -r '.FullSemVer' version.json)" >> gitversion.env - echo "GitVersion_Major=$(jq -r '.Major' version.json)" >> gitversion.env - echo "GitVersion_Minor=$(jq -r '.Minor' version.json)" >> gitversion.env - echo "GitVersion_Patch=$(jq -r '.Patch' version.json)" >> gitversion.env - echo "GitVersion_MajorMinorPatch=$(jq -r '.MajorMinorPatch' version.json)" >> gitversion.env - echo "GitVersion_BuildMetaData=$(jq -r '.BuildMetaData' version.json)" >> gitversion.env - - - name: tagging - depends_on: [gitversion] - when: - event: push - branch: main - image: alpine/git - environment: - CI_TOKEN: - from_secret: CI_TOKEN - commands: - - ls - - cat gitversion.env - - git config --global user.email "ci@noreply.boxyfoxy.net" - - git config --global user.name "CI Bot" - - git remote set-url origin https://CodeByMrFinchum:$${CI_TOKEN}@code.boxyfoxy.net/$${CI_REPO}.git - - . gitversion.env - - git tag $GitVersion_SemVer - - git push origin tag $GitVersion_SemVer - - - name: build - depends_on: [gitversion, tagging] - when: - event: push - branch: main - image: python:3.9.21 - commands: - - ls - - cat gitversion.env - - export $(cat gitversion.env | xargs) - - sed -i "s/^__version__ = .*/__version__ = \"$GitVersion_SemVer\"/" src/PyPiUpdater/__init__.py - - cat src/PyPiUpdater/__init__.py - - python3 -m pip install build - - python3 -m build - - - name: publish_pypi - depends_on: [gitversion, tagging, build] - when: - event: push - branch: main - image: python:3.9.21 - environment: - TWINE_PASSWORD: - from_secret: TWINE_API - TWINE_USERNAME: "__token__" - commands: - - ls - - python3 -m pip install twine - - python3 -m twine upload dist/* - - - name: publish_forgejo - depends_on: [gitversion, tagging, build] - when: - event: push - branch: main - image: python:3.9.21 - environment: - TWINE_PASSWORD: - from_secret: PKG_TOKEN - TWINE_USERNAME: "CodeByMrFinchum" - commands: - - ls - - python3 -m pip install twine - - python3 -m twine upload --verbose --repository-url https://code.boxyfoxy.net/api/packages/CodeByMrFinchum/pypi dist/* diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e847e5..60dc87f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,21 +1,5 @@ # Changelog -## 0.8-0.9: CI woodpecker (25.04.10-11) -- Changes to the pipeline no - -## 0.7.x -### 0.7.2: Removed Debugging Leftovers -- Cleaned up code used for debugging. - -### 0.7.1: Fixed Prerelease Update Detection -- Prevented prerelease versions from being listed as updates, as they must be installed manually. - -### 0.7.0: Added Function to Install Packages -- Introduced the `install_package` function, allowing packages to be installed directly through the app. - - Useful for optional dependencies that need to be installed separately. This enables installation via the UI. - ---- - ## 0.6.x ### 0.6.1: Classifier - Added Classifier for pypi diff --git a/README.md b/README.md index ceb666a..c3f04c1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ # PyPiUpdater -Developed on my [forgejo instance](https://code.boxyfoxy.net/CodeByMrFinchum), [GitLab](https://gitlab.com/CodeByMrFinchum) is used as backup. - **UNFINISHED** Still early code, functions might change drasticly **PyPiUpdater** is a Python library for managing updates of packages installed via `pip`. diff --git a/pip_README.md b/pip_README.md index 81c43b3..2fb85ac 100644 --- a/pip_README.md +++ b/pip_README.md @@ -1,3 +1,3 @@ Simple program to update package from PyPi with pip. -For more info see [PyPiUpdater forgejo](https://code.boxyfoxy.net/CodeByMrFinchum/PyPiUpdater) or backup repo [PyPiUpdater gitlab](https://gitlab.com/CodeByMrFinchum/PyPiUpdater#). +For more info see [PyPiUpdater gitlab](https://gitlab.com/CodeByMrFinchum/PyPiUpdater#). diff --git a/pyproject.toml b/pyproject.toml index 2aeb735..e0c386a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ readme = "README.md" requires-python = ">=3.8" dependencies = ["requests", "packaging"] classifiers = [ - "Development Status :: 3 - Alpha", + "Development Status :: 4 - Beta", "Programming Language :: Python :: 3", "Topic :: Software Development :: Libraries :: Python Modules", "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)", diff --git a/src/PyPiUpdater/__init__.py b/src/PyPiUpdater/__init__.py index 621ee43..136d36c 100644 --- a/src/PyPiUpdater/__init__.py +++ b/src/PyPiUpdater/__init__.py @@ -1,5 +1,4 @@ -from .single_updater import PyPiUpdater -#from .multi_updater import MultiPackageUpdater +from .pypi_updater import PyPiUpdater __all__ = ["PyPiUpdater"] diff --git a/src/PyPiUpdater/multi_updater.py b/src/PyPiUpdater/multi_updater.py deleted file mode 100644 index 71e55a9..0000000 --- a/src/PyPiUpdater/multi_updater.py +++ /dev/null @@ -1,4 +0,0 @@ - -class MultiPackageUpdater: - def __init__(self, log_path): - print("Not ready yet...") diff --git a/src/PyPiUpdater/single_updater.py b/src/PyPiUpdater/pypi_updater.py similarity index 80% rename from src/PyPiUpdater/single_updater.py rename to src/PyPiUpdater/pypi_updater.py index 3e4e6d6..4c5b835 100644 --- a/src/PyPiUpdater/single_updater.py +++ b/src/PyPiUpdater/pypi_updater.py @@ -6,7 +6,6 @@ import time import json import re from packaging import version -from packaging.version import parse, Version from xml.etree import ElementTree as ET class PyPiUpdater: @@ -26,7 +25,7 @@ class PyPiUpdater: self.last_update_check = 0.1 def _get_latest_version(self): - """Fetch the latest stable version from PyPI RSS feed.""" + """Fetch the latest version from PyPI RSS feed.""" rss_url = f"https://pypi.org/rss/project/{self.package_name.lower()}/releases.xml" try: @@ -34,23 +33,9 @@ class PyPiUpdater: response.raise_for_status() root = ET.fromstring(response.content) - # Extract all versions from the feed - versions = [] - for item in root.findall(".//item/title"): - version_text = item.text.strip() - parsed_version = parse(version_text) - # Check if the version is stable (not a pre-release) - if isinstance(parsed_version, Version) and not parsed_version.is_prerelease: - versions.append(parsed_version) - - # Return the latest stable version - if versions: - latest_version = str(max(versions)) - self.latest_version = latest_version - return [latest_version, None] - - return [None, "No stable versions found"] - + latest_version = root.find(".//item/title").text.strip() + self.latest_version = latest_version + return [latest_version, None] except requests.exceptions.RequestException as e: return [None, f"Network error: {str(e)}"] except Exception as e: @@ -161,14 +146,3 @@ class PyPiUpdater: """Write data to JSON log file.""" with open(self.log_path, "w") as f: json.dump(data, f, indent=4) - - @staticmethod - def install_package(package_name): - """Attempts to install a package via pip.""" - try: - subprocess.run([sys.executable, "-m", "pip", "install", package_name], check = True) - print("Successfull") - return [True, f"{package_name} installed successfully!"] - except subprocess.CalledProcessError as e: - print("Failed") - return [False, f"Failed to install {package_name}:\n{e.stderr}"]