Template
release/: the newest stage's manufacturing files and documentation
A stage tag (v*) now builds, with kicad-cli, pandoc and pdflatex in the CI image (.gitea/scripts/release-files.py): - per board: Gerbers + Excellon drill zip (JLCPCB-compatible settings), BOM (grouped, DNP left out), pick and place, schematic and PCB PDFs, 3D renders; - docs/*.md and docs/tex/*.tex as PDF, tag and commit in the footer; - release/README.md with tag, commit, ERC/DRC result, files, SHA-256 and the stage's CHANGELOG section. Every file name carries the tag. release-attach.py attaches the files plus a zip of the whole folder to the tag's release (replacing assets of an earlier run); for the newest stage tag (not older stages, not pre-releases) the job commits them to release/ on main with [skip ci]. .gitignore: !/release/ after Release/ (Windows matches it case-insensitively); .gitattributes: release/** -text so the SHA-256 match on every checkout. TEMPLATE.md: "Release files" section, rules and CI updated. Tested in git.b4l.co.th/b4l/kicad10_auto_node with harNES's board and docs: v0.1 committed, v0.0 and v0.2-rc.1 left release/ alone, v0.2 tagged on an older commit landed on top of a moved main; uploads byte-exact against a stub of the Gitea release API.
This commit is contained in:
1 parent
0e002be80c
commit
52a40c1c3e
11 files changed
+654
-53
No files matched your search
@@ -1,9 +1,14 @@
|
||||
name: Release outputs
|
||||
name: Release
|
||||
|
||||
# On a tag v* (a prototype stage): the KiBot outputs of every board, zipped per
|
||||
# board, attached to the tag's release (created when missing). The job token
|
||||
# must be allowed to write releases. Adapted from LVSolarBuck; runs for the
|
||||
# first time at the first tag.
|
||||
# On a tag v* (a prototype stage), .gitea/scripts/release-files.py builds the
|
||||
# stage's release files: for every board Gerbers and drill (zip), BOM, pick
|
||||
# and place, schematic and PCB PDFs and 3D renders; the documentation
|
||||
# (docs/*.md, docs/tex/*.tex) as PDF. They are attached to the tag's release
|
||||
# (created when missing) and, when the tag is the newest stage, committed to
|
||||
# release/ on main, so release/ always holds the latest stage. The commit
|
||||
# carries [skip ci] and touches no path another workflow watches. The job
|
||||
# token must be allowed to write releases and to push to main. Firmware and
|
||||
# software tags (firmware/..., software/...) do not start it.
|
||||
on:
|
||||
push:
|
||||
tags: ['v*']
|
||||
@@ -11,47 +16,54 @@ on:
|
||||
jobs:
|
||||
release:
|
||||
runs-on: kicad10_auto
|
||||
permissions:
|
||||
contents: write
|
||||
concurrency:
|
||||
group: release-${{ github.repository }}
|
||||
cancel-in-progress: false
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: KiBot outputs per board
|
||||
run: |
|
||||
mkdir -p dist
|
||||
for pro in $(find hardware -mindepth 2 -maxdepth 2 -name '*.kicad_pro' | sort); do
|
||||
dir=$(dirname "$pro"); board=$(basename "$dir")
|
||||
(cd "$dir" && kibot -c "$GITHUB_WORKSPACE/kibot.yaml" -d "$GITHUB_WORKSPACE/out/$board") \
|
||||
|| echo "::warning::KiBot reported problems for $board"
|
||||
python3 -c 'import shutil, sys; shutil.make_archive(sys.argv[1], "zip", sys.argv[2])' \
|
||||
"dist/$board-${GITHUB_REF_NAME}" "out/$board"
|
||||
done
|
||||
ls -la dist
|
||||
- name: Release files
|
||||
run: python3 .gitea/scripts/release-files.py "$GITHUB_REF_NAME" --out /tmp/release
|
||||
|
||||
- name: Attach to the release
|
||||
env:
|
||||
TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
run: python3 .gitea/scripts/release-attach.py /tmp/release
|
||||
|
||||
- name: Commit to release/ on main
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
run: |
|
||||
python3 - <<'EOF'
|
||||
import json, os, pathlib, urllib.error, urllib.request, uuid
|
||||
api = f"{os.environ['GITHUB_SERVER_URL']}/api/v1/repos/{os.environ['GITHUB_REPOSITORY']}"
|
||||
tag = os.environ["GITHUB_REF_NAME"]
|
||||
auth = {"Authorization": f"token {os.environ['TOKEN']}"}
|
||||
|
||||
def call(method, url, body=None, ctype="application/json"):
|
||||
req = urllib.request.Request(url, data=body, method=method, headers={**auth, "Content-Type": ctype})
|
||||
with urllib.request.urlopen(req) as r:
|
||||
return json.load(r)
|
||||
|
||||
try:
|
||||
rel = call("GET", f"{api}/releases/tags/{tag}")
|
||||
except urllib.error.HTTPError as e:
|
||||
if e.code != 404:
|
||||
raise
|
||||
rel = call("POST", f"{api}/releases", json.dumps({"tag_name": tag, "name": tag}).encode())
|
||||
for f in sorted(pathlib.Path("dist").glob("*.zip")):
|
||||
b = uuid.uuid4().hex
|
||||
head = (f"--{b}\r\nContent-Disposition: form-data; name=\"attachment\"; filename=\"{f.name}\"\r\n"
|
||||
"Content-Type: application/zip\r\n\r\n").encode()
|
||||
body = head + f.read_bytes() + f"\r\n--{b}--\r\n".encode()
|
||||
call("POST", f"{api}/releases/{rel['id']}/assets?name={f.name}", body, f"multipart/form-data; boundary={b}")
|
||||
print("attached", f.name)
|
||||
EOF
|
||||
tag="$GITHUB_REF_NAME"
|
||||
# stage tags only (v0.1, v0.2, v1.0); a pre-release such as v0.3-rc.1 leaves release/ alone
|
||||
newest=$(git tag -l 'v*' --sort=-v:refname | grep -E '^v[0-9]+(\.[0-9]+)+$' | head -1 || true)
|
||||
if [ "$tag" != "$newest" ]; then
|
||||
echo "$tag is not the newest stage (${newest:-none}): release/ is left as it is."
|
||||
exit 0
|
||||
fi
|
||||
git config user.name "Release CI"
|
||||
git config user.email "ci@noreply.git.b4l.co.th"
|
||||
REPO_URL=$(git config --get remote.origin.url)
|
||||
AUTHED_URL=${REPO_URL/https:\/\//https:\/\/${GITEA_TOKEN}@}
|
||||
# main may move while this runs: start again from the newest main
|
||||
for i in 1 2 3; do
|
||||
git fetch -q "$AUTHED_URL" main
|
||||
git checkout -q -f -B main FETCH_HEAD
|
||||
rm -rf release
|
||||
mkdir release
|
||||
cp -r /tmp/release/. release/
|
||||
git add -A -- release
|
||||
if git diff --cached --quiet; then echo "release/ already holds $tag."; exit 0; fi
|
||||
git commit -q -m "Release $tag: manufacturing files and documentation [skip ci]"
|
||||
if git push -q "$AUTHED_URL" HEAD:main; then
|
||||
echo "Pushed $(git rev-parse --short HEAD): release/ holds $tag"
|
||||
exit 0
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
echo "::error::Could not push release/ to main"
|
||||
exit 1
|
||||
Reference in new issue
Block a user