diff --git a/.gitea/workflows/update-readme.yaml b/.gitea/workflows/update-readme.yaml index a6f5176..8d28f9b 100644 --- a/.gitea/workflows/update-readme.yaml +++ b/.gitea/workflows/update-readme.yaml @@ -17,11 +17,6 @@ jobs: with: python-version: '3.10' - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install docker - - name: Log in to Docker Registry uses: docker/login-action@v2 with: @@ -30,10 +25,11 @@ jobs: password: ${{ secrets.DOCKER_PASSWORD }} - name: Generate Docker Images Table - run: python scripts/build-readme.py + run: python scripts/update-readme.py env: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} + DOCKER_REGISTRY: docker.lakes.house + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} - name: Commit changes if README was updated run: | diff --git a/README.md b/README.md index 2e14c4c..6574cfc 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ -# unity-editor +# Unity Docker Images -Docker images for the unity editor to be used in CI \ No newline at end of file +A table of available Docker images for Unity CI/CD: + + +| unity | android | webgl | +|---------|----------|----------| +| 6000.0.35f1 | ubuntu-6000.0.35f1-android-runner | ubuntu-6000.0.35f1-webgl-runner | + diff --git a/scripts/build-readme.py b/scripts/build-readme.py deleted file mode 100644 index 60eb879..0000000 --- a/scripts/build-readme.py +++ /dev/null @@ -1,83 +0,0 @@ -import docker -import re -import os -from collections import defaultdict - -# Connect to Docker registry -client = docker.from_env() -client.login( - username=os.environ["DOCKER_USERNAME"], - password=os.environ["DOCKER_PASSWORD"], - registry="docker.lakes.house" -) - -# Define the base repository -base_repo = "docker.lakes.house/unityci/editor" - -# Get all images -images = [] -try: - # For a real registry we would use the client.images.search, but for private registry - # we need to list tags for the repository - # This might require API calls specific to your registry - # For this example, we assume we can get a list of tags - response = client.api.get_registry_data(base_repo) - for tag in response.get("tags", []): - images.append(f"{base_repo}:{tag}") -except Exception as e: - print(f"Error listing images: {e}") - # Fallback approach or error handling - -# Process images to extract Unity versions and platforms -unity_platforms = defaultdict(set) -image_map = defaultdict(dict) - -pattern = re.compile(r"ubuntu-(\d+\.\d+\.\d+\w*)-(\w+)-runner") - -for image in images: - match = pattern.search(image) - if match: - unity_version = match.group(1) - platform = match.group(2) - unity_platforms[unity_version].add(platform) - image_map[unity_version][platform] = image - -# Get all unique platforms -all_platforms = set() -for platforms in unity_platforms.values(): - all_platforms.update(platforms) -all_platforms = sorted(list(all_platforms)) - -# Generate markdown table -markdown = "# Unity Docker Images\n\n" -markdown += "A table of available Docker images for Unity CI/CD:\n\n" -markdown += "| Unity Version |" - -# Add platform headers -for platform in all_platforms: - markdown += f" {platform} |" -markdown += "\n|" - -# Add separator row -for _ in range(len(all_platforms) + 1): - markdown += " --- |" -markdown += "\n" - -# Add rows for each Unity version -for unity_version in sorted(unity_platforms.keys()): - markdown += f"| {unity_version} |" - - for platform in all_platforms: - if platform in image_map[unity_version]: - image_name = image_map[unity_version][platform].split("/")[-1] - markdown += f" `{image_name}` |" - else: - markdown += " - |" - - markdown += "\n" - -# Write to README.md -with open("README.md", "w") as f: - f.write(markdown) - -print("README updated successfully!") \ No newline at end of file diff --git a/scripts/update-readme.py b/scripts/update-readme.py new file mode 100644 index 0000000..7787f77 --- /dev/null +++ b/scripts/update-readme.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python3 + +import argparse +import requests +import json +import sys +import os +import re +from urllib.parse import urlparse + + +def get_docker_hub_tags(repository, limit=1000): + """ + Get tags for a Docker Hub repository + """ + url = f"https://hub.docker.com/v2/repositories/{repository}/tags" + params = {"page_size": limit} + + # Check for Docker Hub credentials in environment variables + username = os.getenv('DOCKER_USERNAME') + password = os.getenv('DOCKER_PASSWORD') + + # Create session for potential authentication + session = requests.Session() + + # Authenticate if credentials are provided + if username and password: + auth_url = "https://hub.docker.com/v2/users/login/" + auth_data = {"username": username, "password": password} + + try: + auth_response = session.post(auth_url, json=auth_data) + auth_response.raise_for_status() + # Token is automatically stored in the session cookies + except requests.exceptions.RequestException as e: + print(f"Warning: Docker Hub authentication failed: {e}") + # Continue without authentication + + all_tags = [] + + while url: + response = session.get(url, params=params) + if response.status_code != 200: + print(f"Error: Unable to fetch tags. Status code: {response.status_code}") + print(f"Response: {response.text}") + sys.exit(1) + + data = response.json() + all_tags.extend([tag["name"] for tag in data["results"]]) + + # Get next page URL if it exists + url = data.get("next") + # Clear params since the next URL already includes them + params = {} + + return all_tags + +def get_private_registry_tags(registry, repository): + """ + Get tags for a repository in a private registry + """ + # Check for registry credentials in environment variables + username = os.getenv('DOCKER_USERNAME') + password = os.getenv('DOCKER_PASSWORD') + + # Ensure registry URL starts with https:// + registry_url = registry if registry.startswith(('http://', 'https://')) else f'https://{registry}' + + # Try to get an auth token first (token-based auth) + headers = {} + url = f"{registry_url}/v2/{repository}/tags/list" + + # Make the request with appropriate authentication + if username and password: + # Use basic auth if we have credentials but no token + response = requests.get(url, headers=headers, auth=(username, password)) + else: + # Use token auth or no auth + response = requests.get(url, headers=headers) + + if response.status_code != 200: + print(f"Error: Unable to fetch tags. Status code: {response.status_code}") + print(f"Response: {response.text}") + sys.exit(1) + + data = response.json() + return data.get("tags", []) + +def main(): + parser = argparse.ArgumentParser(description="Get all tags for a Docker image") + parser.add_argument("image", help="Docker image name (e.g., 'library/ubuntu' or 'nginx')") + parser.add_argument("--registry", help="Registry URL for private registry (can also set DOCKER_REGISTRY env var)", default=None) + parser.add_argument("--limit", type=int, help="Maximum number of tags to retrieve (Docker Hub only)", default=1000) + parser.add_argument("--output", help="Output file path (default: stdout)") + args = parser.parse_args() + + # Check for registry in environment variable if not specified in args + registry = args.registry or os.getenv('DOCKER_REGISTRY') + repository = args.image + + if registry: + print(f"Fetching tags for {repository} from {registry}...") + tags = get_private_registry_tags(registry, repository) + else: + print(f"Fetching tags for {repository} from Docker Hub...") + tags = get_docker_hub_tags(repository, args.limit) + + # Sort tags + tags.sort() + + versions={} + + pattern = re.compile(r"(\w+)-(\d+\.\d+\.\d+\w*)-(\w+)-runner") + for tag in tags: + matches = pattern.match(tag) + if matches: + [ image_os, version, component ] = matches.groups() + if version not in versions: + versions[version] = {} + versions[version][component] = tag + + # Get all unique components across all versions + print(versions) + all_components = set() + for version_components in versions.values(): + all_components.update(version_components.keys()) + all_components = sorted(list(all_components)) + + # Create markdown table header with components as columns + markdown = "| unity |" + for component in all_components: + markdown += f" {component} |" + markdown += "\n|---------|" + "----------|" * len(all_components) + "\n" + + for version in sorted(versions.keys()): + markdown += f"| {version} |" + for component in all_components: + tag = versions[version].get(component, "") + markdown += f" {tag} |" + markdown += "\n" + + # Read existing README.md + print("Updating README") + readme_path = "README.md" + if os.path.exists(readme_path): + with open(readme_path, 'r') as f: + content = f.read() + + # Replace content between markers + pattern = r'().*()' + new_content = re.sub(pattern, r'\1\n' + markdown + r'\2', content, flags=re.DOTALL) + + # Write back to README.md + with open(readme_path, 'w') as f: + f.write(new_content) + + print("Done!") + +if __name__ == "__main__": + # Print environment variable usage information + if len(sys.argv) == 1 or (len(sys.argv) == 2 and sys.argv[1] in ['-h', '--help']): + print("\nEnvironment Variables:") + print(" DOCKER_REGISTRY - URL of private Docker registry") + print(" DOCKER_USERNAME - Username") + print(" DOCKER_PASSWORD - Password") + print("\nExample:") + print(" export DOCKER_REGISTRY=https://registry.example.com") + print(" export DOCKER_USERNAME=username") + print(" export DOCKER_PASSWORD=password") + print(" python docker_image_tags.py myproject/api\n") + + main() \ No newline at end of file