diff options
author | Clement Tsang <34804052+ClementTsang@users.noreply.github.com> | 2022-11-06 03:19:52 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-06 03:19:52 -0500 |
commit | 29bc0b67bae1598cae1fa5202dae3999c7c05f69 (patch) | |
tree | 442b80bffe1a52af2cdfdb9b6dc35506bbc107f8 /scripts | |
parent | 8c3e9669b8f2519c2479d0b241e7db129ca63ed4 (diff) |
ci: rename deployment folder to scripts (#873)
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/cirrus/build.py | 182 | ||||
-rw-r--r-- | scripts/packager.py | 75 | ||||
-rw-r--r-- | scripts/windows/choco/bottom.nuspec.template | 57 | ||||
-rw-r--r-- | scripts/windows/choco/choco_packager.py | 51 | ||||
-rw-r--r-- | scripts/windows/choco/chocolateyinstall.ps1.template | 16 |
5 files changed, 381 insertions, 0 deletions
diff --git a/scripts/cirrus/build.py b/scripts/cirrus/build.py new file mode 100644 index 00000000..d1d4bac1 --- /dev/null +++ b/scripts/cirrus/build.py @@ -0,0 +1,182 @@ +#!/bin/python3 + +# A simple script to trigger Cirrus CI builds and download the release artifacts +# through Cirrus CI's GraphQL interface. +# +# Expects the Cirrus CI API key to be set in the CIRRUS_KEY environment variable. + +import os +import json +import sys +from textwrap import dedent +from time import sleep, time +from pathlib import Path +from typing import Optional + +from urllib.request import Request, urlopen, urlretrieve + +URL = "https://api.cirrus-ci.com/graphql" +TASKS = [ + ("freebsd_build", "bottom_x86_64-unknown-freebsd.tar.gz"), + ("macos_build", "bottom_aarch64-apple-darwin.tar.gz"), +] +DL_URL_TEMPLATE = "https://api.cirrus-ci.com/v1/artifact/build/%s/%s/binaries/%s" + + +def make_query_request(key: str, branch: str, build_type: str): + print("Creating query request.") + mutation_id = "Cirrus CI Build {}-{}-{}".format(build_type, branch, int(time())) + query = """ + mutation CreateCirrusCIBuild ( + $repo: ID!, + $branch: String!, + $mutation_id: String! + ) { + createBuild( + input: { + repositoryId: $repo, + branch: $branch, + clientMutationId: $mutation_id, + } + ) { + build { + id, + status + } + } + } + """ + params = { + "repo": "6646638922956800", + "branch": branch, + "mutation_id": mutation_id, + } + data = {"query": dedent(query), "variables": params} + data = json.dumps(data).encode() + + request = Request(URL, data=data, method="POST") + request.add_header("Authorization", "Bearer {}".format(key)) + + return request + + +def check_build_status(key: str, id: str) -> Optional[str]: + query = """ + query BuildStatus($id: ID!) { + build(id: $id) { + status + } + } + """ + params = { + "id": id, + } + + data = {"query": dedent(query), "variables": params} + data = json.dumps(data).encode() + + request = Request(URL, data=data, method="POST") + request.add_header("Authorization", "Bearer {}".format(key)) + with urlopen(request) as response: + response = json.load(response) + if response.get("errors") is not None: + print("There was an error in the returned response.") + return None + + try: + status = response["data"]["build"]["status"] + return status + except KeyError: + print("There was an issue with creating a build job.") + return None + + +def try_download(build_id: str, dl_path: Path): + for (task, file) in TASKS: + url = DL_URL_TEMPLATE % (build_id, task, file) + out = dl_path / file + print("Downloading {} to {}".format(file, out)) + urlretrieve(url, out) + + +def main(): + args = sys.argv + env = os.environ + + key = env["CIRRUS_KEY"] + branch = args[1] + dl_path = args[2] if len(args) >= 3 else "" + dl_path = Path(dl_path) + build_type = args[3] if len(args) >= 4 else "build" + build_id = args[4] if len(args) >= 5 else None + + # Check if this build has already been completed before. + if build_id is not None: + print("Previous build ID was provided, checking if complete.") + status = check_build_status(key, build_id) + if status.startswith("COMPLETE"): + print("Starting download of previous build ID") + try_download(build_id, dl_path) + else: + # Try up to three times + MAX_ATTEMPTS = 3 + success = False + + for i in range(MAX_ATTEMPTS): + if success: + break + print("Attempt {}:".format(i + 1)) + + with urlopen(make_query_request(key, branch, build_type)) as response: + response = json.load(response) + + if response.get("errors") is not None: + print("There was an error in the returned response.") + continue + + try: + build_id = response["data"]["createBuild"]["build"]["id"] + print("Created build job {}.".format(build_id)) + except KeyError: + print("There was an issue with creating a build job.") + continue + + # First, sleep 4 minutes, as it's unlikely it'll finish before then. + SLEEP_MINUTES = 4 + print("Sleeping for {} minutes.".format(SLEEP_MINUTES)) + sleep(60 * SLEEP_MINUTES) + print("Mandatory nap over. Starting to check for completion.") + + MINUTES = 10 + SLEEP_SEC = 30 + TRIES = int(MINUTES * (60 / SLEEP_SEC)) # Works out to 20 tries. + + for attempt in range(TRIES): + print("Checking...") + status = check_build_status(key, build_id) + if status.startswith("COMPLETE"): + print("Build complete. Downloading artifact files.") + sleep(5) + try_download(build_id, dl_path) + success = True + break + else: + print("Build status: {}".format(status or "unknown")) + if status == "ABORTED": + print("Build aborted, bailing.") + break + elif status.lower().startswith("fail"): + print("Build failed, bailing.") + break + elif attempt + 1 < TRIES: + sleep(SLEEP_SEC) + else: + print("Build failed to complete after {} minutes, bailing.".format(MINUTES)) + continue + + if not success: + exit(2) + + +if __name__ == "__main__": + main() diff --git a/scripts/packager.py b/scripts/packager.py new file mode 100644 index 00000000..30f56182 --- /dev/null +++ b/scripts/packager.py @@ -0,0 +1,75 @@ +import hashlib +import sys +from string import Template + +args = sys.argv +version = args[1] +template_file_path = args[2] +generated_file_path = args[3] + +# SHA512, SHA256, or SHA1 +hash_type = args[4] + +# Deployment files +deployment_file_path_1 = args[5] +deployment_file_path_2 = args[6] if len(args) > 6 else None +deployment_file_path_3 = args[7] if len(args) > 7 else None + +print("Generating package for file: %s" % deployment_file_path_1) +if deployment_file_path_2 is not None: + print("and for file: %s" % deployment_file_path_2) +if deployment_file_path_3 is not None: + print("and for file: %s" % deployment_file_path_3) +print(" VERSION: %s" % version) +print(" TEMPLATE PATH: %s" % template_file_path) +print(" SAVING AT: %s" % generated_file_path) +print(" USING HASH TYPE: %s" % hash_type) + + +def get_hash(deployment_file): + if str.lower(hash_type) == "sha512": + deployment_hash = hashlib.sha512(deployment_file.read()).hexdigest() + elif str.lower(hash_type) == "sha256": + deployment_hash = hashlib.sha256(deployment_file.read()).hexdigest() + elif str.lower(hash_type) == "sha1": + deployment_hash = hashlib.sha1(deployment_file.read()).hexdigest() + else: + print('Unsupported hash format "%s". Please use SHA512, SHA256, or SHA1.', hash_type) + exit(1) + + print("Generated hash: %s" % str(deployment_hash)) + return deployment_hash + + +with open(deployment_file_path_1, "rb") as deployment_file_1: + deployment_hash_1 = get_hash(deployment_file_1) + + deployment_hash_2 = None + if deployment_file_path_2 is not None: + with open(deployment_file_path_2, "rb") as deployment_file_2: + deployment_hash_2 = get_hash(deployment_file_2) + + deployment_hash_3 = None + if deployment_file_path_3 is not None: + with open(deployment_file_path_3, "rb") as deployment_file_3: + deployment_hash_3 = get_hash(deployment_file_3) + + with open(template_file_path, "r") as template_file: + template = Template(template_file.read()) + + substitutes = dict() + substitutes["version"] = version + substitutes["hash1"] = deployment_hash_1 + if deployment_hash_2 is not None: + substitutes["hash2"] = deployment_hash_2 + if deployment_hash_3 is not None: + substitutes["hash3"] = deployment_hash_3 + + substitute = template.safe_substitute(substitutes) + + print("\n================== Generated package file ==================\n") + print(substitute) + print("\n============================================================\n") + + with open(generated_file_path, "w") as generated_file: + generated_file.write(substitute) diff --git a/scripts/windows/choco/bottom.nuspec.template b/scripts/windows/choco/bottom.nuspec.template new file mode 100644 index 00000000..7d176f4e --- /dev/null +++ b/scripts/windows/choco/bottom.nuspec.template @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Read this before creating packages: https://chocolatey.org/docs/create-packages --> +<!-- It is especially important to read the above link to understand additional requirements when publishing packages to the community feed aka dot org (https://chocolatey.org/packages). --> + +<!-- Test your packages in a test environment: https://github.com/chocolatey/chocolatey-test-environment --> + +<!-- +This is a nuspec. It mostly adheres to https://docs.nuget.org/create/Nuspec-Reference. Chocolatey uses a special version of NuGet.Core that allows us to do more than was initially possible. As such there are certain things to be aware of: + +* the package xmlns schema url may cause issues with nuget.exe +* Any of the following elements can ONLY be used by choco tools - projectSourceUrl, docsUrl, mailingListUrl, bugTrackerUrl, packageSourceUrl, provides, conflicts, replaces +* nuget.exe can still install packages with those elements but they are ignored. Any authoring tools or commands will error on those elements +--> + +<!-- You can embed software files directly into packages, as long as you are not bound by distribution rights. --> +<!-- * If you are an organization making private packages, you probably have no issues here --> +<!-- * If you are releasing to the community feed, you need to consider distribution rights. --> +<!-- Do not remove this test for UTF-8: if “Ω” doesn’t appear as greek uppercase omega letter enclosed in quotation marks, you should use an editor that supports UTF-8, not this one. --> +<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd"> + <metadata> + <!-- == PACKAGE SPECIFIC SECTION == --> + <id>bottom</id> + <version>$version</version> + + <!-- == SOFTWARE SPECIFIC SECTION == --> + <!-- This section is about the software itself --> + <title>bottom</title> + <authors>Clement Tsang</authors> + <projectUrl>https://github.com/ClementTsang/bottom</projectUrl> + <licenseUrl>https://github.com/ClementTsang/bottom/blob/master/LICENSE</licenseUrl> + <requireLicenseAcceptance>true</requireLicenseAcceptance> + <projectSourceUrl>https://github.com/ClementTsang/bottom</projectSourceUrl> + <packageSourceUrl>https://github.com/ClementTsang/choco-bottom</packageSourceUrl> + <docsUrl>https://clementtsang.github.io/bottom/stable</docsUrl> + <bugTrackerUrl>https://github.com/ClementTsang/bottom/issues</bugTrackerUrl> + <tags>cli cross-platform terminal top tui monitoring bottom btm</tags> + <summary>A customizable cross-platform graphical process/system monitor for the terminal.</summary> + <description> + A customizable cross-platform graphical process/system monitor for the terminal. Supports Linux, macOS, and Windows. Inspired by [gtop](https://github.com/aksakalli/gtop), [gotop](https://github.com/xxxserxxx/gotop) and [htop](https://github.com/htop-dev/htop). + + **Usage** + To use, run `btm` in a terminal. + + For more [documentation and usage](https://github.com/ClementTsang/bottom/blob/master/README.md), see the [official repo](https://github.com/ClementTsang/bottom). + + + **Note** + This currently depends on Visual C++ Redistributable for Visual Studio 2015 https://chocolatey.org/packages/vcredist2015. + </description> + <releaseNotes>https://github.com/ClementTsang/bottom/releases/tag/$version/</releaseNotes> + </metadata> + <files> + <!-- this section controls what actually gets packaged into the Chocolatey package --> + <file src="tools\**" target="tools" /> + <!--Building from Linux? You may need this instead: <file src="tools/**" target="tools" />--> + </files> +</package> diff --git a/scripts/windows/choco/choco_packager.py b/scripts/windows/choco/choco_packager.py new file mode 100644 index 00000000..daf3f15f --- /dev/null +++ b/scripts/windows/choco/choco_packager.py @@ -0,0 +1,51 @@ +# Because choco is a special case and I'm too lazy to make my +# packaging script robust enough, so whatever, hard-code time. + +import hashlib +import sys +from string import Template +import os + +args = sys.argv +deployment_file_path_64 = args[1] +version = args[2] +nuspec_template = args[3] +ps1_template = args[4] +generated_nuspec = args[5] +generated_ps1 = args[6] +generated_ps1_dir = args[7] + +print("Generating Chocolatey package for:") +print(" 64-bit: %s" % deployment_file_path_64) +print(" VERSION: %s" % version) +print(" NUSPEC TEMPLATE: %s" % nuspec_template) +print(" PS1 TEMPLATE: %s" % ps1_template) +print(" GENERATED NUSPEC: %s" % generated_nuspec) +print(" GENERATED PS1: %s" % generated_ps1) +print(" GENERATED PS1 DIR: %s" % generated_ps1_dir) + +with open(deployment_file_path_64, "rb") as deployment_file_64: + hash_64 = hashlib.sha1(deployment_file_64.read()).hexdigest() + + print("Generated hash for 64-bit program: %s" % str(hash_64)) + + with open(nuspec_template, "r") as template_file: + template = Template(template_file.read()) + substitute = template.safe_substitute(version=version) + print("\n================== Generated nuspec file ==================\n") + print(substitute) + print("\n============================================================\n") + + with open(generated_nuspec, "w") as generated_file: + generated_file.write(substitute) + + os.makedirs(generated_ps1_dir) + with open(ps1_template, "r") as template_file: + template = Template(template_file.read()) + substitute = template.safe_substitute(version=version, hash_64=hash_64) + print("\n================== Generated chocolatey-install file ==================\n") + print(substitute) + print("\n============================================================\n") + + with open(generated_ps1, "w") as generated_file: + generated_file.write(substitute) diff --git a/scripts/windows/choco/chocolateyinstall.ps1.template b/scripts/windows/choco/chocolateyinstall.ps1.template new file mode 100644 index 00000000..a9245d18 --- /dev/null +++ b/scripts/windows/choco/chocolateyinstall.ps1.template @@ -0,0 +1,16 @@ +$ErrorActionPreference = 'Stop'; +$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" +$url = 'https://github.com/ClementTsang/bottom/releases/download/$version/bottom_x86_64-pc-windows-msvc.zip' + +$packageArgs = @{ + packageName = $env:ChocolateyPackageName + softwareName = 'bottom' + unzipLocation = $toolsDir + fileType = 'exe' + url = $url + checksum = '$hash_64' + checksumType = 'sha1' + +} +Install-ChocolateyZipPackage @packageArgs +j
\ No newline at end of file |