Files
disko/scripts/create-release.nix
T

156 lines
4.4 KiB
Nix

{
writeShellApplication,
bash,
coreutils,
git,
gh,
nix-fast-build,
}:
writeShellApplication {
name = "create-release";
runtimeInputs = [
bash
git
gh
coreutils
nix-fast-build
];
text = ''
set -x
version=''${1:-}
if [[ -z "$version" ]]; then
echo "USAGE: nix run .#create-release -- <version>" >&2
exit 1
fi
# Check if we're running from the root of the repository
if [[ ! -f "flake.nix" || ! -f "version.nix" ]]; then
echo "This script must be run from the root of the repository" >&2
exit 1
fi
# Check if the version matches the semver pattern (without suffixes)
semver_regex="^([0-9]+)\.([0-9]+)\.([0-9]+)$"
if [[ ! "$version" =~ $semver_regex ]]; then
echo "Version must match the semver pattern (e.g., 1.0.0, 2.3.4)" >&2
exit 1
fi
if [[ "$(git symbolic-ref --short HEAD)" != "master" ]]; then
echo "must be on master branch" >&2
exit 1
fi
# Ensure there are no uncommitted or unpushed changes
uncommitted_changes=$(git diff --compact-summary)
if [[ -n "$uncommitted_changes" ]]; then
echo -e "There are uncommitted changes, exiting:\n''${uncommitted_changes}" >&2
exit 1
fi
git pull https://github.com/nix-community/disko master
unpushed_commits=$(git log --format=oneline origin/master..master)
if [[ "$unpushed_commits" != "" ]]; then
echo -e "\nThere are unpushed changes, exiting:\n$unpushed_commits" >&2
exit 1
fi
branch_name="release/v$version"
# Check if branch already exists
if git show-ref --verify --quiet "refs/heads/$branch_name"; then
echo "Branch $branch_name already exists locally, please delete it first" >&2
exit 1
fi
# Check if tag already exists (locally or remotely)
if git show-ref --verify --quiet "refs/tags/v$version" || git ls-remote --tags origin "v$version" | grep -q .; then
echo "Tag v$version already exists, aborting" >&2
exit 1
fi
# Create release branch
git checkout -b "$branch_name"
# Update the version file
cat > version.nix <<EOF
{
version = "$version";
released = true;
}
EOF
# Commit the release version bump
git commit -am "release: v$version"
# Push branch and create PR
git push -u origin "$branch_name"
pr_url=$(gh pr create --title "release: v$version" --body "Release v$version" --base master)
echo "Created PR: $pr_url"
# Add to merge queue
gh pr merge --merge --auto "$pr_url"
echo "PR added to merge queue, waiting for merge..."
# Wait for PR to be merged
while true; do
state=$(gh pr view "$pr_url" --json state --jq '.state')
if [[ "$state" == "MERGED" ]]; then
echo "PR merged!"
break
elif [[ "$state" == "CLOSED" ]]; then
echo "PR was closed without merging, aborting release" >&2
git checkout master
git branch -D "$branch_name"
exit 1
fi
echo "Waiting for PR to merge (current state: $state)..."
sleep 10
done
# Switch back to master and pull the merged commit
git checkout master
git pull origin master
# Delete the local release branch
git branch -D "$branch_name"
# Tag the release and push tags
git tag -a "v$version" -m "release: v$version"
git tag -d "latest" 2>/dev/null || true
git tag -a "latest" -m "release: v$version"
git push origin "v$version"
git push --force origin latest
# Create follow-up branch to reset released flag
followup_branch="release/v$version-followup"
git checkout -b "$followup_branch"
cat > version.nix <<EOF
{
version = "$version";
released = false;
}
EOF
git commit -am "release: reset released flag"
git push -u origin "$followup_branch"
followup_pr_url=$(gh pr create --title "release: reset released flag after v$version" --body "Reset released flag after v$version release" --base master)
echo "Created follow-up PR: $followup_pr_url"
gh pr merge --merge --auto "$followup_pr_url"
# Switch back to master
git checkout master
# Create a draft GitHub release with auto-generated notes
release_url=$(gh release create "v$version" --draft --generate-notes --verify-tag)
edit_url=''${release_url/\/tag\//\/edit\/}
echo
echo "Release v$version complete!"
echo "Edit and publish the draft release:"
echo
echo " $edit_url"
'';
}