Compare commits

...

10 Commits

Author SHA1 Message Date
release-bot
52d129f50a chore(release): bump version to v26.03.21.e [skip ci] 2026-03-21 22:55:39 +00:00
c8b43a3f8f fix(release): exclude current tag from previous tag lookup and handle empty result
All checks were successful
Changelog + Release on main / changelog_and_release (push) Successful in 9m57s
- Exclude newly created tag from PREV_TAG detection to avoid self-referencing ranges
- Add fallback to prevent workflow failure when no previous tag exists
- Update Node version in workflow configuration

Signed-off-by: Alexander Lyall <alex@adcm.uk>
2026-03-21 22:50:21 +00:00
63e2c267fb Merge pull request 'chore(deps): update dependency node to v22.22.1' (#22) from renovate/node-22.x into main
Some checks failed
Changelog + Release on main / changelog_and_release (push) Failing after 39s
Reviewed-on: #22
2026-03-21 22:47:57 +00:00
renovate[bot]
14c2dfdb20 chore(deps): update dependency node to v22.22.1
All checks were successful
Pre-release on non-main branches / prerelease (push) Successful in 30s
2026-03-21 22:46:49 +00:00
68f1ed5d81 chore: add git-cliff configuration
Some checks failed
Changelog + Release on main / changelog_and_release (push) Failing after 33s
feat(release): implement incremental changelog and versioned release workflow

- Generate changelog from previous release tag to HEAD
- Replace full-history changelog with incremental git-cliff usage
- Add automatic version bump from date-based tag
- Commit and push version updates (package.json and lockfile)
- Refactor workflow order to align changelog, versioning, and build
- Improve Node setup and add version checks
- Introduce cliff.toml configuration for grouped changelog output
- Add generated version.json for runtime version display
- Update footer layout to include dynamic version and release link

Signed-off-by: Alexander Lyall <alex@adcm.uk>
2026-03-21 22:45:22 +00:00
release-bot
875ab670d5 chore(release): bump version to v26.03.21.d [skip ci] 2026-03-21 22:24:55 +00:00
43cef42c3b Merge pull request 'chore(deps): update actions/setup-node action to v6' (#21) from renovate/actions-setup-node-6.x into main
All checks were successful
Changelog + Release on main / changelog_and_release (push) Successful in 10m57s
Reviewed-on: #21
2026-03-21 22:18:31 +00:00
renovate[bot]
29dd867bcb chore(deps): update actions/setup-node action to v6
All checks were successful
Pre-release on non-main branches / prerelease (push) Successful in 42s
2026-03-21 22:17:06 +00:00
dba93b67fd Changed release action
Some checks are pending
Changelog + Release on main / changelog_and_release (push) Has started running
Signed-off-by: Alexander Lyall <alex@adcm.uk>
2026-03-21 22:15:45 +00:00
5d23d0639e Added versioning information to footer of website. General updates to the release action
Some checks failed
Changelog + Release on main / changelog_and_release (push) Failing after 6m47s
Signed-off-by: Alexander Lyall <alex@adcm.uk>
2026-03-21 22:04:49 +00:00
6 changed files with 344 additions and 79 deletions

View File

@@ -15,7 +15,7 @@ jobs:
with:
fetch-depth: 0
- name: Stop if this is the bot changelog commit
- name: Stop if this is the bot changelog/version commit
shell: bash
run: |
set -e
@@ -36,82 +36,11 @@ jobs:
sudo install /tmp/git-cliff-*/git-cliff /usr/local/bin/git-cliff
git-cliff --version
- name: Generate CHANGELOG.md (Keep a Changelog)
shell: bash
run: |
set -e
git-cliff --config cliff.toml --output CHANGELOG.md
test -s CHANGELOG.md
- name: Commit and push CHANGELOG.md if changed (CHANGELOG_PAT)
shell: bash
env:
CHANGELOG_PAT: ${{ secrets.CHANGELOG_PAT }}
run: |
set -e
if git diff --quiet -- CHANGELOG.md; then
echo "No changelog changes."
else
git config user.name "changelog-bot"
git config user.email "changelog-bot@users.noreply.local"
git add CHANGELOG.md
git commit -m "docs(changelog): update changelog [skip ci]"
origin_url="$(git remote get-url origin)"
# Convert SSH origin to HTTPS if needed
if echo "$origin_url" | grep -q "^git@"; then
host="$(echo "$origin_url" | sed -E 's#git@([^:]+):.*#\1#')"
path="$(echo "$origin_url" | sed -E 's#git@[^:]+:(.*)#\1#')"
origin_url="https://$host/$path"
fi
authed_url="$(echo "$origin_url" | sed -E "s#^https://#https://oauth2:${CHANGELOG_PAT}@#")"
git push "$authed_url" HEAD:main
fi
- name: Extract newest changelog section for release body
shell: bash
run: |
set -e
# Extract the first "## ..." section (newest section) from CHANGELOG.md
# Includes the "## ..." heading and everything until the next "## ..." heading.
awk '
/^## / { if (seen) exit; seen=1 }
seen { print }
' CHANGELOG.md > RELEASE_NOTES.md
# Clean trailing whitespace/newlines a bit
sed -i 's/[[:space:]]*$//' RELEASE_NOTES.md
test -s RELEASE_NOTES.md
echo "---- RELEASE_NOTES.md ----"
head -n 60 RELEASE_NOTES.md
echo "--------------------------"
- name: Create export zip (Computing:Box Website.zip)
shell: bash
run: |
set -e
if [ ! -d "dist" ]; then
echo "❌ dist/ folder not found in repo root"
ls -la
exit 1
fi
rm -f "Computing:Box Website.zip"
(cd dist && zip -r "../Computing:Box Website.zip" .)
test -s "Computing:Box Website.zip"
ls -lh "Computing:Box Website.zip"
- name: Prepare YY.MM.DD letter-suffix tag + release name
shell: bash
run: |
set -e
# Version: YY.MM.DD (UTC). Swap to `date +...` if you prefer UK-local runner time.
VERSION="$(date -u +'%y.%m.%d')"
PREFIX="v${VERSION}."
@@ -135,12 +64,216 @@ jobs:
TAG="${PREFIX}${next_letter}"
RELEASE_NAME="Computing:Box v${VERSION}.${next_letter}"
origin_url="$(git remote get-url origin)"
if echo "$origin_url" | grep -q "^git@"; then
host="$(echo "$origin_url" | sed -E 's#git@([^:]+):.*#\1#')"
path="$(echo "$origin_url" | sed -E 's#git@[^:]+:(.*)#\1#')"
origin_url="https://$host/$path"
fi
base="$(echo "$origin_url" | sed -E 's#(https?://[^/]+)/.*#\1#')"
repo_path="$(echo "$origin_url" | sed -E 's#https?://[^/]+/##')"
repo_path="$(echo "$repo_path" | sed -E 's/\.git$//')"
RELEASE_URL="${base}/${repo_path}/releases/tag/${TAG}"
echo "TAG=$TAG" >> "$GITHUB_ENV"
echo "RELEASE_NAME=$RELEASE_NAME" >> "$GITHUB_ENV"
echo "ZIP_PATH=Computing:Box Website.zip" >> "$GITHUB_ENV"
echo "RELEASE_URL=$RELEASE_URL" >> "$GITHUB_ENV"
echo "Using tag: $TAG"
echo "Release name: $RELEASE_NAME"
echo "Release URL: $RELEASE_URL"
- name: Find previous release tag
shell: bash
run: |
set -e
PREV_TAG="$(
git tag --list 'v*' \
| grep -E '^v[0-9]{2}\.[0-9]{2}\.[0-9]{2}[a-z]$' \
| grep -Fxv "$TAG" \
| sort -V \
| tail -n 1 \
|| true
)"
if [ -n "$PREV_TAG" ]; then
echo "PREV_TAG=$PREV_TAG" >> "$GITHUB_ENV"
echo "Previous release tag: $PREV_TAG"
else
echo "PREV_TAG=" >> "$GITHUB_ENV"
echo "No previous release tag found."
fi
- name: Generate CHANGELOG.md from previous release to HEAD
shell: bash
run: |
set -e
if [ -n "${PREV_TAG}" ]; then
echo "Generating changelog from ${PREV_TAG}..HEAD"
git-cliff --config cliff.toml "${PREV_TAG}..HEAD" --output CHANGELOG.md
else
echo "Generating changelog from full history"
git-cliff --config cliff.toml --output CHANGELOG.md
fi
test -s CHANGELOG.md
echo "---- CHANGELOG.md ----"
head -n 120 CHANGELOG.md
echo "----------------------"
- name: Commit and push CHANGELOG.md if changed (CHANGELOG_PAT)
shell: bash
env:
CHANGELOG_PAT: ${{ secrets.CHANGELOG_PAT }}
run: |
set -e
if git diff --quiet -- CHANGELOG.md; then
echo "No changelog changes."
else
git config user.name "changelog-bot"
git config user.email "changelog-bot@users.noreply.local"
git add CHANGELOG.md
git commit -m "docs(changelog): update changelog [skip ci]"
origin_url="$(git remote get-url origin)"
if echo "$origin_url" | grep -q "^git@"; then
host="$(echo "$origin_url" | sed -E 's#git@([^:]+):.*#\1#')"
path="$(echo "$origin_url" | sed -E 's#git@[^:]+:(.*)#\1#')"
origin_url="https://$host/$path"
fi
authed_url="$(echo "$origin_url" | sed -E "s#^https://#https://oauth2:${CHANGELOG_PAT}@#")"
git push "$authed_url" HEAD:main
fi
- name: Prepare release notes
shell: bash
run: |
set -e
cp CHANGELOG.md RELEASE_NOTES.md
test -s RELEASE_NOTES.md
echo "---- RELEASE_NOTES.md ----"
head -n 120 RELEASE_NOTES.md
echo "--------------------------"
- name: Derive semver package version from tag
shell: bash
run: |
set -e
PACKAGE_VERSION="$(echo "$TAG" | sed -E 's/^v([0-9]{2})\.0?([0-9]{1,2})\.0?([0-9]{1,2})([a-z])$/\1.\2.\3-\4/')"
if [ -z "$PACKAGE_VERSION" ]; then
echo "❌ Failed to derive PACKAGE_VERSION from TAG=$TAG"
exit 1
fi
echo "PACKAGE_VERSION=$PACKAGE_VERSION" >> "$GITHUB_ENV"
echo "Using package version: $PACKAGE_VERSION"
- name: Generate version file for Astro footer
shell: bash
run: |
set -e
mkdir -p src/generated
cat > src/generated/version.json <<EOF
{
"version": "${TAG}",
"url": "${RELEASE_URL}"
}
EOF
echo "Generated src/generated/version.json"
cat src/generated/version.json
- name: Set up Node
uses: actions/setup-node@v6
with:
node-version: 25
cache: npm
- name: Check Node version
shell: bash
run: |
node -v
npm -v
- name: Install dependencies
shell: bash
run: |
set -e
npm ci
- name: Update package.json and package-lock.json version
shell: bash
run: |
set -e
npm version "$PACKAGE_VERSION" --no-git-tag-version
echo "package.json version:"
node -p "require('./package.json').version"
echo "package-lock.json version:"
node -p "require('./package-lock.json').version"
- name: Commit and push version bump (CHANGELOG_PAT)
shell: bash
env:
CHANGELOG_PAT: ${{ secrets.CHANGELOG_PAT }}
run: |
set -e
if git diff --quiet -- package.json package-lock.json; then
echo "No version changes to commit."
else
git config user.name "release-bot"
git config user.email "release-bot@users.noreply.local"
git add package.json package-lock.json
git commit -m "chore(release): bump version to ${PACKAGE_VERSION} [skip ci]"
origin_url="$(git remote get-url origin)"
if echo "$origin_url" | grep -q "^git@"; then
host="$(echo "$origin_url" | sed -E 's#git@([^:]+):.*#\1#')"
path="$(echo "$origin_url" | sed -E 's#git@[^:]+:(.*)#\1#')"
origin_url="https://$host/$path"
fi
authed_url="$(echo "$origin_url" | sed -E "s#^https://#https://oauth2:${CHANGELOG_PAT}@#")"
git push "$authed_url" HEAD:main
fi
- name: Build Astro site
shell: bash
run: |
set -e
npm run build
test -d dist
- name: Create export zip (Computing:Box Website.zip)
shell: bash
run: |
set -e
if [ ! -d "dist" ]; then
echo "❌ dist/ folder not found in repo root"
ls -la
exit 1
fi
rm -f "Computing:Box Website.zip"
(cd dist && zip -r "../Computing:Box Website.zip" .)
test -s "Computing:Box Website.zip"
ls -lh "Computing:Box Website.zip"
- name: Create and push tag (CHANGELOG_PAT)
shell: bash
@@ -153,7 +286,6 @@ jobs:
origin_url="$(git remote get-url origin)"
# Convert SSH origin to HTTPS if needed
if echo "$origin_url" | grep -q "^git@"; then
host="$(echo "$origin_url" | sed -E 's#git@([^:]+):.*#\1#')"
path="$(echo "$origin_url" | sed -E 's#git@[^:]+:(.*)#\1#')"
@@ -198,7 +330,7 @@ jobs:
"tag_name": tag,
"target_commitish": "main",
"name": name,
"body": body, # newest section only
"body": body,
"draft": False,
"prerelease": False,
}

35
cliff.toml Normal file
View File

@@ -0,0 +1,35 @@
[changelog]
header = """
# Changelog
"""
body = """
{% for group, commits in commits | group_by(attribute="group") %}
## {{ group }}
{% for commit in commits %}
- {{ commit.message | upper_first }}
{% endfor %}
{% endfor %}
"""
footer = ""
[git]
conventional_commits = false
filter_unconventional = false
split_commits = false
topo_order = true
# IMPORTANT: match your tag format
tag_pattern = "^v[0-9]{2}\\.[0-9]{2}\\.[0-9]{2}[a-z]$"
commit_parsers = [
{ message = "^feat", group = "🚀 Features" },
{ message = "^fix", group = "🐛 Fixes" },
{ message = "^refactor", group = "♻️ Refactoring" },
{ message = "^docs", group = "📚 Documentation" },
{ message = "^chore", group = "💼 Other" },
# catch-all so NOTHING is dropped
{ message = ".*", group = "💼 Other" },
]

91
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "computing-box",
"version": "2.0.0",
"version": "26.3.2-1.e",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "computing-box",
"version": "2.0.0",
"version": "26.3.2-1.e",
"dependencies": {
"astro": "^6.0.8"
}
@@ -680,6 +680,9 @@
"cpu": [
"arm"
],
"libc": [
"glibc"
],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -696,6 +699,9 @@
"cpu": [
"arm64"
],
"libc": [
"glibc"
],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -712,6 +718,9 @@
"cpu": [
"ppc64"
],
"libc": [
"glibc"
],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -728,6 +737,9 @@
"cpu": [
"riscv64"
],
"libc": [
"glibc"
],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -744,6 +756,9 @@
"cpu": [
"s390x"
],
"libc": [
"glibc"
],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -760,6 +775,9 @@
"cpu": [
"x64"
],
"libc": [
"glibc"
],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -776,6 +794,9 @@
"cpu": [
"arm64"
],
"libc": [
"musl"
],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -792,6 +813,9 @@
"cpu": [
"x64"
],
"libc": [
"musl"
],
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
@@ -808,6 +832,9 @@
"cpu": [
"arm"
],
"libc": [
"glibc"
],
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -830,6 +857,9 @@
"cpu": [
"arm64"
],
"libc": [
"glibc"
],
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -852,6 +882,9 @@
"cpu": [
"ppc64"
],
"libc": [
"glibc"
],
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -874,6 +907,9 @@
"cpu": [
"riscv64"
],
"libc": [
"glibc"
],
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -896,6 +932,9 @@
"cpu": [
"s390x"
],
"libc": [
"glibc"
],
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -918,6 +957,9 @@
"cpu": [
"x64"
],
"libc": [
"glibc"
],
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -940,6 +982,9 @@
"cpu": [
"arm64"
],
"libc": [
"musl"
],
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -962,6 +1007,9 @@
"cpu": [
"x64"
],
"libc": [
"musl"
],
"license": "Apache-2.0",
"optional": true,
"os": [
@@ -1172,6 +1220,9 @@
"cpu": [
"arm"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -1185,6 +1236,9 @@
"cpu": [
"arm"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -1198,6 +1252,9 @@
"cpu": [
"arm64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -1211,6 +1268,9 @@
"cpu": [
"arm64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -1224,6 +1284,9 @@
"cpu": [
"loong64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -1237,6 +1300,9 @@
"cpu": [
"loong64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -1250,6 +1316,9 @@
"cpu": [
"ppc64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -1263,6 +1332,9 @@
"cpu": [
"ppc64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -1276,6 +1348,9 @@
"cpu": [
"riscv64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -1289,6 +1364,9 @@
"cpu": [
"riscv64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -1302,6 +1380,9 @@
"cpu": [
"s390x"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -1315,6 +1396,9 @@
"cpu": [
"x64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -1328,6 +1412,9 @@
"cpu": [
"x64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [

View File

@@ -1,7 +1,7 @@
{
"name": "computing-box",
"type": "module",
"version": "2.0.0",
"version": "26.3.2-1.e",
"scripts": {
"dev": "astro dev",
"build": "astro build",

View File

@@ -0,0 +1,4 @@
{
"version": "dev",
"url": "#"
}

View File

@@ -1,5 +1,9 @@
---
import "../styles/global.css";
import versionInfo from "../generated/version.json";
const version = versionInfo.version;
const releaseUrl = versionInfo.url;
const { title = "Computing:Box" } = Astro.props;
---
@@ -60,7 +64,10 @@ const { title = "Computing:Box" } = Astro.props;
<a href="/legal-code" style="margin-left: 32px; color: var(--muted); text-decoration: underline;">Legal Code</a>
</div>
<div>Computer Science Concept Simulators</div>
<div>© {new Date().getFullYear()} Computing:Box • Created with ♥ by Mr A Lyall</div>
<div> Version:
<a href={releaseUrl} target="_blank" rel="noopener noreferrer">
{version}
</a> • © {new Date().getFullYear()} Computing:Box • Created with ♥ by Mr A Lyall</div>
</div>
</footer>
</body>