diff --git a/.github/hotcrp.env b/.github/hotcrp.env new file mode 100644 index 0000000..5b6e6c1 --- /dev/null +++ b/.github/hotcrp.env @@ -0,0 +1,6 @@ +# HotCRP submission settings. +# HOTCRP_TOKEN is intentionally not stored here. Configure it as a GitHub +# Actions repository secret, or provide it in the local environment. +: "${HOTCRP_ACTION_UPLOAD_ENABLED:=false}" +: "${HOTCRP_SITE_URL:=https://TODO.hotcrp.com}" +: "${HOTCRP_PID:=TODO}" diff --git a/.github/workflows/build_paper.yml b/.github/workflows/build_paper.yml index 1257c71..9c4242a 100644 --- a/.github/workflows/build_paper.yml +++ b/.github/workflows/build_paper.yml @@ -47,6 +47,19 @@ jobs: files: | paper.pdf submission.pdf + + - name: Set up Python for HotCRP response validation + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + uses: actions/setup-python@v5 + with: + python-version: "3.x" + + - name: Upload to HotCRP + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + env: + HOTCRP_TOKEN: ${{ secrets.HOTCRP_TOKEN }} + run: bash ./tools/upload-to-hotcrp.sh .github/hotcrp.env + build-texlive-2024: runs-on: ubuntu-latest diff --git a/README.md b/README.md index 7d3a444..bca03ab 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ Download: [Paper (with comments)](../../releases/latest/download/paper.pdf) [Submission (without comments)](../../releases/latest/download/submission.pdf) | + ### Conference: ASPLOS - Abstract: 2025-08-13T23:59:00-05:00 @@ -67,3 +68,28 @@ git merge upstream/main ```bash tools/generate_lexers_json.py ``` + +## HotCRP CI/CD + +This repository has support for opt-in automatic submission of `submission.pdf` to HotCRP on every push to main. +This requires setting up the submission in HotCRP first. + +0. For this example, we will take `https://asplos26.hotcrp.com` as the HotCRP site. +1. Create the paper submission on the HotCRP website. `HOTCRP_PID` is the paper's submission ID in the URL (eg. `https://asplos26.hotcrp.com/paper/HOTCRP_PID`) +2. Create an Authentication Token in HotCRP's **Account Settings**: (eg. `https://asplos26.hotcrp.com/profile/developer`) +3. Set up `.github/hotcrp.env` with the values from HotCRP, and set `HOTCRP_ACTION_UPLOAD_ENABLED:=true` to enable uploading by GitHub Actions. + +```sh +: "${HOTCRP_SITE_URL:=https://asplos26.hotcrp.com}" +: "${HOTCRP_PID:=67}" +: "${HOTCRP_ACTION_UPLOAD_ENABLED:=true}" +``` + +4. Lastly, add the `HOTCRP_TOKEN` repository secret in GitHub under **Settings -> Secrets and variables -> Actions**. + +The submission script can also be run locally instead of via GitHub actions. +Don't forget to provide the token in the environment. + +```sh +HOTCRP_TOKEN=... bash tools/upload-to-hotcrp.sh .github/hotcrp.env +``` diff --git a/paper.tex b/paper.tex index 1e3e7a9..c364e29 100644 --- a/paper.tex +++ b/paper.tex @@ -52,12 +52,16 @@ \usepackage{etoolbox} \usepackage[acronym,shortcuts]{glossaries} \usepackage{amsmath} -\usepackage{thmtools} % required for autoref to lemmas \usepackage{algorithm} \usepackage[noend]{algpseudocode} \usepackage{hyphenat} \usepackage[shortcuts]{extdash} +% Load thmtools after acmart has created its built-in theorem environments. +% Newer thmtools aliases shared counters before \newtheorem, which collides +% with acmart's default conjecture/proposition/lemma definitions otherwise. +\AtEndPreamble{\usepackage{thmtools}} + \input{tex/setup.tex} \input{tex/acm.tex} diff --git a/tools/upload-to-hotcrp.sh b/tools/upload-to-hotcrp.sh new file mode 100755 index 0000000..57f7fbe --- /dev/null +++ b/tools/upload-to-hotcrp.sh @@ -0,0 +1,139 @@ +#!/usr/bin/env bash +set -euo pipefail + +default_config_file=".github/hotcrp.env" +config_file="${1:-$default_config_file}" + +usage() { + cat <<'EOF' +Usage: + tools/upload-to-hotcrp.sh [CONFIG_FILE] + tools/upload-to-hotcrp.sh --help + +Uploads a paper PDF to the configured HotCRP submission, to be run from root of +the repository. + +CONFIG_FILE is sourced as a shell env file, with .github/hotcrp as the default. +Environment variables take precedence over CONFIG_FILE defaults when CONFIG_FILE +uses Bash default assignments such as : "${HOTCRP_PID:=TODO}". + +Required values: + HOTCRP_SITE_URL HotCRP site base URL, e.g. https://asplos26.hotcrp.com + HOTCRP_PID Numeric HotCRP paper ID + HOTCRP_TOKEN HotCRP API token + +GitHub Actions control: + HOTCRP_ACTION_UPLOAD_ENABLED + In GitHub Actions, must be exactly true to upload. + Defaults to false. + +Optional overrides: + HOTCRP_PDF PDF to upload. Defaults to submission.pdf. + +Local example: + HOTCRP_TOKEN=... tools/upload-to-hotcrp.sh .github/hotcrp.env + HOTCRP_SITE_URL=... HOTCRP_PID=123 HOTCRP_TOKEN=... tools/upload-to-hotcrp.sh +EOF +} + +die() { + printf 'error: %s\n' "$*" >&2 + exit 1 +} + +require_var() { + local name="$1" + local value="${!name:-}" + + if [ -z "$value" ] || [[ "$value" == *TODO* ]]; then + die "$name is not set. Update $config_file or provide it in the environment." + fi +} + +require_command() { + local name="$1" + + command -v "$name" >/dev/null 2>&1 || die "required command is not available: $name" +} + +case "${1:-}" in + -h|--help) + usage + exit 0 + ;; +esac + +if [ "$#" -gt 0 ] || [ -f "$config_file" ]; then + [ -f "$config_file" ] || die "missing HotCRP config file: $config_file" + + set -a + . "$config_file" + set +a +fi + +HOTCRP_ACTION_UPLOAD_ENABLED="${HOTCRP_ACTION_UPLOAD_ENABLED:-false}" +HOTCRP_PDF="${HOTCRP_PDF:-submission.pdf}" + +if [ "${GITHUB_ACTIONS:-false}" = "true" ] && [ "$HOTCRP_ACTION_UPLOAD_ENABLED" != "true" ]; then + printf 'HotCRP upload is disabled by %s; set HOTCRP_ACTION_UPLOAD_ENABLED=true to enable it.\n' "$config_file" + exit 0 +fi + +require_var HOTCRP_SITE_URL +require_var HOTCRP_PID +require_var HOTCRP_TOKEN + +require_command curl +require_command python3 +require_command zip + +HOTCRP_SITE_URL="${HOTCRP_SITE_URL%/}" + +case "$HOTCRP_PID" in + ''|*[!0-9]*) + die "HOTCRP_PID must be a numeric paper ID." + ;; +esac + +[ -f "$HOTCRP_PDF" ] || die "missing PDF to upload: $HOTCRP_PDF" + +workdir="$(mktemp -d)" +trap 'rm -rf "$workdir"' EXIT + +cp "$HOTCRP_PDF" "$workdir/submission.pdf" + +cat > "$workdir/data.json" < hotcrp-response.json + +# Error reporting uses Python3's stdlib json to avoid installing extra packages +# in the actions container +python3 - <<'PY' +import json +import sys + +with open("hotcrp-response.json") as f: + response = json.load(f) + +print(json.dumps(response, indent=2)) + +if not response.get("ok") or not response.get("valid", False): + sys.exit("HotCRP upload failed") +PY