diff --git a/.github/workflows/gam.yml b/.github/workflows/gam.yml new file mode 100644 index 00000000..0299b119 --- /dev/null +++ b/.github/workflows/gam.yml @@ -0,0 +1,83 @@ +name: Deploy Templates to GAM + +permissions: + contents: read + +concurrency: + group: 'deploy' + cancel-in-progress: true + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + lint: + name: Linting + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Setup node + uses: guardian/actions-setup-node@main + + - name: Install dependencies + uses: bahmutov/npm-install@v1 + + - name: Lint files + run: yarn lint + + types: + name: Typescript + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: Setup node + uses: guardian/actions-setup-node@main + + - name: Install dependencies + uses: bahmutov/npm-install@v1 + + - name: Check typescript + run: yarn tsc + + deploy: + runs-on: ubuntu-latest + needs: [lint, types] + + steps: + - uses: actions/checkout@v2 + + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: '3.11' + + - name: Install pipenv + run: pip install pipenv + + - name: Setup Node + uses: actions/setup-node@v3 + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build + run: yarn build + + - name: Install Dependencies + run: pipenv install + working-directory: ./scripts/deploy + + - name: Deploy Templates to GAM + run: pipenv run python deploy.py + working-directory: ./scripts/deploy + env: + GAM_APPLICATION_NAME: ${{ secrets.GAM_APPLICATION_NAME }} + GAM_NETWORK_CODE: ${{ secrets.GAM_NETWORK_CODE }} + SERVICE_ACCOUNT_KEY_FILE: ${{ secrets.SERVICE_ACCOUNT_KEY_FILE }} diff --git a/.prettierignore b/.prettierignore index a5bc5a05..b9955e52 100644 --- a/.prettierignore +++ b/.prettierignore @@ -6,4 +6,4 @@ legacy /.svelte-kit # Python -scripts/upload +scripts/deploy diff --git a/scripts/upload/.env.example b/scripts/deploy/.env.example similarity index 100% rename from scripts/upload/.env.example rename to scripts/deploy/.env.example diff --git a/scripts/upload/Pipfile b/scripts/deploy/Pipfile similarity index 86% rename from scripts/upload/Pipfile rename to scripts/deploy/Pipfile index 45456ad8..2edcca99 100644 --- a/scripts/upload/Pipfile +++ b/scripts/deploy/Pipfile @@ -12,4 +12,3 @@ termcolor = "*" [requires] python_version = "3.11" -python_full_version = "3.11.2" diff --git a/scripts/upload/Pipfile.lock b/scripts/deploy/Pipfile.lock similarity index 100% rename from scripts/upload/Pipfile.lock rename to scripts/deploy/Pipfile.lock diff --git a/scripts/upload/README.md b/scripts/deploy/README.md similarity index 82% rename from scripts/upload/README.md rename to scripts/deploy/README.md index 9af387e4..95395fc7 100644 --- a/scripts/upload/README.md +++ b/scripts/deploy/README.md @@ -1,20 +1,18 @@ -# Upload to GAM +# Deploy to GAM This script will attempt to upload all commercial templates to GAM, replacing the corresponding generated HTML & CSS. The script checks for the presence of an `ad.json` file in the template directory. This file must contain the key `nativeStyleId`, specifying the ID for the corresponding [native style][native-style] in GAM. [native-style]: https://support.google.com/admanager/answer/13404315?hl=en&ref_topic=7032550&sjid=6297647672569553146-EU -It's written in python because Google does not offer a JS SDK. - ## Requirements - Python 3.x - An OAuth2 client id and secret ## Running locally ```bash -$ cd scripts/upload +$ cd scripts/deploy $ cp .env.example .env # fill this in $ pipenv install -$ pipenv run python upload.py +$ pipenv run python deploy.py ``` diff --git a/scripts/upload/upload.py b/scripts/deploy/deploy.py similarity index 65% rename from scripts/upload/upload.py rename to scripts/deploy/deploy.py index 35b1e155..c3d0485c 100644 --- a/scripts/upload/upload.py +++ b/scripts/deploy/deploy.py @@ -1,39 +1,26 @@ import os +import tempfile from dotenv import load_dotenv import json -from googleads import ad_manager, common +from googleads import ad_manager, common, oauth2 import datetime -from termcolor import colored, cprint +from termcolor import cprint load_dotenv() template_dir = os.path.realpath( - os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../build-static") + os.path.join(os.path.dirname(os.path.abspath(__file__)), + "../../build-static") ) config = { "application_name": os.environ.get("GAM_APPLICATION_NAME"), - "network_code": os.environ.get("GAM_NETWORK_CODE"), - "client_id": os.environ.get("GAM_CLIENT_ID"), - "client_secret": os.environ.get("GAM_CLIENT_SECRET"), - "refresh_token": os.environ.get("GAM_REFRESH_TOKEN"), + "network_code": os.environ.get("GAM_NETWORK_CODE") } - -config_yaml = """ -ad_manager: - application_name: {application_name} - network_code: {network_code} - client_id: {client_id} - client_secret: {client_secret} - refresh_token: {refresh_token} -""".format( - **config -) - -html_prefix = "".format( +html_prefix = "".format( datetime.datetime.now().strftime("%m/%d/%Y") ) -css_prefix = "/* DO NOT EDIT -- FILE GENERATED AND UPLOADED AUTOMATICALLY FROM https://github.com/guardian/commercial-templates ON {} */".format( +css_prefix = "/* DO NOT EDIT -- FILE GENERATED AND DEPLOYED AUTOMATICALLY FROM https://github.com/guardian/commercial-templates ON {} */".format( datetime.datetime.now().strftime("%m/%d/%Y") ) @@ -65,7 +52,8 @@ def upload_template( version="v202208", where="id = %s" % templateInfo["nativeStyleId"] ) - response = native_style_service.getNativeStylesByStatement(statement.ToStatement()) + response = native_style_service.getNativeStylesByStatement( + statement.ToStatement()) if "results" in response and len(response["results"]): style = response["results"][0] @@ -84,7 +72,8 @@ def upload_template( cprint("[!] Error updating native style: %s" % e, "red") return - cprint('[✔️] Native style "%s" was updated.' % (style["name"]), "green") + cprint('[✔️] Native style "%s" was updated.' % + (style["name"]), "green") else: cprint( '[i] No native styles found to update for "%s" with nativeStyleId "%s"' @@ -100,10 +89,24 @@ def main(native_style_service: common.GoogleSoapService): if __name__ == "__main__": - ad_manager_client = ad_manager.AdManagerClient.LoadFromString(config_yaml) + key_json = os.environ.get("SERVICE_ACCOUNT_KEY_FILE") or "" - native_style_service = ad_manager_client.GetService( - "NativeStyleService", version="v202305" - ) + fd, key_file = tempfile.mkstemp() + + try: + with os.fdopen(fd, 'w') as tmp: + tmp.write(key_json) + + oauth2_client = oauth2.GoogleServiceAccountClient( + key_file, oauth2.GetAPIScope('ad_manager')) + + ad_manager_client = ad_manager.AdManagerClient( + oauth2_client, config['application_name'], config['network_code']) + + native_style_service = ad_manager_client.GetService( + "NativeStyleService", version="v202305" + ) - main(native_style_service) + main(native_style_service) + finally: + os.remove(key_file) diff --git a/src/templates/csr/public-good/ad.json b/src/templates/csr/public-good/ad.json new file mode 100644 index 00000000..abe677f1 --- /dev/null +++ b/src/templates/csr/public-good/ad.json @@ -0,0 +1,3 @@ +{ + "nativeStyleId": "756061" +} diff --git a/src/templates/ssr/interscroller/ad.json b/src/templates/ssr/interscroller/ad.json new file mode 100644 index 00000000..31786ef6 --- /dev/null +++ b/src/templates/ssr/interscroller/ad.json @@ -0,0 +1,3 @@ +{ + "nativeStyleId": "290379" +}