Skip to content
Merged
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
53 changes: 45 additions & 8 deletions .github/scripts/generate_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@
from urllib.parse import quote
from pathlib import Path
from github import Github
from typing import List, Dict
from typing import List, Dict, Set

# Define yanked versions - modify this dictionary as needed
yanked_versions = {
"confluent-kafka": {
"2.11.0+gr",
"2.11.0+gr.1",
},
}

HTML_TEMPLATE = """<!DOCTYPE html>
<html>
Expand All @@ -21,7 +29,7 @@
</body>
</html>
"""

def normalize(name):
"""Normalize package name according to PEP 503."""
return re.sub(r"[-_.]+", "-", name).lower()
Expand All @@ -32,12 +40,25 @@ def calculate_sha256(file_path):

return digest.hexdigest()

def extract_version_from_filename(filename: str) -> str:
"""Extract version from wheel or sdist filename."""
# Remove extension
name = filename.replace('.tar.gz', '').replace('.whl', '')

# For wheels: package-version-python-abi-platform
# For sdist: package-version
parts = name.split('-')
if len(parts) >= 2:
return parts[1]
return ""

class PackageIndexBuilder:
def __init__(self, token: str, repo_name: str, output_dir: str):
def __init__(self, token: str, repo_name: str, output_dir: str, yanked_versions: Dict[str, Set[str]] = None):
self.github = Github(token)
self.repo = self.github.get_repo(repo_name)
self.output_dir = Path(output_dir)
self.packages: Dict[str, List[Dict]] = {}
self.yanked_versions = yanked_versions or {}

# Set up authenticated session
self.session = requests.Session()
Expand All @@ -46,9 +67,13 @@ def __init__(self, token: str, repo_name: str, output_dir: str):
"Accept": "application/octet-stream",
})

def collect_packages(self):
def is_version_yanked(self, package_name: str, version: str) -> bool:
"""Check if a specific version of a package is yanked."""
normalized_package = normalize(package_name)
return normalized_package in self.yanked_versions and version in self.yanked_versions[normalized_package]

print ("Query release assets")
def collect_packages(self):
print("Query release assets")

for release in self.repo.get_releases():
for asset in release.get_assets():
Expand All @@ -57,11 +82,13 @@ def collect_packages(self):
if package_name not in self.packages:
self.packages[package_name] = []

version = extract_version_from_filename(asset.name)
self.packages[package_name].append({
'filename': asset.name,
'url': asset.url,
'size': asset.size,
'upload_time': asset.created_at.strftime('%Y-%m-%d %H:%M:%S'),
'version': version,
})

def generate_index_html(self):
Expand All @@ -84,7 +111,9 @@ def generate_index_html(self):
file_links = []
assets = sorted(assets, key=lambda x: x["filename"])
for filename, items in itertools.groupby(assets, key=lambda x: x["filename"]):
url = next(items)['url']
asset_info = next(items)
url = asset_info['url']
version = asset_info['version']

# Download the file
with open(package_dir / filename, 'wb') as f:
Expand All @@ -96,7 +125,15 @@ def generate_index_html(self):
f.write(chunk)

sha256_hash = calculate_sha256(package_dir / filename)
file_links.append(f'<a href="{quote(filename)}#sha256={sha256_hash}">{filename}</a><br/>')

# Check if this version is yanked
yanked_attr = ""
if self.is_version_yanked(package, version):
yanked_attr = ' data-yanked="true"'

file_links.append(
f'<a href="{quote(filename)}#sha256={sha256_hash}"{yanked_attr}>{filename}</a><br/>'
)

package_index = HTML_TEMPLATE.format(
package_name=f"Links for {package}",
Expand Down Expand Up @@ -126,7 +163,7 @@ def main():
print ("Missing required environment variables")
sys.exit(1)

builder = PackageIndexBuilder(token, repo, output_dir)
builder = PackageIndexBuilder(token, repo, output_dir, yanked_versions)
builder.build()

if __name__ == "__main__":
Expand Down
36 changes: 25 additions & 11 deletions .github/workflows/package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,25 +52,18 @@ jobs:
name: wheels-${{ env.OS_NAME }}-${{ env.ARCH }}
path: wheelhouse/confluent_kafka*.whl

publish_pypi_index:
create_release_artifacts:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
name: Build a PyPI-compatible index
name: Create release artifacts
needs: [build-linux-x64, build-windows]
runs-on: ubuntu-latest
permissions:
contents: write
actions: read
packages: read
pages: write
id-token: write
steps:
- uses: actions/checkout@v2
steps:
- uses: actions/download-artifact@v4
with:
path: artifacts
pattern: wheels-*
merge-multiple: true

- name: Create release
uses: softprops/action-gh-release@v2
with:
Expand All @@ -79,6 +72,22 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

publish_simple_package_index:
name: Build&publish a PyPI-compatible package index
runs-on: ubuntu-latest
needs: [create_release_artifacts]
if: always() && !failure() && !cancelled() && (github.event_name == 'push')
concurrency:
group: simple_package_index
cancel-in-progress: true
permissions:
contents: write
actions: read
packages: read
pages: write
id-token: write
steps:
- uses: actions/checkout@v2
- name: Generate Package Index
run: |
python -m pip install --upgrade pip
Expand All @@ -94,4 +103,9 @@ jobs:
path: 'dist'

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

- name: Display GitHub Pages URL
run: |
echo "Package Index URL: ${{ steps.deployment.outputs.page_url }}"
Loading