Compare commits

..

30 commits
0.0 ... master

Author SHA1 Message Date
Benjamin Renard
95a013e74b
Code cleaning
All checks were successful
Run tests / test-precommit (push) Successful in 56s
2024-04-22 19:20:25 +02:00
81c05a244e Switch from Woodpecker CI to Forgejo Actions
All checks were successful
Run tests / test-precommit (push) Successful in 1m20s
2024-03-15 08:56:03 +01:00
cab1379b22 Introduce pre-commit hooks 2024-03-15 08:52:56 +01:00
Benjamin Renard
1f2ae28cf0 Try to auto-detect revision in append mode if not specified
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2022-12-13 10:45:28 +01:00
Benjamin Renard
bc072ccf32 Fix release notes generation even if no new version is detected 2022-12-13 10:44:33 +01:00
Benjamin Renard
bbae5ea39e build.sh: exclude CI, build.sh, README.md and merge related commits generating debian changelog
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2022-12-12 19:51:41 +01:00
Benjamin Renard
e99758fe0e Update usage in README.md 2022-12-12 19:47:47 +01:00
Benjamin Renard
70381153b9 Fix handling tag on excluded commits and even if there is no message for this version
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2022-12-12 19:15:55 +01:00
Benjamin Renard
f659811be5 Add -x/--exclude parameter to allow to exclude some commits from generated changelog
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2022-12-12 15:05:09 +01:00
Benjamin Renard
d7ff1fd03f Remove the hard-coded "-1" suffix to package versions
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
The --version-suffix parameter permit to add it if need.
2022-12-12 14:43:39 +01:00
Benjamin Renard
cafe12ed3d Add -C/--clean-tags-regex to allow tag names cleaning when computing package version
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2022-12-12 14:33:31 +01:00
Benjamin Renard
0824d02cd6 Split long commit message to multiple lines to respect the maximun of 80 characters per line imposed by Lantian
All checks were successful
ci/woodpecker/tag/woodpecker Pipeline was successful
ci/woodpecker/push/woodpecker Pipeline was successful
2022-12-12 11:32:27 +01:00
Benjamin Renard
5c5481ea57 Add --revision parameter to allow to control the commits used to generate the changelog 2022-12-12 11:19:08 +01:00
Benjamin Renard
e71611f17a Add -A/--append parameter to append generated changelog lines to existing file instead of overwriting it 2022-12-12 11:17:01 +01:00
Benjamin Renard
0c3ddea197 Restore compatibility with python 3.5 2022-11-24 11:09:41 +01:00
Benjamin Renard
9c9773f489 CI: use brenard/aptly-publish image for publish-apt job
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2022-08-01 23:16:12 +02:00
Benjamin Renard
6aefda385c Fix pylint/flake8 errors of last commit
All checks were successful
ci/woodpecker/tag/woodpecker Pipeline was successful
ci/woodpecker/push/woodpecker Pipeline was successful
2022-08-01 19:56:26 +02:00
Benjamin Renard
2198fa2b21 Add -R/--release-notes parameter
Some checks failed
ci/woodpecker/tag/woodpecker Pipeline failed
2022-08-01 19:52:29 +02:00
Benjamin Renard
a0a7c5e0ab Fix missing line returns after version first line
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2022-08-01 15:16:56 +02:00
Benjamin Renard
21692634f2 Fix flake8 warning
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2022-05-01 01:55:46 +02:00
Benjamin Renard
e61d82e025 Fix some pylint warning (and CI step dependency)
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2022-05-01 01:52:46 +02:00
Benjamin Renard
e6dfa50e0e CI: Add publishing (gitea version & debian package)
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2022-05-01 01:23:05 +02:00
Benjamin Renard
812d4a051a Add -N/--maintainer-name & -E/--maintainer-email parameters
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2022-04-30 22:23:41 +02:00
ce9181f53f Fix some pylint warnings and add custom .pylintrc file
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2022-04-17 00:34:05 +02:00
71c550a5ce CI: Fix missing dependencies
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2022-04-17 00:21:35 +02:00
4a4eb8d0e1 Add first test of .woodpecker.yml
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2022-04-17 00:05:29 +02:00
a109b47ba7 Fix some flake8 warnings 2022-04-17 00:01:18 +02:00
Benjamin Renard
4d36fa0c0e Add --always parameter to git describe 2022-03-17 18:56:36 +01:00
Benjamin Renard
7987b25f66 Add alternative installation methods 2022-03-17 17:09:53 +01:00
Benjamin Renard
66d9a0b0b0 Explicitly use python3 2022-03-17 16:55:04 +01:00
16 changed files with 562 additions and 120 deletions

View file

@ -0,0 +1,81 @@
---
name: Build and publish Debian package
on: [create]
jobs:
build:
runs-on: docker
container:
image: docker.io/brenard/debian-python-deb:latest
steps:
- name: Check out repository code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build Debian package
env:
MAINTAINER_NAME: ${{ vars.MAINTAINER_NAME }}
MAINTAINER_EMAIL: ${{ vars.MAINTAINER_EMAIL }}
DEBIAN_CODENAME: ${{ vars.DEBIAN_CODENAME }}
run: |
echo "${{ secrets.GPG_KEY }}"|base64 -d|gpg --import
./build.sh
rm -fr dist/gitdch-*
mv gitdch dist/
- name: Upload Debian package files
uses: actions/upload-artifact@v3
with:
name: dist
path: |
dist
publish-forgejo:
runs-on: docker
container:
image: docker.io/brenard/debian-python-deb:latest
steps:
- name: Download Debian package files
uses: actions/download-artifact@v3
with:
name: dist
- name: Create the release
id: create-release
shell: bash
run: |
mkdir release
mv *.deb release/
mv gitdch release/
{
echo 'release_note<<EOF'
cat release_notes.md
echo 'EOF'
} >> "$GITHUB_OUTPUT"
- name: Publish release on Forgejo
uses: actions/forgejo-release@v1
with:
direction: upload
url: https://gitea.zionetrix.net
token: ${{ secrets.forgejo_token }}
release-dir: release
release-notes: ${{ steps.create-release.outputs.release_note }}
publish-aptly:
runs-on: docker
container:
image: docker.io/brenard/aptly-publish:latest
steps:
- name: "Download Debian package files"
uses: actions/download-artifact@v3
with:
name: dist
- name: "Publish Debian package on Aptly repository"
uses: https://gitea.zionetrix.net/bn8/aptly-publish@master
with:
api_url: ${{ vars.apt_api_url }}
api_username: ${{ vars.apt_api_username }}
api_password: ${{ secrets.apt_api_password }}
repo_name: ${{ vars.apt_repo_name }}
path: "./"
source_name: ${{ vars.apt_source_name }}

View file

@ -0,0 +1,21 @@
---
name: Run tests
on: [push]
jobs:
test-precommit:
runs-on: docker
container:
image: docker.io/brenard/python-pre-commit:latest
steps:
- name: Check out repository code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install python dependencies
env:
DEBIAN_FRONTEND: noninteractive
run: |
apt-get update
apt-get -y install --no-install-recommends python3-git git
- name: Run pre-commit
run: pre-commit run --all-files

1
.gitignore vendored
View file

@ -1 +1,2 @@
*~ *~
dist

64
.pre-commit-config.yaml Normal file
View file

@ -0,0 +1,64 @@
# Pre-commit hooks to run tests and ensure code is cleaned.
# See https://pre-commit.com for more information
---
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.6
hooks:
- id: ruff
args: ["--fix"]
- repo: https://github.com/asottile/pyupgrade
rev: v3.15.0
hooks:
- id: pyupgrade
args: ["--keep-percent-format", "--py37-plus"]
- repo: https://github.com/psf/black
rev: 23.11.0
hooks:
- id: black
args: ["--target-version", "py37", "--line-length", "100"]
- repo: https://github.com/PyCQA/isort
rev: 5.12.0
hooks:
- id: isort
args: ["--profile", "black", "--line-length", "100"]
- repo: https://github.com/PyCQA/flake8
rev: 6.1.0
hooks:
- id: flake8
args: ["--max-line-length=100"]
- repo: https://github.com/codespell-project/codespell
rev: v2.2.2
hooks:
- id: codespell
args:
- --ignore-words-list=exten
- --skip="./.*,*.csv,*.json,*.ini,*.subject,*.txt,*.html,*.log,*.conf"
- --quiet-level=2
- --ignore-regex=.*codespell-ignore$
# - --write-changes # Uncomment to write changes
exclude_types: [csv, json]
- repo: https://github.com/adrienverge/yamllint
rev: v1.32.0
hooks:
- id: yamllint
ignore: .github/
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.7.1
hooks:
- id: prettier
args: ["--print-width", "100"]
- repo: local
hooks:
- id: pylint
name: pylint
entry: pylint
language: system
types: [python]
require_serial: true
- repo: https://github.com/PyCQA/bandit
rev: 1.7.5
hooks:
- id: bandit
args: [--skip, "B101", --recursive]
minimum_pre_commit_version: 3.2.0

7
.pylintrc Normal file
View file

@ -0,0 +1,7 @@
[MESSAGES CONTROL]
disable=invalid-name,
locally-disabled,
too-many-arguments,
too-many-branches,
line-too-long,
consider-using-f-string, # to keep compatibility with python 3.5

7
.yamllint.yml Normal file
View file

@ -0,0 +1,7 @@
---
extends: default
rules:
line-length:
max: 100
level: warning

View file

@ -3,20 +3,47 @@
Simple python script using GitPython library to generate debian Simple python script using GitPython library to generate debian
changelog file from git commit history. Each existing tags is changelog file from git commit history. Each existing tags is
considered as a release version and current working version is considered as a release version and current working version is
numbered using ''git describe --tags'' command. numbered using ''git describe --always --tags'' command.
# Installation # Installation
## Dependencies
``` ```
apt install git python3-git apt install git python3-git
```
## Using git
```
git clone https://gogs.zionetrix.net/bn8/gitdch.git /usr/local/src/gitdch git clone https://gogs.zionetrix.net/bn8/gitdch.git /usr/local/src/gitdch
ln -s /usr/local/src/gitdch/gitdch /usr/local/bin/gitdch ln -s /usr/local/src/gitdch/gitdch /usr/local/bin/gitdch
``` ```
# Usage ## Using wget
```
usage: gitdch [-h] [-d] [-v] [-w] [-l LOGFILE] [-q] [-p GIT_PATH] [-o OUTPUT] [-n PACKAGE_NAME] [-V VERSION] [--version-suffix VERSION_SUFFIX] [-c CODE_NAME] [-u URGENCY]
Generate Debian package changelog from git ```
wget -O /usr/local/bin/gitdch https://gogs.zionetrix.net/bn8/gitdch/raw/master/gitdch
chmod +x /usr/local/bin/gitdch
```
## Using curl
```
curl -o /usr/local/bin/gitdch https://gogs.zionetrix.net/bn8/gitdch/raw/master/gitdch
chmod +x /usr/local/bin/gitdch
```
# Usage
```
usage: gitdch [-h] [-d] [-v] [-w] [-l LOGFILE] [-q] [-p GIT_PATH] [-o OUTPUT] [-A]
[-n PACKAGE_NAME] [-V VERSION] [--version-suffix VERSION_SUFFIX]
[-c CODE_NAME] [-u URGENCY] [-N MAINTAINER_NAME] [-E MAINTAINER_EMAIL]
[-R RELEASE_NOTES] [--revision REVISION] [-C CLEAN_TAGS_REGEX]
[-x EXCLUDE]
Generate Debian package changelog from git (version: 0.0)
optional arguments: optional arguments:
-h, --help show this help message and exit -h, --help show this help message and exit
@ -25,21 +52,46 @@ optional arguments:
-w, --warning Show warning messages -w, --warning Show warning messages
-l LOGFILE, --log-file LOGFILE -l LOGFILE, --log-file LOGFILE
Log file path Log file path
-q, --quiet Quiet mode: do not log on console (only if log file is provided) -q, --quiet Quiet mode: do not log on console (only if log file is
provided)
-p GIT_PATH, --path GIT_PATH -p GIT_PATH, --path GIT_PATH
Git repository path (default: ./) Git repository path (default: ./)
-o OUTPUT, --output OUTPUT -o OUTPUT, --output OUTPUT
Generated Debian changelog output path (default: stdout) Generated Debian changelog output path (default: stdout)
-A, --append Append mode: if the output changelog file already exists,
append generated changelog lines at the beginning of the file
(optional, default: overwriting the file)
-n PACKAGE_NAME, --package-name PACKAGE_NAME -n PACKAGE_NAME, --package-name PACKAGE_NAME
Package name Package name
-V VERSION, --version VERSION -V VERSION, --version VERSION
Currrent version (default: autodetected using git describe --tags) Current version (default: autodetected using git describe
--always --tags)
--version-suffix VERSION_SUFFIX --version-suffix VERSION_SUFFIX
Suffix for autodetected version Suffix for autodetected version
-c CODE_NAME, --code-name CODE_NAME -c CODE_NAME, --code-name CODE_NAME
Debian code name (default: unstable) Debian code name (default: unstable)
-u URGENCY, --urgency URGENCY -u URGENCY, --urgency URGENCY
Package urgency (default: medium) Package urgency (default: medium)
-N MAINTAINER_NAME, --maintainer-name MAINTAINER_NAME
Maintainer name (default: last commit author name)
-E MAINTAINER_EMAIL, --maintainer-email MAINTAINER_EMAIL
Maintainer email (default: last commit author email)
-R RELEASE_NOTES, --release-notes RELEASE_NOTES
Specify an optional Markdown release notes output path
--revision REVISION Specify the revision to use to generate the changelog (see
git-rev-parse for viable options, optional, default:
generate the changelog with all commits of the current
branch)
-C CLEAN_TAGS_REGEX, --clean-tags-regex CLEAN_TAGS_REGEX
Clean tags regex: you could specify regex to clean tag names
when computing package versions. For instance, to drop a
"-eeXXX" suffix of tag names, specify -C "\-ee[0-9]{3}$"
(optional, multiple regex allowed)
-x EXCLUDE, --exclude EXCLUDE
Commit exclusion regex: you could specify regex to exclude
some commits from generated changelog entries. For instance,
to exclude commits with message starting with "CI: ",
specify -x "^CI: " (optional, multiple regex allowed)
``` ```
## Copyright ## Copyright
@ -53,4 +105,3 @@ This program is free software; you can redistribute it and/or modify it under th
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

67
build.sh Executable file
View file

@ -0,0 +1,67 @@
#!/bin/bash
QUIET_ARG=""
[ "$1" == "--quiet" ] && QUIET_ARG="--quiet"
# Enter source directory
cd $( dirname $0 )
echo "Clean previous build..."
rm -fr dist
echo "Detect version using git describe..."
VERSION="$( git describe --tags|sed 's/^[^0-9]*//' )"
echo "Create building environemt..."
BDIR=dist/gitdch-$VERSION
mkdir -p $BDIR
[ -z "$QUIET_ARG" ] && RSYNC_ARG="-v" || RSYNC_ARG=""
rsync -a $RSYNC_ARG debian/ $BDIR/debian/
cp gitdch $BDIR/
echo "Set VERSION=$VERSION in gitdch using sed..."
sed -i "s/^VERSION *=.*$/VERSION = '$VERSION'/" $BDIR/gitdch
if [ -z "$DEBIAN_CODENAME" ]
then
echo "Retrieve debian codename using lsb_release..."
DEBIAN_CODENAME=$( lsb_release -c -s )
else
echo "Use debian codename from environment ($DEBIAN_CODENAME)"
fi
echo "Generate debian changelog using gitdch..."
GITDCH_ARGS=('--verbose')
[ -n "$QUIET_ARG" ] && GITDCH_ARGS=('--warning')
if [ -n "$MAINTAINER_NAME" ]
then
echo "Use maintainer name from environment ($MAINTAINER_NAME)"
GITDCH_ARGS+=("--maintainer-name" "${MAINTAINER_NAME}")
fi
if [ -n "$MAINTAINER_EMAIL" ]
then
echo "Use maintainer email from environment ($MAINTAINER_EMAIL)"
GITDCH_ARGS+=("--maintainer-email" "$MAINTAINER_EMAIL")
fi
./gitdch \
--package-name gitdch \
--version "${VERSION}" \
--code-name $DEBIAN_CODENAME \
--output $BDIR/debian/changelog \
--release-notes dist/release_notes.md \
--exclude "^CI: " \
--exclude "\.woodpecker\.yml" \
--exclude "build\.sh" \
--exclude "README\.md" \
--exclude "^Merge branch " \
"${GITDCH_ARGS[@]}"
if [ -n "$MAINTAINER_NAME" -a -n "$MAINTAINER_EMAIL" ]
then
echo "Set Maintainer field in debian control file ($MAINTAINER_NAME <$MAINTAINER_EMAIL>)..."
sed -i "s/^Maintainer: .*$/Maintainer: $MAINTAINER_NAME <$MAINTAINER_EMAIL>/" $BDIR/debian/control
fi
echo "Build debian package..."
cd $BDIR
dpkg-buildpackage

1
debian/compat vendored Normal file
View file

@ -0,0 +1 @@
11

15
debian/control vendored Normal file
View file

@ -0,0 +1,15 @@
Source: gitdch
Section: admin
Priority: optional
Maintainer: Debian Zionetrix - gitdch <debian+gitdch@zionetrix.net>
Build-Depends: debhelper (>> 11.0.0), python3, git, python3-git
Standards-Version: 3.9.6
Package: gitdch
Architecture: all
Depends: ${misc:Depends}, python3, git, python3-git
Description: Generate debian changelog file from git commit history
Simple python script using GitPython library to generate debian
changelog file from git commit history. Each existing tags is
considered as a release version and current working version is
numbered using ''git describe --always --tags'' command.

20
debian/copyright vendored Normal file
View file

@ -0,0 +1,20 @@
This package was written by Benjamin Renard <brenard@zionetrix.net>.
Copyright (C) 2022 Benjamin Renard <brenard@zionetrix.net>
gitdch is licensed under the GNU general public license, version 3.
gitdch is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2, or (at your option) any later version.
gitdch is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
gitdch; see the file COPYING. If not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
On Debian systems, a copy of the GNU General Public License is available in
/usr/share/common-licenses/GPL-3 as part of the base-files package.

1
debian/dirs vendored Normal file
View file

@ -0,0 +1 @@
usr/bin

1
debian/install vendored Normal file
View file

@ -0,0 +1 @@
gitdch usr/bin

4
debian/rules vendored Executable file
View file

@ -0,0 +1,4 @@
#!/usr/bin/make -f
#export DH_VERBOSE=1
%:
dh $@

1
debian/source/format vendored Normal file
View file

@ -0,0 +1 @@
1.0

318
gitdch
View file

@ -1,4 +1,4 @@
#!/usr/bin/python #!/usr/bin/env python3
""" Generate Debian package changelog from git """ """ Generate Debian package changelog from git """
@ -7,118 +7,148 @@ import logging
import os import os
import re import re
import sys import sys
import textwrap
import git import git
from git.exc import GitCommandError
default_git_path = './' VERSION = "0.0"
default_code_name = 'unstable' DEFAULT_GIT_PATCH = "./"
default_urgency = 'medium' DEFAULT_CODE_NAME = "unstable"
DEFAULT_URGENCY = "medium"
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=f"{__doc__} (version: {VERSION})")
parser.add_argument("-d", "--debug", action="store_true", help="Show debug messages")
parser.add_argument("-v", "--verbose", action="store_true", help="Show verbose messages")
parser.add_argument("-w", "--warning", action="store_true", help="Show warning messages")
parser.add_argument("-l", "--log-file", help="Log file path")
parser.add_argument( parser.add_argument(
'-d', '--debug', "-q",
action='store_true', "--quiet",
help='Show debug messages' action="store_true",
help="Quiet mode: do not log on console (only if log file is provided)",
) )
parser.add_argument( parser.add_argument(
'-v', '--verbose', "-p",
action='store_true', "--path",
help='Show verbose messages' help=f"Git repository path (default: {DEFAULT_GIT_PATCH})",
default=DEFAULT_GIT_PATCH,
) )
parser.add_argument( parser.add_argument(
'-w', '--warning', "-o",
action='store_true', "--output",
help='Show warning messages' help="Generated Debian changelog output path (default: stdout)",
) )
parser.add_argument( parser.add_argument(
'-l', "-A",
'--log-file', "--append",
action="store", action="store_true",
type=str, help=(
dest="logfile", "Append mode: if the output changelog file already exists, append "
help="Log file path" "generated changelog lines at the beginning of the file (optional, "
"default: overwriting the file)"
),
)
parser.add_argument("-n", "--package-name", help="Package name")
parser.add_argument(
"-V",
"--version",
help=("Current version (default: autodetected using git describe " "--always --tags)"),
) )
parser.add_argument( parser.add_argument(
'-q', '--quiet', "--version-suffix",
action='store_true', help="Suffix for autodetected version",
help='Quiet mode: do not log on console (only if log file is provided)'
) )
parser.add_argument( parser.add_argument(
'-p', "-c",
'--path', "--code-name",
type=str, help=f"Debian code name (default: {DEFAULT_CODE_NAME})",
dest='git_path', default=DEFAULT_CODE_NAME,
help='Git repository path (default: %s)' % default_git_path,
default=default_git_path
) )
parser.add_argument( parser.add_argument(
'-o', "-u",
'--output', "--urgency",
type=str, help=f"Package urgency (default: {DEFAULT_URGENCY})",
dest='output', default=DEFAULT_URGENCY,
help='Generated Debian changelog output path (default: stdout)',
) )
parser.add_argument( parser.add_argument(
'-n', "-N",
'--package-name', "--maintainer-name",
type=str, help="Maintainer name (default: last commit author name)",
dest='package_name',
help='Package name'
) )
parser.add_argument( parser.add_argument(
'-V', "-E",
'--version', "--maintainer-email",
type=str, help="Maintainer email (default: last commit author email)",
dest='version',
help='Currrent version (default: autodetected using git describe --tags)'
) )
parser.add_argument( parser.add_argument(
'--version-suffix', "-R",
type=str, "--release-notes",
dest='version_suffix', help="Specify an optional Markdown release notes output path",
help='Suffix for autodetected version'
) )
parser.add_argument( parser.add_argument(
'-c', "--revision",
'--code-name', help=(
type=str, "Specify the revision to use to generate the changelog (see "
dest='code_name', "git-rev-parse for viable options, optional, default: generate the "
help='Debian code name (default: %s)' % default_code_name, "changelog with all commits of the current branch) "
default=default_code_name ),
) )
parser.add_argument( parser.add_argument(
'-u', "-C",
'--urgency', "--clean-tags-regex",
type=str, action="append",
dest='urgency', type=re.compile,
help='Package urgency (default: %s)' % default_urgency, help=(
default=default_urgency "Clean tags regex: you could specify regex to clean tag names when "
'computing package versions. For instance, to drop a "-eeXXX" suffix '
'of tag names, specify -C "\\-ee[0-9]{3}$" (optional, multiple regex '
"allowed)"
),
default=[],
)
parser.add_argument(
"-x",
"--exclude",
action="append",
type=re.compile,
help=(
"Commit exclusion regex: you could specify regex to exclude some "
"commits from generated changelog entries. For instance, to exclude "
'commits with message starting with "CI: ", specify -x "^CI: " '
"(optional, multiple regex allowed)"
),
default=[],
) )
options = parser.parse_args() options = parser.parse_args()
if not options.package_name: if not options.package_name:
parser.error( parser.error("You must provide package name using -n/--package-name parameter")
'You must provide package name using -n/--package-name paramter')
# Initialize log # Initialize log
log = logging.getLogger() log = logging.getLogger()
logformat = logging.Formatter( logformat = logging.Formatter(
"%(asctime)s - {0} - %(levelname)s : %(message)s".format( f"%(asctime)s - {os.path.basename(sys.argv[0])} - %(levelname)s : %(message)s"
os.path.basename(sys.argv[0])
)
) )
# Set root logger to DEBUG (filtering done by handlers) # Set root logger to DEBUG (filtering done by handlers)
log.setLevel(logging.DEBUG) log.setLevel(logging.DEBUG)
@ -131,60 +161,90 @@ elif options.verbose:
elif options.warning: elif options.warning:
log_level = logging.WARNING log_level = logging.WARNING
if options.logfile: if options.log_file:
logfile = logging.FileHandler(options.logfile) log_file = logging.FileHandler(options.log_file)
logfile.setFormatter(logformat) log_file.setFormatter(logformat)
logfile.setLevel(log_level if log_level is not None else logging.INFO) log_file.setLevel(log_level if log_level is not None else logging.INFO)
log.addHandler(logfile) log.addHandler(log_file)
if not options.quiet or not options.logfile: if not options.quiet or not options.log_file:
logconsole = logging.StreamHandler() logconsole = logging.StreamHandler()
logconsole.setLevel(log_level if log_level is not None else logging.FATAL) logconsole.setLevel(log_level if log_level is not None else logging.FATAL)
logconsole.setFormatter(logformat) logconsole.setFormatter(logformat)
log.addHandler(logconsole) log.addHandler(logconsole)
repo = git.Repo(options.git_path) repo = git.Repo(options.path)
log.info('Generate changelog from git commits')
versions = []
tag_commits = dict(
(tag.commit.binsha, tag)
for tag in repo.tags
)
def clean_deb_version(version_name): def clean_deb_version(version_name):
"""Clean debian version name""" """Clean debian version name"""
version_name = re.sub('^[^0-9]*', '', version_name) version_name = re.sub("^[^0-9]*", "", version_name)
for clean_regex in options.clean_tags_regex:
version_name = clean_regex.sub("", version_name)
if options.version_suffix: if options.version_suffix:
version_name += options.version_suffix version_name += options.version_suffix
return version_name return version_name
if not options.version:
log.info("Detect current version from git tags & commits")
options.version = clean_deb_version(repo.git.describe("--always", "--tags"))
log.info("Current version detected: %s", options.version)
if options.output and options.append and not options.revision:
log.info(
"Append mode enabled but no revision specify, try to detect it from "
"last modification of the changelog file"
)
try:
last_change_commit = next(repo.iter_commits(paths=options.output))
# pylint: disable=consider-using-f-string
options.revision = f"{last_change_commit}..HEAD"
log.info(
'Last change commit of the output file is "%s": use revision "%s"',
last_change_commit,
options.revision,
)
except StopIteration:
log.warning(
"Fail to auto-detect last change commit of changelog file: it "
"seem not tracked. Continue without revision."
)
except GitCommandError:
log.warning(
"Fail to auto-detect last change commit of changelog file. May "
"be it's outside of the git repository. Continue without "
"revision."
)
# Reset repo object of to avoid BrokenPipeError
repo = git.Repo(options.path)
log.info("Generate changelog from git commits")
versions = []
tag_commits = {tag.commit.binsha: tag for tag in repo.tags}
def add_version(): def add_version():
"""Add version info""" """Add version info"""
if messages: global messages # pylint: disable=global-statement
log.info('Add version %s:\n - %s', version, '\n - '.join(messages)) if not version_commit:
versions.append({ return
'name': version, if not messages:
'tag': tag, messages = [f"Release version {version}"]
'commit': version_commit, log.info("Add version %s:\n - %s", version, "\n - ".join(messages))
'messages': messages, versions.append({"name": version, "tag": tag, "commit": version_commit, "messages": messages})
})
tag = None tag = None
version_commit = None version_commit = None
version = options.version or clean_deb_version(repo.git.describe('--tags')) version = options.version
messages = [] messages = []
for commit in repo.iter_commits(): for commit in repo.iter_commits(rev=options.revision):
if version_commit is None: log.debug("Commit %s (%s)", commit, commit.summary)
version_commit = commit
log.debug('Commit %s', commit)
if commit.binsha in tag_commits: if commit.binsha in tag_commits:
new_tag = tag_commits[commit.binsha] new_tag = tag_commits[commit.binsha]
log.debug('Reach new tag %s', new_tag) log.debug("Reach new tag %s", new_tag)
add_version() add_version()
@ -192,36 +252,76 @@ for commit in repo.iter_commits():
version = clean_deb_version(tag.name) version = clean_deb_version(tag.name)
version_commit = commit version_commit = commit
messages = [] messages = []
log.debug('Iter commits for version %s') log.debug("Iter commits for version %s", version)
if version_commit is None:
version_commit = commit
excluded = False
for regex in options.exclude:
if regex.search(commit.summary):
excluded = True
log.debug(
'Exclude commit %s ("%s", match with "%s")',
commit,
commit.summary,
regex.pattern,
)
if not excluded:
messages.append(commit.summary) messages.append(commit.summary)
add_version() add_version()
log.info('%d versions found', len(versions)) log.info("%d versions found", len(versions))
changelog_lines = [] changelog_lines = []
for version in versions: for version in versions:
# pylint: disable=consider-using-f-string
changelog_lines.append( changelog_lines.append(
'{package} ({version}-1) {code_name}; urgency={urgency}\n\n'.format( "{package} ({version}) {code_name}; urgency={urgency}\n\n".format(
package=options.package_name, package=options.package_name,
version=version['name'], version=version["name"],
code_name=options.code_name, code_name=options.code_name,
urgency=options.urgency urgency=options.urgency,
) )
) )
for message in version['messages']:
changelog_lines.append(' * {0}\n'.format(message))
for message in version["messages"]:
for idx, line in enumerate(textwrap.wrap(message, 76, break_long_words=True)):
# pylint: disable=consider-using-f-string
changelog_lines.append("{}{}\n".format(" * " if not idx else " ", line))
# pylint: disable=consider-using-f-string
changelog_lines.append( changelog_lines.append(
"\n -- {name} <{email}> {date}\n\n".format( "\n -- {name} <{email}> {date}\n\n".format(
name=version['commit'].author.name, name=(
email=version['commit'].author.email, options.maintainer_name
date=version['commit'].committed_datetime.strftime( if options.maintainer_name
"%a, %d %b %Y %H:%M:%S %z") else version["commit"].author.name
),
email=(
options.maintainer_email
if options.maintainer_email
else version["commit"].author.email
),
date=version["commit"].committed_datetime.strftime("%a, %d %b %Y %H:%M:%S %z"),
) )
) )
if options.output: if options.output:
log.info('Write generated Debian changelog in file %s', options.output) log.info("Write generated Debian changelog in file %s", options.output)
with open(options.output, 'w') as fd: if options.append and os.path.exists(options.output):
with open(options.output, encoding="utf8") as fd:
changelog_lines += [""]
changelog_lines += fd.readlines()
with open(options.output, "w", encoding="utf8") as fd:
fd.writelines(changelog_lines) fd.writelines(changelog_lines)
else: else:
print(''.join(changelog_lines)) print("".join(changelog_lines))
if options.release_notes:
log.info("Generate Markdown release notes")
release_notes_lines = ["# Changelog:\n\n"]
if versions:
release_notes_lines.extend([f"* {message}\n" for message in versions[0]["messages"]])
else:
release_notes_lines.extend([f"* Release version {options.version}\n"])
log.info("Write generated Markdown release notes in file %s", options.release_notes)
with open(options.release_notes, "w", encoding="utf8") as fd:
fd.writelines(release_notes_lines)