Publish package
This commit is contained in:
parent
982053c93c
commit
c5cdeb2c21
57
.github/workflows/build.yml
vendored
57
.github/workflows/build.yml
vendored
@ -1,57 +0,0 @@
|
|||||||
on:
|
|
||||||
push:
|
|
||||||
pull_request:
|
|
||||||
workflow_run:
|
|
||||||
|
|
||||||
name: Build and deploy
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
# Could instead install `texlive-full`, but that takes ~20 minutes.
|
|
||||||
# We'll specify the packages we need manually.
|
|
||||||
- name: "Install TeXLive"
|
|
||||||
run: |
|
|
||||||
sudo apt update
|
|
||||||
DEBIAN_FRONTEND=noninteractive \
|
|
||||||
sudo apt install --yes \
|
|
||||||
texlive texlive-xetex \
|
|
||||||
texlive-games texlive-fonts-extra texlive-latex-extra \
|
|
||||||
texlive-pictures texlive-pstricks
|
|
||||||
|
|
||||||
# Typst isn't packaged, and manual download gives us
|
|
||||||
# more control anyway.
|
|
||||||
- name: "Download Typst"
|
|
||||||
run: |
|
|
||||||
wget -q "https://github.com/typst/typst/releases/download/v0.12.0/typst-x86_64-unknown-linux-musl.tar.xz"
|
|
||||||
tar -xf "typst-x86_64-unknown-linux-musl.tar.xz"
|
|
||||||
mv "typst-x86_64-unknown-linux-musl/typst" .
|
|
||||||
rm "typst-x86_64-unknown-linux-musl.tar.xz"
|
|
||||||
rm -dr "typst-x86_64-unknown-linux-musl"
|
|
||||||
|
|
||||||
# Builds all handouts, LaTeX and Typst
|
|
||||||
- name: "Build handouts"
|
|
||||||
run: TYPST_PATH="$(pwd)/typst" python tools/build/main.py
|
|
||||||
|
|
||||||
# Upload logs, even if build fails.
|
|
||||||
# LaTeX stdout/stderr isn't always helpful.
|
|
||||||
- name: "Save LaTeX logs"
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
name: "LaTeX logs"
|
|
||||||
path: "**/*.log"
|
|
||||||
retention-days: 1
|
|
||||||
|
|
||||||
# Upload build output
|
|
||||||
- name: "Save output"
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: "Build output"
|
|
||||||
path: "output/*"
|
|
||||||
retention-days: 10
|
|
107
.github/workflows/ci.yml
vendored
Normal file
107
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
typos:
|
||||||
|
name: "Typos"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Check typos
|
||||||
|
uses: crate-ci/typos@master
|
||||||
|
with:
|
||||||
|
config: ./tools/typos.toml
|
||||||
|
|
||||||
|
typstyle:
|
||||||
|
name: "Typst formatting"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: "Download Typstyle"
|
||||||
|
run: |
|
||||||
|
wget -q "https://github.com/Enter-tainer/typstyle/releases/download/v0.12.14/typstyle-x86_64-unknown-linux-musl"
|
||||||
|
chmod +x typstyle-x86_64-unknown-linux-musl
|
||||||
|
|
||||||
|
- name: Check typst formatting
|
||||||
|
run: |
|
||||||
|
find . -name "*.typ" -type f -print0 | xargs -0 \
|
||||||
|
./typstyle-x86_64-unknown-linux-musl --check
|
||||||
|
|
||||||
|
build:
|
||||||
|
needs:
|
||||||
|
- typos
|
||||||
|
- typstyle
|
||||||
|
|
||||||
|
name: "Build"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
# Could instead install `texlive-full`, but that takes ~20 minutes.
|
||||||
|
# We'll specify the packages we need manually.
|
||||||
|
- name: "Install TeXLive"
|
||||||
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
DEBIAN_FRONTEND=noninteractive \
|
||||||
|
sudo apt install --yes \
|
||||||
|
texlive texlive-xetex \
|
||||||
|
texlive-games texlive-fonts-extra texlive-latex-extra \
|
||||||
|
texlive-pictures texlive-pstricks \
|
||||||
|
python3-requests
|
||||||
|
|
||||||
|
# Typst isn't packaged, and manual download gives us
|
||||||
|
# more control anyway.
|
||||||
|
- name: "Download Typst"
|
||||||
|
run: |
|
||||||
|
wget -q "https://github.com/typst/typst/releases/download/v0.12.0/typst-x86_64-unknown-linux-musl.tar.xz"
|
||||||
|
tar -xf "typst-x86_64-unknown-linux-musl.tar.xz"
|
||||||
|
mv "typst-x86_64-unknown-linux-musl/typst" .
|
||||||
|
rm "typst-x86_64-unknown-linux-musl.tar.xz"
|
||||||
|
rm -dr "typst-x86_64-unknown-linux-musl"
|
||||||
|
|
||||||
|
# Builds all handouts, LaTeX and Typst
|
||||||
|
- name: "Build handouts"
|
||||||
|
run: TYPST_PATH="$(pwd)/typst" python tools/scripts/build.py
|
||||||
|
|
||||||
|
# Upload logs, even if build fails.
|
||||||
|
# LaTeX stdout/stderr isn't always helpful.
|
||||||
|
- name: "Save LaTeX logs"
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
name: "LaTeX logs"
|
||||||
|
path: "**/*.log"
|
||||||
|
retention-days: 14
|
||||||
|
|
||||||
|
# Upload build output
|
||||||
|
- name: "Save output"
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: "Build output"
|
||||||
|
path: "output/*"
|
||||||
|
retention-days: 7
|
||||||
|
|
||||||
|
- name: "Publish package (hash)"
|
||||||
|
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
run: |
|
||||||
|
PUBLISH_USER="${{ secrets.PUBLISH_USER }}" \
|
||||||
|
PUBLISH_KEY="${{ secrets.PUBLISH_KEY }}" \
|
||||||
|
VERSION="${{ github.sha }}" \
|
||||||
|
PACKAGE="${{ vars.PACKAGE }}" \
|
||||||
|
python tools/scripts/publish.py
|
||||||
|
|
||||||
|
- name: "Publish package (latest)"
|
||||||
|
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
run: |
|
||||||
|
PUBLISH_USER="${{ secrets.PUBLISH_USER }}" \
|
||||||
|
PUBLISH_KEY="${{ secrets.PUBLISH_KEY }}" \
|
||||||
|
VERSION="latest" \
|
||||||
|
PACKAGE="${{ vars.PACKAGE }}" \
|
||||||
|
python tools/scripts/publish.py
|
30
.github/workflows/lints.yml
vendored
30
.github/workflows/lints.yml
vendored
@ -1,30 +0,0 @@
|
|||||||
on:
|
|
||||||
push:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
name: Lints
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
typos:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Check typos
|
|
||||||
uses: crate-ci/typos@master
|
|
||||||
with:
|
|
||||||
config: ./tools/typos.toml
|
|
||||||
|
|
||||||
typstyle:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: "Download Typstyle"
|
|
||||||
run: |
|
|
||||||
wget -q "https://github.com/Enter-tainer/typstyle/releases/download/v0.12.14/typstyle-x86_64-unknown-linux-musl"
|
|
||||||
chmod +x typstyle-x86_64-unknown-linux-musl
|
|
||||||
|
|
||||||
- name: Check typst formatting
|
|
||||||
run: |
|
|
||||||
find . -name "*.typ" -type f -print0 | xargs -0 \
|
|
||||||
./typstyle-x86_64-unknown-linux-musl --check
|
|
@ -126,6 +126,9 @@ def build_typst(source_dir: Path, out_subdir: Path) -> IndexEntry | None:
|
|||||||
return None
|
return None
|
||||||
meta = read_meta_toml(meta_path)
|
meta = read_meta_toml(meta_path)
|
||||||
|
|
||||||
|
handout_file = sanitize_file_name(f"{meta['title']}.pdf")
|
||||||
|
solutions_file = sanitize_file_name(f"{meta['title']}.sols.pdf")
|
||||||
|
|
||||||
# Do nothing if not published
|
# Do nothing if not published
|
||||||
if not meta["publish_handout"]:
|
if not meta["publish_handout"]:
|
||||||
return None
|
return None
|
||||||
@ -136,7 +139,6 @@ def build_typst(source_dir: Path, out_subdir: Path) -> IndexEntry | None:
|
|||||||
out = OUT_DIR / out_subdir
|
out = OUT_DIR / out_subdir
|
||||||
out.mkdir(parents=True, exist_ok=True)
|
out.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
file_name = sanitize_file_name(f"{meta['title']}.pdf")
|
|
||||||
res = subprocess.run(
|
res = subprocess.run(
|
||||||
[
|
[
|
||||||
TYPST_PATH,
|
TYPST_PATH,
|
||||||
@ -145,7 +147,7 @@ def build_typst(source_dir: Path, out_subdir: Path) -> IndexEntry | None:
|
|||||||
"main.typ",
|
"main.typ",
|
||||||
"--input",
|
"--input",
|
||||||
"show_solutions=false",
|
"show_solutions=false",
|
||||||
f"{out}/{file_name}",
|
f"{out}/{handout_file}",
|
||||||
],
|
],
|
||||||
cwd=source_dir,
|
cwd=source_dir,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
@ -158,14 +160,13 @@ def build_typst(source_dir: Path, out_subdir: Path) -> IndexEntry | None:
|
|||||||
# Build solutions
|
# Build solutions
|
||||||
if meta["publish_solutions"]:
|
if meta["publish_solutions"]:
|
||||||
log(f"Building typst (solutions): {source_dir}")
|
log(f"Building typst (solutions): {source_dir}")
|
||||||
file_name = sanitize_file_name(f"{meta['title']}.sols.pdf")
|
|
||||||
res = subprocess.run(
|
res = subprocess.run(
|
||||||
[
|
[
|
||||||
TYPST_PATH,
|
TYPST_PATH,
|
||||||
"compile",
|
"compile",
|
||||||
"--ignore-system-fonts",
|
"--ignore-system-fonts",
|
||||||
"main.typ",
|
"main.typ",
|
||||||
f"{out}/{file_name}",
|
f"{out}/{solutions_file}",
|
||||||
],
|
],
|
||||||
cwd=source_dir,
|
cwd=source_dir,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
@ -178,11 +179,9 @@ def build_typst(source_dir: Path, out_subdir: Path) -> IndexEntry | None:
|
|||||||
return {
|
return {
|
||||||
"title": meta["title"],
|
"title": meta["title"],
|
||||||
"group": str(out_subdir),
|
"group": str(out_subdir),
|
||||||
"handout_file": f"{out_subdir}/{meta['title']}.pdf",
|
"handout_file": str(out / handout_file),
|
||||||
"solutions_file": (
|
"solutions_file": (
|
||||||
f"{out_subdir}/{meta['title']}.sols.pdf"
|
str(out / solutions_file) if meta["publish_solutions"] else None
|
||||||
if meta["publish_solutions"]
|
|
||||||
else None
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,6 +197,9 @@ def build_xetex(source_dir: Path, out_subdir: Path) -> IndexEntry | None:
|
|||||||
return None
|
return None
|
||||||
meta = read_meta_toml(meta_path)
|
meta = read_meta_toml(meta_path)
|
||||||
|
|
||||||
|
handout_file = sanitize_file_name(f"{meta['title']}.pdf")
|
||||||
|
solutions_file = sanitize_file_name(f"{meta['title']}.sols.pdf")
|
||||||
|
|
||||||
# Do nothing if not published
|
# Do nothing if not published
|
||||||
if not meta["publish_handout"]:
|
if not meta["publish_handout"]:
|
||||||
return None
|
return None
|
||||||
@ -219,9 +221,8 @@ def build_xetex(source_dir: Path, out_subdir: Path) -> IndexEntry | None:
|
|||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
)
|
)
|
||||||
|
|
||||||
file_name = sanitize_file_name(f"{meta['title']}.pdf")
|
|
||||||
try:
|
try:
|
||||||
shutil.copy(source_dir / "main.pdf", f"{out}/{file_name}")
|
shutil.copy(source_dir / "main.pdf", f"{out}/{handout_file}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log(f"Error: {e}")
|
log(f"Error: {e}")
|
||||||
log_error(res)
|
log_error(res)
|
||||||
@ -243,9 +244,8 @@ def build_xetex(source_dir: Path, out_subdir: Path) -> IndexEntry | None:
|
|||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
)
|
)
|
||||||
|
|
||||||
file_name = sanitize_file_name(f"{meta['title']}.sols.pdf")
|
|
||||||
try:
|
try:
|
||||||
shutil.copy(source_dir / "main.pdf", f"{out}/{file_name}")
|
shutil.copy(source_dir / "main.pdf", f"{out}/{solutions_file}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log(f"Error: {e}")
|
log(f"Error: {e}")
|
||||||
log_error(res)
|
log_error(res)
|
||||||
@ -256,11 +256,9 @@ def build_xetex(source_dir: Path, out_subdir: Path) -> IndexEntry | None:
|
|||||||
return {
|
return {
|
||||||
"title": meta["title"],
|
"title": meta["title"],
|
||||||
"group": str(out_subdir),
|
"group": str(out_subdir),
|
||||||
"handout_file": f"{out_subdir}/{meta['title']}.pdf",
|
"handout_file": str(out / handout_file),
|
||||||
"solutions_file": (
|
"solutions_file": (
|
||||||
f"{out_subdir}/{meta['title']}.sols.pdf"
|
str(out / solutions_file) if meta["publish_solutions"] else None
|
||||||
if meta["publish_solutions"]
|
|
||||||
else None
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
78
tools/scripts/publish.py
Normal file
78
tools/scripts/publish.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
URL = "https://git.betalupi.com"
|
||||||
|
USER = os.environ["PUBLISH_USER"]
|
||||||
|
PACKAGE = os.environ["PACKAGE"]
|
||||||
|
VERSION = os.environ["VERSION"]
|
||||||
|
AUTH = requests.auth.HTTPBasicAuth(USER, os.environ["PUBLISH_KEY"])
|
||||||
|
|
||||||
|
ROOT: Path = Path(os.getcwd())
|
||||||
|
SRC_DIR: Path = ROOT / "output"
|
||||||
|
|
||||||
|
|
||||||
|
def log(msg):
|
||||||
|
print(f"[PUBLISH.PY] {msg}")
|
||||||
|
|
||||||
|
|
||||||
|
log(f"Version is {VERSION}")
|
||||||
|
log(f"Package is {PACKAGE}")
|
||||||
|
log(f"Running in {ROOT}")
|
||||||
|
if not ROOT.is_dir():
|
||||||
|
log("Root is not a directory, cannot continue")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
log(f"Source dir is {SRC_DIR}")
|
||||||
|
if not SRC_DIR.exists():
|
||||||
|
log("Source dir doesn't exist, cannot continue")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
log(f"Deleting existing package {SRC_DIR}")
|
||||||
|
res = requests.delete(
|
||||||
|
f"{URL}/api/packages/{USER}/generic/{PACKAGE}/{VERSION}",
|
||||||
|
auth=AUTH,
|
||||||
|
)
|
||||||
|
if res.status_code != 204:
|
||||||
|
log(f"Deletion failed with code {res.status_code}, this is ok")
|
||||||
|
|
||||||
|
|
||||||
|
def upload(data, target: str):
|
||||||
|
res = requests.put(
|
||||||
|
f"{URL}/api/packages/{USER}/generic/{PACKAGE}/{VERSION}/{target}",
|
||||||
|
auth=AUTH,
|
||||||
|
data=data,
|
||||||
|
)
|
||||||
|
|
||||||
|
if res.status_code != 201:
|
||||||
|
log(f"Upload failed with code {res.status_code}")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
return f"{URL}/api/packages/{USER}/generic/{PACKAGE}/{VERSION}/{target}"
|
||||||
|
|
||||||
|
|
||||||
|
index_file = SRC_DIR / "index.json"
|
||||||
|
with index_file.open("r") as f:
|
||||||
|
index = json.load(f)
|
||||||
|
|
||||||
|
new_index = []
|
||||||
|
for handout in index:
|
||||||
|
title = handout["title"]
|
||||||
|
group = handout["group"]
|
||||||
|
h_file = SRC_DIR / handout["handout_file"]
|
||||||
|
s_file = SRC_DIR / handout["handout_file"]
|
||||||
|
log(f"Uploading {title}")
|
||||||
|
|
||||||
|
h_url = None
|
||||||
|
s_url = None
|
||||||
|
|
||||||
|
h_url = upload(h_file.open("rb").read(), f"{group} - {title}.pdf")
|
||||||
|
if s_file is not None:
|
||||||
|
s_url = upload(s_file.open("rb").read(), f"{group} - {title}.sols.pdf")
|
||||||
|
|
||||||
|
new_index.append(
|
||||||
|
{"title": title, "group": group, "handout": h_url, "solutions": s_url}
|
||||||
|
)
|
||||||
|
|
||||||
|
upload(json.dumps(new_index), "index.json")
|
@ -2,6 +2,7 @@ exclude = ["venv"]
|
|||||||
line-length = 88
|
line-length = 88
|
||||||
indent-width = 4
|
indent-width = 4
|
||||||
target-version = "py39"
|
target-version = "py39"
|
||||||
|
include = ["scripts/**/*.py"]
|
||||||
|
|
||||||
[lint]
|
[lint]
|
||||||
select = ["E4", "E7", "E9", "F"]
|
select = ["E4", "E7", "E9", "F"]
|
Loading…
x
Reference in New Issue
Block a user