Repository: ObolNetwork/charon

Issue:
Improve our release process
# 🎯 Problem to be solved
Currently our release process is quite outdated, created couple of years ago. It would be good to update it with the most up-to-date developments in Charon.

# 🛠️ Proposed solution
- [x] We have a design doc where all the steps for a release are outlined, but it's more than 2 years old, pre-v1. It would be better to have a new updated doc that also encompasses the steps for minor and patch releases.
- [x] Second improvement of our release process would be to have template for our release notes. Currently it's more or less freestyle of how we structure them, but it will be easier for us and the users if there is some systematic structure.
- [x] What will speed up a lot the process is having automated Kurtosis testing for tagged versions. Currently we are working on deploying those tests on k8s in order to streamline multiple deployments. Once we are comfortable with this, it would be relatively easy to plug that into the pipelines.


Hints from issue comments:

Solution patch:
diff --git a/testutil/genchangelog/template.md b/testutil/genchangelog/template.md
index 2860e423..db20f8e9 100644
--- a/testutil/genchangelog/template.md
+++ b/testutil/genchangelog/template.md
@@ -2,7 +2,9 @@
 
 ![Obol Logo](https://obol.tech/obolnetwork.png)
 
-This release introduces general fixes and improvements including progress on great new features.
+<!-- TODO: Add resume of the release in free text -->
+
+Read the rest of the release notes for more:
 
 **Full Changelog**: [{{.RangeText}}]({{.RangeLink}})
 {{range .Categories}}
@@ -11,6 +13,27 @@ This release introduces general fixes and improvements including progress on gre
 - {{.Title}} {{.Label}} ({{range $i, $v := .PRs}}{{if $i}},{{end}}{{$v.Label}}{{end}})
   {{- end}}
 {{end}}
+## Compatibility Matrix
+
+<!-- TODO: Update versions with which this version is compatible -->
+This release of Charon is backwards compatible with Charon v1.0, v1.1, v1.2.
+
+The below matrix details a combination of beacon node (consensus layer) + validator clients and their corresponding versions the DV Labs team have tested with this Charon release. More validator and consensus client will be added to this list as they are supported in our automated testing framework.
+
+**Legend**
+- ✅: All duties succeed in testing
+- 🟡: All duties succeed in testing, except non-penalised aggregation duties
+- 🟠: Duties may fail for this combination
+- 🔴: One or more duties fails consistently
+
+<!-- TODO: Update clients versions, results and remarks -->
+| Validator 👉 Consensus 👇 | Teku v25.3.0 | Lighthouse v7.0.0 | Lodestar v1.28.1 | Nimbus v25.3.1 | Prysm v5.3.1 | Remarks |
+|---------------------------|--------------|-------------------|------------------|----------------|--------------|---------|
+| Teku v25.3.0              |       ✅     |         ✅        |        ✅        |       ✅       |       ✅     |         |
+| Lighthouse v7.0.0         |       ✅     |         ✅        |        ✅        |       ✅       |       ✅     |         |
+| Lodestar v1.28.1          |       ✅     |         ✅        |        ✅        |       ✅       |       ✅     |         |
+| Nimbus v25.3.1            |       ✅     |         ✅        |        ✅        |       ✅       |       ✅     |         |
+| Prysm v5.3.1              |       ✅     |         ✅        |        ✅        |       ✅       |       ✅     |         |
 
 ## What's Changed
 {{range .ExtraPRs}}



Test patch:
diff --git a/core/fetcher/graffiti_internal_test.go b/core/fetcher/graffiti_internal_test.go
index 71ea80fd..43ccdaab 100644
--- a/core/fetcher/graffiti_internal_test.go
+++ b/core/fetcher/graffiti_internal_test.go
@@ -22,21 +22,21 @@ func TestFetchBeaconNodeToken(t *testing.T) {
 		eth2Cl := mocks.NewClient(t)
 		eth2Cl.On("NodeVersion", mock.Anything, mock.Anything).Return(nil, errors.New("")).Once()
 		token := fetchBeaconNodeToken(eth2Cl)
-		require.Equal(t, "", token)
+		require.Empty(t, token)
 	})
 
 	t.Run("fetch token unexpected response", func(t *testing.T) {
 		eth2Cl := mocks.NewClient(t)
 		eth2Cl.On("NodeVersion", mock.Anything, mock.Anything).Return(&eth2api.Response[string]{Data: "IncorrectUserAgent"}, nil).Once()
 		token := fetchBeaconNodeToken(eth2Cl)
-		require.Equal(t, "", token)
+		require.Empty(t, token)
 	})
 
 	t.Run("fetch token not predicted in map", func(t *testing.T) {
 		eth2Cl := mocks.NewClient(t)
 		eth2Cl.On("NodeVersion", mock.Anything, mock.Anything).Return(&eth2api.Response[string]{Data: "Dune/v1.3 (Windows)"}, nil).Once()
 		token := fetchBeaconNodeToken(eth2Cl)
-		require.Equal(t, "", token)
+		require.Empty(t, token)
 	})
 
 	t.Run("fetch token", func(t *testing.T) {
diff --git a/testutil/genchangelog/main.go b/testutil/genchangelog/main.go
index d0656d4b..9413e65c 100644
--- a/testutil/genchangelog/main.go
+++ b/testutil/genchangelog/main.go
@@ -377,6 +377,11 @@ func prFromLog(l log) (pullRequest, bool) {
 		return pullRequest{}, false
 	}
 
+	if strings.Contains(l.Subject, "chore(deps)") {
+		fmt.Printf("Skipping renovate PR (%s): %s\n", l.Commit, l.Subject)
+		return pullRequest{}, false
+	}
+
 	var ok bool
 
 	pr := pullRequest{