Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tests/adds checking scripts #134

Draft
wants to merge 3 commits into
base: staging
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions .circleci/check_compatibility.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#!/usr/bin/env python3

import sys
import requests
from packaging.specifiers import SpecifierSet
from packaging.version import Version, InvalidVersion, parse
import re


def main():
if len(sys.argv) != 2:
print("Usage: python check_compatibility.py <python_version>")
sys.exit(1)

python_version = sys.argv[1]
all_passed = True

GREEN = "\033[0;32m"
RED = "\033[0;31m"
NC = "\033[0m" # No Color

def check_compatibility():
nonlocal all_passed
try:
with open("/Users/ibraheem/Desktop/btcli/btcli/requirements.txt", "r") as f:
requirements = f.readlines()
except FileNotFoundError:
print(f"{RED}requirements.txt file not found.{NC}")
sys.exit(1)

for line in requirements:
line = line.strip()
# Skip empty lines and comments
if not line or line.startswith("#"):
continue
# Skip lines starting with git+
if line.startswith("git+"):
continue

# Extract package name and version specifier
package_name_and_specifier = re.split("[;]", line)[0].strip()
package_name = re.split("[!=<>~]", package_name_and_specifier)[0]
package_name = package_name.split("[")[0] # Remove extras
version_specifier = package_name_and_specifier[len(package_name) :].strip()

# Request PyPi for package details
print(f"Checking {package_name}... ", end="")
url = f"https://pypi.org/pypi/{package_name}/json"
response = requests.get(url)
if response.status_code != 200:
print(
f"{RED}Information not available for {package_name}. Failure.{NC}"
)
all_passed = False
continue

# Parse the data
data = response.json()
requires_python = data["info"]["requires_python"]

# Parse the version specifier from requirements.txt
requirement_specifier = (
SpecifierSet(version_specifier) if version_specifier else None
)

# Get all available versions of the package
available_versions = [parse(v) for v in data["releases"].keys()]
available_versions.sort(reverse=True)

# Filter versions that satisfy the requirement specifier
if requirement_specifier:
matching_versions = [
v for v in available_versions if requirement_specifier.contains(v)
]
else:
matching_versions = available_versions

# Check for versions compatible with the specified Python version
compatible_versions = []
for version in matching_versions:
releases = data["releases"].get(str(version), [])
for release in releases:
# Check if the release has a 'requires_python' field
release_requires_python = (
release.get("requires_python") or requires_python
)
if release_requires_python:
try:
specifier = SpecifierSet(release_requires_python)
if specifier.contains(Version(python_version)):
compatible_versions.append(version)
break # No need to check other files for this version
except InvalidVersion as e:
print(f"{RED}Invalid version in requires_python: {e}{NC}")
all_passed = False
break
else:
# If no requires_python, assume compatible
compatible_versions.append(version)
break
if compatible_versions:
break # Found the highest compatible version

if compatible_versions:
print(
f"{GREEN}Supported (compatible version: {compatible_versions[0]}){NC}"
)
else:
print(f"{RED}Not compatible with Python {python_version}.{NC}")
all_passed = False

check_compatibility()

if all_passed:
print(
f"{GREEN}All requirements are compatible with Python {python_version}.{NC}"
)
print(f"{GREEN}All tests passed.{NC}")
else:
print(
f"{RED}Some requirements are NOT compatible with Python {python_version}.{NC}"
)
print(f"{RED}Some tests did not pass.{NC}")
sys.exit(1)


if __name__ == "__main__":
main()
26 changes: 26 additions & 0 deletions .circleci/check_pr_status.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash

# Extract the repository owner
REPO_OWNER=$(echo $CIRCLE_PULL_REQUEST | awk -F'/' '{print $(NF-3)}')

# Extract the repository name
REPO_NAME=$(echo $CIRCLE_PULL_REQUEST | awk -F'/' '{print $(NF-2)}')

# Extract the pull request number
PR_NUMBER=$(echo $CIRCLE_PULL_REQUEST | awk -F'/' '{print $NF}')


PR_DETAILS=$(curl -s \
"https://api.github.com/repos/$REPO_OWNER/$REPO_NAME/pulls/$PR_NUMBER")


IS_DRAFT=$(echo "$PR_DETAILS" | jq -r .draft)
echo $IS_DRAFT

if [ "$IS_DRAFT" == "true" ]; then
echo "This PR is a draft. Skipping the workflow."
exit 1
else
echo "This PR is not a draft. Proceeding with the workflow."
exit 0
fi
10 changes: 10 additions & 0 deletions .circleci/check_requirements.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

# Check if requirements files have changed in the last commit
if git diff --name-only HEAD~1 | grep -E 'requirements/prod.txt|requirements/dev.txt'; then
echo "Requirements files have changed. Running compatibility checks..."
echo 'export REQUIREMENTS_CHANGED="true"' >> $BASH_ENV
else
echo "Requirements files have not changed. Skipping compatibility checks..."
echo 'export REQUIREMENTS_CHANGED="false"' >> $BASH_ENV
fi
102 changes: 102 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
version: 2.1

orbs:
python: circleci/[email protected]
python-lib: dialogue/[email protected]

jobs:
# Check if the PR is a draft
check-if-pr-is-draft:
docker:
- image: cimg/python:3.10
steps:
- checkout
- run:
name: Install jq and curl
command: sudo apt-get update && sudo apt-get install -y jq curl
- run:
name: Check if PR is a draft
command: ./check_pr_status.sh

# Compatibility check across all supported versions
check_compatibility:
parameters:
python_version:
type: string
docker:
- image: cimg/python:<< parameters.python_version >>
steps:
- checkout
- run:
name: Install dependencies
command: |
sudo apt-get update
sudo apt-get install -y jq curl
python -m pip install --upgrade pip
pip install requests packaging
- run:
name: Check compatibility for Python << parameters.python_version >>
command: |
python .circleci/check_compatibility.py << parameters.python_version >>

# Linting with Ruff (Run once on the latest Python version)
ruff:
resource_class: small
docker:
- image: cimg/python:3.12.0
steps:
- checkout
- restore_cache:
name: Restore cached Ruff venv
keys:
- v2-pypi-py-ruff-3.12.0
- run:
name: Update & Activate Ruff venv
command: |
python -m venv .venv
. .venv/bin/activate
python -m pip install --upgrade pip
pip install ruff
- save_cache:
name: Save cached Ruff venv
paths:
- ".venv/"
key: v2-pypi-py-ruff-3.12.0
- run:
name: Ruff linting
command: |
. .venv/bin/activate
ruff check .

workflows:
version: 2
main_workflow:
jobs:
- check-if-pr-is-draft

# Compatibility checks for multiple Python versions
- check_compatibility:
requires:
- check-if-pr-is-draft
python_version: "3.9.0"
name: check-compatibility-3.9.0
- check_compatibility:
requires:
- check-if-pr-is-draft
python_version: "3.10.0"
name: check-compatibility-3.10.0
- check_compatibility:
requires:
- check-if-pr-is-draft
python_version: "3.11.0"
name: check-compatibility-3.11.0
- check_compatibility:
requires:
- check-if-pr-is-draft
python_version: "3.12.0"
name: check-compatibility-3.12.0

# Linting workflow using Ruff
- ruff:
requires:
- check-if-pr-is-draft
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ fuzzywuzzy~=0.18.0
netaddr~=1.3.0
numpy>=2.0.1
Jinja2
pycryptodome # Crypto
pycryptodome
PyYAML~=6.0.1
pytest
python-Levenshtein
Expand Down
Loading