diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 891fe66f..b16b14fc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,87 +1,29 @@ -name: FastAPI CI/CD +name: Build and Push Docker Image on: - # Trigger the workflow on push push: branches: - # Push events on main branch - - main + - nikita -# The Job defines a series of steps that execute on the same runner. jobs: - CI: - # Define the runner used in the workflow + build: runs-on: ubuntu-latest - steps: - # Check out repo so our workflow can access it - - uses: actions/checkout@v2 - # Step-1 Setup Python - - name: Set up Python - # This action sets up a Python environment for use in actions - uses: actions/setup-python@v2 - with: - python-version: 3.9 - # optional: architecture: x64 x64 or x86. Defaults to x64 if not specified + steps: + - name: Checkout code + uses: actions/checkout@v2 - # Step-2 Install Python Virtual ENV - - name: Install Python Virtual ENV - run: pip3 install virtualenv + - name: Login to ECR + env: + AWS_REGION: us-west-1 + run: | + aws ecr get-login-password --region us-west-1 | docker login --username AWS --password-stdin 948023073771.dkr.ecr.us-west-1.amazonaws.com - # # Step-3 Setup Virtual ENV - # # https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows - # - name: Virtual ENV - # uses: actions/cache@v2 - # id: cache-venv # name for referring later - # with: - # path: venv # what we cache: the Virtual ENV - # # The cache key depends on requirements.txt - # key: ${{ runner.os }}-venv-${{ hashFiles('**/requirements*.txt') }} - # restore-keys: | - # ${{ runner.os }}-venv- - # Step-4 Build a Virtual ENV, but only if it doesn't already exist - - name: Activate Virtual ENV - run: python -m venv venv && source venv/bin/activate && pip3 install -r requirements.txt - # if: steps.cache-venv.outputs.cache-hit != 'true' + - name: Build Docker image + run: docker build -t fastapi-demo . - - name: Create archive of dependencies - run: | - cd ./venv/lib/python3.9/site-packages - zip -r9 ../../../../app.zip . - - name: Add APP files to Zip file - run: zip -g ./app.zip -r . - - name: Upload zip file artifact - uses: actions/upload-artifact@v2 - with: - name: app - path: app.zip + - name: Tag Docker image + run: docker tag fastapi-demo:latest 948023073771.dkr.ecr.us-west-1.amazonaws.com/fastapi-demo:latest - CD: - runs-on: ubuntu-latest - needs: [CI] - if: github.ref == 'refs/heads/main' && github.event_name == 'push' - steps: - - name: Install AWS CLI - uses: unfor19/install-aws-cli-action@v1 - with: - version: 1 - env: - AWS_ACCESS_KEY_ID: AKIA5ZOUUDPV4JSVHC5U - AWS_SECRET_ACCESS_KEY: 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 - AWS_DEFAULT_REGION: us-west-1 - - name: Download Lambda app.zip - uses: actions/download-artifact@v2 - with: - name: app - - name: Upload to S3 - run: aws s3 cp app.zip s3://hiroshi-nikita/app.zip - env: - AWS_ACCESS_KEY_ID: AKIA5ZOUUDPV4JSVHC5U - AWS_SECRET_ACCESS_KEY: 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 - AWS_DEFAULT_REGION: us-west-1 - - name: Deploy new Lambda - run: aws lambda update-function-code --function-name Webhook --s3-bucket hiroshi-nikita --s3-key app.zip - env: - AWS_ACCESS_KEY_ID: AKIA5ZOUUDPV4JSVHC5U - AWS_SECRET_ACCESS_KEY: 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 - AWS_DEFAULT_REGION: us-west-1 + - name: Push Docker image to ECR + run: docker push 948023073771.dkr.ecr.us-west-1.amazonaws.com/fastapi-demo:latest diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..de8b541b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +FROM public.ecr.aws/lambda/python:3.10 + +COPY . ${LAMBDA_TASK_ROOT} + +RUN pip install -r requirements.txt --target "${LAMBDA_TASK_ROOT}" + + +CMD ["main.handler"] \ No newline at end of file diff --git a/README.md b/README.md index 4192a8c5..d4347314 100644 Binary files a/README.md and b/README.md differ diff --git a/config.py b/config.py index eb71002d..49d7cdc6 100644 --- a/config.py +++ b/config.py @@ -7,18 +7,18 @@ load_dotenv() # GitHub Credentials from environment variables -GITHUB_APP_ID = os.getenv("APP_ID_GITHUB") +GITHUB_APP_ID = os.environ.get("APP_ID_GITHUB") # GITHUB_CLIENT_ID = os.getenv("GITHUB_CLIENT_ID") # GITHUB_CLIENT_SECRET = os.getenv("GITHUB_CLIENT_SECRET") # GITHUB_INSTALLATION_ID = os.getenv("GITHUB_INSTALLATION_ID") -GITHUB_PRIVATE_KEY_ENCODED = os.getenv("GITHUB_PRIVATE_KEY") +GITHUB_PRIVATE_KEY_ENCODED = os.environ.get("GITHUB_PRIVATE_KEY") GITHUB_PRIVATE_KEY = ''#base64.b64decode(GITHUB_PRIVATE_KEY_ENCODED) -GITHUB_WEBHOOK_SECRET = os.getenv("GITHUB_WEBHOOK_SECRET") +GITHUB_WEBHOOK_SECRET = os.environ.get("GITHUB_WEBHOOK_SECRET") # Supabase Credentials from environment variables -SUPABASE_URL = os.getenv("SUPABASE_URL") -SUPABASE_SERVICE_ROLE_KEY = os.getenv("SUPABASE_SERVICE_ROLE_KEY") -SUPABASE_JWT_SECRET_KEY = os.getenv("SUPABASE_JWT_SECRET_KEY") +SUPABASE_URL = os.environ.get("SUPABASE_URL") +SUPABASE_SERVICE_ROLE_KEY = os.environ.get("SUPABASE_SERVICE_ROLE_KEY") +SUPABASE_JWT_SECRET_KEY = os.environ.get("SUPABASE_JWT_SECRET_KEY") # General LABEL = "pragent" diff --git a/main.py b/main.py index 6e7db7d2..e36f36cb 100644 --- a/main.py +++ b/main.py @@ -1,19 +1,25 @@ + + import json from fastapi import FastAPI, HTTPException, Request import urllib.parse +from config import GITHUB_APP_ID + from services.github.webhook_handler import handle_webhook_event from mangum import Mangum -app = FastAPI() -handler = Mangum(app=app) +app = FastAPI( title="hello world", + openapi_prefix="/prod") +handler = Mangum(app) @app.post("/webhook") async def handle_webhook(request: Request): try: print("Webhook received") + print("GITHUB APP ID: ", GITHUB_APP_ID) payload = await request.body() decoded_data = urllib.parse.unquote(payload.decode()) json_data = json.loads(decoded_data) @@ -31,7 +37,9 @@ async def handle_webhook(request: Request): async def root(): return {"message": "Hello World"} -# if __name__ == "__main__": -# import uvicorn -# uvicorn.run(app, host="0.0.0.0", port=8000) + +@app.get("/") +async def root(): + return {"message": "Hello HOME"} + diff --git a/payloads/removed.json b/payloads/removed.json new file mode 100644 index 00000000..e69de29b diff --git a/services/github/webhook_handler.py b/services/github/webhook_handler.py index f2051adb..210adc50 100644 --- a/services/github/webhook_handler.py +++ b/services/github/webhook_handler.py @@ -24,6 +24,7 @@ from pathlib import Path async def handle_installation_created(payload): + print("INSTALLING") installation_id = payload["installation"]["id"] account_login = payload["installation"]["account"]["login"] html_url = payload["installation"]["account"]["html_url"] @@ -36,7 +37,7 @@ async def handle_installation_created(payload): if action == 'added': repositories = [obj.get('full_name') for obj in payload["repositories_added"]] repository_ids = [obj.get('id') for obj in payload["repositories_added"]] - + print("SUPA") supabase_manager.save_installation_token(installation_id, account_login, html_url, repositories, repository_ids) @@ -59,7 +60,7 @@ async def handle_issue_labeled(payload): with open('privateKey.pem', 'rb') as pem_file: signing_key = pem_file.read() - + # Create JWT TOken new_uuid = uuid.uuid4() print("UUID: ", new_uuid) payload = { @@ -80,7 +81,8 @@ async def handle_issue_labeled(payload): response = requests.post(f'https://api.github.com/app/installations/{installation_id}/access_tokens', headers=headers) token = response.json().get('token') - + + # Clone Repo in /tmp folder git.Repo.clone_from(f'https://x-access-token:{token}@github.com/nikitamalinov/lalager', f'./tmp/{new_uuid}') io = InputOutput( @@ -142,6 +144,7 @@ async def handle_issue_labeled(payload): io.tool_output() coder.run(with_message="add header with tag 'Hello World' to homepage") + # Go into tmp repo repo_path = Path.cwd() / f'tmp/{new_uuid}' original_path = os.getcwd() os.chdir(repo_path) @@ -153,7 +156,7 @@ async def handle_issue_labeled(payload): repo.create_head(branch) repo.git.push('origin', branch) - # Push to branch to create PR + # Creates PR remote_url = repo.remotes.origin.url repo_name = remote_url.split('/')[-1].replace('.git', '') repo_owner = remote_url.split('/')[-2] @@ -177,6 +180,7 @@ async def handle_issue_labeled(payload): async def handle_webhook_event(payload): # TODO Verify webhook using webhoo.verify from octokit + if('action' in payload): action = payload.get("action") if (action == "created" or action == "added") and "installation" in payload: diff --git a/services/supabase/supabase_manager.py b/services/supabase/supabase_manager.py index 37528d40..75158e79 100644 --- a/services/supabase/supabase_manager.py +++ b/services/supabase/supabase_manager.py @@ -7,25 +7,30 @@ def __init__(self, url, key): self.client: Client = create_client(url, key) def save_installation_token(self, installation_id, account_login, html_url, repositories, repository_ids): - data, _ = self.client.table("repo_info").select("*").eq("installation_id", installation_id).execute() - if(len(data[1]) > 0): - self.client.table("repo_info").update({ - "installation_id": installation_id, - "login": account_login, - 'html_url': html_url, - "repositories": repositories, - "repository_ids": repository_ids, - "deleted_at": None, - }).eq("installation_id", installation_id).execute() - else: - self.client.table("repo_info").insert({ - "installation_id": installation_id, - "login": account_login, - 'html_url': html_url, - "repositories": repositories, - "repository_ids": repository_ids, - }).execute() - + print("SAVING") + try: + data, _ = self.client.table("repo_info").select("*").eq("installation_id", installation_id).execute() + if(len(data[1]) > 0): + self.client.table("repo_info").update({ + "installation_id": installation_id, + "login": account_login, + 'html_url': html_url, + "repositories": repositories, + "repository_ids": repository_ids, + "deleted_at": None, + }).eq("installation_id", installation_id).execute() + else: + self.client.table("repo_info").insert({ + "installation_id": installation_id, + "login": account_login, + 'html_url': html_url, + "repositories": repositories, + "repository_ids": repository_ids, + }).execute() + except Exception as e: + print(e) + print("DONE") + def get_installation_id(self, repository_id): data, _ = self.client.table("repo_info").select("installation_id").contains('repository_ids', [str(repository_id)]).execute() if(data[1] and data[0][1]):