From d8cf76a9efe367bc704f55ffa8da46d5dab74816 Mon Sep 17 00:00:00 2001
From: delehef <github@odena.eu>
Date: Sat, 25 Jan 2025 02:17:17 +0200
Subject: [PATCH] ci: add a release pipeline (#440)

---
 .github/changelog.sh                  |  9 +++
 .github/workflows/prepare-release.yml | 33 ++++++++++
 .github/workflows/release.yml         | 20 ++++++
 CHANGELOG.md                          |  0
 Cargo.toml                            |  4 ++
 VERSION                               |  0
 cliff.toml                            | 93 +++++++++++++++++++++++++++
 gnark-utils/Cargo.toml                |  2 +-
 groth16-framework/Cargo.toml          | 12 ++--
 inspect/Cargo.toml                    |  6 +-
 mp2-common/Cargo.toml                 |  4 +-
 mp2-test/Cargo.toml                   |  8 +--
 mp2-v1/Cargo.toml                     | 16 ++---
 parsil/Cargo.toml                     |  6 +-
 recursion-framework/Cargo.toml        |  4 +-
 ryhope/Cargo.toml                     |  2 +-
 verifiable-db/Cargo.toml              | 10 +--
 17 files changed, 194 insertions(+), 35 deletions(-)
 create mode 100755 .github/changelog.sh
 create mode 100644 .github/workflows/prepare-release.yml
 create mode 100644 .github/workflows/release.yml
 create mode 100644 CHANGELOG.md
 create mode 100644 VERSION
 create mode 100644 cliff.toml

diff --git a/.github/changelog.sh b/.github/changelog.sh
new file mode 100755
index 000000000..a05c68461
--- /dev/null
+++ b/.github/changelog.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+#
+# This is a hack to palliate the fact that cargo-release runs the pre-release
+# hook once for each crate, instead of only once for the whole workspace.
+# Calling git-cliff multiple times with the same argument is idempotent, so we
+# call it with settings generating the workspace-level changelog once for every
+# crate.
+git-cliff -o $WORKSPACE_ROOT/CHANGELOG.md --tag $NEW_VERSION -w $WORKSPACE_ROOT
+echo $NEW_VERSION > $WORKSPACE_ROOT/VERSION
diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml
new file mode 100644
index 000000000..d4ff98301
--- /dev/null
+++ b/.github/workflows/prepare-release.yml
@@ -0,0 +1,33 @@
+name: Open a release PR
+on:
+  workflow_dispatch:
+    inputs:
+      bump:
+        description: Release Level
+        required: true
+        type: choice
+        options:
+          - patch
+          - minor
+          - major
+
+jobs:
+  make-release-pr:
+    permissions:
+      id-token: write
+      pull-requests: write
+      contents: write
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - uses: chainguard-dev/actions/setup-gitsign@main
+      - name: Install tooling
+        uses: taiki-e/install-action@v2
+        with:
+          tool: cargo-release,git-cliff
+      - uses: cargo-bins/release-pr@v2
+        with:
+          version: ${{ inputs.bump }}
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+          # Keep all the crates versions in sync
+          crate-release-all: true
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 000000000..cb73e0e4d
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,20 @@
+name: Create Release
+
+on:
+  push:
+    branches:
+      - main
+
+jobs:
+  create-release:
+    runs-on: ubuntu-latest
+    if: contains( github.event.head_commit.message, 'release:' )
+    steps:
+      - uses: actions/checkout@v4
+      - name: Get version
+        id: set-tag
+        run:  echo "tag=$(cat VERSION)" >> $GITHUB_OUTPUT
+      - uses: ncipollo/release-action@v1
+        with:
+          commit: "main"
+          tag: ${{ steps.set-tag.outputs.tag }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 000000000..e69de29bb
diff --git a/Cargo.toml b/Cargo.toml
index 9436c46a4..d6af4c21f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -121,3 +121,7 @@ lto = "fat"
 plonky2 = { git = "https://github.com/Lagrange-Labs/plonky2", branch = "upstream" }
 plonky2_monolith = { git = "https://github.com/Lagrange-Labs/monolith" }
 plonky2_field = { git = "https://github.com/Lagrange-Labs/plonky2", branch = "upstream" }
+
+[workspace.metadata.release]
+publish = false
+pre-release-hook = ["sh", "../.github/changelog.sh"]
diff --git a/VERSION b/VERSION
new file mode 100644
index 000000000..e69de29bb
diff --git a/cliff.toml b/cliff.toml
new file mode 100644
index 000000000..17056bfa3
--- /dev/null
+++ b/cliff.toml
@@ -0,0 +1,93 @@
+# git-cliff ~ default configuration file
+# https://git-cliff.org/docs/configuration
+#
+# Lines starting with "#" are comments.
+# Configuration options are organized into tables and keys.
+# See documentation for more information on available options.
+
+[changelog]
+# template for the changelog header
+header = """
+# Changelog\n
+"""
+# template for the changelog body
+# https://keats.github.io/tera/docs/#introduction
+body = """
+{% if version %}\
+    ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
+{% else %}\
+    ## [unreleased]
+{% endif %}\
+{% if previous %}\
+    {% if previous.commit_id and commit_id %}
+        [{{ previous.commit_id | truncate(length=7, end="") }}]({{ previous.commit_id }})...\
+            [{{ commit_id | truncate(length=7, end="") }}]({{ commit_id }})
+    {% endif %}\
+{% endif %}\
+{% for group, commits in commits | group_by(attribute="group") %}
+    ### {{ group | striptags | trim | upper_first }}
+    {% for commit in commits | filter(attribute="scope") | sort(attribute="scope") %}
+        - {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
+            {% if commit.breaking %}[**breaking**] {% endif %}\
+            {{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ commit.id }}))\\
+    {% endfor %}
+     {% raw %}\n{% endraw %}\
+    {%- for commit in commits %}
+        - {{ commit.message | upper_first }}
+    {% endfor -%}
+    {% raw %}\n{% endraw %}\
+{% endfor %}\n
+"""
+# template for the changelog footer
+footer = """
+<!-- generated by git-cliff -->
+"""
+# remove the leading and trailing s
+trim = true
+# postprocessors
+postprocessors = [
+  # { pattern = '<REPO>', replace = "https://github.com/orhun/git-cliff" }, # replace repository URL
+]
+# render body even when there are no releases to process
+# render_always = true
+# output file path
+# output = "test.md"
+
+[git]
+# parse the commits based on https://www.conventionalcommits.org
+conventional_commits = true
+# filter out the commits that are not conventional
+filter_unconventional = true
+# process each line of a commit as an individual commit
+split_commits = false
+# regex for preprocessing the commit messages
+commit_preprocessors = [
+  # Replace issue numbers
+  #{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](<REPO>/issues/${2}))"},
+  # Check spelling of the commit with https://github.com/crate-ci/typos
+  # If the spelling is incorrect, it will be automatically fixed.
+  #{ pattern = '.*', replace_command = 'typos --write-changes -' },
+]
+# regex for parsing and grouping commits
+commit_parsers = [
+  { message = "^feat", group = "<!-- 0 -->Features" },
+  { message = "^fix", group = "<!-- 1 -->Bug Fixes" },
+  { message = "^doc", group = "<!-- 3 -->Documentation" },
+  { message = "^perf", group = "<!-- 4 -->Performance" },
+  { message = "^refactor", group = "<!-- 2 -->Refactor" },
+  { message = "^style", group = "<!-- 5 -->Styling" },
+  { message = "^test", group = "<!-- 6 -->Testing" },
+  { message = "^chore\\(release\\): prepare for", skip = true },
+  { message = "^chore\\(deps.*\\)", skip = true },
+  { message = "^chore\\(pr\\)", skip = true },
+  { message = "^chore\\(pull\\)", skip = true },
+  { message = "^chore|^ci", group = "<!-- 7 -->Miscellaneous Tasks" },
+  { body = ".*security", group = "<!-- 8 -->Security" },
+  { message = "^revert", group = "<!-- 9 -->Revert" },
+]
+# filter out the commits that are not matched by commit parsers
+filter_commits = false
+# sort the tags topologically
+topo_order = false
+# sort the commits inside sections by oldest/newest order
+sort_commits = "oldest"
diff --git a/gnark-utils/Cargo.toml b/gnark-utils/Cargo.toml
index ec0f0d2f8..a0f039e28 100644
--- a/gnark-utils/Cargo.toml
+++ b/gnark-utils/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "gnark-utils"
-version = "0.1.0"
+version = "1.1.3"
 edition = "2021"
 
 [build-dependencies]
diff --git a/groth16-framework/Cargo.toml b/groth16-framework/Cargo.toml
index 7922499e1..51a77220d 100644
--- a/groth16-framework/Cargo.toml
+++ b/groth16-framework/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "groth16_framework"
-version = "0.1.0"
+version = "1.1.3"
 edition = "2021"
 
 [dependencies]
@@ -14,8 +14,8 @@ revm.workspace = true
 serde.workspace = true
 serde_json.workspace = true
 
-gnark-utils = { path = "../gnark-utils" }
-mp2_common = { path = "../mp2-common" }
+gnark-utils = { path = "../gnark-utils" , version = "1.1.3" }
+mp2_common = { path = "../mp2-common" , version = "1.1.3" }
 
 [dev-dependencies]
 env_logger.workspace = true
@@ -23,7 +23,7 @@ itertools.workspace = true
 rand.workspace = true
 serial_test.workspace = true
 sha2.workspace = true
-mp2_test = { path = "../mp2-test" }
+mp2_test = { path = "../mp2-test" , version = "1.1.3" }
 
-recursion_framework = { path = "../recursion-framework" }
-verifiable-db = { path = "../verifiable-db" }
+recursion_framework = { path = "../recursion-framework" , version = "1.1.3" }
+verifiable-db = { path = "../verifiable-db" , version = "1.1.3" }
diff --git a/inspect/Cargo.toml b/inspect/Cargo.toml
index 5200c87bf..4f3f35e58 100644
--- a/inspect/Cargo.toml
+++ b/inspect/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "inspect"
-version = "0.1.0"
+version = "1.1.3"
 edition = "2021"
 
 [dependencies]
@@ -14,5 +14,5 @@ serde.workspace = true
 tabled.workspace = true
 tokio.workspace = true
 
-ryhope = { path = "../ryhope" }
-mp2_v1 = { path = "../mp2-v1" }
+ryhope = { path = "../ryhope" , version = "1.1.3" }
+mp2_v1 = { path = "../mp2-v1" , version = "1.1.3" }
diff --git a/mp2-common/Cargo.toml b/mp2-common/Cargo.toml
index 2ca2673a0..c8906e887 100644
--- a/mp2-common/Cargo.toml
+++ b/mp2-common/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "mp2_common"
-version = "0.1.0"
+version = "1.1.3"
 edition = "2021"
 
 [dependencies]
@@ -33,7 +33,7 @@ rand.workspace = true
 rstest.workspace = true
 tokio.workspace = true
 
-mp2_test = { path = "../mp2-test" }
+mp2_test = { path = "../mp2-test" , version = "1.1.3" }
 
 [features]
 ci = ["mp2_test/ci"]
diff --git a/mp2-test/Cargo.toml b/mp2-test/Cargo.toml
index e4fd7ddbb..da862bd79 100644
--- a/mp2-test/Cargo.toml
+++ b/mp2-test/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "mp2_test"
-version = "0.1.0"
+version = "1.1.3"
 edition = "2021"
 
 [dependencies]
@@ -14,9 +14,9 @@ plonky2_ecgfp5.workspace = true
 rand.workspace = true
 serde.workspace = true
 
-mp2_common = { path = "../mp2-common" }
-recursion_framework = { path = "../recursion-framework" }
-ryhope = { path = "../ryhope" }
+mp2_common = { path = "../mp2-common" , version = "1.1.3" }
+recursion_framework = { path = "../recursion-framework" , version = "1.1.3" }
+ryhope = { path = "../ryhope" , version = "1.1.3" }
 
 [features]
 ci = []
diff --git a/mp2-v1/Cargo.toml b/mp2-v1/Cargo.toml
index d7b9b3856..60430962d 100644
--- a/mp2-v1/Cargo.toml
+++ b/mp2-v1/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "mp2_v1"   # TODO: fix the name to a meaningful one.
-version = "0.1.0"
+version = "1.1.3"
 edition = "2021"
 
 [dependencies]
@@ -27,11 +27,11 @@ serde_json.workspace = true
 tokio-postgres.workspace = true
 tracing.workspace = true
 
-mp2_common = { path = "../mp2-common" }
-recursion_framework = { path = "../recursion-framework" }
-ryhope = { path = "../ryhope" }
-parsil = { path = "../parsil" }
-verifiable-db = { path = "../verifiable-db" }
+mp2_common = { path = "../mp2-common" , version = "1.1.3" }
+recursion_framework = { path = "../recursion-framework" , version = "1.1.3" }
+ryhope = { path = "../ryhope" , version = "1.1.3" }
+parsil = { path = "../parsil" , version = "1.1.3" }
+verifiable-db = { path = "../verifiable-db" , version = "1.1.3" }
 
 [dev-dependencies]
 alloy.workspace = true
@@ -54,8 +54,8 @@ testfile.workspace = true
 tokio-postgres.workspace = true
 tokio.workspace = true
 
-mp2_test = { path = "../mp2-test" }
-parsil = { path = "../parsil" }
+mp2_test = { path = "../mp2-test" , version = "1.1.3" }
+parsil = { path = "../parsil" , version = "1.1.3" }
 
 [features]
 original_poseidon = ["mp2_common/original_poseidon"]
diff --git a/parsil/Cargo.toml b/parsil/Cargo.toml
index e899a11d1..ae87b450d 100644
--- a/parsil/Cargo.toml
+++ b/parsil/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "parsil"
-version = "0.1.0"
+version = "1.1.3"
 edition = "2021"
 
 [lib]
@@ -24,8 +24,8 @@ sqlparser.workspace = true
 stderrlog = { workspace = true, optional = true }
 thiserror.workspace = true
 
-ryhope = { path = "../ryhope" }
-verifiable-db = { path = "../verifiable-db" }
+ryhope = { path = "../ryhope" , version = "1.1.3" }
+verifiable-db = { path = "../verifiable-db" , version = "1.1.3" }
 
 [features]
 cli = ["dep:stderrlog", "dep:clap"]
diff --git a/recursion-framework/Cargo.toml b/recursion-framework/Cargo.toml
index 0552c3477..15a564006 100644
--- a/recursion-framework/Cargo.toml
+++ b/recursion-framework/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "recursion_framework"
-version = "0.1.0"
+version = "1.1.3"
 edition = "2021"
 
 [dependencies]
@@ -9,7 +9,7 @@ log.workspace = true
 plonky2.workspace = true
 serde.workspace = true
 
-mp2_common = { path = "../mp2-common" }
+mp2_common = { path = "../mp2-common" , version = "1.1.3" }
 
 [dev-dependencies]
 bincode.workspace = true
diff --git a/ryhope/Cargo.toml b/ryhope/Cargo.toml
index ce9e7bfea..93280168f 100644
--- a/ryhope/Cargo.toml
+++ b/ryhope/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "ryhope"
-version = "0.1.0"
+version = "1.1.3"
 edition = "2021"
 
 [lib]
diff --git a/verifiable-db/Cargo.toml b/verifiable-db/Cargo.toml
index 8b50d33d5..1c1c1618f 100644
--- a/verifiable-db/Cargo.toml
+++ b/verifiable-db/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "verifiable-db"
-version = "0.1.0"
+version = "1.1.3"
 edition = "2021"
 
 [dependencies]
@@ -17,10 +17,10 @@ plonky2_ecgfp5.workspace = true
 rand.workspace = true
 serde.workspace = true
 
-mp2_common = { path = "../mp2-common" }
-recursion_framework = { path = "../recursion-framework" }
-ryhope = { path = "../ryhope" }
-mp2_test = { path = "../mp2-test" }
+mp2_common = { path = "../mp2-common" , version = "1.1.3" }
+recursion_framework = { path = "../recursion-framework" , version = "1.1.3" }
+ryhope = { path = "../ryhope" , version = "1.1.3" }
+mp2_test = { path = "../mp2-test" , version = "1.1.3" }
 
 [dev-dependencies]
 futures.workspace = true