From 7448ee3b21a8c26291b2e9279f3bbe9ca27dc19d Mon Sep 17 00:00:00 2001 From: Aadil Latif Date: Wed, 7 Jan 2026 17:11:29 -0700 Subject: [PATCH] new updates --- .github/workflows/publish-on-release.yml | 53 ++++++++ .gitignore | 3 +- LocalFeeder/Dockerfile | 1 + broker/oedisi.code-workspace | 7 + recorder/Dockerfile | 1 + workflow_runner.py | 157 +++++++++++++++++++++++ 6 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/publish-on-release.yml create mode 100644 broker/oedisi.code-workspace create mode 100644 workflow_runner.py diff --git a/.github/workflows/publish-on-release.yml b/.github/workflows/publish-on-release.yml new file mode 100644 index 0000000..eaa27ef --- /dev/null +++ b/.github/workflows/publish-on-release.yml @@ -0,0 +1,53 @@ +name: Publish Docker Images on Release + +on: + release: + types: [published] + workflow_dispatch: + inputs: + release_tag: + description: 'Release tag to use (e.g., v1.2.3). If empty, uses release tag from the release event.' + required: false + default: 'v0.0.1' + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Log in to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME_AL }} + password: ${{ secrets.DOCKERHUB_API_KEY_AL }} + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install docker python-dotenv requests rich + + - name: Run workflow_runner.py + env: + RELEASE_TAG: ${{ github.event.inputs.release_tag || github.ref_name }} + DOCKERHUB_USERNAME_AL: ${{ secrets.DOCKERHUB_USERNAME_AL }} + DOCKERHUB_API_KEY_AL: ${{ secrets.DOCKERHUB_API_KEY_AL }} + MAILJET_API_KEY: ${{ secrets.MAILJET_API_KEY }} + MAILJET_API_SECRET: ${{ secrets.MAILJET_API_SECRET }} + run: | + python workflow_runner.py \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3db999d..4bd01e1 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ test_system_runner.json recorder_* local_feeder build -.vscode/ \ No newline at end of file +.vscode/ +.env \ No newline at end of file diff --git a/LocalFeeder/Dockerfile b/LocalFeeder/Dockerfile index 8a2427b..ad0d88a 100644 --- a/LocalFeeder/Dockerfile +++ b/LocalFeeder/Dockerfile @@ -1,4 +1,5 @@ FROM python:3.10.6-slim-bullseye +LABEL org.opencontainers.image.authors="Joseph McKinsey " RUN apt-get update RUN apt-get install -y git ssh RUN mkdir LocalFeeder diff --git a/broker/oedisi.code-workspace b/broker/oedisi.code-workspace new file mode 100644 index 0000000..9e68e72 --- /dev/null +++ b/broker/oedisi.code-workspace @@ -0,0 +1,7 @@ +{ + "folders": [ + { + "path": ".." + } + ] +} \ No newline at end of file diff --git a/recorder/Dockerfile b/recorder/Dockerfile index 82988ba..0da4479 100644 --- a/recorder/Dockerfile +++ b/recorder/Dockerfile @@ -1,4 +1,5 @@ FROM python:3.10.6-slim-bullseye +LABEL org.opencontainers.image.authors="Aadil Latif " RUN apt-get update RUN apt-get install -y git ssh RUN mkdir Recorder diff --git a/workflow_runner.py b/workflow_runner.py new file mode 100644 index 0000000..94f012b --- /dev/null +++ b/workflow_runner.py @@ -0,0 +1,157 @@ +from requests.auth import HTTPBasicAuth +from collections import defaultdict +from pathlib import Path +import requests +import json +import os + +from dotenv import load_dotenv +import requests +from rich import print +import docker + + +load_dotenv() + +# --- Configuration --- +DOCKERHUB_USERNAME_AL = os.getenv("DOCKERHUB_USERNAME_AL") +DOCKERHUB_API_KEY_AL = os.getenv("DOCKERHUB_API_KEY_AL") +MAILJET_API_KEY = os.environ["MAILJET_API_KEY"] +MAILJET_API_SECRET = os.environ["MAILJET_API_SECRET"] +TAG = os.environ["RELEASE_TAG"] + + +def collect_components(): + # Simulate collecting components + print("Collecting components...") + components = json.load(open("components.json", "r")) # Load components from a JSON file + for component_name, component_path in components.items(): + try: + print(f"Building image for component {component_name}...") + component_path = Path(component_path).parent + if not component_path.is_dir(): + raise ValueError(f"Component path {component_path} is not a directory") + if not (component_path / "Dockerfile").is_file(): + raise ValueError(f"No Dockerfile found in {component_path}") + build_and_push_docker_image(component_name, component_path, ) + except Exception as e: + print(f"An unexpected error occurred: {e}") + +def build_and_push_docker_image(image_name, docker_file_path, tag="v0.0.1"): + client = docker.from_env() + REPOSITORY_NAME = f"{DOCKERHUB_USERNAME_AL}/{image_name}:{tag}".lower() + email_msg = f"Building Docker image: {REPOSITORY_NAME} from directory {docker_file_path}" + + try: + # Build the image + image, build_logs = client.images.build( + path=str(docker_file_path), + tag=REPOSITORY_NAME, + rm=True, # Remove intermediate containers after a successful build + nocache=False, # Do not use cache when building the image + ) + + email_msg += f"\nSuccessfully built image: {REPOSITORY_NAME}" + + labels = image.attrs['Config'].get('Labels') or {} + author_names = [] + author_emails = [] + authors_label = labels.get("org.opencontainers.image.authors") + if authors_label: + for author in authors_label.split(","): + author = author.strip() + if "<" in author and ">" in author: + name, email = author.split("<", 1) + author_names.append(name.strip()) + author_emails.append(email.strip("> ").strip()) + else: + author_names.append(author) + author_emails.append(None) + + print(f"Image authors: {{'names': author_names, 'emails': author_emails}}") + + + except docker.errors.BuildError as e: + email_msg += f"\nError building image: {e}" + print(f"Error building image: {e}") + return + + print(f"2. Logging in to Docker Hub as {DOCKERHUB_USERNAME_AL}") + email_msg += f"\nLogging in to Docker Hub as {DOCKERHUB_USERNAME_AL}" + + email_msg += f"\nPushing image to Docker Hub: {REPOSITORY_NAME}" + print(f"3. Pushing image to Docker Hub: {REPOSITORY_NAME}") + try: + # Push the image to Docker Hub + # The push operation returns an iterator of events + push_logs = client.images.push( + repository=f"{DOCKERHUB_USERNAME_AL}/{image_name}".lower(), + tag=TAG, + stream=True, + decode=True + ) + for line in push_logs: + if 'status' in line: + print(line['status']) + elif 'error' in line: + print(f"Error during push: {line['error']}") + email_msg += f"\nError during push: {line['error']}" + + print("Image pushed successfully to Docker Hub.") + email_msg += f"\nImage pushed successfully to Docker Hub." + + + except docker.errors.APIError as e: + print(f"Docker API Error during push: {e}") + email_msg += f"Docker API Error during push: {e}" + except Exception as e: + print(f"An unexpected error occurred: {e}") + email_msg += f"An unexpected error occurred: {e}" + + for name, email in zip(author_names, author_emails): + if not email: + print(f"Skipping author '{name}' - no email available") + continue + + payload = { + "Messages": [ + { + "From": { + "Email": "aadil.latif@gmail.com", + "Name": "Aadil Latif" + }, + "To": [ + { + "Email": email, + "Name": name + } + ], + "Subject": "OEDISI GitHub Workflow Notification", + "TextPart": email_msg, + } + ] + } + + try: + response = requests.post( + "https://api.mailjet.com/v3.1/send", + json=payload, + auth=HTTPBasicAuth(MAILJET_API_KEY, MAILJET_API_SECRET), + timeout=30, + ) + response.raise_for_status() + print(f"Mail sent to {email}: {response.status_code}") + except requests.exceptions.HTTPError as http_err: + # Surface the server response body to help debugging 400 errors + try: + err_text = response.text + except Exception: + err_text = str(http_err) + print(f"Mailjet HTTP error for {email}: {response.status_code} - {err_text}") + except Exception as e: + print(f"Failed to send mail to {email}: {e}") + + +if __name__ == "__main__": + os.system("docker login -u {} -p {}".format(DOCKERHUB_USERNAME_AL, DOCKERHUB_API_KEY_AL)) + collect_components() \ No newline at end of file