diff --git a/.github/workflows/pipeline.yaml b/.github/workflows/pipeline.yaml index 36a2b15..87cec4e 100644 --- a/.github/workflows/pipeline.yaml +++ b/.github/workflows/pipeline.yaml @@ -1,20 +1,17 @@ name: Tech Report API Pipeline -on: - push: - branches: - - 'main' - - 'feature**' - delete: - branches: - - 'feature**' - -# env: -# PIPELINE_USER_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} +on: [push] + +env: + PIPELINE_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }} + PIPELINE_SA_KEY: ${{ secrets.GCP_SA_KEY }} + PIPELINE_PROJECT_DATABASE_DEV: ${{ secrets.GCP_PROJECT_DATABASE_DEV }} + PIPELINE_PROJECT_DATABASE_PROD: ${{ secrets.GCP_PROJECT_DATABASE_PROD }} + PIPELINE_GOOGLE_SERVICE_ACCOUNT_CLOUD_FUNCTIONS: ${{ secrets.GCP_SERVICE_ACCOUNT_CLOUD_FUNCTIONS }} + PIPELINE_GOOGLE_SERVICE_ACCOUNT_API_GATEWAY: ${{ secrets.GCP_SERVICE_ACCOUNT_API_GATEWAY }} jobs: test: - if: github.event_name == 'push' runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -31,3 +28,104 @@ jobs: run: | python -m pytest -W "ignore" + deploy_development: + if: github.ref == 'refs/heads/development' + runs-on: ubuntu-latest + needs: [test] + defaults: + run: + working-directory: ./terraform/dev + steps: + - uses: actions/checkout@v4 + - name: Google Cloud Auth + uses: 'google-github-actions/auth@v2' + with: + project_id: ${{ env.PIPELINE_PROJECT_ID }} + credentials_json: ${{ env.PIPELINE_SA_KEY }} + + - uses: hashicorp/setup-terraform@v3 + + - name: Terraform fmt + id: fmt + run: terraform fmt -check + continue-on-error: true + + - name: Terraform Init + id: init + run: terraform init + + - name: Terraform Validate + id: validate + run: terraform validate -no-color + + - name: Terraform Plan + id: plan + run: | + terraform plan -no-color -var="google_service_account_cloud_functions=${{ env.PIPELINE_GOOGLE_SERVICE_ACCOUNT_CLOUD_FUNCTIONS }}" \ + -var="google_service_account_api_gateway=${{ env.PIPELINE_GOOGLE_SERVICE_ACCOUNT_API_GATEWAY }}" \ + -var="project_database=${{ env.PIPELINE_PROJECT_DATABASE_DEV }}" + continue-on-error: true + + - name: Terraform Plan status + if: steps.plan.outcome == 'failure' + run: exit 1 + + - name: Terraform Apply + id: apply + run: | + terraform apply -var="google_service_account_cloud_functions=${{ env.PIPELINE_GOOGLE_SERVICE_ACCOUNT_CLOUD_FUNCTIONS }}" \ + -var="google_service_account_api_gateway=${{ env.PIPELINE_GOOGLE_SERVICE_ACCOUNT_API_GATEWAY }}" \ + -var="project_database=${{ env.PIPELINE_PROJECT_DATABASE_DEV }}" \ + -auto-approve + + deploy_production: + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + needs: [test] + defaults: + run: + working-directory: ./terraform/prod + steps: + - uses: actions/checkout@v4 + - name: Google Cloud Auth + uses: 'google-github-actions/auth@v2' + with: + project_id: ${{ env.PIPELINE_PROJECT_ID }} + credentials_json: ${{ env.PIPELINE_SA_KEY }} + + - uses: hashicorp/setup-terraform@v3 + + - name: Terraform fmt + id: fmt + run: terraform fmt -check + continue-on-error: true + + - name: Terraform Init + id: init + run: terraform init + + - name: Terraform Validate + id: validate + run: terraform validate -no-color + + - name: Terraform Plan + id: plan + run: | + terraform plan -no-color -var="google_service_account_cloud_functions=${{ env.PIPELINE_GOOGLE_SERVICE_ACCOUNT_CLOUD_FUNCTIONS }}" \ + -var="google_service_account_api_gateway=${{ env.PIPELINE_GOOGLE_SERVICE_ACCOUNT_API_GATEWAY }}" \ + -var="project_database=${{ env.PIPELINE_PROJECT_DATABASE_PROD }}" + continue-on-error: true + + - name: Terraform Plan status + if: steps.plan.outcome == 'failure' + run: exit 1 + + - name: Terraform Apply + id: apply + run: | + terraform apply -var="google_service_account_cloud_functions=${{ env.PIPELINE_GOOGLE_SERVICE_ACCOUNT_CLOUD_FUNCTIONS }}" \ + -var="google_service_account_api_gateway=${{ env.PIPELINE_GOOGLE_SERVICE_ACCOUNT_API_GATEWAY }}" \ + -var="project_database=${{ env.PIPELINE_PROJECT_DATABASE_PROD }}" \ + -auto-approve + + \ No newline at end of file diff --git a/functions/adoption/main.py b/functions/adoption/main.py index 5f7148f..4f6b3bf 100644 --- a/functions/adoption/main.py +++ b/functions/adoption/main.py @@ -10,7 +10,6 @@ def dispatcher(request): if request.method == "OPTIONS": return respond_cors() - # Set CORS headers for the main request headers = {"Access-Control-Allow-Origin": "*"} args = request.args.to_dict() diff --git a/terraform/dev/local.auto.tfvars.template b/terraform/dev/local.auto.tfvars.template new file mode 100644 index 0000000..3ebe52e --- /dev/null +++ b/terraform/dev/local.auto.tfvars.template @@ -0,0 +1,4 @@ +google_service_account_api_gateway = "" +google_service_account_cloud_functions = "" +project_database = "" + diff --git a/terraform/dev/main.tf b/terraform/dev/main.tf index 9e7c953..8a8cb78 100644 --- a/terraform/dev/main.tf +++ b/terraform/dev/main.tf @@ -7,17 +7,163 @@ provider "google" { terraform { backend "gcs" { - bucket = var.project_bucket + bucket = "tf-state-backingapi-20230314" prefix = "dev" } } -module "backend-api" { - source = "./../modules/api-gateway" - environment = "dev" - project = "httparchive" - region = "us-east1" - service_account_email = var.google_service_account_api_gateway +resource "google_api_gateway_api" "api" { + provider = google-beta + api_id = "api-gw-dev" + display_name = "The dev API Gateway" + project = "httparchive" +} + +# A Configuration, consisting of an OpenAPI specification +resource "google_api_gateway_api_config" "api_config" { + provider = google-beta + api = google_api_gateway_api.api.api_id + api_config_id_prefix = "api" + project = "httparchive" + display_name = "The dev Config" + openapi_documents { + document { + path = "spec.yaml" + contents = base64encode(<<-EOF +swagger: "2.0" +info: + title: reports-backend-api + description: API tech report + version: 1.0.0 +schemes: + - https +produces: + - application/json +paths: + /v1/categories: + get: + summary: categories + operationId: getCategories + x-google-backend: + address: https://us-east1-httparchive.cloudfunctions.net/categories-dev + deadline: 60 + # security: + # - api_key: [] + responses: + 200: + description: String + /v1/adoption: + get: + summary: adoption + operationId: getadoptionReports + x-google-backend: + address: https://us-east1-httparchive.cloudfunctions.net/adoption-dev + deadline: 60 + # security: + # - api_key: [] + responses: + 200: + description: String + /v1/page-weight: + get: + summary: pageWeight + operationId: getpageWeight + x-google-backend: + address: https://us-east1-httparchive.cloudfunctions.net/page-weight-dev + deadline: 60 + # security: + # - api_key: [] + responses: + 200: + description: String + /v1/lighthouse: + get: + summary: lighthouse + operationId: getLighthouseReports + x-google-backend: + address: https://us-east1-httparchive.cloudfunctions.net/lighthouse-dev + deadline: 60 + # security: + # - api_key: [] + responses: + 200: + description: String + /v1/cwv: + get: + summary: cwv + operationId: getCwv + x-google-backend: + address: https://us-east1-httparchive.cloudfunctions.net/cwvtech-dev + deadline: 60 + # security: + # - api_key: [] + responses: + 200: + description: String + /v1/ranks: + get: + summary: ranks + operationId: getRanks + x-google-backend: + address: https://us-east1-httparchive.cloudfunctions.net/ranks-dev + deadline: 60 + # security: + # - api_key: [] + responses: + 200: + description: String + /v1/geos: + get: + summary: geos + operationId: getGeos + x-google-backend: + address: https://us-east1-httparchive.cloudfunctions.net/geos-dev + deadline: 60 + # security: + # - api_key: [] + responses: + 200: + description: String + /v1/technologies: + get: + summary: geos + operationId: getTechnologies + x-google-backend: + address: https://us-east1-httparchive.cloudfunctions.net/technologies-dev + deadline: 60 + # security: + # - api_key: [] + responses: + 200: + description: String +EOF + ) + } + } + gateway_config { + backend_config { + google_service_account = var.google_service_account_api_gateway + } + } +} +# The actual API Gateway +resource "google_api_gateway_gateway" "gateway" { + provider = google-beta + project = "httparchive" + region = "us-east1" + api_config = google_api_gateway_api_config.api_config.id + gateway_id = "dev-gw" + display_name = "devApi Gateway" + labels = { + owner = "tech_report_api" + environment = "dev" + } + depends_on = [google_api_gateway_api_config.api_config] + lifecycle { + replace_triggered_by = [ + google_api_gateway_api_config.api_config + ] + } } module "cwvtech" { diff --git a/terraform/dev/variables.tf b/terraform/dev/variables.tf index 132ac52..792ef08 100644 --- a/terraform/dev/variables.tf +++ b/terraform/dev/variables.tf @@ -13,8 +13,3 @@ variable "project_database" { description = "The database name" } - -variable "project_bucket" { - type = string - description = "The project name" -} \ No newline at end of file diff --git a/terraform/prod/local.auto.tfvars.template b/terraform/prod/local.auto.tfvars.template new file mode 100644 index 0000000..3ebe52e --- /dev/null +++ b/terraform/prod/local.auto.tfvars.template @@ -0,0 +1,4 @@ +google_service_account_api_gateway = "" +google_service_account_cloud_functions = "" +project_database = "" + diff --git a/terraform/prod/main.tf b/terraform/prod/main.tf index 5a4a4c1..f9bfbe5 100644 --- a/terraform/prod/main.tf +++ b/terraform/prod/main.tf @@ -7,17 +7,162 @@ provider "google" { terraform { backend "gcs" { - bucket = var.project_bucket + bucket = "tf-state-backingapi-20230314" prefix = "prod" } } -module "backend-api" { - source = "./../modules/api-gateway" - environment = "prod" - project = "httparchive" - region = "us-east1" - service_account_email = var.google_service_account_api_gateway +resource "google_api_gateway_api" "api" { + provider = google-beta + api_id = "api-gw-prod" + display_name = "The prod API Gateway" + project = "httparchive" +} + +resource "google_api_gateway_api_config" "api_config" { + provider = google-beta + api = google_api_gateway_api.api.api_id + api_config_id_prefix = "api" + project = "httparchive" + display_name = "The prod Config" + openapi_documents { + document { + path = "spec.yaml" + contents = base64encode(<<-EOF +swagger: "2.0" +info: + title: reports-backend-api + description: API tech report + version: 1.0.0 +schemes: + - https +produces: + - application/json +paths: + /v1/categories: + get: + summary: categories + operationId: getCategories + x-google-backend: + address: https://us-east1-httparchive.cloudfunctions.net/categories-prod + deadline: 60 + # security: + # - api_key: [] + responses: + 200: + description: String + /v1/adoption: + get: + summary: adoption + operationId: getadoptionReports + x-google-backend: + address: https://us-east1-httparchive.cloudfunctions.net/adoption-prod + deadline: 60 + # security: + # - api_key: [] + responses: + 200: + description: String + /v1/page-weight: + get: + summary: pageWeight + operationId: getpageWeight + x-google-backend: + address: https://us-east1-httparchive.cloudfunctions.net/page-weight-prod + deadline: 60 + # security: + # - api_key: [] + responses: + 200: + description: String + /v1/lighthouse: + get: + summary: lighthouse + operationId: getLighthouseReports + x-google-backend: + address: https://us-east1-httparchive.cloudfunctions.net/lighthouse-prod + deadline: 60 + # security: + # - api_key: [] + responses: + 200: + description: String + /v1/cwv: + get: + summary: cwv + operationId: getCwv + x-google-backend: + address: https://us-east1-httparchive.cloudfunctions.net/cwvtech-prod + deadline: 60 + # security: + # - api_key: [] + responses: + 200: + description: String + /v1/ranks: + get: + summary: ranks + operationId: getRanks + x-google-backend: + address: https://us-east1-httparchive.cloudfunctions.net/ranks-prod + deadline: 60 + # security: + # - api_key: [] + responses: + 200: + description: String + /v1/geos: + get: + summary: geos + operationId: getGeos + x-google-backend: + address: https://us-east1-httparchive.cloudfunctions.net/geos-prod + deadline: 60 + # security: + # - api_key: [] + responses: + 200: + description: String + /v1/technologies: + get: + summary: geos + operationId: getTechnologies + x-google-backend: + address: https://us-east1-httparchive.cloudfunctions.net/technologies-prod + deadline: 60 + # security: + # - api_key: [] + responses: + 200: + description: String +EOF + ) + } + } + gateway_config { + backend_config { + google_service_account = var.google_service_account_api_gateway + } + } +} + +resource "google_api_gateway_gateway" "gateway" { + provider = google-beta + project = "httparchive" + region = "us-east1" + api_config = google_api_gateway_api_config.api_config.id + gateway_id = "prod-gw" + display_name = "prod Api Gateway" + labels = { + owner = "tech_report_api" + environment = "prod" + } + depends_on = [google_api_gateway_api_config.api_config] + lifecycle { + replace_triggered_by = [ + google_api_gateway_api_config.api_config + ] + } } module "cwvtech" { diff --git a/terraform/prod/variables.tf b/terraform/prod/variables.tf index 132ac52..8c938b2 100644 --- a/terraform/prod/variables.tf +++ b/terraform/prod/variables.tf @@ -12,9 +12,4 @@ variable "project_database" { type = string description = "The database name" -} - -variable "project_bucket" { - type = string - description = "The project name" } \ No newline at end of file diff --git a/tests/test_report/libs/test_result.py b/tests/test_report/libs/test_result.py deleted file mode 100644 index 2d3eefd..0000000 --- a/tests/test_report/libs/test_result.py +++ /dev/null @@ -1,32 +0,0 @@ -import pytest -from functions.report.libs.result import Result - -def test_success(): - r = Result(status="success") - assert r.success() == True - assert r.failure() == False - -def test_failure(): - r = Result(errors=["some error"]) - assert r.success() == False - assert r.failure() == True - -def test_default_status(): - r = Result() - assert r.status == "ok" - assert r.success() == True - assert r.failure() == False - -def test_custom_status(): - r = Result(status="custom") - assert r.status == "custom" - assert r.success() == True - assert r.failure() == False - -def test_result(): - r = Result(result="some result") - assert r.result == "some result" - -def test_errors(): - r = Result(errors=["some error"]) - assert r.errors == ["some error"] diff --git a/tests/test_report/libs/test_utils.py b/tests/test_report/libs/test_utils.py deleted file mode 100644 index bbcebda..0000000 --- a/tests/test_report/libs/test_utils.py +++ /dev/null @@ -1,29 +0,0 @@ -from functions.report.libs.utils import * -from functions.report.libs.result import Result -import json - -def test_output(): - # Create a mock result object with a successful status - result_success = Result(status="success", result={"message": "Hello, world!"}) - - # Call the output function with the mock result object - output_result_success = output(result_success) - - # Verify that the output has the correct HTTP status code and payload - assert output_result_success[1] == 200 - assert json.loads(output_result_success[0]) == {"message": "Hello, world!"} - - # Create a mock result object with an error status - result_error = Result(status="error", errors=[["param", "Invalid request"]]) - - # Call the output function with the mock result object - output_result_error = output(result_error) - - # Verify that the output has the correct HTTP status code and payload - assert output_result_error[1] == 400 - assert json.loads(output_result_error[0]) == [{"param": "Invalid request"}] - -def test_convert_to_hashes(): - input_arr = [["geo", "missing geo parameters"], ["app", "missing geo parameters"]] - expected_output_arr = [{'geo': 'missing geo parameters'}, {'app': 'missing geo parameters'}] - assert convert_to_hashes(input_arr) == expected_output_arr diff --git a/tests/test_report/test_report_main.py b/tests/test_report/test_report_main.py deleted file mode 100644 index e69de29..0000000