morphata 2.2.0__tar.gz → 2.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {morphata-2.2.0 → morphata-2.2.2}/.envrc +1 -1
- {morphata-2.2.0 → morphata-2.2.2}/.gitignore +5 -1
- {morphata-2.2.0 → morphata-2.2.2}/CHANGELOG.md +44 -0
- {morphata-2.2.0 → morphata-2.2.2}/PKG-INFO +2 -2
- {morphata-2.2.0 → morphata-2.2.2}/bench/test_equivalence_perf.py +1 -1
- {morphata-2.2.0 → morphata-2.2.2}/bench/test_hoa_exporter_perf.py +1 -1
- {morphata-2.2.0 → morphata-2.2.2}/bench/test_hoa_parser_perf.py +1 -1
- {morphata-2.2.0 → morphata-2.2.2}/bench/test_sere_nlm_perf.py +1 -1
- {morphata-2.2.0 → morphata-2.2.2}/bench/test_transforms_perf.py +1 -1
- {morphata-2.2.0 → morphata-2.2.2}/ci/make-release +16 -18
- {morphata-2.2.0 → morphata-2.2.2}/pixi.lock +907 -842
- {morphata-2.2.0 → morphata-2.2.2}/pixi.toml +2 -1
- {morphata-2.2.0 → morphata-2.2.2}/pyproject.toml +11 -3
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/__init__.py +2 -0
- morphata-2.2.2/src/morphata/_version.py +24 -0
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/acc_expr.py +1 -2
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/acceptance.py +4 -6
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/builder.py +4 -1
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/hoa/__main__.py +1 -1
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/hoa/parser.py +4 -5
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/logic/_common.py +17 -10
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/logic/ltl.py +1 -1
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/logic/psl.py +3 -4
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/logic/sere.py +25 -21
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/operators/_backend.py +3 -2
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/operators/matrix.py +20 -17
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/operators/polynomial.py +28 -16
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/symbolic/automaton.py +62 -26
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/symbolic/bdd.py +247 -292
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/symbolic/utils.py +21 -16
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/utils.py +1 -1
- {morphata-2.2.0 → morphata-2.2.2}/tests/conftest.py +3 -4
- {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/test_parser.py +1 -1
- {morphata-2.2.0 → morphata-2.2.2}/tests/logic/test_ltl.py +1 -2
- {morphata-2.2.0 → morphata-2.2.2}/tests/logic/test_psl.py +18 -16
- {morphata-2.2.0 → morphata-2.2.2}/tests/logic/test_sere.py +21 -17
- {morphata-2.2.0 → morphata-2.2.2}/tests/operators/test_matrix.py +2 -2
- {morphata-2.2.0 → morphata-2.2.2}/tests/operators/test_polynomial.py +1 -1
- {morphata-2.2.0 → morphata-2.2.2}/tests/symbolic/test_bdd_helpers.py +3 -3
- {morphata-2.2.0 → morphata-2.2.2}/tests/symbolic/test_compose.py +96 -1
- {morphata-2.2.0 → morphata-2.2.2}/tests/symbolic/test_language_equivalence.py +52 -2
- {morphata-2.2.0 → morphata-2.2.2}/tests/symbolic/test_ltlf2dfa_equivalence.py +2 -2
- {morphata-2.2.0 → morphata-2.2.2}/tests/symbolic/test_symbolic_automaton.py +230 -5
- {morphata-2.2.0 → morphata-2.2.2}/tests/symbolic/test_to_hoa.py +2 -2
- {morphata-2.2.0 → morphata-2.2.2}/tests/symbolic/test_transforms.py +4 -4
- {morphata-2.2.0 → morphata-2.2.2}/tests/test_acceptance_validation.py +1 -1
- {morphata-2.2.0 → morphata-2.2.2}/tests/test_alphabet.py +2 -2
- {morphata-2.2.0 → morphata-2.2.2}/uv.lock +70 -93
- {morphata-2.2.0 → morphata-2.2.2}/.basedpyright/baseline.json +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/.dockerignore +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/.editorconfig +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/.envrc.recommended +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/.fdignore +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/.gitattributes +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/.mailmap +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/.python-version +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/.rstcheck.cfg +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/AGENTS.md +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/CLAUDE.md +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/CONTRIBUTING.md +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/LICENSE +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/README.rst +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/bench/README.md +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/bench/__init__.py +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/bench/conftest.py +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/Makefile +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/_static/navigation.html +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/api/modules.rst +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/api/morphata.acc_expr.rst +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/api/morphata.acceptance.rst +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/api/morphata.alphabet.rst +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/api/morphata.builder.rst +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/api/morphata.hoa.rst +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/api/morphata.logic.rst +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/api/morphata.operators.rst +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/api/morphata.symbolic.rst +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/changelog.md +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/concepts/acceptance.rst +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/concepts/hoa.rst +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/concepts/index.rst +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/concepts/operators.rst +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/concepts/symbolic.rst +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/concepts/weights.rst +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/conf.py +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/index.rst +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/docs/quick-start.rst +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/justfile +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/mypy.ini +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/project.utf-8.add +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/project.utf-8.add.spl +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/pyrightconfig.json +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/pytest.toml +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/rules/no-derivative-multiarg.yml +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/rules/no-typing-as-ty.yml +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/sgconfig.yml +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/alphabet.py +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/hoa/__init__.py +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/hoa/hoa.lark +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/logic/__init__.py +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/logic/__init__.pyi +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/operators/__init__.py +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/py.typed +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/src/morphata/symbolic/__init__.py +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut1.hoa +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut11.hoa +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut2.hoa +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut3.2.hoa +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut3.hoa +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut4.hoa +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut5.hoa +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut6.hoa +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut7.hoa +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/aut8.hoa +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/finite_aut.hoa +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/gen_buchi_3.hoa +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/gen_cobuchi_2.hoa +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/rabin_2pair.hoa +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/streett_2pair.hoa +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/hoa/test_exporter.py +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/logic/__init__.py +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/symbolic/test_from_hoaf.py +0 -0
- {morphata-2.2.0 → morphata-2.2.2}/tests/test_builder.py +0 -0
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
# generated version file
|
|
2
|
+
src/morphata/_version.py
|
|
3
|
+
|
|
1
4
|
# generated type stubs
|
|
2
5
|
/typings/
|
|
3
6
|
# pixi environments
|
|
4
|
-
.pixi
|
|
7
|
+
.pixi/*
|
|
8
|
+
!.pixi/config.toml
|
|
5
9
|
|
|
6
10
|
# Created by https://www.toptal.com/developers/gitignore/api/python
|
|
7
11
|
# Edit at https://www.toptal.com/developers/gitignore?templates=python
|
|
@@ -1,5 +1,49 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.2.2 — 2026-08-23
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Fixes a bug with complement and composition of nondeterministic automata
|
|
8
|
+
|
|
9
|
+
`__invert__` dualized each
|
|
10
|
+
(guard, successor)
|
|
11
|
+
pair on its own, leaving the implicit disjunction across a state's pairs undualized.
|
|
12
|
+
Read each state's relation back through `partition_by_state_residual` first,
|
|
13
|
+
so the disjunction sits inside one residual per disjoint guard class;
|
|
14
|
+
missing moves come back as a `false` residual, whose dual is the correct `true`.
|
|
15
|
+
|
|
16
|
+
`compose_automata` remapped only the reachable states,
|
|
17
|
+
so a fresh index could land on an unreachable state that kept its own index
|
|
18
|
+
and silently overwrite a transition row.
|
|
19
|
+
Remap every state and prune the unreachable rows afterwards.
|
|
20
|
+
`reindex_states` now rejects an assignment whose image collides with a state it does
|
|
21
|
+
not remap, so the same mistake raises instead of corrupting.
|
|
22
|
+
|
|
23
|
+
Together these made `is_language_equivalent` report False
|
|
24
|
+
for automata with identical languages.
|
|
25
|
+
|
|
26
|
+
## 2.2.1 — 2026-08-20
|
|
27
|
+
|
|
28
|
+
This version bump is mostly a cleanup after the 2.2.0 rewrite,
|
|
29
|
+
but also swaps `dd` for `pollywog` as the wrapper around CUDD
|
|
30
|
+
for the symbolic automaton.
|
|
31
|
+
The main reason for the latter is that `dd` wasn't well-typed,
|
|
32
|
+
and because `dd` doesn't expose Algebraic Decision Diagrams,
|
|
33
|
+
which may be useful for a future symbolic weighted automaton.
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- The BDD layer now uses `pollywog` instead of `dd`,
|
|
38
|
+
and the symbolic automaton code was adjusted to match.
|
|
39
|
+
Most of the visible work here is internal:
|
|
40
|
+
manager transfers and substitutions were tightened up,
|
|
41
|
+
and the tests moved along with the backend swap.
|
|
42
|
+
- Project versioning now comes from the VCS tag instead of being hard-coded in
|
|
43
|
+
`pyproject.toml`.
|
|
44
|
+
The release script now takes an explicit target version,
|
|
45
|
+
and `morphata.__version__` is exported from the generated version file.
|
|
46
|
+
|
|
3
47
|
## 2.2.0 — 2026-08-19
|
|
4
48
|
|
|
5
49
|
This is a major release as it cleans up a lot of bad code,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: morphata
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.2
|
|
4
4
|
Summary: Representation theory for automata, made practical.
|
|
5
5
|
Project-URL: Documentation, https://docs.anandb.dev/morphata
|
|
6
6
|
Project-URL: Repository, https://git.anandb.dev/morphata.git
|
|
@@ -14,11 +14,11 @@ Requires-Python: >=3.12
|
|
|
14
14
|
Requires-Dist: algebraic-arrays>=1.3.0
|
|
15
15
|
Requires-Dist: attrs>=25.4.0
|
|
16
16
|
Requires-Dist: cattrs>=26.1.0
|
|
17
|
-
Requires-Dist: dd>=0.6.0
|
|
18
17
|
Requires-Dist: jaxtyping>=0.3
|
|
19
18
|
Requires-Dist: lark>=1.3.1
|
|
20
19
|
Requires-Dist: logic-asts>=1.8
|
|
21
20
|
Requires-Dist: numpy
|
|
21
|
+
Requires-Dist: pollywog>=0.1.1
|
|
22
22
|
Requires-Dist: typing-extensions>=4.14
|
|
23
23
|
Provides-Extra: dot
|
|
24
24
|
Requires-Dist: pydot>=4.0.1; extra == 'dot'
|
|
@@ -15,8 +15,8 @@ from __future__ import annotations
|
|
|
15
15
|
|
|
16
16
|
from collections.abc import Set as AbstractSet
|
|
17
17
|
|
|
18
|
-
import logic_asts.ltl as ltl
|
|
19
18
|
import pytest
|
|
19
|
+
from logic_asts import ltl
|
|
20
20
|
from pytest_benchmark.fixture import BenchmarkFixture as Benchmark
|
|
21
21
|
|
|
22
22
|
from morphata.alphabet import powerset_alphabet
|
|
@@ -25,8 +25,8 @@ from __future__ import annotations
|
|
|
25
25
|
|
|
26
26
|
from collections.abc import Set as AbstractSet
|
|
27
27
|
|
|
28
|
-
import logic_asts.ltl as ltl
|
|
29
28
|
import pytest
|
|
29
|
+
from logic_asts import ltl
|
|
30
30
|
from pytest_benchmark.fixture import BenchmarkFixture as Benchmark
|
|
31
31
|
|
|
32
32
|
from morphata.alphabet import powerset_alphabet
|
|
@@ -30,9 +30,9 @@ import functools
|
|
|
30
30
|
from pathlib import Path
|
|
31
31
|
|
|
32
32
|
import logic_asts as logic
|
|
33
|
-
import logic_asts.ltl as ltl
|
|
34
33
|
import pytest
|
|
35
34
|
from lark import Lark
|
|
35
|
+
from logic_asts import ltl
|
|
36
36
|
from pytest_benchmark.fixture import BenchmarkFixture as Benchmark
|
|
37
37
|
|
|
38
38
|
from morphata.alphabet import powerset_alphabet
|
|
@@ -27,8 +27,8 @@ from __future__ import annotations
|
|
|
27
27
|
from collections.abc import Set as AbstractSet
|
|
28
28
|
|
|
29
29
|
import logic_asts as logic
|
|
30
|
-
import logic_asts.sere as sere
|
|
31
30
|
import pytest
|
|
31
|
+
from logic_asts import sere
|
|
32
32
|
from pytest_benchmark.fixture import BenchmarkFixture as Benchmark
|
|
33
33
|
|
|
34
34
|
from morphata.alphabet import BooleanAlphabet, powerset_alphabet
|
|
@@ -26,8 +26,8 @@ from __future__ import annotations
|
|
|
26
26
|
from collections.abc import Set as AbstractSet
|
|
27
27
|
|
|
28
28
|
import logic_asts as logic
|
|
29
|
-
import logic_asts.ltl as ltl
|
|
30
29
|
import pytest
|
|
30
|
+
from logic_asts import ltl
|
|
31
31
|
from pytest_benchmark.fixture import BenchmarkFixture as Benchmark
|
|
32
32
|
|
|
33
33
|
from morphata.alphabet import powerset_alphabet
|
|
@@ -4,14 +4,14 @@ set -euo pipefail
|
|
|
4
4
|
# Usage ------------------------------------------------------------------
|
|
5
5
|
usage() {
|
|
6
6
|
cat <<EOF
|
|
7
|
-
Usage: $(basename "$0") <
|
|
7
|
+
Usage: $(basename "$0") <version>
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
(
|
|
9
|
+
version Target release version, without a leading 'v'
|
|
10
|
+
(the project version is derived from the git tag)
|
|
11
11
|
|
|
12
12
|
Examples:
|
|
13
|
-
$(basename "$0")
|
|
14
|
-
$(basename "$0")
|
|
13
|
+
$(basename "$0") 2.3.0
|
|
14
|
+
$(basename "$0") 2.2.2
|
|
15
15
|
EOF
|
|
16
16
|
exit 1
|
|
17
17
|
}
|
|
@@ -23,7 +23,7 @@ fi
|
|
|
23
23
|
PROJECT_DIR="$(cd "$(dirname "$(realpath "${BASH_SOURCE[0]}")")/.." && pwd)"
|
|
24
24
|
cd "$PROJECT_DIR"
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
NEW_VERSION="${1#v}"
|
|
27
27
|
|
|
28
28
|
# Helpers ----------------------------------------------------------------
|
|
29
29
|
is_jj() { [[ -d "$PROJECT_DIR/.jj" ]]; }
|
|
@@ -64,48 +64,46 @@ elif [[ "$UNRELEASED_COUNT" -gt 1 ]]; then
|
|
|
64
64
|
exit 1
|
|
65
65
|
fi
|
|
66
66
|
|
|
67
|
-
#
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
# Determine versions and check tag
|
|
68
|
+
OLD_TAG="$(git describe --tags --abbrev=0 --match 'v*' 2>/dev/null || true)"
|
|
69
|
+
OLD_VERSION="${OLD_TAG#v}"
|
|
70
70
|
TAG="v${NEW_VERSION}"
|
|
71
71
|
RELEASE_DATE="$(date +%Y-%m-%d)"
|
|
72
72
|
|
|
73
|
-
echo "==>
|
|
74
|
-
echo " Current version: $OLD_VERSION"
|
|
73
|
+
echo "==> Releasing version $NEW_VERSION..."
|
|
74
|
+
echo " Current version: ${OLD_VERSION:-<none>}"
|
|
75
75
|
echo " New version: $NEW_VERSION"
|
|
76
76
|
echo " Tag: $TAG"
|
|
77
77
|
echo " Date: $RELEASE_DATE"
|
|
78
78
|
|
|
79
79
|
if git rev-parse -q --verify "refs/tags/$TAG" >/dev/null 2>&1; then
|
|
80
80
|
echo "error: tag '$TAG' already exists" >&2
|
|
81
|
-
echo "error: refusing to bump $BUMP version" >&2
|
|
82
81
|
exit 1
|
|
83
82
|
fi
|
|
84
|
-
uv version --bump "$BUMP"
|
|
85
83
|
|
|
86
84
|
# Promote CHANGELOG `Unreleased` to the new version
|
|
87
85
|
echo "==> Promoting CHANGELOG Unreleased -> ${NEW_VERSION} (${RELEASE_DATE})"
|
|
88
86
|
sed -i "s/^## Unreleased$/## ${NEW_VERSION} \xe2\x80\x94 ${RELEASE_DATE}/" CHANGELOG.md
|
|
89
87
|
|
|
90
88
|
# Commit
|
|
91
|
-
COMMIT_MSG="chore(release): $
|
|
89
|
+
COMMIT_MSG="chore(release): ${NEW_VERSION}"
|
|
92
90
|
echo "==> Committing: $COMMIT_MSG"
|
|
93
91
|
|
|
94
92
|
if is_jj; then
|
|
95
93
|
jj commit -m "$COMMIT_MSG"
|
|
96
94
|
else
|
|
97
|
-
git add
|
|
95
|
+
git add CHANGELOG.md
|
|
98
96
|
git commit -m "$COMMIT_MSG"
|
|
99
97
|
fi
|
|
100
98
|
|
|
101
99
|
# Build the tag annotation from the just-promoted CHANGELOG section.
|
|
102
|
-
# Title is "release:
|
|
100
|
+
# Title is "release: <ver>"; body is the section content (the
|
|
103
101
|
# lines between the new `## <ver> ...` heading and the next `## ` heading).
|
|
104
|
-
TAG_TITLE="release: $
|
|
102
|
+
TAG_TITLE="release: ${NEW_VERSION}"
|
|
105
103
|
TAG_BODY="$(awk -v ver="$NEW_VERSION" -v prev="$OLD_VERSION" '
|
|
106
104
|
$0 ~ "^## " ver "( |$)" { capture = 1; next }
|
|
107
105
|
capture && /^## / {
|
|
108
|
-
if ($0 !~ "^## " prev "( |$)") {
|
|
106
|
+
if (prev != "" && $0 !~ "^## " prev "( |$)") {
|
|
109
107
|
printf "error: expected next changelog heading to be %s, got: %s\n", \
|
|
110
108
|
"## " prev, $0 > "/dev/stderr"
|
|
111
109
|
exit 2
|