changelog2version

A tool to extarct version information from a changelog.

Home

Source code

git clone https://projects.rickardlindberg.me/scm/changelog2version.git

Website

https://projects.rickardlindberg.me/changelog2version

Recent events

2026-01-11 20:11 Rickard pushed to changelog2version

commit 399fafb2c66d27c2c04079af8f0bf48e3c706a13
Author: Rickard Lindberg <rickard@rickardlindberg.me>
Date:   Sun Jan 11 20:11:50 2026 +0100

    Document

diff --git a/README.md b/README.md
index 44fba91..b7967ed 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,8 @@ It will generate `version.sh` like this:
 ```:tests/expected_release.sh
 
 `version.sh` is typically sourced from a build script to gain access to the
-variables.
+variables. The `VCS_*` environment variables are assumed to be provided by the
+continuous integration system.
 
 ## How to make a release
 

2026-01-11 11:07 Rickard pushed to changelog2version

commit 79ce2e6bc16bf4470caebc196f3e42f96b6bfc20
Author: Rickard Lindberg <rickard@rickardlindberg.me>
Date:   Sun Jan 11 11:07:27 2026 +0100

    Bump changelog2version for new version scheme

diff --git a/make.sh b/make.sh
index 874062f..728c2e9 100755
--- a/make.sh
+++ b/make.sh
@@ -6,7 +6,7 @@ RLWORKBENCH_VERSION=1.1.0
 RLWORKBENCH_FOLDER_NAME=rlworkbench-$RLWORKBENCH_VERSION
 RLWORKBENCH_ARCHIVE=https://projects.rickardlindberg.me/artifacts/rlworkbench/$RLWORKBENCH_VERSION/$RLWORKBENCH_FOLDER_NAME.tgz
 
-CHANGELOG2VERSION_VERSION=1.1.0
+CHANGELOG2VERSION_VERSION=1.2.0
 CHANGELOG2VERSION_FOLDER_NAME=changelog2version-$CHANGELOG2VERSION_VERSION
 CHANGELOG2VERSION_ARCHIVE=https://projects.rickardlindberg.me/artifacts/changelog2version/$CHANGELOG2VERSION_VERSION/$CHANGELOG2VERSION_FOLDER_NAME.tgz
 

commit 946624f4f06ebc978d47151f74bb416f03613ab4
Author: Rickard Lindberg <rickard@rickardlindberg.me>
Date:   Sun Jan 11 11:06:53 2026 +0100

    Use PROJECTS2_TAGS

diff --git a/release.sh b/release.sh
index fd9bc37..097c533 100755
--- a/release.sh
+++ b/release.sh
@@ -15,4 +15,4 @@ cp out/changelog2version $TARGET
 
 (cd out/release && tar czvvf $ARCHIVE_NAME $FOLDER_NAME)
 
-echo "{\"artifacts\": [{\"source\": \"out/release/$ARCHIVE_NAME\", \"destination\": \"$VERSION/$ARCHIVE_NAME\"}]}" > Dockerfile.release.ci.files
+echo "{\"artifacts\": [{\"source\": \"out/release/$ARCHIVE_NAME\", \"destination\": \"$VERSION/$ARCHIVE_NAME\"$PROJECTS2_TAGS}]}" > Dockerfile.release.ci.files

commit e2682a8964d1eb4de5ec869b3c6d49a50baae57b
Author: Rickard Lindberg <rickard@rickardlindberg.me>
Date:   Sun Jan 11 11:06:42 2026 +0100

    Prepare for next release

diff --git a/README.md b/README.md
index 271560c..44fba91 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,8 @@ The process for making a release of a piece of software that uses
 
 ## Changelog
 
+### 1.3.0
+
 ### 1.2.0 (2026-01-11)
 
 * Base beta version on `VCS_COMMITS_SINCE*`

2026-01-11 11:04 Rickard pushed to changelog2version

commit dc628300075e061ea4b7a72e4fb654e89156a0dc
Author: Rickard Lindberg <rickard@rickardlindberg.me>
Date:   Sun Jan 11 11:04:50 2026 +0100

    Release 1.2.0

diff --git a/README.md b/README.md
index c90f496..271560c 100644
--- a/README.md
+++ b/README.md
@@ -41,7 +41,7 @@ The process for making a release of a piece of software that uses
 
 ## Changelog
 
-### 1.2.0
+### 1.2.0 (2026-01-11)
 
 * Base beta version on `VCS_COMMITS_SINCE*`
 

commit 0dff2a5d7c4d9bb396b5efa45939ed4d534bfe80
Author: Rickard Lindberg <rickard@rickardlindberg.me>
Date:   Sun Jan 11 11:04:33 2026 +0100

    Document VCS_COMMITS_SINCE

diff --git a/README.md b/README.md
index 57f2d1b..c90f496 100644
--- a/README.md
+++ b/README.md
@@ -43,6 +43,8 @@ The process for making a release of a piece of software that uses
 
 ### 1.2.0
 
+* Base beta version on `VCS_COMMITS_SINCE*`
+
 ### 1.1.0 (2026-01-10)
 
 * Can skip code blocks when searching for changelog

2026-01-11 11:02 Rickard pushed to changelog2version

commit 422c32c70a549302d68768690cea7cf3d59b8c05
Author: Rickard Lindberg <rickard@rickardlindberg.me>
Date:   Sun Jan 11 11:02:31 2026 +0100

    Fix variable name

diff --git a/changelog2version.meta b/changelog2version.meta
index 3b818b6..699168b 100644
--- a/changelog2version.meta
+++ b/changelog2version.meta
@@ -16,7 +16,7 @@ versionPreRelease = '### ' versionNumber:x '\n' -> {
     "VERSION=" x "\n"
     "if [ \"$VCS_SHORT_ID\" = \"\" ]; then\n" >
         "VCS_SHORT_ID=dev\n"
-        "VCS_COMMITS_SINCE=0\n"
+        "VCS_COMMITS_SINCE" <since "=0\n"
     < "else\n" >
         "if [ \"$VCS_COMMITS_SINCE" <since "\" = \"\" ]; then\n" >
             "echo \"Could not find environment variable VCS_COMMITS_SINCE" <since "\"\n"
diff --git a/tests/expected_beta.sh b/tests/expected_beta.sh
index 14ccffb..4f75e27 100644
--- a/tests/expected_beta.sh
+++ b/tests/expected_beta.sh
@@ -1,7 +1,7 @@
 VERSION=1.2.3
 if [ "$VCS_SHORT_ID" = "" ]; then
     VCS_SHORT_ID=dev
-    VCS_COMMITS_SINCE=0
+    VCS_COMMITS_SINCE_1_2_2=0
 else
     if [ "$VCS_COMMITS_SINCE_1_2_2" = "" ]; then
         echo "Could not find environment variable VCS_COMMITS_SINCE_1_2_2"

2026-01-11 11:00 Rickard pushed to changelog2version

commit 9ffc52fff8d60a0c2e1d552e8c19d985e23ad797
Author: Rickard Lindberg <rickard@rickardlindberg.me>
Date:   Sun Jan 11 10:58:28 2026 +0100

    Use scheme based on VCS_COMMITS_SINCE* for betas

diff --git a/changelog2version.meta b/changelog2version.meta
index ee75184..3b818b6 100644
--- a/changelog2version.meta
+++ b/changelog2version.meta
@@ -1,32 +1,51 @@
 main = findChangelog:x -> { x };
 
-findChangelog = skip* changelog:x -> { x };
-    skip = !changelog skipBlock;
-    skipBlock = codeBlock | restLine;
-    codeBlock = '```' restLine skipCodeBlock* '```\n';
-    skipCodeBlock = !'```\n' restLine;
+findChangelog = skipChangelog* changelog:x previousRelease:y -> { $since x y };
+    skipChangelog = !changelog skip;
 
-changelog = '## Changelog\n\n' versionLine:x -> { x };
-
-versionLine =
-    | '### ' versionNumber:x '\n' -> {
-        "VERSION=" x "\n"
-        "FULL_VERSION=" x "-beta.$YMD+$VCS_SHORT_ID\n"
-        "PROJECTS2_TAGS=', \"tags\": []'\n"
-    }
-    | '### ' versionNumber:x ' (' date ')\n' -> {
-        "VERSION=" x "\n"
-        "FULL_VERSION=" x "\n"
-        "PROJECTS2_TAGS=', \"tags\": [\"" x "\"]'\n"
-    }
+changelog = '## Changelog\n\n' currentVersion:x -> { x };
+    currentVersion = versionPreRelease:x -> { x } | versionRelease:x -> { x };
+
+previousRelease =
+    | skipVersionRelease* versionReleaseNumber:x -> { >since { "_" x } }
+    |                                      -> {}
     ;
+    skipVersionRelease = !versionReleaseNumber skip;
 
-versionNumber = number '.' number '.' number;
+versionPreRelease = '### ' versionNumber:x '\n' -> {
+    "VERSION=" x "\n"
+    "if [ \"$VCS_SHORT_ID\" = \"\" ]; then\n" >
+        "VCS_SHORT_ID=dev\n"
+        "VCS_COMMITS_SINCE=0\n"
+    < "else\n" >
+        "if [ \"$VCS_COMMITS_SINCE" <since "\" = \"\" ]; then\n" >
+            "echo \"Could not find environment variable VCS_COMMITS_SINCE" <since "\"\n"
+            "exit 1\n"
+        < "fi\n"
+    < "fi\n"
+    "FULL_VERSION=" x "-beta.$VCS_COMMITS_SINCE" <since "+$VCS_SHORT_ID\n"
+    "PROJECTS2_TAGS=', \"tags\": []'\n"
+};
 
-date = number '-' number '-' number;
+versionRelease = '### ' versionNumber:x ' (' date ')\n' -> {
+    "VERSION=" x "\n"
+    "FULL_VERSION=" x "\n"
+    "PROJECTS2_TAGS=', \"tags\": [\"" x "\"]'\n"
+};
+
+versionReleaseNumber = '### ' versionNumberUnderscore:x ' (' date ')\n' -> { x };
 
-restLine = notNewline* '\n';
+skip = codeBlock | restLine;
+    codeBlock = '```' restLine skipCodeBlock* '```\n';
+    skipCodeBlock = !'```\n' restLine;
+    restLine = notNewline* '\n';
     notNewline = !'\n' .;
 
+versionNumber = number '.' number '.' number;
+
+versionNumberUnderscore = number:x '.' number:y '.' number:z -> { x "_" y "_" z };
+
+date = number '-' number '-' number;
+
 number = digit digit*;
     digit = '0'-'9';
diff --git a/make.sh b/make.sh
index 807d75b..874062f 100755
--- a/make.sh
+++ b/make.sh
@@ -25,6 +25,8 @@ changelog2version <README.md >out/version.sh
 
 gcc -O2 out/changelog2version.c -o out/changelog2version
 
+diff <(out/changelog2version <tests/first_beta.md) tests/expected_first_beta.sh
+
 diff <(out/changelog2version <tests/beta.md) tests/expected_beta.sh
 
 diff <(out/changelog2version <tests/release.md) tests/expected_release.sh
diff --git a/tests/expected_beta.sh b/tests/expected_beta.sh
index d8d8468..14ccffb 100644
--- a/tests/expected_beta.sh
+++ b/tests/expected_beta.sh
@@ -1,3 +1,12 @@
 VERSION=1.2.3
-FULL_VERSION=1.2.3-beta.$YMD+$VCS_SHORT_ID
+if [ "$VCS_SHORT_ID" = "" ]; then
+    VCS_SHORT_ID=dev
+    VCS_COMMITS_SINCE=0
+else
+    if [ "$VCS_COMMITS_SINCE_1_2_2" = "" ]; then
+        echo "Could not find environment variable VCS_COMMITS_SINCE_1_2_2"
+        exit 1
+    fi
+fi
+FULL_VERSION=1.2.3-beta.$VCS_COMMITS_SINCE_1_2_2+$VCS_SHORT_ID
 PROJECTS2_TAGS=', "tags": []'
diff --git a/tests/expected_first_beta.sh b/tests/expected_first_beta.sh
new file mode 100644
index 0000000..40dcb8d
--- /dev/null
+++ b/tests/expected_first_beta.sh
@@ -0,0 +1,12 @@
+VERSION=1.2.2
+if [ "$VCS_SHORT_ID" = "" ]; then
+    VCS_SHORT_ID=dev
+    VCS_COMMITS_SINCE=0
+else
+    if [ "$VCS_COMMITS_SINCE" = "" ]; then
+        echo "Could not find environment variable VCS_COMMITS_SINCE"
+        exit 1
+    fi
+fi
+FULL_VERSION=1.2.2-beta.$VCS_COMMITS_SINCE+$VCS_SHORT_ID
+PROJECTS2_TAGS=', "tags": []'
diff --git a/tests/first_beta.md b/tests/first_beta.md
new file mode 100644
index 0000000..a44a3a5
--- /dev/null
+++ b/tests/first_beta.md
@@ -0,0 +1,5 @@
+## Changelog
+
+### 1.2.2
+
+* Added feature Y

2026-01-10 19:17 Rickard pushed to changelog2version

commit 07e8e736c54c5d6591bb6f98df422bdc97c62395
Author: Rickard Lindberg <rickard@rickardlindberg.me>
Date:   Sat Jan 10 19:16:53 2026 +0100

    Fix grammar

diff --git a/README.md b/README.md
index d44620d..57f2d1b 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ It will generate `version.sh` like this:
 
 ```:tests/expected_release.sh
 
-`version.sh` is typically sourced from a build script to gain access the
+`version.sh` is typically sourced from a build script to gain access to the
 variables.
 
 ## How to make a release

2026-01-10 19:14 Rickard pushed to changelog2version

commit 4d062e0caa9f79223b4cea1260c25bbece041800
Author: Rickard Lindberg <rickard@rickardlindberg.me>
Date:   Sat Jan 10 19:13:33 2026 +0100

    Better documentation

diff --git a/README.md b/README.md
index f2c8522..d44620d 100644
--- a/README.md
+++ b/README.md
@@ -10,43 +10,30 @@ changelog2version <README.md >version.sh
 
 With a `README.md` like this:
 
-```markup
-## Changelog
-
-### 1.0.0 (2026-01-10)
-```
+```:tests/beta.md
 
-It will generate this:
+It will generate `version.sh` like this:
 
-```sh
-VERSION=1.0.0
-FULL_VERSION=1.0.0
-```
+```:tests/expected_beta.sh
 
 With a `README.md` like this:
 
-```markup
-## Changelog
-
-### 1.1.0
+```:tests/release.md
 
-### 1.0.0 (2026-01-10)
-```
+It will generate `version.sh` like this:
 
-It will generate this:
+```:tests/expected_release.sh
 
-```sh
-VERSION=1.1.0
-FULL_VERSION=1.1.0-beta.$YMD+$VCS_SHORT_ID
-```
+`version.sh` is typically sourced from a build script to gain access the
+variables.
 
 ## How to make a release
 
 The process for making a release of a piece of software that uses
-`changelog2version` in and
+`changelog2version` and
 [projects2](https://projects.rickardlindberg.me/projects2/) is this:
 
-1. Add a date to the current version number in the changelog
+1. Add a date to the current version in the changelog
 2. Commit and push that
    * This will create the release
    * This will print instructions how to tag the commit
diff --git a/make.sh b/make.sh
index 875a81d..807d75b 100755
--- a/make.sh
+++ b/make.sh
@@ -25,30 +25,6 @@ changelog2version <README.md >out/version.sh
 
 gcc -O2 out/changelog2version.c -o out/changelog2version
 
-echo_beta() {
-    echo '## Changelog'
-    echo ''
-    echo '### 1.2.3'
-}
-
-expected_beta() {
-    echo 'VERSION=1.2.3'
-    echo 'FULL_VERSION=1.2.3-beta.$YMD+$VCS_SHORT_ID'
-    echo "PROJECTS2_TAGS=', \"tags\": []'"
-}
-
-diff <(echo_beta | out/changelog2version) <(expected_beta)
-
-echo_release() {
-    echo '## Changelog'
-    echo ''
-    echo '### 1.2.3 (2026-01-10)'
-}
-
-expected_release() {
-    echo 'VERSION=1.2.3'
-    echo 'FULL_VERSION=1.2.3'
-    echo "PROJECTS2_TAGS=', \"tags\": [\"1.2.3\"]'"
-}
-
-diff <(echo_release | out/changelog2version) <(expected_release)
+diff <(out/changelog2version <tests/beta.md) tests/expected_beta.sh
+
+diff <(out/changelog2version <tests/release.md) tests/expected_release.sh
diff --git a/tests/beta.md b/tests/beta.md
new file mode 100644
index 0000000..f11f0f7
--- /dev/null
+++ b/tests/beta.md
@@ -0,0 +1,9 @@
+## Changelog
+
+### 1.2.3
+
+* Added feature Y
+
+### 1.2.2 (2026-01-05)
+
+* Added feature X
diff --git a/tests/expected_beta.sh b/tests/expected_beta.sh
new file mode 100644
index 0000000..d8d8468
--- /dev/null
+++ b/tests/expected_beta.sh
@@ -0,0 +1,3 @@
+VERSION=1.2.3
+FULL_VERSION=1.2.3-beta.$YMD+$VCS_SHORT_ID
+PROJECTS2_TAGS=', "tags": []'
diff --git a/tests/expected_release.sh b/tests/expected_release.sh
new file mode 100644
index 0000000..705b83f
--- /dev/null
+++ b/tests/expected_release.sh
@@ -0,0 +1,3 @@
+VERSION=1.2.3
+FULL_VERSION=1.2.3
+PROJECTS2_TAGS=', "tags": ["1.2.3"]'
diff --git a/tests/release.md b/tests/release.md
new file mode 100644
index 0000000..8028b60
--- /dev/null
+++ b/tests/release.md
@@ -0,0 +1,9 @@
+## Changelog
+
+### 1.2.3 (2026-01-10)
+
+* Added feature Y
+
+### 1.2.2 (2026-01-05)
+
+* Added feature X
diff --git a/website.sh b/website.sh
index f567268..a04d54c 100755
--- a/website.sh
+++ b/website.sh
@@ -2,7 +2,7 @@
 
 set -e -x
 
-MARKUP2WEBSITE_VERSION=1.1.0
+MARKUP2WEBSITE_VERSION=1.2.0
 MARKUP2WEBSITE_FOLDER_NAME=markup2website-$MARKUP2WEBSITE_VERSION
 MARKUP2WEBSITE_ARCHIVE=https://projects.rickardlindberg.me/artifacts/markup2website/$MARKUP2WEBSITE_VERSION/$MARKUP2WEBSITE_FOLDER_NAME.tgz
 

2026-01-10 15:37 Rickard pushed to changelog2version

commit 89c0b4911ed4490cf762ec7cbb367e62fceaa225
Author: Rickard Lindberg <rickard@rickardlindberg.me>
Date:   Sat Jan 10 15:37:30 2026 +0100

    Document how to make a release

diff --git a/README.md b/README.md
index a9537c5..f2c8522 100644
--- a/README.md
+++ b/README.md
@@ -40,6 +40,18 @@ VERSION=1.1.0
 FULL_VERSION=1.1.0-beta.$YMD+$VCS_SHORT_ID
 ```
 
+## How to make a release
+
+The process for making a release of a piece of software that uses
+`changelog2version` in and
+[projects2](https://projects.rickardlindberg.me/projects2/) is this:
+
+1. Add a date to the current version number in the changelog
+2. Commit and push that
+   * This will create the release
+   * This will print instructions how to tag the commit
+3. Add the next version in the changelog to start work on that version
+
 ## Changelog
 
 ### 1.2.0

2026-01-10 15:31 Rickard pushed to changelog2version

commit 58e4c1e70cc168757e594d9a52f2abdfe7b92400
Author: Rickard Lindberg <rickard@rickardlindberg.me>
Date:   Sat Jan 10 15:30:49 2026 +0100

    Clean up

diff --git a/README.md b/README.md
index d2e9a6b..a9537c5 100644
--- a/README.md
+++ b/README.md
@@ -42,6 +42,8 @@ FULL_VERSION=1.1.0-beta.$YMD+$VCS_SHORT_ID
 
 ## Changelog
 
+### 1.2.0
+
 ### 1.1.0 (2026-01-10)
 
 * Can skip code blocks when searching for changelog
diff --git a/make.sh b/make.sh
index e93e748..875a81d 100755
--- a/make.sh
+++ b/make.sh
@@ -4,16 +4,25 @@ set -e -x
 
 RLWORKBENCH_VERSION=1.1.0
 RLWORKBENCH_FOLDER_NAME=rlworkbench-$RLWORKBENCH_VERSION
-RLWORKBENCH_ARCHIVE_NAME=$RLWORKBENCH_FOLDER_NAME.tgz
+RLWORKBENCH_ARCHIVE=https://projects.rickardlindberg.me/artifacts/rlworkbench/$RLWORKBENCH_VERSION/$RLWORKBENCH_FOLDER_NAME.tgz
+
+CHANGELOG2VERSION_VERSION=1.1.0
+CHANGELOG2VERSION_FOLDER_NAME=changelog2version-$CHANGELOG2VERSION_VERSION
+CHANGELOG2VERSION_ARCHIVE=https://projects.rickardlindberg.me/artifacts/changelog2version/$CHANGELOG2VERSION_VERSION/$CHANGELOG2VERSION_FOLDER_NAME.tgz
 
 rm -rf out
 mkdir out
 
-curl https://projects.rickardlindberg.me/artifacts/rlworkbench/$RLWORKBENCH_VERSION/$RLWORKBENCH_ARCHIVE_NAME | tar xzvv -C out
+curl $RLWORKBENCH_ARCHIVE | tar xzvv -C out
+
+curl $CHANGELOG2VERSION_ARCHIVE | tar xzvv -C out
 
-PATH="out/$RLWORKBENCH_FOLDER_NAME:$PATH"
+PATH="out/$RLWORKBENCH_FOLDER_NAME:out/$CHANGELOG2VERSION_FOLDER_NAME:$PATH"
 
 rlworkbench_cli run changelog2version.meta >out/changelog2version.c
+
+changelog2version <README.md >out/version.sh
+
 gcc -O2 out/changelog2version.c -o out/changelog2version
 
 echo_beta() {
diff --git a/release.sh b/release.sh
index aa9e816..fd9bc37 100755
--- a/release.sh
+++ b/release.sh
@@ -4,17 +4,15 @@ set -e -x
 
 ./make.sh
 
-out/changelog2version <README.md >out/version.sh
-
 source out/version.sh
 
 FOLDER_NAME=changelog2version-$FULL_VERSION
-TARGET=out/$FOLDER_NAME
+TARGET=out/release/$FOLDER_NAME
 ARCHIVE_NAME=$FOLDER_NAME.tgz
 
-mkdir $TARGET
+mkdir -p $TARGET
 cp out/changelog2version $TARGET
 
-(cd out && tar czvvf $ARCHIVE_NAME $FOLDER_NAME)
+(cd out/release && tar czvvf $ARCHIVE_NAME $FOLDER_NAME)
 
-echo "{\"artifacts\": [{\"source\": \"out/$ARCHIVE_NAME\", \"destination\": \"$VERSION/$ARCHIVE_NAME\"}]}" > Dockerfile.release.ci.files
+echo "{\"artifacts\": [{\"source\": \"out/release/$ARCHIVE_NAME\", \"destination\": \"$VERSION/$ARCHIVE_NAME\"}]}" > Dockerfile.release.ci.files

2026-01-10 14:11 Rickard pushed to changelog2version

commit 85d93c49bf073794ce6227d888d7a0a6d6ba6fd2
Author: Rickard Lindberg <rickard@rickardlindberg.me>
Date:   Sat Jan 10 14:11:11 2026 +0100

    Release 1.1.0

diff --git a/README.md b/README.md
index 0a12b0c..d2e9a6b 100644
--- a/README.md
+++ b/README.md
@@ -42,7 +42,7 @@ FULL_VERSION=1.1.0-beta.$YMD+$VCS_SHORT_ID
 
 ## Changelog
 
-### 1.1.0
+### 1.1.0 (2026-01-10)
 
 * Can skip code blocks when searching for changelog
 * Generate `PROJECTS2_TAGS`