Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d36bc234d8 |
@@ -7,6 +7,11 @@ and releases use [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Reproducible tagged-source archives and SHA-256 checksums through `make dist`
|
||||
- Automated release-version consistency testing
|
||||
|
||||
## [0.1.0] - 2026-07-26
|
||||
|
||||
### Added
|
||||
|
||||
@@ -14,6 +14,10 @@ Before proposing a code change:
|
||||
6. Do not include real domains, addresses, passwords, hashes, logs or private
|
||||
server configuration.
|
||||
|
||||
Release maintainers should create an annotated version tag before running
|
||||
`make dist`. The target archives the tag corresponding to the executable's
|
||||
version and writes a SHA-256 checksum beside the resulting archive.
|
||||
|
||||
Changes affecting transactions, rollback, password handling, ownership, path
|
||||
validation or command execution require particular care and should include
|
||||
failure-path tests.
|
||||
|
||||
@@ -7,13 +7,21 @@ DESTDIR ?=
|
||||
PYTHON ?= python3
|
||||
INSTALL ?= install
|
||||
GZIP ?= gzip
|
||||
GIT ?= git
|
||||
SHA256SUM ?= sha256sum
|
||||
|
||||
SBINDIR := $(DESTDIR)$(PREFIX)/sbin
|
||||
MANDIR := $(DESTDIR)$(PREFIX)/share/man/man8
|
||||
BACKUPDIR := $(DESTDIR)/var/backups/vmailctl
|
||||
CONFIG := $(DESTDIR)$(SYSCONFDIR)/vmailctl.conf
|
||||
VERSION := $(shell sed -n 's/^VERSION = "\(.*\)"/\1/p' vmailctl)
|
||||
RELEASE_TAG ?= v$(VERSION)
|
||||
DISTDIR ?= dist
|
||||
DIST_NAME := vmailctl-$(VERSION)
|
||||
DIST_ARCHIVE := $(DISTDIR)/$(DIST_NAME).tar.gz
|
||||
DIST_CHECKSUM := $(DIST_ARCHIVE).sha256
|
||||
|
||||
.PHONY: all check man-check install
|
||||
.PHONY: all check man-check dist install
|
||||
|
||||
all: check
|
||||
|
||||
@@ -24,6 +32,28 @@ check:
|
||||
man-check:
|
||||
groff -man -z -ww man/vmailctl.8
|
||||
|
||||
dist: check man-check
|
||||
@test -n "$(VERSION)" || { echo "Cannot determine VERSION" >&2; exit 1; }
|
||||
@$(GIT) rev-parse --verify --quiet \
|
||||
"refs/tags/$(RELEASE_TAG)^{commit}" >/dev/null || { \
|
||||
echo "Release tag $(RELEASE_TAG) does not exist" >&2; exit 1; \
|
||||
}
|
||||
@$(INSTALL) -d -m 0755 "$(DISTDIR)"
|
||||
@set -eu; \
|
||||
archive_tmp="$(DIST_ARCHIVE).tmp"; \
|
||||
checksum_tmp="$(DIST_CHECKSUM).tmp"; \
|
||||
trap 'rm -f -- "$$archive_tmp" "$$checksum_tmp"' EXIT; \
|
||||
LC_ALL=C $(GIT) archive --format=tar \
|
||||
--prefix="$(DIST_NAME)/" "$(RELEASE_TAG)" | \
|
||||
$(GZIP) -n -9 >"$$archive_tmp"; \
|
||||
mv -f -- "$$archive_tmp" "$(DIST_ARCHIVE)"; \
|
||||
(cd "$(DISTDIR)" && \
|
||||
$(SHA256SUM) "$(DIST_NAME).tar.gz") >"$$checksum_tmp"; \
|
||||
mv -f -- "$$checksum_tmp" "$(DIST_CHECKSUM)"; \
|
||||
trap - EXIT
|
||||
@echo "Created $(DIST_ARCHIVE)"
|
||||
@echo "Created $(DIST_CHECKSUM)"
|
||||
|
||||
install:
|
||||
$(INSTALL) -d -m 0755 $(SBINDIR)
|
||||
$(INSTALL) -m 0755 vmailctl $(SBINDIR)/vmailctl
|
||||
|
||||
@@ -137,6 +137,20 @@ make check
|
||||
|
||||
If GNU `groff` is installed, `make man-check` also validates the manual page.
|
||||
|
||||
## Release archives
|
||||
|
||||
Maintainers can create a reproducible source archive and SHA-256 checksum from
|
||||
the annotated tag matching the version in `vmailctl`:
|
||||
|
||||
```sh
|
||||
make dist
|
||||
```
|
||||
|
||||
The files are written beneath `dist/`. The archive is generated from the tag,
|
||||
not the working tree, so an existing release cannot silently acquire later
|
||||
changes. This maintainer target requires Git, `gzip`, `sha256sum`, and GNU
|
||||
`groff`.
|
||||
|
||||
## Development and provenance
|
||||
|
||||
The initial version was designed and developed by Eric Ireland with assistance
|
||||
|
||||
+14
-1
@@ -14,7 +14,8 @@ import unittest
|
||||
from unittest import mock
|
||||
|
||||
|
||||
SOURCE = Path(__file__).resolve().parents[1] / "vmailctl"
|
||||
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
||||
SOURCE = PROJECT_ROOT / "vmailctl"
|
||||
SPEC = importlib.util.spec_from_loader(
|
||||
"vmailctl",
|
||||
SourceFileLoader("vmailctl", os.fspath(SOURCE)),
|
||||
@@ -208,6 +209,18 @@ class PasswordTests(unittest.TestCase):
|
||||
self.assertEqual(mocked_run.call_args.kwargs["input_text"], "secret-value\nsecret-value\n")
|
||||
|
||||
|
||||
class ReleaseMetadataTests(unittest.TestCase):
|
||||
def test_version_is_consistent_across_public_documentation(self):
|
||||
version = vmailctl.VERSION
|
||||
readme = (PROJECT_ROOT / "README.md").read_text(encoding="utf-8")
|
||||
changelog = (PROJECT_ROOT / "CHANGELOG.md").read_text(encoding="utf-8")
|
||||
manual = (PROJECT_ROOT / "man" / "vmailctl.8").read_text(encoding="utf-8")
|
||||
|
||||
self.assertIn(f"`{version}` is a public beta", readme)
|
||||
self.assertIn(f"## [{version}]", changelog)
|
||||
self.assertIn(f'"vmailctl {version}"', manual)
|
||||
|
||||
|
||||
class TransactionLogicTests(unittest.TestCase):
|
||||
def fixture_settings(self, root: Path):
|
||||
users = root / "virtual-users"
|
||||
|
||||
Reference in New Issue
Block a user