Compare commits
9 Commits
1d7bc19965
...
v0.6.1
Author | SHA1 | Date | |
---|---|---|---|
5d8d995a04 | |||
36f6e7314a
|
|||
bc8ae46b4a | |||
dde2363ad7
|
|||
32e3b51a77
|
|||
da387f2ee6
|
|||
08679c2680
|
|||
7b6f9ef224
|
|||
6ca389d5cb
|
5
.gitea/default_merge_message/MERGE_TEMPLATE.md
Normal file
5
.gitea/default_merge_message/MERGE_TEMPLATE.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
chore(pr): ${PullRequestTitle} ${PullRequestReference}
|
||||||
|
|
||||||
|
${PullRequestDescription}
|
||||||
|
|
||||||
|
Merged from ${HeadBranch} into ${BaseBranch}
|
45
.gitea/scripts/cleanup_versions.sh
Executable file
45
.gitea/scripts/cleanup_versions.sh
Executable file
@@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# cleanup_dev_versions.sh - Delete old PyPI dev versions from Gitea package registry
|
||||||
|
|
||||||
|
# Required environment variables
|
||||||
|
USERNAME="${TWINE_USERNAME}"
|
||||||
|
TOKEN="${TWINE_PASSWORD}"
|
||||||
|
REPO="${GITHUB_REPOSITORY}" # e.g., maxp/repocat
|
||||||
|
API_BASE="${GITHUB_API_URL%/}" # Strip trailing slash if present
|
||||||
|
|
||||||
|
OWNER="${REPO%%/*}"
|
||||||
|
PACKAGE_NAME="${REPO##*/}"
|
||||||
|
API_URL="${API_BASE}/packages/${OWNER}/pypi/${PACKAGE_NAME}"
|
||||||
|
|
||||||
|
# Fetch the list of versions
|
||||||
|
response=$(curl -s -u "$USERNAME:$TOKEN" "$API_URL")
|
||||||
|
|
||||||
|
# Extract all .dev versions, sort by creation time
|
||||||
|
mapfile -t versions_to_delete < <(echo "$response" | jq -r '
|
||||||
|
map(select(.version | test("\\.dev"))) |
|
||||||
|
sort_by(.created_at) |
|
||||||
|
.[0:-1][] |
|
||||||
|
.version')
|
||||||
|
|
||||||
|
# Determine latest version to keep
|
||||||
|
latest_version=$(echo "$response" | jq -r '
|
||||||
|
map(select(.version | test("\\.dev"))) |
|
||||||
|
sort_by(.created_at) |
|
||||||
|
last.version')
|
||||||
|
|
||||||
|
if [[ -z "$latest_version" || ${#versions_to_delete[@]} -eq 0 ]]; then
|
||||||
|
echo "No old .dev versions to delete."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Keeping latest .dev version: $latest_version"
|
||||||
|
|
||||||
|
# Delete old .dev versions
|
||||||
|
for version in "${versions_to_delete[@]}"; do
|
||||||
|
echo "Deleting old .dev version: $version"
|
||||||
|
curl -s -X DELETE -u "$USERNAME:$TOKEN" "$API_URL/$version"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Cleanup complete."
|
21
.gitea/scripts/get-release-id.sh
Executable file
21
.gitea/scripts/get-release-id.sh
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Eingaben
|
||||||
|
TAG="$1"
|
||||||
|
TOKEN="${ACTIONS_RUNTIME_TOKEN:-<fallback_token>}"
|
||||||
|
REPO="${GITHUB_REPOSITORY:-owner/example}"
|
||||||
|
API="${GITHUB_API_URL:-https://gitea.example.tld/api/v1}"
|
||||||
|
|
||||||
|
OWNER=$(echo "$REPO" | cut -d/ -f1)
|
||||||
|
NAME=$(echo "$REPO" | cut -d/ -f2)
|
||||||
|
|
||||||
|
RESPONSE=$(curl -sf \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
"$API/repos/$OWNER/$NAME/releases/tags/$TAG")
|
||||||
|
|
||||||
|
RELEASE_ID=$(echo "$RESPONSE" | jq -r '.id')
|
||||||
|
echo "Release-ID für $TAG ist: $RELEASE_ID"
|
||||||
|
|
||||||
|
# Für GitHub Actions als Umgebungsvariable
|
||||||
|
echo "GT_RELEASE_ID=$RELEASE_ID" >> "$GITHUB_ENV"
|
14
.gitea/scripts/set_poetry_version.sh
Executable file
14
.gitea/scripts/set_poetry_version.sh
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
BASE_VERSION=$(cat VERSION)
|
||||||
|
NIGHTLY_SUFFIX=""
|
||||||
|
|
||||||
|
if [[ "$1" == "nightly" ]]; then
|
||||||
|
# Beispiel: 20240511.1358 → 11. Mai, 13:58 Uhr
|
||||||
|
NIGHTLY_SUFFIX=".dev$(date +%Y%m%d%H%M)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
FULL_VERSION="${BASE_VERSION}${NIGHTLY_SUFFIX}"
|
||||||
|
|
||||||
|
echo "Using version: $FULL_VERSION"
|
||||||
|
poetry version "$FULL_VERSION"
|
21
.gitea/scripts/sync_version_from_poetry.sh
Executable file
21
.gitea/scripts/sync_version_from_poetry.sh
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Stelle sicher, dass wir im Projektverzeichnis sind
|
||||||
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
|
cd "$ROOT_DIR"
|
||||||
|
|
||||||
|
PYPROJECT="pyproject.toml"
|
||||||
|
VERSION_FILE="VERSION"
|
||||||
|
|
||||||
|
# Extrahiere die Version mit grep + sed (keine externen Abhängigkeiten nötig)
|
||||||
|
VERSION=$(grep -E '^version\s*=' "$PYPROJECT" | head -n1 | sed -E 's/.*=\s*"([^"]+)".*/\1/')
|
||||||
|
|
||||||
|
if [[ -z "$VERSION" ]]; then
|
||||||
|
echo "❌ Version konnte nicht aus $PYPROJECT gelesen werden."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "%s" "$VERSION" > "$VERSION_FILE"
|
||||||
|
echo "✅ Version synchronisiert: $VERSION → $VERSION_FILE"
|
40
.gitea/scripts/upload-asset.sh
Executable file
40
.gitea/scripts/upload-asset.sh
Executable file
@@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Eingabeparameter
|
||||||
|
FILE_PATH="$1" # z. B. ./dist/build.zip
|
||||||
|
CUSTOM_NAME="${2:-}" # optional: anderer Name unter dem das Asset gespeichert werden soll
|
||||||
|
RELEASE_ID="${GT_RELEASE_ID:-}" # aus Umgebung
|
||||||
|
|
||||||
|
# Validierung
|
||||||
|
if [[ -z "$RELEASE_ID" ]]; then
|
||||||
|
echo "❌ RELEASE_ID ist nicht gesetzt. Abbruch."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$FILE_PATH" ]]; then
|
||||||
|
echo "❌ Datei '$FILE_PATH' existiert nicht. Abbruch."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Default-Konfiguration
|
||||||
|
TOKEN="${ACTIONS_RUNTIME_TOKEN:-<fallback_token>}"
|
||||||
|
REPO="${GITHUB_REPOSITORY:-owner/example}"
|
||||||
|
API="${GITHUB_API_URL:-https://gitea.example.tld/api/v1}"
|
||||||
|
|
||||||
|
# Owner/Repo auflösen
|
||||||
|
OWNER=$(echo "$REPO" | cut -d/ -f1)
|
||||||
|
NAME=$(echo "$REPO" | cut -d/ -f2)
|
||||||
|
|
||||||
|
# Dateiname setzen
|
||||||
|
FILENAME="${CUSTOM_NAME:-$(basename "$FILE_PATH")}"
|
||||||
|
|
||||||
|
echo "🔼 Uploading '$FILE_PATH' as '$FILENAME' to release ID $RELEASE_ID"
|
||||||
|
|
||||||
|
# Upload
|
||||||
|
curl -sf -X POST \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
-F "attachment=@$FILE_PATH" \
|
||||||
|
"$API/repos/$OWNER/$NAME/releases/$RELEASE_ID/assets?name=$FILENAME"
|
||||||
|
|
||||||
|
echo "✅ Upload abgeschlossen: $FILENAME"
|
@@ -1,30 +1,33 @@
|
|||||||
# .gitea/workflows/publish.yml
|
name: Build and Publish nightly package
|
||||||
|
|
||||||
name: Build and Publish
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
paths:
|
branches:
|
||||||
- "pyproject.toml" # Nur bei Änderungen an dieser Datei
|
- main
|
||||||
workflow_dispatch: # Manuelles Anstoßen zulassen
|
paths-ignore:
|
||||||
|
- 'CHANGELOG.md'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-publish:
|
build-and-publish:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: ⚙️ Prepare Environment Variables
|
|
||||||
run: |
|
|
||||||
echo "AGENT_TOOLSDIRECTORY=/home/runner/toolcache" >> $GITHUB_ENV
|
|
||||||
mkdir -p /home/runner/toolcache
|
|
||||||
|
|
||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: 🐍 Setup Python
|
- name: 🐍 Setup Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.12"
|
||||||
|
|
||||||
|
- name: 🔄 Restore cache
|
||||||
|
uses: https://git.0xmax42.io/actions/cache@v1
|
||||||
|
with:
|
||||||
|
key: poetry-v1-${{ runner.os }}-${{ hashFiles('poetry.lock') }}
|
||||||
|
paths: |
|
||||||
|
~/.cache/pypoetry
|
||||||
|
~/.cache/pip
|
||||||
|
|
||||||
- name: Install Poetry
|
- name: Install Poetry
|
||||||
run: |
|
run: |
|
||||||
@@ -35,6 +38,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
poetry install
|
poetry install
|
||||||
|
|
||||||
|
- name: Set version from VERSION file (with nightly suffix)
|
||||||
|
run: ./.gitea/scripts/set_poetry_version.sh nightly
|
||||||
|
|
||||||
- name: Build Package
|
- name: Build Package
|
||||||
working-directory: .
|
working-directory: .
|
||||||
run: |
|
run: |
|
||||||
@@ -47,3 +53,10 @@ jobs:
|
|||||||
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
|
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
|
||||||
run: |
|
run: |
|
||||||
poetry run twine upload --repository-url ${{ secrets.TWINE_URL }} dist/*
|
poetry run twine upload --repository-url ${{ secrets.TWINE_URL }} dist/*
|
||||||
|
|
||||||
|
- name: Cleanup old dev versions
|
||||||
|
run: |
|
||||||
|
.gitea/scripts/cleanup_versions.sh '\.dev'
|
||||||
|
env:
|
||||||
|
TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }}
|
||||||
|
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
|
64
.gitea/workflows/build-and-deploy-release.yml
Normal file
64
.gitea/workflows/build-and-deploy-release.yml
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
name: Build and Publish nightly package
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-publish:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.release.tag_name }}
|
||||||
|
|
||||||
|
- name: 🐍 Setup Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: "3.12"
|
||||||
|
|
||||||
|
- name: 🔄 Restore cache
|
||||||
|
uses: https://git.0xmax42.io/actions/cache@v1
|
||||||
|
with:
|
||||||
|
key: poetry-v1-${{ runner.os }}-${{ hashFiles('poetry.lock') }}
|
||||||
|
paths: |
|
||||||
|
~/.cache/pypoetry
|
||||||
|
~/.cache/pip
|
||||||
|
|
||||||
|
- name: Install Poetry
|
||||||
|
run: |
|
||||||
|
pip install poetry
|
||||||
|
|
||||||
|
- name: Install Project Dependencies
|
||||||
|
working-directory: .
|
||||||
|
run: |
|
||||||
|
poetry install
|
||||||
|
|
||||||
|
- name: Build Package
|
||||||
|
working-directory: .
|
||||||
|
run: |
|
||||||
|
poetry build
|
||||||
|
|
||||||
|
- name: Get built wheel filename
|
||||||
|
id: get_whl
|
||||||
|
run: |
|
||||||
|
echo "whl_file=$(basename dist/*.whl)" >> $GITHUB_OUTPUT
|
||||||
|
echo "sdist_file=$(basename dist/*.tar.gz)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Publish to Gitea Package Registry
|
||||||
|
working-directory: .
|
||||||
|
env:
|
||||||
|
TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }}
|
||||||
|
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
|
||||||
|
run: |
|
||||||
|
poetry run twine upload --repository-url ${{ secrets.TWINE_URL }} dist/*
|
||||||
|
|
||||||
|
- name: Get Release ID from tag
|
||||||
|
run: .gitea/scripts/get-release-id.sh "${{ github.event.release.tag_name }}"
|
||||||
|
|
||||||
|
- name: Upload assets
|
||||||
|
run: |
|
||||||
|
.gitea/scripts/upload-asset.sh ./dist/${{ steps.get_whl.outputs.whl_file }}
|
||||||
|
.gitea/scripts/upload-asset.sh ./dist/${{ steps.get_whl.outputs.sdist_file }}
|
18
.gitea/workflows/release.yml
Normal file
18
.gitea/workflows/release.yml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
name: Auto Changelog & (Release)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Release
|
||||||
|
uses: https://git.0xmax42.io/actions/auto-changelog-release-action@v0
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.RELEASE_PUBLISH_TOKEN }}
|
31
CHANGELOG.md
Normal file
31
CHANGELOG.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [0.6.1] - 2025-07-16
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- *(ci)* Add workflows for nightly builds and releases - ([da387f2](https://git.0xmax42.io/maxp/hdlbuild/commit/da387f2ee602390d616c79bf4057ccf941e21462))
|
||||||
|
|
||||||
|
### 🚜 Refactor
|
||||||
|
|
||||||
|
- Use typer for CLI argument parsing - ([6ca389d](https://git.0xmax42.io/maxp/hdlbuild/commit/6ca389d5cbbeff53faab9d61376a8c77ed097b6c))
|
||||||
|
- Improves project configuration - ([175bf48](https://git.0xmax42.io/maxp/hdlbuild/commit/175bf4882a8f172ee536d726b31136690572be36))
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- *(readme)* Expand README with detailed usage and setup - ([fa7e738](https://git.0xmax42.io/maxp/hdlbuild/commit/fa7e738b7eade5a627218741a6fb4bd1617f7801))
|
||||||
|
|
||||||
|
### 🎨 Styling
|
||||||
|
|
||||||
|
- *(pyproject)* Simplify include array formatting - ([08679c2](https://git.0xmax42.io/maxp/hdlbuild/commit/08679c2680b49119e0414688a80e8dc2659236b4))
|
||||||
|
- Updates VS Code editor color scheme - ([1d7bc19](https://git.0xmax42.io/maxp/hdlbuild/commit/1d7bc1996522ab54970348b5118ad319849a6a1f))
|
||||||
|
|
||||||
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|
||||||
|
- *(config)* Add git-cliff configuration file - ([dde2363](https://git.0xmax42.io/maxp/hdlbuild/commit/dde2363ad7dd2fd2d48c6154e3b88c1c4a6867fd))
|
||||||
|
- Updates project version to 0.6.0 - ([7b6f9ef](https://git.0xmax42.io/maxp/hdlbuild/commit/7b6f9ef2240864b103903e79c895a76db59c14fa))
|
||||||
|
- Remove build-deb.yml workflow file - ([0d26c42](https://git.0xmax42.io/maxp/hdlbuild/commit/0d26c42f8ae419d509aa47d3f7a23bfdd08cf79b))
|
||||||
|
|
||||||
|
|
104
cliff.toml
Normal file
104
cliff.toml
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
# CLIFF_VERSION=2.8.0
|
||||||
|
# git-cliff ~ default configuration file
|
||||||
|
# https://git-cliff.org/docs/configuration
|
||||||
|
#
|
||||||
|
# Lines starting with "#" are comments.
|
||||||
|
# Configuration options are organized into tables and keys.
|
||||||
|
# See documentation for more information on available options.
|
||||||
|
[remote.gitea]
|
||||||
|
owner = "maxp"
|
||||||
|
repo = "hdlbuild"
|
||||||
|
|
||||||
|
[changelog]
|
||||||
|
# postprocessors
|
||||||
|
postprocessors = [
|
||||||
|
{ pattern = '<GITEA_URL>', replace = "https://git.0xmax42.io" }, # replace gitea url
|
||||||
|
]
|
||||||
|
|
||||||
|
# template for the changelog header
|
||||||
|
header = """
|
||||||
|
# Changelog\n
|
||||||
|
All notable changes to this project will be documented in this file.\n
|
||||||
|
"""
|
||||||
|
# template for the changelog body
|
||||||
|
# https://keats.github.io/tera/docs/#introduction
|
||||||
|
body = """
|
||||||
|
{%- macro remote_url() -%}
|
||||||
|
<GITEA_URL>/{{ remote.gitea.owner }}/{{ remote.gitea.repo }}
|
||||||
|
{%- endmacro -%}
|
||||||
|
|
||||||
|
{% if version %}\
|
||||||
|
{% if previous.version %}\
|
||||||
|
## [{{ version | trim_start_matches(pat="v") }}]\
|
||||||
|
({{ self::remote_url() }}/compare/{{ previous.version }}..{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }}
|
||||||
|
{% else %}\
|
||||||
|
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
|
||||||
|
{% endif %}\
|
||||||
|
{% else %}\
|
||||||
|
## [unreleased]
|
||||||
|
{% endif %}\
|
||||||
|
{% for group, commits in commits | group_by(attribute="group") %}
|
||||||
|
### {{ group | striptags | trim | upper_first }}
|
||||||
|
{% for commit in commits %}
|
||||||
|
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
|
||||||
|
{% if commit.breaking %}[**breaking**] {% endif %}\
|
||||||
|
{{ commit.message | upper_first }} - \
|
||||||
|
([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}\n
|
||||||
|
"""
|
||||||
|
# template for the changelog footer
|
||||||
|
footer = """
|
||||||
|
|
||||||
|
"""
|
||||||
|
# remove the leading and trailing s
|
||||||
|
trim = true
|
||||||
|
|
||||||
|
# render body even when there are no releases to process
|
||||||
|
# render_always = true
|
||||||
|
# output file path
|
||||||
|
# output = "test.md"
|
||||||
|
|
||||||
|
[git]
|
||||||
|
# parse the commits based on https://www.conventionalcommits.org
|
||||||
|
conventional_commits = true
|
||||||
|
# filter out the commits that are not conventional
|
||||||
|
filter_unconventional = true
|
||||||
|
# process each line of a commit as an individual commit
|
||||||
|
split_commits = false
|
||||||
|
# regex for preprocessing the commit messages
|
||||||
|
commit_preprocessors = [
|
||||||
|
# Replace issue numbers
|
||||||
|
#{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](<REPO>/issues/${2}))"},
|
||||||
|
# Check spelling of the commit with https://github.com/crate-ci/typos
|
||||||
|
# If the spelling is incorrect, it will be automatically fixed.
|
||||||
|
#{ pattern = '.*', replace_command = 'typos --write-changes -' },
|
||||||
|
]
|
||||||
|
# regex for parsing and grouping commits
|
||||||
|
commit_parsers = [
|
||||||
|
{ message = "^feat", group = "<!-- 0 -->🚀 Features" },
|
||||||
|
{ message = "^fix", group = "<!-- 1 -->🐛 Bug Fixes" },
|
||||||
|
{ message = "^doc", group = "<!-- 3 -->📚 Documentation" },
|
||||||
|
{ message = "^perf", group = "<!-- 4 -->⚡ Performance" },
|
||||||
|
{ message = "^refactor", group = "<!-- 2 -->🚜 Refactor" },
|
||||||
|
{ message = "^style", group = "<!-- 5 -->🎨 Styling" },
|
||||||
|
{ message = "^test", group = "<!-- 6 -->🧪 Testing" },
|
||||||
|
{ message = "^chore\\(changelog\\)", skip = true },
|
||||||
|
{ message = "^chore\\(version\\)", skip = true },
|
||||||
|
{ message = "^chore\\(release\\): prepare for", skip = true },
|
||||||
|
{ message = "^chore\\(deps.*\\)", skip = true },
|
||||||
|
{ message = "^chore\\(pr\\)", skip = true },
|
||||||
|
{ message = "^chore\\(pull\\)", skip = true },
|
||||||
|
{ message = "^chore|^ci", group = "<!-- 7 -->⚙️ Miscellaneous Tasks" },
|
||||||
|
{ body = ".*security", group = "<!-- 8 -->🛡️ Security" },
|
||||||
|
{ message = "^revert", group = "<!-- 9 -->◀️ Revert" },
|
||||||
|
{ message = ".*", group = "<!-- 10 -->💼 Other" },
|
||||||
|
]
|
||||||
|
# Regex to select git tags that represent releases.
|
||||||
|
tag_pattern = "v[0-9]+\\.[0-9]+\\.[0-9]+"
|
||||||
|
# filter out the commits that are not matched by commit parsers
|
||||||
|
filter_commits = false
|
||||||
|
# sort the tags topologically
|
||||||
|
topo_order = false
|
||||||
|
# sort the commits inside sections by oldest/newest order
|
||||||
|
sort_commits = "newest"
|
@@ -1,14 +1,12 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "hdlbuild"
|
name = "hdlbuild"
|
||||||
version = "0.5.3"
|
version = "0.6.1"
|
||||||
description = "Flexible FPGA Build System"
|
description = "Flexible FPGA Build System"
|
||||||
authors = ["0xMax42 <Mail@0xMax42.io>"]
|
authors = ["0xMax42 <Mail@0xMax42.io>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
packages = [{ include = "hdlbuild", from = "src" }]
|
packages = [{ include = "hdlbuild", from = "src" }]
|
||||||
include = [
|
include = ["src/hdlbuild/templates/*"]
|
||||||
"src/hdlbuild/templates/*"
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.poetry.scripts]
|
[tool.poetry.scripts]
|
||||||
hdlbuild = "hdlbuild.cli:main"
|
hdlbuild = "hdlbuild.cli:main"
|
||||||
@@ -19,6 +17,7 @@ pyyaml = "^6.0.2"
|
|||||||
pydantic = "^2.11.3"
|
pydantic = "^2.11.3"
|
||||||
rich = "^14.0.0"
|
rich = "^14.0.0"
|
||||||
gitpython = "^3.1.44"
|
gitpython = "^3.1.44"
|
||||||
|
typer = "^0.16.0"
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
twine = "^6.1.0"
|
twine = "^6.1.0"
|
||||||
|
@@ -1,32 +1,32 @@
|
|||||||
import argparse
|
import typer
|
||||||
from importlib.metadata import version, PackageNotFoundError
|
from importlib.metadata import version, PackageNotFoundError
|
||||||
from hdlbuild.commands import register_commands
|
|
||||||
|
|
||||||
def get_version():
|
from hdlbuild.commands.build import cli as build_cli
|
||||||
|
from hdlbuild.commands.clean import cli as clean_cli
|
||||||
|
from hdlbuild.commands.dep import cli as dep_cli
|
||||||
|
from hdlbuild.commands.test import cli as test_cli
|
||||||
|
from hdlbuild.commands.init import cli as init_cli
|
||||||
|
|
||||||
|
def get_version() -> str:
|
||||||
try:
|
try:
|
||||||
return version("hdlbuild") # Paketname aus pyproject.toml
|
return version("hdlbuild")
|
||||||
except PackageNotFoundError:
|
except PackageNotFoundError:
|
||||||
return "unknown"
|
return "unknown"
|
||||||
|
|
||||||
|
app = typer.Typer(
|
||||||
|
rich_help_panel="ℹ️ HDLBuild – FPGA‑Build‑Tool",
|
||||||
|
help=f"hdlbuild v{get_version()} – Build‑Management for FPGA projects"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Unter‑Kommandos registrieren (entspricht add_subparsers)
|
||||||
|
app.add_typer(build_cli, name="build", help="Build the project")
|
||||||
|
app.add_typer(clean_cli, name="clean", help="Clean build artifacts")
|
||||||
|
app.add_typer(dep_cli, name="dep", help="Resolve dependencies")
|
||||||
|
app.add_typer(test_cli, name="test", help="Run simulations/testbenches")
|
||||||
|
app.add_typer(init_cli, name="init", help="Initialize project")
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
version_str = get_version()
|
app()
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description=f"hdlbuild v{version_str} - Build management tool for FPGA projects",
|
|
||||||
formatter_class=argparse.RawTextHelpFormatter
|
|
||||||
)
|
|
||||||
|
|
||||||
subparsers = parser.add_subparsers(
|
|
||||||
title="Commands",
|
|
||||||
description="Available commands",
|
|
||||||
dest="command",
|
|
||||||
required=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Register all commands
|
|
||||||
register_commands(subparsers)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
args.func(args)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
@@ -1 +0,0 @@
|
|||||||
from .commands import register_commands
|
|
@@ -1,30 +1,34 @@
|
|||||||
from hdlbuild.tools.xilinx_ise.main import xilinx_ise_all, xilinx_ise_synth
|
import typer
|
||||||
from hdlbuild.utils.console_utils import ConsoleUtils
|
|
||||||
from hdlbuild.utils.directory_manager import ensure_directories_exist
|
|
||||||
from hdlbuild.utils.project_loader import load_project_config
|
|
||||||
|
|
||||||
class BuildCommand:
|
from hdlbuild.tools.xilinx_ise.main import xilinx_ise_all, xilinx_ise_synth
|
||||||
def __init__(self):
|
from hdlbuild.utils.console_utils import ConsoleUtils
|
||||||
self.console_utils = ConsoleUtils("hdlbuild")
|
from hdlbuild.utils.directory_manager import ensure_directories_exist
|
||||||
|
from hdlbuild.utils.project_loader import load_project_config
|
||||||
|
|
||||||
def register(self, subparsers):
|
cli = typer.Typer(rich_help_panel="🔨 Build Commands")
|
||||||
parser = subparsers.add_parser("build", help="Start the build process")
|
|
||||||
parser.add_argument(
|
|
||||||
"target",
|
|
||||||
nargs="?",
|
|
||||||
choices=["synth"],
|
|
||||||
help="Specify 'synth' to only synthesize the design (optional)"
|
|
||||||
)
|
|
||||||
parser.set_defaults(func=self.execute)
|
|
||||||
|
|
||||||
def execute(self, args):
|
@cli.callback(invoke_without_command=True)
|
||||||
"""Starts the build process."""
|
def build(
|
||||||
self.project = load_project_config()
|
target: str = typer.Argument(
|
||||||
if args.target == "synth":
|
None,
|
||||||
self.console_utils.print("Starting synth process...")
|
help="Optional: 'synth' to run synthesis only",
|
||||||
ensure_directories_exist(True)
|
show_default=False,
|
||||||
xilinx_ise_synth(self.project)
|
rich_help_panel="🔨 Build Commands",
|
||||||
else:
|
)
|
||||||
self.console_utils.print("Starting build process...")
|
) -> None:
|
||||||
ensure_directories_exist(True)
|
"""
|
||||||
xilinx_ise_all(self.project)
|
Run the full build flow or synthesis only.
|
||||||
|
|
||||||
|
* `hdlbuild build` → full flow
|
||||||
|
* `hdlbuild build synth` → synthesis only
|
||||||
|
"""
|
||||||
|
console = ConsoleUtils("hdlbuild")
|
||||||
|
project = load_project_config()
|
||||||
|
|
||||||
|
ensure_directories_exist(True)
|
||||||
|
if target == "synth":
|
||||||
|
console.print("Starting synthesis …")
|
||||||
|
xilinx_ise_synth(project)
|
||||||
|
else:
|
||||||
|
console.print("Starting full build …")
|
||||||
|
xilinx_ise_all(project)
|
||||||
|
@@ -1,27 +1,35 @@
|
|||||||
from hdlbuild.utils.console_utils import ConsoleUtils
|
import typer
|
||||||
from hdlbuild.utils.directory_manager import clear_build_directories, clear_directories
|
|
||||||
|
|
||||||
class CleanCommand:
|
from hdlbuild.utils.console_utils import ConsoleUtils
|
||||||
def __init__(self):
|
from hdlbuild.utils.directory_manager import clear_build_directories, clear_directories
|
||||||
self.console_utils = ConsoleUtils("hdlbuild")
|
|
||||||
|
|
||||||
def register(self, subparsers):
|
cli = typer.Typer(rich_help_panel="🧹 Clean Commands")
|
||||||
parser = subparsers.add_parser("clean", help="Clean build artifacts")
|
|
||||||
parser.add_argument(
|
|
||||||
"target",
|
|
||||||
nargs="?",
|
|
||||||
choices=["all"],
|
|
||||||
help="Specify 'all' to clean everything (optional)"
|
|
||||||
)
|
|
||||||
parser.set_defaults(func=self.execute)
|
|
||||||
|
|
||||||
def execute(self, args):
|
@cli.callback(invoke_without_command=True)
|
||||||
"""Cleans the build artifacts."""
|
def clean(
|
||||||
if args.target == "all":
|
target: str = typer.Argument(
|
||||||
self.console_utils.print("Starting clean all process...")
|
None,
|
||||||
clear_directories()
|
help="Optional: 'all' → wipe *all* artefacts, otherwise only the build directory",
|
||||||
self.console_utils.print("All cleaned.")
|
show_default=False,
|
||||||
else:
|
)
|
||||||
self.console_utils.print("Clearing build artifacts...")
|
) -> None:
|
||||||
clear_build_directories()
|
"""
|
||||||
self.console_utils.print("Build artifacts cleaned.")
|
Remove build artefacts (`build/*`) or *everything* (`all`).
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
```bash
|
||||||
|
hdlbuild clean # build/* and temporary files only
|
||||||
|
hdlbuild clean all # also caches, logs, etc.
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
console = ConsoleUtils("hdlbuild")
|
||||||
|
|
||||||
|
if target == "all":
|
||||||
|
console.print("Starting clean‑all …")
|
||||||
|
clear_directories()
|
||||||
|
console.print("All artefacts removed.")
|
||||||
|
else:
|
||||||
|
console.print("Removing build artefacts …")
|
||||||
|
clear_build_directories()
|
||||||
|
console.print("Build artefacts removed.")
|
||||||
|
@@ -1,19 +0,0 @@
|
|||||||
from hdlbuild.commands.build import BuildCommand
|
|
||||||
from hdlbuild.commands.clean import CleanCommand
|
|
||||||
from hdlbuild.commands.dep import DepCommand
|
|
||||||
from hdlbuild.commands.init import InitCommand
|
|
||||||
from hdlbuild.commands.test import TestCommand
|
|
||||||
|
|
||||||
|
|
||||||
def register_commands(subparsers):
|
|
||||||
"""Registers all available commands."""
|
|
||||||
commands = [
|
|
||||||
CleanCommand(),
|
|
||||||
BuildCommand(),
|
|
||||||
DepCommand(),
|
|
||||||
TestCommand(),
|
|
||||||
InitCommand(),
|
|
||||||
]
|
|
||||||
|
|
||||||
for command in commands:
|
|
||||||
command.register(subparsers)
|
|
@@ -1,17 +1,23 @@
|
|||||||
from hdlbuild.dependencies.resolver import DependencyResolver
|
import typer
|
||||||
from hdlbuild.utils.console_utils import ConsoleUtils
|
|
||||||
from hdlbuild.utils.project_loader import load_project_config
|
|
||||||
|
|
||||||
class DepCommand:
|
from hdlbuild.dependencies.resolver import DependencyResolver
|
||||||
def __init__(self):
|
from hdlbuild.utils.console_utils import ConsoleUtils
|
||||||
self.console_utils = ConsoleUtils("hdlbuild")
|
from hdlbuild.utils.project_loader import load_project_config
|
||||||
|
|
||||||
def register(self, subparsers):
|
cli = typer.Typer(rich_help_panel="🔗 Dependency Commands")
|
||||||
parser = subparsers.add_parser("dep", help="Start the dependencies process")
|
|
||||||
parser.set_defaults(func=self.execute)
|
|
||||||
|
|
||||||
def execute(self, args):
|
@cli.callback(invoke_without_command=True)
|
||||||
"""Starts the dependencies process."""
|
def dep() -> None:
|
||||||
self.project = load_project_config()
|
"""
|
||||||
self.console_utils.print("Starting dependencies process...")
|
Resolve all project dependencies.
|
||||||
DependencyResolver(self.project).resolve_all()
|
|
||||||
|
```bash
|
||||||
|
hdlbuild dep
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
console = ConsoleUtils("hdlbuild")
|
||||||
|
project = load_project_config()
|
||||||
|
|
||||||
|
console.print("Resolving dependencies …")
|
||||||
|
DependencyResolver(project).resolve_all()
|
||||||
|
console.print("Dependencies resolved.")
|
||||||
|
@@ -1,36 +1,35 @@
|
|||||||
from pathlib import Path
|
|
||||||
import shutil
|
import shutil
|
||||||
from hdlbuild.dependencies.resolver import DependencyResolver
|
from pathlib import Path
|
||||||
|
import typer
|
||||||
|
|
||||||
from hdlbuild.utils.console_utils import ConsoleUtils
|
from hdlbuild.utils.console_utils import ConsoleUtils
|
||||||
|
|
||||||
class InitCommand:
|
cli = typer.Typer(rich_help_panel="🆕 Init Commands")
|
||||||
def __init__(self):
|
|
||||||
self.console_utils = ConsoleUtils("hdlbuild")
|
|
||||||
|
|
||||||
def register(self, subparsers):
|
@cli.callback(invoke_without_command=True)
|
||||||
parser = subparsers.add_parser("init", help="Initialize a new HDLBuild project")
|
def init() -> None:
|
||||||
parser.set_defaults(func=self.execute)
|
"""
|
||||||
|
Initialise a new HDLBuild project in the current directory.
|
||||||
|
|
||||||
def execute(self, args):
|
Copies `.gitignore` and `project.yml` from the template folder.
|
||||||
"""Initialize a new HDLBuild project."""
|
"""
|
||||||
project_dir = Path.cwd()
|
console = ConsoleUtils("hdlbuild")
|
||||||
|
project_dir = Path.cwd()
|
||||||
|
|
||||||
# Correctly resolve path to templates directory
|
script_dir = Path(__file__).parent.resolve()
|
||||||
script_dir = Path(__file__).parent.resolve()
|
template_dir = (script_dir / ".." / "templates").resolve()
|
||||||
template_dir = (script_dir / ".." / "templates").resolve()
|
|
||||||
|
|
||||||
# Files to copy
|
files = [
|
||||||
files = [
|
("gitignore.template", ".gitignore"),
|
||||||
("gitignore.template", ".gitignore"),
|
("project.yml.template", "project.yml"),
|
||||||
("project.yml.template", "project.yml"),
|
]
|
||||||
]
|
|
||||||
|
|
||||||
for template_name, target_name in files:
|
for template_name, target_name in files:
|
||||||
template_path = template_dir / template_name
|
template_path = template_dir / template_name
|
||||||
target_path = project_dir / target_name
|
target_path = project_dir / target_name
|
||||||
|
|
||||||
if not target_path.exists():
|
if not target_path.exists():
|
||||||
shutil.copy(template_path, target_path)
|
shutil.copy(template_path, target_path)
|
||||||
self.console_utils.print(f"Created {target_name}")
|
console.print(f"Created {target_name}")
|
||||||
else:
|
else:
|
||||||
self.console_utils.print(f"{target_name} already exists, skipping.")
|
console.print(f"{target_name} already exists – skipping.")
|
||||||
|
@@ -1,23 +1,31 @@
|
|||||||
from hdlbuild.tools.xilinx_ise.isim import build_testbench, run_testbench
|
import typer
|
||||||
from hdlbuild.utils.console_utils import ConsoleUtils
|
|
||||||
from hdlbuild.utils.project_loader import load_project_config
|
|
||||||
|
|
||||||
class TestCommand:
|
from hdlbuild.tools.xilinx_ise.isim import build_testbench, run_testbench
|
||||||
def __init__(self):
|
from hdlbuild.utils.console_utils import ConsoleUtils
|
||||||
self.console_utils = ConsoleUtils("hdlbuild")
|
from hdlbuild.utils.project_loader import load_project_config
|
||||||
|
|
||||||
def register(self, subparsers):
|
cli = typer.Typer(rich_help_panel="🧪 Test Commands")
|
||||||
parser = subparsers.add_parser("test", help="Start the Tests process")
|
|
||||||
parser.add_argument(
|
|
||||||
"target",
|
|
||||||
nargs="?",
|
|
||||||
help="Select the target to test"
|
|
||||||
)
|
|
||||||
parser.set_defaults(func=self.execute)
|
|
||||||
|
|
||||||
def execute(self, args):
|
@cli.callback(invoke_without_command=True)
|
||||||
"""Starts the test process."""
|
def test(
|
||||||
self.project = load_project_config()
|
target: str = typer.Argument(
|
||||||
self.console_utils.print("Starting test process...")
|
None,
|
||||||
build_testbench(self.project, args.target)
|
help="Name of the test target (leave empty to run all)",
|
||||||
run_testbench(self.project, args.target)
|
show_default=False,
|
||||||
|
)
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Build and run testbenches.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hdlbuild test # run all TBs
|
||||||
|
hdlbuild test alu # run TB 'alu' only
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
console = ConsoleUtils("hdlbuild")
|
||||||
|
project = load_project_config()
|
||||||
|
|
||||||
|
console.print("Starting test flow …")
|
||||||
|
build_testbench(project, target)
|
||||||
|
run_testbench(project, target)
|
||||||
|
console.print("Tests finished.")
|
||||||
|
Reference in New Issue
Block a user