diff --git a/documentation/misc/RELEASE_ISSUE_TEMPLATE.md b/documentation/misc/RELEASE_ISSUE_TEMPLATE.md new file mode 100644 index 000000000..df5e8d1c5 --- /dev/null +++ b/documentation/misc/RELEASE_ISSUE_TEMPLATE.md @@ -0,0 +1,115 @@ +> Release Issue Template + +# Lotus X.Y.Z Release + +We're happy to announce Lotus X.Y.Z... + +## 🗺 Must-dos for the release + +## 🌟 Nice-to-haves for the release + + + +## 🚢 Estimated shipping date + + + +## 🔦 Highlights + +< top highlights for this release notes > + +## ✅ Release Checklist + +First steps: + + - [ ] Fork a new branch (`release/vX.Y.Z`) from `master` and make any further release related changes to this branch. If any "non-trivial" changes get added to the release, uncheck all the checkboxes and return to this stage. + - [ ] Prep the changelog using `scripts/mkreleaselog`, and add it to `CHANGELOG.md` + - [ ] Bump the version in `version.go` in the `master` branch to `vX.(Y+1).0-dev`. + +Prepping an RC: + +- [ ] version string in `build/version.go` has been updated (in the `release/vX.Y.Z` branch). +- [ ] tag commit with `vX.Y.Z-rcN` +- [ ] cut a pre-release [here](https://github.com/filecoin-project/lotus/releases/new?prerelease=true) + +Testing an RC: + +- [ ] **Stage 0 - Automated Testing** + - Automated Testing + - [ ] CI: Ensure that all tests are passing. + - [ ] Testground tests + +- [ ] **Stage 1 - Internal Testing** + - Upgrade our testnet infra + - [ ] 1 bootstrap node + - [ ] 1 miner + - [ ] Scratch nodes + - [ ] Wait 24 hours, confirm nodes stay in sync + - [ ] Remaining testnet infra + - Upgrade our mainnet infra + - [ ] Subset of development full archival nodes + - [ ] Subset of bootstrappers (1 per region) + - [ ] Confirm nodes stay in sync + - Metrics report + - Block validation time + - Memory / CPU usage + - Number of goroutines + - IPLD block read latency + - Bandwidth usage + - [ ] If anything has worsened significantly, investigate + fix + - Confirm the following work (some combination of Testground / Calibnet / Mainnet / beta users) + - [ ] Seal a sector + - [ ] make a deal + - [ ] Submit a PoSt + - [ ] (optional) let a sector go faulty, and see it be recovered + +- [ ] **Stage 2 - Community Testing** + - [ ] Inform beta miners (@lotus-early-testers-miner in Filecoin Slack #fil-lotus) + - [ ] Ask close ecosystem partners to test their projects (@lotus-early-testers-eco-dev in Filecoin slack #fil-lotus) + - [ ] Powergate + - [ ] Glif + - [ ] Zondax + - [ ] Stats dashboard + - [ ] Community dashboards + - [ ] Infura + - [ ] Sentinel + - [ ] Protofire + - [ ] Fleek + +- [ ] **Stage 3 - Community Prod Testing** + - [ ] Documentation + - [ ] Ensure that [CHANGELOG.md](https://github.com/filecoin-project/lotus/blob/master/CHANGELOG.md) is up to date + - [ ] Check if any [config](https://docs.filecoin.io/get-started/lotus/configuration-and-advanced-usage/#configuration) updates are needed + - [ ] Invite the wider community through (link to the release issue): + - [ ] Create a lotus disucssion, example [here](https://github.com/filecoin-project/lotus/discussions/5595) + - [ ] Link the disucssion in #fil-lotus on Filecoin slack + +- [ ] **Stage 4 - Release** + - [ ] Final preparation + - [ ] Verify that version string in [`version.go`](https://github.com/ipfs/go-ipfs/tree/master/version.go) has been updated. + - [ ] Ensure that [CHANGELOG.md](https://github.com/filecoin-project/lotus/blob/master/CHANGELOG.md) is up to date + - [ ] Ensure that [README.md](https://github.com/filecoin-project/lotus/blob/master/README.md) is up to date + - [ ] Merge `release-vX.Y.Z` into the `releases` branch. + - [ ] Tag this merge commit (on the `releases` branch) with `vX.Y.Z`. + - [ ] Cut the release [here](https://github.com/filecoin-project/lotus/releases/new?prerelease=true&target=releases). + - [ ] Final announcements + - [ ] Update network.filecoin.io for mainnet, calib and nerpa. + - [ ] Add a comment when the final release is tagged, example [here](https://github.com/filecoin-project/lotus/discussions/5905#discussioncomment-571752) + - [ ] repost in #fil-lotus in filecoin slack + - [ ] Inform node provides (Protofire, Digital Ocean..) + +- [ ] **Post-Release** + - [ ] Merge the `releases` branch back into `master`, ignoring the changes to `version.go` (keep the `-dev` version from master). + - [ ] Create an issue using this release issue template for the _next_ release. + +## ❤️ Contributors + +< list generated by scripts/mkreleaselog > + +Would you like to contribute to Lotus and don't know how? Well, there are a few places you can get started: + +- TODO + +## ⁉️ Do you have questions? + +Leave a comment [here]() if you have any questions. diff --git a/scripts/mkreleaselog b/scripts/mkreleaselog new file mode 100755 index 000000000..ffc3d935e --- /dev/null +++ b/scripts/mkreleaselog @@ -0,0 +1,248 @@ +#!/bin/zsh +set -x +set -euo pipefail +export GO111MODULE=on +export GOPATH="$(go env GOPATH)" + +alias jq="jq --unbuffered" + +AUTHORS=( + # orgs + ipfs + ipld + libp2p + multiformats + filecoin-project + ipfs-shipyard + + # Authors of personal repos used by go-ipfs that should be mentioned in the + # release notes. + whyrusleeping + Kubuxu + jbenet + Stebalien + marten-seemann + hsanjuan + lucas-clemente + warpfork +) + +[[ -n "${REPO_FILTER+x}" ]] || REPO_FILTER="github.com/(${$(printf "|%s" "${AUTHORS[@]}"):1})" + +[[ -n "${IGNORED_FILES+x}" ]] || IGNORED_FILES='^\(\.gx\|package\.json\|\.travis\.yml\|go.mod\|go\.sum|\.github|\.circleci\)$' + +NL=$'\n' + +ROOT_DIR="$(git rev-parse --show-toplevel)" + +msg() { + echo "$*" >&2 +} + +statlog() { + local module="$1" + local rpath="$GOPATH/src/$(strip_version "$module")" + local start="${2:-}" + local end="${3:-HEAD}" + local mailmap_file="$rpath/.mailmap" + if ! [[ -e "$mailmap_file" ]]; then + mailmap_file="$ROOT_DIR/.mailmap" + fi + + git -C "$rpath" -c mailmap.file="$mailmap_file" log --use-mailmap --shortstat --no-merges --pretty="tformat:%H%n%aN%n%aE" "$start..$end" | while + read hash + read name + read email + read _ # empty line + read changes + do + changed=0 + insertions=0 + deletions=0 + while read count event; do + if [[ "$event" =~ ^file ]]; then + changed=$count + elif [[ "$event" =~ ^insertion ]]; then + insertions=$count + elif [[ "$event" =~ ^deletion ]]; then + deletions=$count + else + echo "unknown event $event" >&2 + exit 1 + fi + done<<<"${changes//,/$NL}" + + jq -n \ + --arg "hash" "$hash" \ + --arg "name" "$name" \ + --arg "email" "$email" \ + --argjson "changed" "$changed" \ + --argjson "insertions" "$insertions" \ + --argjson "deletions" "$deletions" \ + '{Commit: $hash, Author: $name, Email: $email, Files: $changed, Insertions: $insertions, Deletions: $deletions}' + done +} + +# Returns a stream of deps changed between $1 and $2. +dep_changes() { + { + <"$1" + <"$2" + } | jq -s 'JOIN(INDEX(.[0][]; .Path); .[1][]; .Path; {Path: .[0].Path, Old: (.[1] | del(.Path)), New: (.[0] | del(.Path))}) | select(.New.Version != .Old.Version)' +} + +# resolve_commits resolves a git ref for each version. +resolve_commits() { + jq '. + {Ref: (.Version|capture("^((?.*)\\+incompatible|v.*-(0\\.)?[0-9]{14}-(?[a-f0-9]{12})|(?v.*))$") | .ref1 // .ref2 // .ref3)}' +} + +pr_link() { + local repo="$1" + local prnum="$2" + local ghname="${repo##github.com/}" + printf -- "[%s#%s](https://%s/pull/%s)" "$ghname" "$prnum" "$repo" "$prnum" +} + +# Generate a release log for a range of commits in a single repo. +release_log() { + setopt local_options BASH_REMATCH + + local module="$1" + local start="$2" + local end="${3:-HEAD}" + local repo="$(strip_version "$1")" + local dir="$GOPATH/src/$repo" + + local commit pr + git -C "$dir" log \ + --format='tformat:%H %s' \ + --first-parent \ + "$start..$end" | + while read commit subject; do + # Skip gx-only PRs. + git -C "$dir" diff-tree --no-commit-id --name-only "$commit^" "$commit" | + grep -v "${IGNORED_FILES}" >/dev/null || continue + + if [[ "$subject" =~ '^Merge pull request #([0-9]+) from' ]]; then + local prnum="${BASH_REMATCH[2]}" + local desc="$(git -C "$dir" show --summary --format='tformat:%b' "$commit" | head -1)" + printf -- "- %s (%s)\n" "$desc" "$(pr_link "$repo" "$prnum")" + elif [[ "$subject" =~ '\(#([0-9]+)\)$' ]]; then + local prnum="${BASH_REMATCH[2]}" + printf -- "- %s (%s)\n" "$subject" "$(pr_link "$repo" "$prnum")" + else + printf -- "- %s\n" "$subject" + fi + done +} + +indent() { + sed -e 's/^/ /' +} + +mod_deps() { + go list -mod=mod -json -m all | jq 'select(.Version != null)' +} + +ensure() { + local repo="$(strip_version "$1")" + local commit="$2" + local rpath="$GOPATH/src/$repo" + if [[ ! -d "$rpath" ]]; then + msg "Cloning $repo..." + git clone "http://$repo" "$rpath" >&2 + fi + + if ! git -C "$rpath" rev-parse --verify "$commit" >/dev/null; then + msg "Fetching $repo..." + git -C "$rpath" fetch --all >&2 + fi + + git -C "$rpath" rev-parse --verify "$commit" >/dev/null || return 1 +} + +statsummary() { + jq -s 'group_by(.Author)[] | {Author: .[0].Author, Commits: (. | length), Insertions: (map(.Insertions) | add), Deletions: (map(.Deletions) | add), Files: (map(.Files) | add)}' | + jq '. + {Lines: (.Deletions + .Insertions)}' +} + +strip_version() { + local repo="$1" + if [[ "$repo" =~ '.*/v[0-9]+$' ]]; then + repo="$(dirname "$repo")" + fi + echo "$repo" +} + +recursive_release_log() { + local start="${1:-$(git tag -l | sort -V | grep -v -- '-rc' | grep 'v'| tail -n1)}" + local end="${2:-$(git rev-parse HEAD)}" + local repo_root="$(git rev-parse --show-toplevel)" + local module="$(go list -m)" + local dir="$(go list -m -f '{{.Dir}}')" + + if [[ "${GOPATH}/${module}" -ef "${dir}" ]]; then + echo "This script requires the target module and all dependencies to live in a GOPATH." + return 1 + fi + + ( + local result=0 + local workspace="$(mktemp -d)" + trap "$(printf 'rm -rf "%q"' "$workspace")" INT TERM EXIT + cd "$workspace" + + mkdir extern + ln -s "$repo_root"/extern/filecoin-ffi extern/filecoin-ffi + ln -s "$repo_root"/extern/test-vectors extern/test-vectors + + echo "Computing old deps..." >&2 + git -C "$repo_root" show "$start:go.mod" >go.mod + mod_deps | resolve_commits | jq -s > old_deps.json + + echo "Computing new deps..." >&2 + git -C "$repo_root" show "$end:go.mod" >go.mod + mod_deps | resolve_commits | jq -s > new_deps.json + + rm -f go.mod go.sum + + printf -- "Generating Changelog for %s %s..%s\n" "$module" "$start" "$end" >&2 + + printf -- "- %s:\n" "$module" + release_log "$module" "$start" "$end" | indent + + + statlog "$module" "$start" "$end" > statlog.json + + dep_changes old_deps.json new_deps.json | + jq --arg filter "$REPO_FILTER" 'select(.Path | match($filter))' | + # Compute changelogs + jq -r '"\(.Path) \(.New.Version) \(.New.Ref) \(.Old.Version) \(.Old.Ref // "")"' | + while read module new new_ref old old_ref; do + if ! ensure "$module" "$new_ref"; then + result=1 + local changelog="failed to fetch repo" + else + statlog "$module" "$old_ref" "$new_ref" >> statlog.json + local changelog="$(release_log "$module" "$old_ref" "$new_ref")" + fi + if [[ -n "$changelog" ]]; then + printf -- "- %s (%s -> %s):\n" "$module" "$old" "$new" + echo "$changelog" | indent + fi + done + + echo + echo "Contributors" + echo + + echo "| Contributor | Commits | Lines ± | Files Changed |" + echo "|-------------|---------|---------|---------------|" + statsummary