Merge pull request #2128 from profanity-im/tooling
Improve tooling for development and maintenance
This commit is contained in:
23
.commitlintrc.json
Normal file
23
.commitlintrc.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"extends": ["@commitlint/config-conventional"],
|
||||
"rules": {
|
||||
"type-enum": [
|
||||
2,
|
||||
"always",
|
||||
[
|
||||
"feat",
|
||||
"fix",
|
||||
"docs",
|
||||
"style",
|
||||
"refactor",
|
||||
"perf",
|
||||
"tests",
|
||||
"build",
|
||||
"ci",
|
||||
"chore",
|
||||
"cleanup"
|
||||
]
|
||||
],
|
||||
"subject-case": [0]
|
||||
}
|
||||
}
|
||||
34
.github/workflows/commit-lint.yml
vendored
Normal file
34
.github/workflows/commit-lint.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
name: "Lint"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
commitlint:
|
||||
name: "Conventional Commits"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
# Fetch all history so commitlint can see the commits in the PR
|
||||
fetch-depth: 0
|
||||
|
||||
- name: "Conventional Commits"
|
||||
uses: wagoid/commitlint-github-action@v6
|
||||
|
||||
dco:
|
||||
name: "DCO"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Get PR Commits"
|
||||
id: "get-pr-commits"
|
||||
uses: tim-actions/get-pr-commits@v1.3.0
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: "Check DCO"
|
||||
uses: tim-actions/dco@v1.1.0
|
||||
with:
|
||||
commits: ${{ steps.get-pr-commits.outputs.commits }}
|
||||
10
.github/workflows/main.yml
vendored
10
.github/workflows/main.yml
vendored
@@ -21,28 +21,28 @@ jobs:
|
||||
buildsystem: autotools
|
||||
tests: unit
|
||||
omemo: signal
|
||||
script: ./ci/ci-build.sh
|
||||
script: ./scripts/build-configuration-matrix.sh
|
||||
- flavor: fedora
|
||||
buildsystem: autotools
|
||||
tests: unit
|
||||
omemo: signal
|
||||
script: ./ci/ci-build.sh
|
||||
script: ./scripts/build-configuration-matrix.sh
|
||||
- flavor: ubuntu
|
||||
buildsystem: autotools
|
||||
tests: unit
|
||||
omemo: signal
|
||||
script: ./ci/ci-build.sh
|
||||
script: ./scripts/build-configuration-matrix.sh
|
||||
- flavor: debian
|
||||
buildsystem: meson
|
||||
tests: unit
|
||||
omemo: signal
|
||||
script: ./ci/ci-meson-build.sh
|
||||
script: ./scripts/build-configuration-matrix.sh meson
|
||||
omemo_env: libsignal
|
||||
- flavor: debian
|
||||
buildsystem: meson
|
||||
tests: unit
|
||||
omemo: libomemo
|
||||
script: ./ci/ci-meson-build.sh
|
||||
script: ./scripts/build-configuration-matrix.sh meson
|
||||
omemo_env: libomemo-c
|
||||
|
||||
name: ${{ matrix.flavor }} | ${{ matrix.buildsystem }} | ${{ matrix.tests }} | ${{ matrix.omemo }}
|
||||
|
||||
@@ -192,7 +192,7 @@ snippet to `.git/hooks/pre-push`:
|
||||
```shell
|
||||
#!/bin/sh
|
||||
set -e
|
||||
./ci/ci-build.sh
|
||||
./scripts/build-configuration-matrix.sh
|
||||
```
|
||||
|
||||
This will run the same tests that the CI runs and refuse the push if it fails.
|
||||
@@ -214,7 +214,7 @@ In cases where you want to disable automatic formatting for a specific block of
|
||||
## Verification & Testing
|
||||
|
||||
### Running unit tests
|
||||
Run `make check` to run the unit tests with your current configuration or `./ci/ci-build.sh` to check with different switches passed to configure.
|
||||
Run `make check` to run the unit tests with your current configuration or `./scripts/build-configuration-matrix.sh [autotools|meson]` to check with different switches passed to configure.
|
||||
|
||||
### Writing unit tests
|
||||
We use the [cmocka](https://cmocka.org/) testing framework for unit tests.
|
||||
@@ -331,7 +331,7 @@ meson compile doublecheck
|
||||
|
||||
Alternatively, you can run the script directly:
|
||||
```
|
||||
./scripts/quality-check.sh --fix-formatting --meson # or --autotools
|
||||
./scripts/lint-and-test.sh --fix-formatting --meson # or --autotools
|
||||
```
|
||||
|
||||
### Pre-commit hook
|
||||
@@ -339,7 +339,7 @@ It is highly recommended to install the quality check script as a git pre-commit
|
||||
|
||||
To install the hook:
|
||||
```
|
||||
./scripts/quality-check.sh --install
|
||||
./scripts/lint-and-test.sh --install
|
||||
```
|
||||
|
||||
If you need to bypass the formatting check (e.g. due to a `clang-format` version mismatch), you can set the `SKIP_FORMAT` environment variable:
|
||||
|
||||
@@ -376,4 +376,4 @@ spell:
|
||||
codespell
|
||||
|
||||
doublecheck:
|
||||
@./scripts/quality-check.sh --fix-formatting --autotools
|
||||
@./scripts/lint-and-test.sh --fix-formatting --autotools
|
||||
|
||||
154
ci/ci-build.sh
154
ci/ci-build.sh
@@ -1,154 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
log_content()
|
||||
{
|
||||
echo
|
||||
if [ -f "$1" ]; then
|
||||
echo "Content of $1:"
|
||||
cat "$1"
|
||||
else
|
||||
echo "Log file $1 not found."
|
||||
fi
|
||||
}
|
||||
|
||||
error_handler()
|
||||
{
|
||||
ERR_CODE=$?
|
||||
|
||||
log_content ./config.log
|
||||
log_content ./test-suite.log
|
||||
log_content ./test-suite-memcheck.log
|
||||
|
||||
echo
|
||||
echo "Error ${ERR_CODE} with command '${BASH_COMMAND}' on line ${BASH_LINENO[0]}. Exiting."
|
||||
echo
|
||||
exit ${ERR_CODE}
|
||||
}
|
||||
|
||||
trap error_handler ERR
|
||||
|
||||
num_cores()
|
||||
{
|
||||
# Check for cores, for systems with:
|
||||
# Line 1. Linux w/ coreutils, or...
|
||||
# Line 2. OpenBSD, FreeBSD, NetBSD or macOS, or...
|
||||
# Line 3. Fallback for Linux w/o coreutils (glibc).
|
||||
nproc \
|
||||
|| sysctl -n hw.ncpu \
|
||||
|| getconf _NPROCESSORS_ONLN 2>/dev/null
|
||||
}
|
||||
|
||||
./bootstrap.sh
|
||||
|
||||
tests=()
|
||||
MAKE="make --quiet -j$(num_cores)"
|
||||
CC="gcc"
|
||||
|
||||
ARCH="$(uname | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
case "$ARCH" in
|
||||
linux*)
|
||||
tests=(
|
||||
"--enable-notifications --enable-icons-and-clipboard --enable-otr --enable-pgp
|
||||
--enable-omemo --enable-plugins --enable-c-plugins
|
||||
--enable-python-plugins --with-xscreensaver --enable-omemo-qrcode --enable-gdk-pixbuf"
|
||||
"--disable-notifications --disable-icons-and-clipboard --disable-otr --disable-pgp
|
||||
--disable-omemo --disable-plugins --disable-c-plugins
|
||||
--disable-python-plugins --without-xscreensaver"
|
||||
"--disable-notifications"
|
||||
"--disable-icons-and-clipboard"
|
||||
"--disable-otr"
|
||||
"--disable-pgp"
|
||||
"--disable-omemo --disable-omemo-qrcode"
|
||||
"--disable-pgp --disable-otr"
|
||||
"--disable-pgp --disable-otr --disable-omemo"
|
||||
"--disable-plugins"
|
||||
"--disable-python-plugins"
|
||||
"--disable-c-plugins"
|
||||
"--disable-c-plugins --disable-python-plugins"
|
||||
"--without-xscreensaver"
|
||||
"--disable-gdk-pixbuf"
|
||||
"")
|
||||
source /etc/profile.d/debuginfod.sh 2>/dev/null || true
|
||||
;;
|
||||
darwin*)
|
||||
tests=(
|
||||
"--enable-notifications --enable-icons-and-clipboard --enable-otr --enable-pgp
|
||||
--enable-omemo --enable-plugins --enable-c-plugins
|
||||
--enable-python-plugins"
|
||||
"--disable-notifications --disable-icons-and-clipboard --disable-otr --disable-pgp
|
||||
--disable-omemo --disable-plugins --disable-c-plugins
|
||||
--disable-python-plugins"
|
||||
"--disable-notifications"
|
||||
"--disable-icons-and-clipboard"
|
||||
"--disable-otr"
|
||||
"--disable-pgp"
|
||||
"--disable-omemo"
|
||||
"--disable-pgp --disable-otr"
|
||||
"--disable-pgp --disable-otr --disable-omemo"
|
||||
"--disable-plugins"
|
||||
"--disable-python-plugins"
|
||||
"--disable-c-plugins"
|
||||
"--disable-c-plugins --disable-python-plugins"
|
||||
"")
|
||||
;;
|
||||
openbsd*)
|
||||
MAKE="gmake"
|
||||
# TODO(#1231):
|
||||
# `-std=gnu99 -fexec-charset=UTF-8` to silence:
|
||||
# src/event/server_events.c:1453:19: error: universal character names are only valid in C++ and C99
|
||||
# src/event/server_events.c:1454:19: error: universal character names are only valid in C++ and C99
|
||||
CC="egcc -std=gnu99 -fexec-charset=UTF-8"
|
||||
|
||||
tests=(
|
||||
"--enable-notifications --enable-icons-and-clipboard --enable-otr --enable-pgp
|
||||
--enable-omemo --enable-plugins --enable-c-plugins
|
||||
--enable-python-plugins"
|
||||
"--disable-notifications --disable-icons-and-clipboard --disable-otr --disable-pgp
|
||||
--disable-omemo --disable-plugins --disable-c-plugins
|
||||
--disable-python-plugins"
|
||||
"--disable-notifications"
|
||||
"--disable-icons-and-clipboard"
|
||||
"--disable-otr"
|
||||
"--disable-pgp"
|
||||
"--disable-omemo"
|
||||
"--disable-pgp --disable-otr"
|
||||
"--disable-pgp --disable-otr --disable-omemo"
|
||||
"--disable-plugins"
|
||||
"--disable-python-plugins"
|
||||
"--disable-c-plugins"
|
||||
"--disable-c-plugins --disable-python-plugins"
|
||||
"")
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$ARCH" in
|
||||
linux*)
|
||||
echo
|
||||
echo "--> Building with ./configure ${tests[0]} --enable-valgrind --disable-functional-tests $*"
|
||||
echo
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
./configure ${tests[0]} --enable-valgrind --disable-functional-tests $*
|
||||
|
||||
$MAKE CC="${CC}"
|
||||
$MAKE check-valgrind
|
||||
$MAKE distclean
|
||||
;;
|
||||
esac
|
||||
|
||||
for features in "${tests[@]}"
|
||||
do
|
||||
echo
|
||||
echo "--> Building with ./configure ${features} --disable-functional-tests $*"
|
||||
echo
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
./configure $features --disable-functional-tests $*
|
||||
|
||||
$MAKE CC="${CC}"
|
||||
$MAKE check-unit
|
||||
|
||||
./profanity -v
|
||||
$MAKE clean
|
||||
done
|
||||
@@ -1,72 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Exit on error
|
||||
set -e
|
||||
|
||||
error_handler()
|
||||
{
|
||||
ERR_CODE=$?
|
||||
echo
|
||||
echo "Error ${ERR_CODE} with command '${BASH_COMMAND}' on line ${BASH_LINENO[0]}. Exiting."
|
||||
# Meson logs are stored in the build directory
|
||||
for log in build_run/meson-logs/testlog.txt build_valgrind/meson-logs/testlog.txt; do
|
||||
if [ -f "$log" ]; then
|
||||
echo "--- Meson Test Log ($log) ---"
|
||||
cat "$log"
|
||||
fi
|
||||
done
|
||||
exit ${ERR_CODE}
|
||||
}
|
||||
|
||||
trap error_handler ERR
|
||||
|
||||
tests=(
|
||||
"-Dnotifications=enabled -Dicons-and-clipboard=enabled -Dotr=enabled -Dpgp=enabled -Domemo=enabled -Dc-plugins=enabled -Dpython-plugins=enabled -Dxscreensaver=enabled -Domemo-qrcode=enabled -Dgdk-pixbuf=enabled"
|
||||
""
|
||||
"-Dnotifications=disabled"
|
||||
"-Dicons-and-clipboard=disabled"
|
||||
"-Dotr=disabled"
|
||||
"-Dpgp=disabled"
|
||||
"-Domemo=disabled -Domemo-qrcode=disabled"
|
||||
"-Dpgp=disabled -Dotr=disabled"
|
||||
"-Dpgp=disabled -Dotr=disabled -Domemo=disabled"
|
||||
"-Dpython-plugins=disabled"
|
||||
"-Dc-plugins=disabled"
|
||||
"-Dc-plugins=disabled -Dpython-plugins=disabled"
|
||||
"-Dxscreensaver=disabled"
|
||||
"-Dgdk-pixbuf=disabled"
|
||||
)
|
||||
|
||||
BACKEND_OPT=""
|
||||
if [ -n "${OMEMO_BACKEND}" ]; then
|
||||
BACKEND_OPT="-Domemo-backend=${OMEMO_BACKEND}"
|
||||
fi
|
||||
|
||||
# Run Valgrind check (Only on Linux, on first/full feature set)
|
||||
if [[ "$(uname | tr '[:upper:]' '[:lower:]')" == linux* ]]; then
|
||||
echo "--> Running Valgrind check with full features ${BACKEND_OPT}"
|
||||
|
||||
meson setup build_valgrind ${tests[0]} ${BACKEND_OPT} -Dtests=true -Db_sanitize=address,undefined
|
||||
meson compile -C build_valgrind
|
||||
|
||||
meson test -C build_valgrind "unit tests" --print-errorlogs --wrap=valgrind || echo "Valgrind issues detected"
|
||||
|
||||
rm -rf build_valgrind
|
||||
fi
|
||||
|
||||
# Iterate through all feature combinations
|
||||
for features in "${tests[@]}"
|
||||
do
|
||||
echo "----------------------------------------------------"
|
||||
echo "--> Building with: ${features} ${BACKEND_OPT}"
|
||||
echo "----------------------------------------------------"
|
||||
|
||||
rm -rf build_run
|
||||
|
||||
meson setup build_run ${features} ${BACKEND_OPT} -Dtests=true
|
||||
meson compile -C build_run
|
||||
|
||||
meson test -C build_run "unit tests" --print-errorlogs
|
||||
|
||||
./build_run/profanity -v
|
||||
done
|
||||
@@ -727,7 +727,7 @@ if get_option('tests')
|
||||
endif
|
||||
|
||||
run_target('doublecheck',
|
||||
command: ['scripts/quality-check.sh', '--fix-formatting', '--meson']
|
||||
command: ['scripts/lint-and-test.sh', '--fix-formatting', '--meson']
|
||||
)
|
||||
|
||||
summary({
|
||||
|
||||
35
scripts/README.md
Normal file
35
scripts/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Scripts
|
||||
|
||||
This directory contains various scripts used for development, CI, and maintenance.
|
||||
|
||||
## `lint-and-test.sh`
|
||||
Central validation script mainly for local development.
|
||||
|
||||
- **Purpose:** Runs spelling checks, code formatting, and unit testing.
|
||||
- **Usage:** `./scripts/lint-and-test.sh [options]`
|
||||
- **Options:**
|
||||
- `--fix-formatting`: Automatically apply `clang-format` fixes.
|
||||
- `--autotools` / `--meson`: Run unit tests using the specified build system.
|
||||
- `--hook`: Run in "hook mode" (checks only staged files).
|
||||
- `--install`: Install the script as a git `pre-commit` hook.
|
||||
|
||||
## `build-configuration-matrix.sh`
|
||||
Exhaustive build configuration matrix testing. It ensures that Profanity compiles and passes unit tests across a variety of feature configurations for both Autotools and Meson.
|
||||
|
||||
- **Purpose:** Verifies architectural compatibility by testing many combinations of build flags.
|
||||
- **Usage:** `./scripts/build-configuration-matrix.sh [autotools|meson] [extra-args]`
|
||||
- **Extra Arguments:** Any arguments passed after the build system are forwarded directly to the configuration command (`./configure` or `meson setup`).
|
||||
- **Environment:** Primarily used in CI (GitHub Actions), but can be run locally to verify all configurations.
|
||||
|
||||
## `changelog-helper.py`
|
||||
Generates a sorted changelog from git commits since the last tag.
|
||||
|
||||
- **Purpose:** Automates the creation of release notes by parsing Conventional Commit messages.
|
||||
- **Usage:** `python3 scripts/changelog-helper.py [--pr]`
|
||||
- **Options:** Use `--pr` to append Pull Request numbers to each entry.
|
||||
|
||||
## `check-new-xeps.py`
|
||||
Checks for updates to XMPP Extension Protocols (XEPs).
|
||||
|
||||
- **Purpose:** Compares the versions of XEPs implemented in Profanity (tracked in `profanity.doap`) against the latest versions available at `xmpp.org`.
|
||||
- **Usage:** `python3 scripts/check-new-xeps.py`
|
||||
203
scripts/build-configuration-matrix.sh
Executable file
203
scripts/build-configuration-matrix.sh
Executable file
@@ -0,0 +1,203 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Exhaustive build configuration matrix testing for Profanity
|
||||
# Supports both Autotools and Meson
|
||||
|
||||
set -e
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
log_content() {
|
||||
echo
|
||||
if [ -f "$1" ]; then
|
||||
echo "Content of $1:"
|
||||
cat "$1"
|
||||
else
|
||||
echo "Log file $1 not found."
|
||||
fi
|
||||
}
|
||||
|
||||
error_handler() {
|
||||
ERR_CODE=$?
|
||||
echo -e "${RED}Error ${ERR_CODE} with command '${BASH_COMMAND}' on line ${BASH_LINENO[0]}. Exiting.${NC}"
|
||||
|
||||
if [ "$BUILD_SYSTEM" == "autotools" ]; then
|
||||
log_content ./config.log
|
||||
log_content ./test-suite.log
|
||||
log_content ./test-suite-memcheck.log
|
||||
else
|
||||
for log in build_run/meson-logs/testlog.txt build_valgrind/meson-logs/testlog.txt; do
|
||||
if [ -f "$log" ]; then
|
||||
echo "--- Meson Test Log ($log) ---"
|
||||
cat "$log"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
exit ${ERR_CODE}
|
||||
}
|
||||
|
||||
trap error_handler ERR
|
||||
|
||||
num_cores() {
|
||||
nproc \
|
||||
|| sysctl -n hw.ncpu \
|
||||
|| getconf _NPROCESSORS_ONLN 2>/dev/null \
|
||||
|| echo 2
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 [autotools|meson] [extra-args]"
|
||||
echo ""
|
||||
echo "Run exhaustive build matrix tests for the specified build system."
|
||||
echo "Default build system is 'autotools'."
|
||||
echo ""
|
||||
echo "Extra arguments are passed directly to the configuration command:"
|
||||
echo " - Autotools: ./configure [extra-args]"
|
||||
echo " - Meson: meson setup [extra-args]"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Determine build system
|
||||
BUILD_SYSTEM="autotools"
|
||||
if [[ "$1" == "autotools" || "$1" == "meson" ]]; then
|
||||
BUILD_SYSTEM="$1"
|
||||
shift
|
||||
fi
|
||||
|
||||
if [[ "$1" == "--help" || "$1" == "-h" ]]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
ARCH="$(uname | tr '[:upper:]' '[:lower:]')"
|
||||
EXTRA_ARGS="$*"
|
||||
|
||||
if [ "$BUILD_SYSTEM" == "autotools" ]; then
|
||||
echo -e "${YELLOW}---> Starting Autotools build matrix...${NC}"
|
||||
./bootstrap.sh
|
||||
|
||||
MAKE="make --quiet -j$(num_cores)"
|
||||
CC="gcc"
|
||||
|
||||
case "$ARCH" in
|
||||
linux*)
|
||||
tests=(
|
||||
"--enable-notifications --enable-icons-and-clipboard --enable-otr --enable-pgp
|
||||
--enable-omemo --enable-plugins --enable-c-plugins
|
||||
--enable-python-plugins --with-xscreensaver --enable-omemo-qrcode --enable-gdk-pixbuf"
|
||||
"--disable-notifications --disable-icons-and-clipboard --disable-otr --disable-pgp
|
||||
--disable-omemo --disable-plugins --disable-c-plugins
|
||||
--disable-python-plugins --without-xscreensaver"
|
||||
"--disable-notifications"
|
||||
"--disable-icons-and-clipboard"
|
||||
"--disable-otr"
|
||||
"--disable-pgp"
|
||||
"--disable-omemo --disable-omemo-qrcode"
|
||||
"--disable-pgp --disable-otr"
|
||||
"--disable-pgp --disable-otr --disable-omemo"
|
||||
"--disable-plugins"
|
||||
"--disable-python-plugins"
|
||||
"--disable-c-plugins"
|
||||
"--disable-c-plugins --disable-python-plugins"
|
||||
"--without-xscreensaver"
|
||||
"--disable-gdk-pixbuf"
|
||||
"")
|
||||
source /etc/profile.d/debuginfod.sh 2>/dev/null || true
|
||||
;;
|
||||
*)
|
||||
# Darwin, OpenBSD, etc.
|
||||
if [ "$ARCH" == "openbsd*" ]; then
|
||||
MAKE="gmake"
|
||||
CC="egcc -std=gnu99 -fexec-charset=UTF-8"
|
||||
fi
|
||||
tests=(
|
||||
"--enable-notifications --enable-icons-and-clipboard --enable-otr --enable-pgp
|
||||
--enable-omemo --enable-plugins --enable-c-plugins
|
||||
--enable-python-plugins"
|
||||
"--disable-notifications --disable-icons-and-clipboard --disable-otr --disable-pgp
|
||||
--disable-omemo --disable-plugins --disable-c-plugins
|
||||
--disable-python-plugins"
|
||||
"--disable-notifications"
|
||||
"--disable-icons-and-clipboard"
|
||||
"--disable-otr"
|
||||
"--disable-pgp"
|
||||
"--disable-omemo"
|
||||
"--disable-pgp --disable-otr"
|
||||
"--disable-pgp --disable-otr --disable-omemo"
|
||||
"--disable-plugins"
|
||||
"--disable-python-plugins"
|
||||
"--disable-c-plugins"
|
||||
"--disable-c-plugins --disable-python-plugins"
|
||||
"")
|
||||
;;
|
||||
esac
|
||||
|
||||
# Valgrind check (Linux only)
|
||||
if [[ "$ARCH" == linux* ]]; then
|
||||
echo -e "${YELLOW}--> Building with ./configure ${tests[0]} --enable-valgrind --disable-functional-tests ${EXTRA_ARGS}${NC}"
|
||||
./configure ${tests[0]} --enable-valgrind --disable-functional-tests ${EXTRA_ARGS}
|
||||
$MAKE CC="${CC}"
|
||||
$MAKE check-valgrind
|
||||
$MAKE distclean
|
||||
fi
|
||||
|
||||
for features in "${tests[@]}"
|
||||
do
|
||||
echo -e "${YELLOW}--> Building with ./configure ${features} --disable-functional-tests ${EXTRA_ARGS}${NC}"
|
||||
./configure $features --disable-functional-tests ${EXTRA_ARGS}
|
||||
$MAKE CC="${CC}"
|
||||
$MAKE check-unit
|
||||
./profanity -v
|
||||
$MAKE clean
|
||||
done
|
||||
|
||||
else
|
||||
# Meson Build Matrix
|
||||
echo -e "${YELLOW}---> Starting Meson build matrix...${NC}"
|
||||
|
||||
tests=(
|
||||
"-Dnotifications=enabled -Dicons-and-clipboard=enabled -Dotr=enabled -Dpgp=enabled -Domemo=enabled -Dc-plugins=enabled -Dpython-plugins=enabled -Dxscreensaver=enabled -Domemo-qrcode=enabled -Dgdk-pixbuf=enabled"
|
||||
""
|
||||
"-Dnotifications=disabled"
|
||||
"-Dicons-and-clipboard=disabled"
|
||||
"-Dotr=disabled"
|
||||
"-Dpgp=disabled"
|
||||
"-Domemo=disabled -Domemo-qrcode=disabled"
|
||||
"-Dpgp=disabled -Dotr=disabled"
|
||||
"-Dpgp=disabled -Dotr=disabled -Domemo=disabled"
|
||||
"-Dpython-plugins=disabled"
|
||||
"-Dc-plugins=disabled"
|
||||
"-Dc-plugins=disabled -Dpython-plugins=disabled"
|
||||
"-Dxscreensaver=disabled"
|
||||
"-Dgdk-pixbuf=disabled"
|
||||
)
|
||||
|
||||
BACKEND_OPT=""
|
||||
if [ -n "${OMEMO_BACKEND}" ]; then
|
||||
BACKEND_OPT="-Domemo-backend=${OMEMO_BACKEND}"
|
||||
fi
|
||||
|
||||
# Valgrind check (Linux only)
|
||||
if [[ "$ARCH" == linux* ]]; then
|
||||
echo -e "${YELLOW}--> Running Valgrind check with full features ${BACKEND_OPT} ${EXTRA_ARGS}${NC}"
|
||||
rm -rf build_valgrind
|
||||
meson setup build_valgrind ${tests[0]} ${BACKEND_OPT} -Dtests=true -Db_sanitize=address,undefined ${EXTRA_ARGS}
|
||||
meson compile -C build_valgrind
|
||||
meson test -C build_valgrind "unit tests" --print-errorlogs --wrap=valgrind || echo "Valgrind issues detected"
|
||||
rm -rf build_valgrind
|
||||
fi
|
||||
|
||||
for features in "${tests[@]}"
|
||||
do
|
||||
echo -e "${YELLOW}--> Building with: ${features} ${BACKEND_OPT} ${EXTRA_ARGS}${NC}"
|
||||
rm -rf build_run
|
||||
meson setup build_run ${features} ${BACKEND_OPT} -Dtests=true ${EXTRA_ARGS}
|
||||
meson compile -C build_run
|
||||
meson test -C build_run "unit tests" --print-errorlogs
|
||||
./build_run/profanity -v
|
||||
done
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Build configuration matrix testing successful!${NC}"
|
||||
165
scripts/changelog-helper.py
Executable file
165
scripts/changelog-helper.py
Executable file
@@ -0,0 +1,165 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Since we use Conventional Commits
|
||||
# we can now create our Changelog semi-automatically
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
import argparse
|
||||
from collections import defaultdict
|
||||
|
||||
# Configuration for sections and their order
|
||||
SECTION_CONFIG = [
|
||||
("fix", "Bug Fixes"),
|
||||
("feat", "Features"),
|
||||
("build", "Build System"),
|
||||
("ci", "CI"),
|
||||
("docs", "Documentation"),
|
||||
("perf", "Performance Improvements"),
|
||||
("refactor", "Refactorings"),
|
||||
("cleanup", "Cleanup"),
|
||||
("style", "Style"),
|
||||
("tests", "Tests"),
|
||||
("chore", "Chores"),
|
||||
]
|
||||
SECTIONS = dict(SECTION_CONFIG)
|
||||
TYPE_ORDER = [t for t, _ in SECTION_CONFIG]
|
||||
|
||||
CORRECTIONS = {
|
||||
"ests": "tests",
|
||||
"wleanup": "cleanup",
|
||||
}
|
||||
|
||||
def git_run(args):
|
||||
"""Run a git command and return stripped output lines."""
|
||||
try:
|
||||
result = subprocess.run(["git"] + args, capture_output=True, text=True, check=True)
|
||||
return [line for line in result.stdout.strip().split('\n') if line]
|
||||
except subprocess.CalledProcessError:
|
||||
return []
|
||||
|
||||
def get_last_tag():
|
||||
output = git_run(["describe", "--tags", "--abbrev=0"])
|
||||
return output[0] if output else None
|
||||
|
||||
def get_commits(revision_range):
|
||||
"""Get list of (hash, subject) tuples."""
|
||||
lines = git_run(["log", revision_range, "--format=%H %s"])
|
||||
commits = []
|
||||
for line in lines:
|
||||
parts = line.split(' ', 1)
|
||||
if len(parts) == 2:
|
||||
commits.append(parts)
|
||||
return commits
|
||||
|
||||
def get_pr_mappings(revision_range):
|
||||
"""Map commit hashes to PR numbers found in merge commits."""
|
||||
merge_commits = git_run(["log", revision_range, "--merges", "--format=%H %s"])
|
||||
pr_map = {}
|
||||
pr_re = re.compile(r'Merge pull request #(\d+)')
|
||||
|
||||
for line in merge_commits:
|
||||
parts = line.split(' ', 1)
|
||||
if len(parts) < 2:
|
||||
continue
|
||||
m_hash, m_subject = parts
|
||||
match = pr_re.search(m_subject)
|
||||
if match:
|
||||
pr_num = match.group(1)
|
||||
# Find all commits that are part of this merge branch
|
||||
branch_commits = git_run(["rev-list", f"{m_hash}^1..{m_hash}^2"])
|
||||
for b_hash in branch_commits:
|
||||
pr_map[b_hash] = pr_num
|
||||
return pr_map
|
||||
|
||||
def get_contributors(revision_range):
|
||||
"""Get sorted list of all unique contributors."""
|
||||
cmd = ["log", revision_range, "--format=%an%n%(trailers:key=Co-authored-by,valueonly=true)"]
|
||||
output = git_run(cmd)
|
||||
|
||||
contributors = set()
|
||||
for line in output:
|
||||
# Remove email part if present: "Name <email@example.com>" -> "Name"
|
||||
name = line.split('<')[0].strip()
|
||||
if name:
|
||||
contributors.add(name)
|
||||
|
||||
return sorted(list(contributors))
|
||||
|
||||
def format_description(description):
|
||||
"""Capitalize first letter of description."""
|
||||
description = description.strip()
|
||||
if description and description[0].islower():
|
||||
return description[0].upper() + description[1:]
|
||||
return description
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Generate a sorted changelog from git commits.")
|
||||
parser.add_argument("--pr", action="store_true", help="Append PR number to each commit.")
|
||||
args = parser.parse_args()
|
||||
|
||||
last_tag = get_last_tag()
|
||||
if not last_tag:
|
||||
print("No tags found in the repository.", file=sys.stderr)
|
||||
|
||||
revision_range = f"{last_tag}..HEAD" if last_tag else "HEAD"
|
||||
|
||||
commits = get_commits(revision_range)
|
||||
if not commits:
|
||||
print(f"No commits found since {last_tag if last_tag else 'the beginning'}.")
|
||||
return
|
||||
|
||||
pr_map = get_pr_mappings(revision_range) if args.pr else {}
|
||||
|
||||
# Conventional Commit regex: type(scope): description
|
||||
commit_re = re.compile(r'^(\w+)(?:\(([^)]+)\))?:\s*(.*)$')
|
||||
|
||||
grouped = defaultdict(list)
|
||||
others = []
|
||||
|
||||
for c_hash, c_subject in commits:
|
||||
# Skip merge commits in the output
|
||||
if c_subject.startswith(("Merge pull request", "Merge branch")):
|
||||
continue
|
||||
|
||||
pr_suffix = f" (#{pr_map[c_hash]})" if c_hash in pr_map else ""
|
||||
match = commit_re.match(c_subject)
|
||||
|
||||
if match:
|
||||
ctype = match.group(1).lower()
|
||||
ctype = CORRECTIONS.get(ctype, ctype)
|
||||
description = format_description(match.group(3))
|
||||
grouped[ctype].append(f"{description}{pr_suffix}")
|
||||
else:
|
||||
others.append(f"{c_subject}{pr_suffix}")
|
||||
|
||||
# Output sections in ordered priority
|
||||
all_types = TYPE_ORDER + sorted([t for t in grouped if t not in TYPE_ORDER])
|
||||
first = True
|
||||
for ctype in all_types:
|
||||
if ctype in grouped:
|
||||
if not first:
|
||||
print()
|
||||
section_name = SECTIONS.get(ctype, ctype.capitalize())
|
||||
print(f"{section_name}:")
|
||||
for msg in sorted(grouped[ctype]):
|
||||
print(f"- {msg}")
|
||||
first = False
|
||||
|
||||
if others:
|
||||
if not first:
|
||||
print()
|
||||
print("Others:")
|
||||
for msg in sorted(others):
|
||||
print(f"- {msg}")
|
||||
|
||||
# Contributors section
|
||||
contributors = get_contributors(revision_range)
|
||||
if contributors:
|
||||
print("\nContributors:")
|
||||
for i, name in enumerate(contributors, 1):
|
||||
print(f"{i}. {name}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Central quality check script for Profanity
|
||||
# Central linting and testing script for Profanity
|
||||
|
||||
set -e
|
||||
|
||||
@@ -118,7 +118,7 @@ while [[ "$#" -gt 0 ]]; do
|
||||
echo "Installing pre-commit hook..."
|
||||
mkdir -p .git/hooks
|
||||
echo "#!/usr/bin/env bash" > .git/hooks/pre-commit
|
||||
echo "./scripts/quality-check.sh --hook" >> .git/hooks/pre-commit
|
||||
echo "./scripts/lint-and-test.sh --hook" >> .git/hooks/pre-commit
|
||||
chmod +x .git/hooks/pre-commit
|
||||
echo "Hook installed."
|
||||
exit 0
|
||||
@@ -140,4 +140,4 @@ if [ "$BUILD_SYSTEM" != "none" ]; then
|
||||
run_tests "$BUILD_SYSTEM"
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Quality check successful!${NC}"
|
||||
echo -e "${GREEN}Validation successful!${NC}"
|
||||
Reference in New Issue
Block a user