Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rewrite Cronjob build triggering logic in python; read from influxdb #275

Merged
merged 52 commits into from
Sep 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
daaa305
uv init scripts
alsuren Sep 4, 2024
e705e8a
declare my intentions
alsuren Sep 4, 2024
4e9392c
in scripts uv add influxdb3-python
alsuren Sep 4, 2024
268ff5d
initial stats from influxdb
alsuren Sep 5, 2024
da4c769
point out where arch could be filtered
alsuren Sep 5, 2024
05b7a29
rewrite triggering logic in python
alsuren Sep 6, 2024
86075e2
make recheck
alsuren Sep 6, 2024
0d519a9
exclude prereleases
alsuren Sep 6, 2024
def5be7
automatically install deps
alsuren Sep 6, 2024
142c81d
what does github actions use for its python version?
alsuren Sep 6, 2024
35f3dd9
github actions uses python 3.8
alsuren Sep 6, 2024
ad24c0e
don't evaluate annotations at runtime
alsuren Sep 6, 2024
ab775b8
document make rule
alsuren Sep 6, 2024
22a87f4
make trigger-all; make sure env is correct
alsuren Sep 6, 2024
f66add3
dependabot for python?
alsuren Sep 6, 2024
83ef9f3
NameError: name 'GITHUB_REPOSITORY' is not defined
alsuren Sep 6, 2024
c656083
stricter bash scripting
alsuren Sep 6, 2024
11b9aa2
logging; refactors; run on actions branch?
alsuren Sep 6, 2024
5e34dc3
/bin/sh is dash on ubuntu
alsuren Sep 6, 2024
890d9e7
fix typo
alsuren Sep 6, 2024
1355176
better description
alsuren Sep 6, 2024
a0541f8
why is stderr going missing?
alsuren Sep 6, 2024
5906835
cancel in progress
alsuren Sep 6, 2024
96512fc
delete old bash implementation and unused scripts
alsuren Sep 6, 2024
94b2383
rename to cronjob_scripts/
alsuren Sep 6, 2024
c940f43
I'm not going to fight against the autoformatter
alsuren Sep 6, 2024
6c2ee1c
turns out we use this elsewhere
alsuren Sep 6, 2024
5fb536c
more fixes after rename
alsuren Sep 6, 2024
481980b
just print to stdout?
alsuren Sep 6, 2024
171de24
don't need this either anymore
alsuren Sep 6, 2024
88cf71d
take indentation from main
alsuren Sep 6, 2024
4e45b11
Update cronjob_scripts/checkout_worktree.py
alsuren Sep 7, 2024
aecd866
Update cronjob_scripts/stats.py
alsuren Sep 7, 2024
29333c1
Apply suggestions from code review
alsuren Sep 7, 2024
6bd2e50
not using this either
alsuren Sep 7, 2024
f3a94f8
code review suggestion
alsuren Sep 7, 2024
9df16f7
reinstate supported-targets; unit test to make sure it's correct
alsuren Sep 7, 2024
530c426
we're using 3.8 in CI
alsuren Sep 7, 2024
22a3dcf
assert nonempty crate name
alsuren Sep 7, 2024
cb27dfd
fix current arch detection code
alsuren Sep 7, 2024
3fbb088
nits
alsuren Sep 7, 2024
6010852
note about crates.io db dump
alsuren Sep 7, 2024
de55bbb
only run python tests on linux
alsuren Sep 7, 2024
80acbf7
actually don't put python tests in the matrix in the first place
alsuren Sep 7, 2024
afecc2c
apparently the name is important
alsuren Sep 7, 2024
1858110
cache influxdb client between invocations
alsuren Sep 7, 2024
30bda7d
bit of loop fusion in get_latest_version()
alsuren Sep 7, 2024
62bd530
another walrus suggestion
alsuren Sep 7, 2024
14f912b
stop with the blanket exception hiding
alsuren Sep 7, 2024
745284c
another try-catch-throw turned into an assert
alsuren Sep 8, 2024
52fe242
typo
alsuren Sep 8, 2024
eaadb22
don't ask crates.io more than once about the same crate
alsuren Sep 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,8 @@ updates:
deps:
patterns:
- "*"
- package-ecosystem: "pip"
# This will update cronjob_scripts/requirements.txt
directory: "/cronjob_scripts"
schedule:
interval: "daily"
6 changes: 2 additions & 4 deletions .github/workflows/cronjob.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@ jobs:

- name: Trigger Package Build
id: find_crate
run: |
set -euo pipefail
touch .env
./trigger-package-build.sh
run: make trigger-all
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
INFLUXDB_TOKEN: ${{ secrets.INFLUXDB_TOKEN }}
CRATE_CHECK_LIMIT: 10
2 changes: 1 addition & 1 deletion .github/workflows/selfbuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
TARGET_ARCH: ${{ matrix.target_arch }}
run: |
set -euxo pipefail
touch .env

VERSION="$(
curl \
--user-agent "cargo-quickinstall build pipeline ([email protected])" \
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,12 @@ jobs:
- name: Fetch tags required for testing
run: git fetch --tags

- name: Run test
- name: Run cargo test
run: cargo test

- name: Test python cronjob_scripts
run: make test-cronjob-scripts

e2etest:
runs-on: ${{ matrix.os }}
strategy:
Expand Down
9 changes: 4 additions & 5 deletions .github/workflows/weekly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: Weekly Recheck

concurrency:
group: trigger-package-build
cancel-in-progress: true

# Run every sunday, to recalculate excludes
on:
Expand All @@ -21,11 +22,9 @@ jobs:
ssh-key: ${{ secrets.CRONJOB_DEPLOY_KEY }}
persist-credentials: true

- name: recheck excludes for all archetectures
- name: recheck cargo-quickinstall and some random crates on all architectures
id: find_crate
run: |
set -euo pipefail
touch .env
make recheck
run: make recheck
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
INFLUXDB_TOKEN: ${{ secrets.INFLUXDB_TOKEN }}
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@
.idea
.vagrant
\.DS_Store
__pycache__
# For now, we rely on scripts/requirements.txt to act as our lockfile, because dependabot doesn't support uv yet.
cronjob_scripts/uv.lock
cronjob_scripts/.python-deps-updated.timestamp
51 changes: 33 additions & 18 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,53 @@
publish: release ## alias for `make release`

.PHONY: release
release: ## Publish a new release
release: cronjob_scripts/.python-deps-updated.timestamp ## Publish a new release
(cd cargo-quickinstall/ && cargo release patch --execute --no-push)
git push origin HEAD:release --tags
make recheck
$(MAKE) recheck

cronjob_scripts/requirements.txt: cronjob_scripts/pyproject.toml ## Compile the python dependencies from pyproject.toml into requirements.txt
(cd cronjob_scripts && uv pip compile pyproject.toml --python-version=3.8 --output-file requirements.txt)

# install python dependencies and then record that we've done so so we don't do it again
# WARNING: this will mess with whatever python venv you happen to be in.
# this is run on the github actions runner so we can't use uv
cronjob_scripts/.python-deps-updated.timestamp: cronjob_scripts/requirements.txt
python --version
pip install -r cronjob_scripts/requirements.txt
touch cronjob_scripts/.python-deps-updated.timestamp

.PHONY: windows
windows: ## trigger a windows build
RECHECK=1 TARGET_ARCH=x86_64-pc-windows-msvc ./trigger-package-build.sh
windows: cronjob_scripts/.python-deps-updated.timestamp ## trigger a windows build
RECHECK=1 TARGET_ARCH=x86_64-pc-windows-msvc python cronjob_scripts/trigger-package-build.py

.PHONY: mac
mac: ## trigger a mac build
RECHECK=1 TARGET_ARCH=x86_64-apple-darwin ./trigger-package-build.sh
mac: cronjob_scripts/.python-deps-updated.timestamp ## trigger a mac build
RECHECK=1 TARGET_ARCH=x86_64-apple-darwin python cronjob_scripts/trigger-package-build.py

.PHONY: m1
m1: ## trigger a mac m1 build
RECHECK=1 TARGET_ARCH=aarch64-apple-darwin ./trigger-package-build.sh
m1: cronjob_scripts/.python-deps-updated.timestamp ## trigger a mac m1 build
RECHECK=1 TARGET_ARCH=aarch64-apple-darwin python cronjob_scripts/trigger-package-build.py

.PHONY: linux
linux: ## trigger a linux build
RECHECK=1 TARGET_ARCH=x86_64-unknown-linux-gnu ./trigger-package-build.sh
linux: cronjob_scripts/.python-deps-updated.timestamp ## trigger a linux build
RECHECK=1 TARGET_ARCH=x86_64-unknown-linux-gnu python cronjob_scripts/trigger-package-build.py

.PHONY: linux-musl
linux-musl: ## trigger a musl libc-based linux build
RECHECK=1 TARGET_ARCH=x86_64-unknown-linux-musl ./trigger-package-build.sh

.PHONY: exclude
exclude: ## recompute excludes, but don't push anywhere (see /tmp/cargo-quickinstall-* for repos)
REEXCLUDE=1 ./trigger-package-build.sh
linux-musl: cronjob_scripts/.python-deps-updated.timestamp ## trigger a musl libc-based linux build
RECHECK=1 TARGET_ARCH=x86_64-unknown-linux-musl python cronjob_scripts/trigger-package-build.py

.PHONY: recheck
recheck: ## recompute excludes and start from the top
RECHECK=1 ./trigger-package-build.sh
recheck: cronjob_scripts/.python-deps-updated.timestamp ## build ourself and some random packages on all arches
RECHECK=1 TARGET_ARCH=all python cronjob_scripts/trigger-package-build.py

.PHONY: trigger-all
trigger-all: cronjob_scripts/.python-deps-updated.timestamp ## build some random packages on all arches
TARGET_ARCH=all python cronjob_scripts/trigger-package-build.py

.PHONY: test-cronjob-scripts
test-cronjob-scripts: cronjob_scripts/.python-deps-updated.timestamp ## run the tests for the python cronjob_scripts
python -m unittest discover -s cronjob_scripts

.PHONY: help
help: ## Display this help screen
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Edit the command however you need, and paste it into your CI pipeline.

## Supported targets

Check [supported-targets](/supported-targets) for lists of targets quickinstall
Check [supported-targets](/cronjob_scripts/trigger-package-build.py) for lists of targets quickinstall
alsuren marked this conversation as resolved.
Show resolved Hide resolved
can build for.

## Limitations
Expand Down
32 changes: 0 additions & 32 deletions check-packages.sh

This file was deleted.

1 change: 1 addition & 0 deletions cronjob_scripts/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.8
7 changes: 7 additions & 0 deletions cronjob_scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Scripts

This folder contains python scripts for use in cargo-quickinstall github actions for triggering builds.

This code has some quite heavy python dependencies and strong assumptions about running on unix, so we should not use it on the github actions runners that actually do the package building.

TODO: make a build_scripts/ folder and move all of the package building scripts into there (converting to python as desired).
Empty file added cronjob_scripts/__init__.py
Empty file.
51 changes: 51 additions & 0 deletions cronjob_scripts/architectures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import os
import subprocess


TARGET_ARCH_TO_BUILD_OS = {
"x86_64-apple-darwin": "macos-latest",
"aarch64-apple-darwin": "macos-latest",
"x86_64-unknown-linux-gnu": "ubuntu-20.04",
"x86_64-unknown-linux-musl": "ubuntu-20.04",
"x86_64-pc-windows-msvc": "windows-latest",
"aarch64-pc-windows-msvc": "windows-latest",
"aarch64-unknown-linux-gnu": "ubuntu-20.04",
"aarch64-unknown-linux-musl": "ubuntu-20.04",
"armv7-unknown-linux-musleabihf": "ubuntu-20.04",
"armv7-unknown-linux-gnueabihf": "ubuntu-20.04",
}


def get_build_os(target_arch: str) -> str:
try:
return TARGET_ARCH_TO_BUILD_OS[target_arch]
except KeyError:
raise ValueError(f"Unrecognised target arch: {target_arch}")


def get_target_architectures() -> list[str]:
target_arch = os.environ.get("TARGET_ARCH", None)
if target_arch in TARGET_ARCH_TO_BUILD_OS:
return [target_arch]

if target_arch == "all":
return list(TARGET_ARCH_TO_BUILD_OS.keys())

rustc_version_output = subprocess.run(
["rustc", "--version", "--verbose"], capture_output=True, text=True
)

assert (
rustc_version_output.returncode == 0
), f"rustc --version --verbose failed: {rustc_version_output}"

host_values = [
line.removeprefix("host: ")
for line in rustc_version_output.stdout.splitlines()
if line.startswith("host: ")
]
assert (
len(host_values) == 1
), f"rustc did not tell us its host, or told us multiple: {rustc_version_output}"

return host_values
48 changes: 48 additions & 0 deletions cronjob_scripts/checkout_worktree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from __future__ import annotations

import subprocess


def checkout_worktree_for_arch(target_arch: str):
"""
Checkout a git worktree for the given target_arch, in /tmp.

This is required for reading the exclude files.

This is lifted directly from the old trigger-package-build.sh script, and is only expected to
work on linux/macos with dash/bash.
"""
worktree_path = f"/tmp/cargo-quickinstall-{target_arch}"
bash_script = f"""
set -eux

rm -rf {worktree_path}
NobodyXu marked this conversation as resolved.
Show resolved Hide resolved
git worktree remove -f {worktree_path} || true
git branch -D "trigger/{target_arch}" || true

git worktree add --force --force {worktree_path}
cd {worktree_path}

if git fetch origin "trigger/{target_arch}"; then
git checkout "origin/trigger/{target_arch}" -B "trigger/{target_arch}"
elif ! git checkout "trigger/{target_arch}"; then
# New branch with no history. Credit: https://stackoverflow.com/a/13969482
git checkout --orphan "trigger/{target_arch}"
git rm --cached -r . || true
git commit -m "Initial Commit" --allow-empty
git push origin "trigger/{target_arch}"
fi
"""
subprocess.run(bash_script, shell=True, check=True, text=True)
return worktree_path


if __name__ == "__main__":
import sys

if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} <target_arch>")
sys.exit(1)

worktree_path = checkout_worktree_for_arch(sys.argv[1])
print(f"checked out to {worktree_path}")
84 changes: 84 additions & 0 deletions cronjob_scripts/get_latest_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
from __future__ import annotations

import json
import functools
from typing import TypedDict
import requests

import semver


class CrateVersionDict(TypedDict):
"""
A returned row from the crates.io index API.

Note that the returned row also includes all of the fields from the jsonschema at
https://doc.rust-lang.org/cargo/reference/registry-index.html#json-schema
but I can't be bothered typing them right now.
"""

name: str
vers: str
features: dict[str, list[str]]


def get_index_url(crate: str):
"""
Packages with 1 character names are placed in a directory named 1.
Packages with 2 character names are placed in a directory named 2.
Packages with 3 character names are placed in the directory 3/{first-character} where {first-character} is the first character of the package name.
All other packages are stored in directories named {first-two}/{second-two} where the top directory is the first two characters of the package name, and the next subdirectory is the third and fourth characters of the package name. For example, cargo would be stored in a file named ca/rg/cargo.
-- https://doc.rust-lang.org/cargo/reference/registry-index.html#index-files
"""
alsuren marked this conversation as resolved.
Show resolved Hide resolved
if len(crate) == 0:
raise ValueError("Empty crate name")
if len(crate) == 1:
NobodyXu marked this conversation as resolved.
Show resolved Hide resolved
return f"https://index.crates.io/1/{crate}"
elif len(crate) == 2:
return f"https://index.crates.io/2/{crate}"
elif len(crate) == 3:
return f"https://index.crates.io/3/{crate[0]}/{crate}"
else:
return f"https://index.crates.io/{crate[:2]}/{crate[2:4]}/{crate}"


@functools.lru_cache
def get_latest_version(crate: str) -> CrateVersionDict | None:
"""
Calls the crates.io index API to get the latest version of the given crate.

There is no rate limit on this api, so we can call it as much as we like.
"""
url = get_index_url(crate)

response = requests.get(url)
if response.status_code == 404:
print(f"No crate named {crate}")
return None
response.raise_for_status()

max_version: CrateVersionDict | None = None
max_parsed_version: semver.VersionInfo | None = None
for line in response.text.splitlines():
version = json.loads(line)
parsed_version = semver.VersionInfo.parse(version["vers"])
if version["yanked"] or parsed_version.prerelease:
continue

if max_parsed_version is None or parsed_version > max_parsed_version:
max_version = version
max_parsed_version = parsed_version

return max_version


if __name__ == "__main__":
import sys

if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} <crate>")
sys.exit(1)

version = get_latest_version(sys.argv[1])
if version is not None:
print(version["vers"])
12 changes: 12 additions & 0 deletions cronjob_scripts/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[project]
name = "cronjob-scripts"
version = "0.0.0"
description = "Scripts for use in cargo-quickinstall github actions"
readme = "README.md"
# This is what ubuntu-latest has installed by default
requires-python = ">=3.8"
dependencies = [
"influxdb3-python>=0.8.0",
"requests>=2.32.3",
"semver>=3.0.2",
]
Loading