# typed: strict # frozen_string_literal: true require "abstract_command" module Homebrew module DevCmd class Release < AbstractCommand cmd_args do description <<~EOS Create a new draft Homebrew/brew release with the appropriate version number and release notes. By default, `brew release` will bump the patch version number. Pass `--major` or `--minor` to bump the major or minor version numbers, respectively. The command will fail if the previous major or minor release was made less than one month ago. *Note:* Requires write access to the Homebrew/brew repository. EOS switch "--major", description: "Create a major release." switch "--minor", description: "Create a minor release." conflicts "--major", "--minor" named_args :none end sig { override.void } def run safe_system "git", "-C", HOMEBREW_REPOSITORY, "fetch", "origin" if Homebrew::EnvConfig.no_auto_update? require "utils/github" begin latest_release = GitHub.get_latest_release "Homebrew", "brew" rescue GitHub::API::HTTPNotFoundError odie "No existing releases found!" end latest_version = Version.new latest_release["tag_name"] if args.major? || args.minor? one_month_ago = Date.today << 1 latest_major_minor_release = begin GitHub.get_release "Homebrew", "brew", "#{latest_version.major_minor}.0" rescue GitHub::API::HTTPNotFoundError nil end if latest_major_minor_release.blank? opoo "Unable to determine the release date of the latest major/minor release." elsif Date.parse(latest_major_minor_release["published_at"]) > one_month_ago odie "The latest major/minor release was less than one month ago." end end new_version = if args.major? Version.new "#{latest_version.major.to_i + 1}.0.0" elsif args.minor? Version.new "#{latest_version.major}.#{latest_version.minor.to_i + 1}.0" else Version.new "#{latest_version.major}.#{latest_version.minor}.#{latest_version.patch.to_i + 1}" end.to_s if args.major? || args.minor? latest_major_minor_version = "#{latest_version.major}.#{latest_version.minor.to_i}.0" ohai "Release notes since #{latest_major_minor_version} for #{new_version} blog post:" # release notes without usernames, new contributors, or extra lines blog_post_notes = GitHub.generate_release_notes("Homebrew", "brew", new_version, previous_tag: latest_major_minor_version)["body"] blog_post_notes = blog_post_notes.lines.filter_map do |line| next unless (match = line.match(/^\* (.*) by @[\w-]+ in (.*)$/)) "- [#{match[1]}](#{match[2]})" end.sort puts blog_post_notes end ohai "Creating draft release for version #{new_version}" release_notes = if args.major? || args.minor? "Release notes for this release can be found on the [Homebrew blog](https://brew.sh/blog/#{new_version}).\n" else "" end release_notes += GitHub.generate_release_notes("Homebrew", "brew", new_version, previous_tag: latest_version)["body"] begin release = GitHub.create_or_update_release "Homebrew", "brew", new_version, body: release_notes, draft: true rescue *GitHub::API::ERRORS => e odie "Unable to create release: #{e.message}!" end puts release["html_url"] exec_browser release["html_url"] end end end end