mirror of
https://github.com/lissy93/portainer-templates.git
synced 2026-11-04 09:15:08 +00:00
Adds changelog gen script
This commit is contained in:
1 parent
43f08c2bc1
commit
18ef525524
3 files changed
+296
No files matched your search
@@ -0,0 +1,101 @@
|
||||
{
|
||||
"entries": [
|
||||
{
|
||||
"version": "v1.0.6",
|
||||
"previous": "v1.0.5",
|
||||
"date": "2026-07-18",
|
||||
"templateCount": 676,
|
||||
"added": [
|
||||
"PodFetch"
|
||||
],
|
||||
"removed": [],
|
||||
"updated": []
|
||||
},
|
||||
{
|
||||
"version": "v1.0.5",
|
||||
"previous": "v1.0.4",
|
||||
"date": "2026-07-18",
|
||||
"templateCount": 675,
|
||||
"added": [
|
||||
"systemprompt"
|
||||
],
|
||||
"removed": [],
|
||||
"updated": []
|
||||
},
|
||||
{
|
||||
"version": "v1.0.4",
|
||||
"previous": "v1.0.3",
|
||||
"date": "2026-07-17",
|
||||
"templateCount": 674,
|
||||
"added": [],
|
||||
"removed": [
|
||||
"Openvscode-server"
|
||||
],
|
||||
"updated": []
|
||||
},
|
||||
{
|
||||
"version": "v1.0.3",
|
||||
"previous": "v1.0.2",
|
||||
"date": "2026-07-13",
|
||||
"templateCount": 675,
|
||||
"added": [
|
||||
"Reach Me Out"
|
||||
],
|
||||
"removed": [],
|
||||
"updated": []
|
||||
},
|
||||
{
|
||||
"version": "v1.0.2",
|
||||
"previous": "v1.0.1",
|
||||
"date": "2026-07-11",
|
||||
"templateCount": 674,
|
||||
"added": [
|
||||
"Doplarr_rs"
|
||||
],
|
||||
"removed": [
|
||||
"Doplarr"
|
||||
],
|
||||
"updated": [
|
||||
{
|
||||
"title": "Swag",
|
||||
"fields": [
|
||||
"env"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "v1.0.1",
|
||||
"previous": "v1.0.0",
|
||||
"date": "2026-07-10",
|
||||
"templateCount": 674,
|
||||
"added": [
|
||||
"Cloudflared-web"
|
||||
],
|
||||
"removed": [],
|
||||
"updated": [
|
||||
{
|
||||
"title": "Kimai",
|
||||
"fields": [
|
||||
"env"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Nginx",
|
||||
"fields": [
|
||||
"description"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "v1.0.0",
|
||||
"previous": null,
|
||||
"date": "2026-07-06",
|
||||
"templateCount": 673,
|
||||
"added": [],
|
||||
"removed": [],
|
||||
"updated": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
# Re-generates the changelog.json whenever a new tag is created
|
||||
# To track template changes (added/removed/updated)
|
||||
name: 📋 Changelog
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ['v[0-9]+.[0-9]+.[0-9]+']
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
changelog:
|
||||
name: 📋 Update changelog.json
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
ref: main
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Python 🐍
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Generate changelog 🪵
|
||||
run: python3 lib/changelog.py
|
||||
|
||||
- name: Commit and push ⤴️
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.BOT_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
REPO: ${{ github.repository }}
|
||||
TAG: ${{ github.ref_type == 'tag' && github.ref_name || '' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
git config user.name "Liss-Bot"
|
||||
git config user.email "alicia-gh-bot@mail.as93.net"
|
||||
remote="https://x-access-token:${GH_TOKEN}@github.com/${REPO}.git"
|
||||
git add .github/changelog.json
|
||||
if git diff --staged --quiet; then
|
||||
echo "changelog.json unchanged, nothing to commit"
|
||||
exit 0
|
||||
fi
|
||||
git commit -m "Updates changelog${TAG:+ for ${TAG}} (auto-generated)"
|
||||
# Replay onto latest main in case it moved since checkout (our commit
|
||||
# only touches .github/changelog.json, so this can't conflict)
|
||||
git pull --rebase "$remote" main
|
||||
git push "$remote" HEAD:main
|
||||
|
||||
- name: Summary
|
||||
if: always()
|
||||
env:
|
||||
TAG: ${{ github.ref_type == 'tag' && github.ref_name || 'n/a (manual run)' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
{
|
||||
echo "## Changelog"
|
||||
echo ""
|
||||
echo "| Field | Value |"
|
||||
echo "|-------|-------|"
|
||||
echo "| Trigger | \`${TAG}\` |"
|
||||
if [ -f .github/changelog.json ]; then
|
||||
versions=$(jq '.entries | length' .github/changelog.json)
|
||||
latest=$(jq -r '.entries[0]
|
||||
| "\(.version): ✨ \(.added | length) added · 🗑️ \(.removed | length) removed · ♻️ \(.updated | length) updated"
|
||||
' .github/changelog.json)
|
||||
echo "| Versions | ${versions} |"
|
||||
echo "| Latest | ${latest} |"
|
||||
else
|
||||
echo "| Result | ❌ changelog.json was not generated |"
|
||||
fi
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
@@ -0,0 +1,112 @@
|
||||
"""Generates .github/changelog.json - what changed between each version tag.
|
||||
|
||||
Walks every vMAJOR.MINOR.PATCH tag in version order, diffs the compiled
|
||||
templates.json between consecutive tags, and records the templates added,
|
||||
removed and updated in each version. Rebuilt from scratch on every run, so
|
||||
the output is deterministic (safe to re-run, self-heals, no commit churn).
|
||||
|
||||
Matches the diff semantics of the release notes in release.yml: templates
|
||||
are keyed by title, with `id` ignored (it renumbers on every regeneration,
|
||||
which would otherwise flag everything as updated).
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from log import get_logger, banner
|
||||
|
||||
log = get_logger()
|
||||
|
||||
SEMVER_TAG = re.compile(r'^v\d+\.\d+\.\d+$')
|
||||
|
||||
# Pre-v1.0.0 tags predate the current release cadence, so their diffs are
|
||||
# just a giant re-listing of everything. Start the changelog at v1.0.0
|
||||
FIRST_VERSION = (1, 0, 0)
|
||||
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
root_dir = os.path.join(script_dir, '..')
|
||||
output_path = os.path.join(root_dir, '.github', 'changelog.json')
|
||||
|
||||
def git(*args):
|
||||
"""Run a git command in the repo root and return its stdout"""
|
||||
result = subprocess.run(
|
||||
['git', *args], capture_output=True, text=True, check=True, cwd=root_dir)
|
||||
return result.stdout
|
||||
|
||||
def version(tag):
|
||||
"""Numeric (major, minor, patch) tuple for a vX.Y.Z tag"""
|
||||
return tuple(int(p) for p in tag[1:].split('.'))
|
||||
|
||||
def semver_tags():
|
||||
"""All vMAJOR.MINOR.PATCH tags from FIRST_VERSION onwards, oldest first"""
|
||||
tags = [t for t in git('tag').splitlines() if SEMVER_TAG.match(t)]
|
||||
return sorted((t for t in tags if version(t) >= FIRST_VERSION), key=version)
|
||||
|
||||
def tag_dates():
|
||||
"""Map of tag -> creation date (YYYY-MM-DD)"""
|
||||
lines = git('for-each-ref', '--format=%(refname:short) %(creatordate:short)',
|
||||
'refs/tags').splitlines()
|
||||
return dict(line.split(' ', 1) for line in lines if ' ' in line)
|
||||
|
||||
def templates_at(tag):
|
||||
"""Templates in templates.json at a tag, keyed by title with `id` dropped.
|
||||
Returns None if the file doesn't exist at that tag."""
|
||||
try:
|
||||
raw = git('show', f'{tag}:templates.json')
|
||||
except subprocess.CalledProcessError:
|
||||
return None
|
||||
templates = json.loads(raw).get('templates', [])
|
||||
return {t['title']: {k: v for k, v in t.items() if k != 'id'}
|
||||
for t in templates if isinstance(t, dict) and 'title' in t}
|
||||
|
||||
def diff(old, new):
|
||||
"""Added / removed / updated templates between two title-keyed maps"""
|
||||
added = sorted(new.keys() - old.keys())
|
||||
removed = sorted(old.keys() - new.keys())
|
||||
updated = []
|
||||
for title in sorted(new.keys() & old.keys()):
|
||||
if new[title] != old[title]:
|
||||
fields = sorted(k for k in new[title].keys() | old[title].keys()
|
||||
if new[title].get(k) != old[title].get(k))
|
||||
updated.append({'title': title, 'fields': fields})
|
||||
return added, removed, updated
|
||||
|
||||
def main():
|
||||
banner('Changelog', 'Diff templates.json between version tags')
|
||||
tags = semver_tags()
|
||||
if not tags:
|
||||
log.error('No version tags found (needs full git history, not a shallow clone)')
|
||||
sys.exit(1)
|
||||
dates = tag_dates()
|
||||
|
||||
entries = []
|
||||
previous_tag, previous_map = None, None
|
||||
for tag in tags:
|
||||
current = templates_at(tag)
|
||||
if current is None:
|
||||
log.warning(f'{tag}: no templates.json at this tag, skipping')
|
||||
continue
|
||||
first = previous_map is None
|
||||
added, removed, updated = ([], [], []) if first else diff(previous_map, current)
|
||||
entries.append({
|
||||
'version': tag,
|
||||
'previous': previous_tag,
|
||||
'date': dates.get(tag),
|
||||
'templateCount': len(current),
|
||||
'added': added, 'removed': removed, 'updated': updated,
|
||||
})
|
||||
log.info(f'{tag}: first version ({len(current)} total)' if first else
|
||||
f'{tag}: +{len(added)} added, -{len(removed)} removed, '
|
||||
f'~{len(updated)} updated ({len(current)} total)')
|
||||
previous_tag, previous_map = tag, current
|
||||
|
||||
entries.reverse() # newest first
|
||||
with open(output_path, 'w') as file:
|
||||
json.dump({'entries': entries}, file, indent=2, ensure_ascii=False)
|
||||
file.write('\n')
|
||||
log.info(f'Wrote {len(entries)} versions to {os.path.relpath(output_path, root_dir)}')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in new issue
Block a user