aboutsummaryrefslogtreecommitdiffstats
path: root/static-builds/netlify_build.py
blob: 6686e2abeb42cc383c3701b1f7586a1a6323d68a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
"""Build script to deploy project on netlify."""

# WARNING: This file must remain compatible with python 3.8

# This script performs all the actions required to build and deploy our project on netlify
# It requires the following environment variable:

# TOKEN: A GitHub access token that can download the artifact.
#        For PAT, the only scope needed is `public_repos`

# It depends on the following packages, which are set in the netlify UI:
# httpx == 0.19.0

import os
import time
import zipfile
from pathlib import Path
from urllib import parse

import httpx

API_URL = "https://api.github.com"
OWNER, REPO = parse.urlparse(os.getenv("REPOSITORY_URL")).path.lstrip("/").split("/")[0:2]


def get_build_artifact() -> str:
    """Search for a build artifact, and return the download URL."""
    print("Fetching build URL.")

    if os.getenv("PULL_REQUEST").lower() == "true":
        print(f"Fetching data for PR #{os.getenv('REVIEW_ID')}")

        pull_url = f"{API_URL}/repos/{OWNER}/{REPO}/pulls/{os.getenv('REVIEW_ID')}"
        pull_request = httpx.get(pull_url)
        pull_request.raise_for_status()

        commit_sha = pull_request.json()["head"]["sha"]

        workflows_params = parse.urlencode({
            "event": "pull_request",
            "per_page": 100
        })

    else:
        commit_sha = os.getenv("COMMIT_REF")

        workflows_params = parse.urlencode({
            "event": "push",
            "per_page": 100
        })

    print(f"Fetching action data for commit {commit_sha}")

    workflows = httpx.get(f"{API_URL}/repos/{OWNER}/{REPO}/actions/runs?{workflows_params}")
    workflows.raise_for_status()

    for run in workflows.json()["workflow_runs"]:
        if run["name"] == "Build & Publish Static Preview" and commit_sha == run["head_sha"]:
            print(f"Found action for this commit: {run['id']}\n{run['html_url']}")
            break
    else:
        raise Exception("Could not find the workflow run for this event.")

    polls = 0
    while polls <= 20:
        if run["status"] != "completed":
            print("Action isn't completed, sleeping for 30 seconds.")
            polls += 1
            time.sleep(30)

        elif run["conclusion"] != "success":
            print("Aborting build due to a failure in a previous CI step.")
            exit(0)

        else:
            print(f"Found artifact URL:\n{run['artifacts_url']}")
            return run["artifacts_url"]

        _run = httpx.get(run["url"])
        _run.raise_for_status()
        run = _run.json()

    raise Exception("Polled for the artifact workflow, but it was not ready in time.")


def download_artifact(url: str) -> None:
    """Download a build artifact from `url`, and unzip the content."""
    print("Fetching artifact data.")

    artifacts = httpx.get(url)
    artifacts.raise_for_status()
    artifacts = artifacts.json()

    if artifacts["total_count"] == "0":
        raise Exception(f"No artifacts were found for this build, aborting.\n{url}")

    for artifact in artifacts["artifacts"]:
        if artifact["name"] == "static-build":
            print("Found artifact with build.")
            break
    else:
        raise Exception("Could not find an artifact with the expected name.")

    zipped_content = httpx.get(artifact["archive_download_url"], headers={
        "Authorization": f"token {os.getenv('TOKEN')}"
    })
    zipped_content.raise_for_status()

    zip_file = Path("temp.zip")
    zip_file.write_bytes(zipped_content.read())

    with zipfile.ZipFile(zip_file, "r") as zip_ref:
        zip_ref.extractall("build")

    zip_file.unlink(missing_ok=True)

    print("Wrote artifact content to target directory.")


if __name__ == "__main__":
    print("Build started")
    artifact_url = get_build_artifact()
    download_artifact(artifact_url)