mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-05 03:41:24 +08:00
771 lines
23 KiB
Ruby
771 lines
23 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
RSpec.describe "tasks/release" do
|
|
let(:tmpdir) { Dir.mktmpdir }
|
|
let(:origin_path) { "#{tmpdir}/origin-repo" }
|
|
let(:local_path) { "#{tmpdir}/local-repo" }
|
|
let(:git_tags) { git("tag").lines.map(&:strip) }
|
|
|
|
def git(*args)
|
|
out, err, status = Open3.capture3("git", *args)
|
|
raise "Command failed: git #{args.inspect}\n#{out}\n#{err}" unless status.success?
|
|
out
|
|
end
|
|
|
|
def fake_version_rb(version)
|
|
File.read("#{Rails.root}/lib/version.rb").sub(/STRING = ".*"/, "STRING = \"#{version}\"")
|
|
end
|
|
|
|
def commit_version(version)
|
|
File.write("lib/version.rb", fake_version_rb(version))
|
|
git "add", "."
|
|
git "commit", "-m", "version #{version}"
|
|
git("rev-parse", "HEAD").strip
|
|
end
|
|
|
|
def update_versions_json(overrides)
|
|
Dir.chdir(origin_path) do
|
|
git "checkout", "main"
|
|
current = JSON.parse(File.read("versions.json"))
|
|
File.write("versions.json", JSON.pretty_generate(current.merge(overrides)))
|
|
git "add", "versions.json"
|
|
git "commit", "-m", "Update versions.json"
|
|
end
|
|
end
|
|
|
|
before do
|
|
ENV["RUNNING_RELEASE_IN_RSPEC_TESTS"] = "1"
|
|
|
|
Rake::Task.tasks.each { |t| t.reenable }
|
|
FileUtils.mkdir_p origin_path
|
|
|
|
Dir.chdir(origin_path) do
|
|
FileUtils.mkdir_p "lib"
|
|
FileUtils.mkdir_p "tmp"
|
|
|
|
File.write(".gitignore", "tmp\n")
|
|
File.write("lib/version.rb", fake_version_rb("2025.12.0-latest"))
|
|
versions =
|
|
(1..12).each_with_object({}) do |month, hash|
|
|
hash["2025.#{month}"] = { "released" => month <= 6, "esr" => [1, 7].include?(month) }
|
|
end
|
|
File.write("versions.json", JSON.pretty_generate(versions))
|
|
|
|
git "init"
|
|
git "config", "commit.gpgsign", "false"
|
|
git "checkout", "-b", "main"
|
|
git "add", "."
|
|
git "commit", "-m", "Initial commit"
|
|
|
|
git "checkout", "-b", "stable"
|
|
File.write("#{origin_path}/lib/version.rb", fake_version_rb("3.1.2"))
|
|
git "add", "."
|
|
git "commit", "-m", "Previous stable version bump"
|
|
|
|
git "checkout", "main"
|
|
git "config", "receive.denyCurrentBranch", "ignore"
|
|
end
|
|
|
|
git "clone", "-b", "main", origin_path, local_path
|
|
end
|
|
|
|
after do
|
|
FileUtils.remove_entry(tmpdir)
|
|
ENV.delete("RUNNING_RELEASE_IN_RSPEC_TESTS")
|
|
end
|
|
|
|
describe "release:maybe_tag_release" do
|
|
subject(:run_task) do
|
|
capture_stdout { invoke_rake_task("release:maybe_tag_release", commit_hash) }
|
|
end
|
|
|
|
let(:commit_hash) { commit_version(version) }
|
|
|
|
context "when commit is not on a release branch" do
|
|
let(:version) { "2025.6.0" }
|
|
|
|
it "does not create a tag" do
|
|
Dir.chdir(local_path) do
|
|
git "switch", "-c", "some-other-branch"
|
|
|
|
expect { run_task }.not_to change { git_tags }
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when tag does not exist" do
|
|
let(:version) { "2025.3.0" }
|
|
let!(:commit_hash) { Dir.chdir(local_path) { commit_version(version) } }
|
|
|
|
it "creates the tag" do
|
|
Dir.chdir(local_path) do
|
|
git "branch", "release/2025.3"
|
|
|
|
expect(run_task).to include("Tagging release v2025.3.0")
|
|
expect(git_tags).to include("v2025.3.0")
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when version is a pre-release" do
|
|
let(:version) { "2025.4.0-latest" }
|
|
|
|
it "tags the pre-release version" do
|
|
Dir.chdir(local_path) do
|
|
expect(run_task).to include("Tagging release v2025.4.0-latest")
|
|
expect(git_tags).to include("v2025.4.0-latest")
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when version is a security patchlevel" do
|
|
let(:version) { "2025.4.0-latest.1" }
|
|
|
|
it "tags the patchlevel version" do
|
|
Dir.chdir(local_path) do
|
|
expect(run_task).to include("Tagging release v2025.4.0-latest.1")
|
|
expect(git_tags).to include("v2025.4.0-latest.1")
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when tag already exists" do
|
|
let(:version) { "2025.5.0" }
|
|
let!(:commit_hash) { Dir.chdir(local_path) { commit_version(version) } }
|
|
|
|
it "skips tagging" do
|
|
Dir.chdir(local_path) do
|
|
git "branch", "release/2025.5"
|
|
git "tag", "-a", "v2025.5.0", "-m", "version 2025.5.0"
|
|
|
|
expect { run_task }.not_to change { git_tags }
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "release:update_release_tags" do
|
|
subject(:run_task) do
|
|
capture_stdout { invoke_rake_task("release:update_release_tags", commit_hash) }
|
|
end
|
|
|
|
let(:commit_hash) { commit_version(version) }
|
|
|
|
context "when version is newer than latest release" do
|
|
let(:version) { "2025.6.0" }
|
|
|
|
it "creates release alias tags" do
|
|
Dir.chdir(local_path) do
|
|
run_task
|
|
expect(git_tags).to contain_exactly(*ReleaseUtils::RELEASE_TAGS)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when version is older than latest release" do
|
|
let(:version) { "2025.1.0" }
|
|
|
|
it "skips release tags" do
|
|
Dir.chdir(local_path) do
|
|
expect(run_task).to include("older than latest release")
|
|
expect(git_tags).not_to include(*ReleaseUtils::RELEASE_TAGS)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when version is a non-ESR release" do
|
|
let(:version) { "2025.6.0" }
|
|
|
|
it "does not create ESR tags" do
|
|
Dir.chdir(local_path) do
|
|
run_task
|
|
expect(git_tags).not_to include(*ReleaseUtils::ESR_TAGS)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when version is in the latest released ESR series" do
|
|
let(:version) { "2025.7.1" }
|
|
|
|
before { update_versions_json({ "2025.7" => { "released" => true, "esr" => true } }) }
|
|
|
|
it "creates both release and ESR alias tags" do
|
|
Dir.chdir(local_path) do
|
|
run_task
|
|
expect(git_tags).to include(*ReleaseUtils::RELEASE_TAGS, *ReleaseUtils::ESR_TAGS)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when version is newer than the latest ESR but not an ESR itself" do
|
|
let(:version) { "2025.8.0" }
|
|
|
|
before do
|
|
update_versions_json(
|
|
{
|
|
"2025.7" => {
|
|
"released" => true,
|
|
"esr" => true,
|
|
},
|
|
"2025.8" => {
|
|
"released" => true,
|
|
"esr" => false,
|
|
},
|
|
},
|
|
)
|
|
end
|
|
|
|
it "creates release tags but not ESR tags" do
|
|
Dir.chdir(local_path) do
|
|
run_task
|
|
expect(git_tags).to contain_exactly(*ReleaseUtils::RELEASE_TAGS)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "release:maybe_cut_branch" do
|
|
subject(:run_task) do
|
|
capture_stdout { invoke_rake_task("release:maybe_cut_branch", latest_hash) }
|
|
end
|
|
|
|
context "when development cycle changes" do
|
|
let!(:previous_hash) { Dir.chdir(local_path) { commit_version(previous_version) } }
|
|
let!(:latest_hash) { Dir.chdir(local_path) { commit_version(current_version) } }
|
|
let(:release_branch) { "release/#{previous_version.split(".").first(2).join(".")}" }
|
|
let(:parent_of_tip) do
|
|
Dir.chdir(origin_path) do
|
|
git "checkout", release_branch
|
|
git("rev-parse", "HEAD^1").strip
|
|
end
|
|
end
|
|
let(:version_on_branch) do
|
|
Dir.chdir(origin_path) do
|
|
git "checkout", release_branch
|
|
File.read("lib/version.rb")[/STRING = "(.*)"/, 1]
|
|
end
|
|
end
|
|
|
|
context "when going from one minor to another" do
|
|
let(:previous_version) { "2025.1.0-latest" }
|
|
let(:current_version) { "2025.2.0-latest" }
|
|
|
|
it "creates a release branch based on the previous commit" do
|
|
Dir.chdir(local_path) { run_task }
|
|
expect(parent_of_tip).to eq(previous_hash)
|
|
end
|
|
|
|
it "strips the -latest suffix" do
|
|
Dir.chdir(local_path) { run_task }
|
|
expect(version_on_branch).to eq("2025.1.0")
|
|
end
|
|
end
|
|
|
|
context "when going from a patchlevel to a new minor" do
|
|
let(:previous_version) { "2025.11.0-latest.2" }
|
|
let(:current_version) { "2025.12.0-latest" }
|
|
|
|
it "creates a release branch based on the previous commit" do
|
|
Dir.chdir(local_path) { run_task }
|
|
expect(parent_of_tip).to eq(previous_hash)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when development cycle stays the same" do
|
|
def origin_branches
|
|
Dir.chdir(origin_path) { git("branch").lines.map(&:strip) }
|
|
end
|
|
|
|
context "when bumping from latest to latest.1" do
|
|
let!(:latest_hash) { Dir.chdir(local_path) { commit_version("2025.12.0-latest.1") } }
|
|
|
|
it "does not create a branch" do
|
|
Dir.chdir(local_path) { expect { run_task }.not_to change { origin_branches } }
|
|
end
|
|
end
|
|
|
|
context "when bumping from latest.1 to latest.2" do
|
|
let!(:intermediate_hash) { Dir.chdir(local_path) { commit_version("2025.12.0-latest.1") } }
|
|
let!(:latest_hash) { Dir.chdir(local_path) { commit_version("2025.12.0-latest.2") } }
|
|
|
|
it "does not create a branch" do
|
|
Dir.chdir(local_path) { expect { run_task }.not_to change { origin_branches } }
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "release:prepare_next_version" do
|
|
subject(:run_task) do
|
|
Dir.chdir(local_path) do
|
|
freeze_time(frozen_time) do
|
|
capture_stdout { invoke_rake_task("release:prepare_next_version") }
|
|
end
|
|
end
|
|
end
|
|
|
|
let(:bumped_version) do
|
|
on_version_bump_branch { File.read("lib/version.rb")[/STRING = "(.*)"/, 1] }
|
|
end
|
|
|
|
def on_version_bump_branch
|
|
Dir.chdir(origin_path) do
|
|
git "reset", "--hard"
|
|
git "checkout", "version-bump/main"
|
|
yield
|
|
end
|
|
end
|
|
|
|
context "with a custom version on main" do
|
|
before do
|
|
Dir.chdir(local_path) do
|
|
commit_version(initial_version)
|
|
git "push", "origin", "main"
|
|
end
|
|
end
|
|
|
|
context "when current version is older than target month" do
|
|
let(:frozen_time) { "2025-09-15" }
|
|
let(:initial_version) { "2024.1.0-latest" }
|
|
|
|
it "bumps to the current month" do
|
|
run_task
|
|
expect(bumped_version).to eq("2025.9.0-latest")
|
|
end
|
|
end
|
|
|
|
context "when current version matches target month" do
|
|
let(:frozen_time) { "2025-10-15" }
|
|
let(:initial_version) { "2025.10.0-latest" }
|
|
|
|
it "increments to next month" do
|
|
run_task
|
|
expect(bumped_version).to eq("2025.11.0-latest")
|
|
end
|
|
end
|
|
|
|
context "when current version has a security patchlevel" do
|
|
let(:frozen_time) { "2025-10-15" }
|
|
let(:initial_version) { "2025.10.0-latest.2" }
|
|
|
|
it "increments to next month and drops patchlevel" do
|
|
run_task
|
|
expect(bumped_version).to eq("2025.11.0-latest")
|
|
end
|
|
end
|
|
|
|
context "when PR creation succeeds" do
|
|
let(:frozen_time) { "2025-10-15" }
|
|
let(:initial_version) { "2025.5.0-latest" }
|
|
let(:commit_message) { on_version_bump_branch { git("log", "-1", "--pretty=%B").strip } }
|
|
|
|
before do
|
|
allow(ReleaseUtils).to receive(:gh).with("pr", "create", any_args).and_return(true)
|
|
run_task
|
|
end
|
|
|
|
it "includes the version bump description" do
|
|
expect(commit_message).to include("Begin development of v2025.10.0-latest")
|
|
expect(commit_message).to include(
|
|
"Merging this will trigger the creation of a `release/2025.5` branch on the preceding commit.",
|
|
)
|
|
end
|
|
|
|
it "creates a PR" do
|
|
commit_message
|
|
|
|
expect(ReleaseUtils).to have_received(:gh).with(
|
|
"pr",
|
|
"create",
|
|
"--base",
|
|
"main",
|
|
"--head",
|
|
"version-bump/main",
|
|
"--title",
|
|
"DEV: Begin development of v2025.10.0-latest",
|
|
"--body",
|
|
a_string_including(
|
|
"Merging this will trigger the creation of a `release/2025.5` branch",
|
|
),
|
|
"--label",
|
|
ReleaseUtils::PR_LABEL,
|
|
)
|
|
end
|
|
end
|
|
|
|
context "when PR creation fails" do
|
|
let(:frozen_time) { "2025-10-15" }
|
|
let(:initial_version) { "2025.5.0-latest" }
|
|
|
|
before do
|
|
allow(ReleaseUtils).to receive(:gh).with("pr", "create", any_args).and_return(false)
|
|
allow(ReleaseUtils).to receive(:gh).with("pr", "edit", any_args).and_return(true)
|
|
end
|
|
|
|
it "falls back to editing the PR" do
|
|
run_task
|
|
|
|
expect(ReleaseUtils).to have_received(:gh).with(
|
|
"pr",
|
|
"edit",
|
|
"version-bump/main",
|
|
"--title",
|
|
"DEV: Begin development of v2025.10.0-latest",
|
|
"--body",
|
|
a_string_including(
|
|
"Merging this will trigger the creation of a `release/2025.5` branch",
|
|
),
|
|
"--add-label",
|
|
ReleaseUtils::PR_LABEL,
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when incrementing past December" do
|
|
let(:frozen_time) { "2025-12-15" }
|
|
|
|
it "rolls over to next year" do
|
|
run_task
|
|
expect(bumped_version).to eq("2026.1.0-latest")
|
|
end
|
|
end
|
|
|
|
context "when updating versions.json" do
|
|
let(:frozen_time) { "2025-12-28" }
|
|
let(:versions_json) { on_version_bump_branch { JSON.parse(File.read("versions.json")) } }
|
|
|
|
it "adds new version entry" do
|
|
run_task
|
|
expect(versions_json["2026.1"]).to eq(
|
|
{
|
|
"developmentStartDate" => "2025-12-28",
|
|
"releaseDate" => "2026-01",
|
|
"supportEndDate" => "2026-09",
|
|
"released" => false,
|
|
"esr" => true,
|
|
"supported" => true,
|
|
},
|
|
)
|
|
end
|
|
|
|
it "marks previous version as released" do
|
|
run_task
|
|
expect(versions_json["2025.12"]).to include(
|
|
"released" => true,
|
|
"releaseDate" => "2025-12-28",
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "release:stage_security_fixes" do
|
|
subject(:run_task) do
|
|
Dir.chdir(local_path) do
|
|
capture_stdout { invoke_rake_task("release:stage_security_fixes", base_branch) }
|
|
end
|
|
end
|
|
|
|
let(:base_branch) { "main" }
|
|
let(:origin_main_commits) do
|
|
Dir.chdir(origin_path) { git("log", "--pretty=%s", base_branch).lines.map(&:strip) }
|
|
end
|
|
let(:pr_list_json) do
|
|
[
|
|
{
|
|
"number" => 1,
|
|
"title" => "Security fix one",
|
|
"body" =>
|
|
"Description for fix one\nhttps://github.com/discourse/discourse/security/advisories/GHSA-1111-2222-3333",
|
|
"headRefName" => "security-fix-one",
|
|
},
|
|
{
|
|
"number" => 2,
|
|
"title" => "Security fix two",
|
|
"body" =>
|
|
"https://github.com/discourse/discourse/security/advisories/GHSA-aaaa-bbbb-cccc",
|
|
"headRefName" => "security-fix-two",
|
|
},
|
|
].to_json
|
|
end
|
|
|
|
def origin_file(path)
|
|
Dir.chdir(origin_path) { git("show", "#{base_branch}:#{path}") }
|
|
end
|
|
|
|
before do
|
|
allow(ReleaseUtils).to receive(:gh).and_call_original
|
|
allow(ReleaseUtils).to receive(:gh).with(
|
|
"pr",
|
|
"list",
|
|
"--repo",
|
|
"discourse/discourse-private-mirror",
|
|
"--base",
|
|
base_branch,
|
|
"--state",
|
|
"open",
|
|
"--json",
|
|
"number,title,body,headRefName",
|
|
"--limit",
|
|
"100",
|
|
capture: true,
|
|
).and_return(pr_list_json)
|
|
|
|
ENV["SECURITY_FIX_GHSA_IDS"] = "GHSA-1111-2222-3333,GHSA-aaaa-bbbb-cccc"
|
|
|
|
Dir.chdir(origin_path) do
|
|
git "checkout", "-b", "security-fix-one"
|
|
File.write("firstfile.txt", "contents")
|
|
git "add", "firstfile.txt"
|
|
git "commit", "-m", "security fix one, commit one"
|
|
File.write("secondfile.txt", "contents")
|
|
git "add", "secondfile.txt"
|
|
git "commit", "-m", "security fix one, commit two"
|
|
git "checkout", "main"
|
|
git "checkout", "-b", "security-fix-two"
|
|
File.write("somefile.txt", "contents")
|
|
git "add", "somefile.txt"
|
|
git "commit", "-m", "security fix two"
|
|
end
|
|
|
|
# Add privatemirror as alias for origin so fetch works
|
|
Dir.chdir(local_path) { git "remote", "add", "privatemirror", origin_path }
|
|
end
|
|
|
|
after { ENV.delete("SECURITY_FIX_GHSA_IDS") }
|
|
|
|
context "when accepting the version bump" do
|
|
before { run_task }
|
|
|
|
it "squash-merges security fix PRs in order" do
|
|
expect(origin_main_commits).to eq(
|
|
[
|
|
"DEV: Bump development branch to v2025.12.0-latest.1",
|
|
"Security fix two",
|
|
"Security fix one",
|
|
"Initial commit",
|
|
],
|
|
)
|
|
end
|
|
|
|
it "includes files from all security fixes" do
|
|
expect(origin_file("firstfile.txt")).to eq("contents")
|
|
expect(origin_file("secondfile.txt")).to eq("contents")
|
|
expect(origin_file("somefile.txt")).to eq("contents")
|
|
end
|
|
|
|
it "bumps the development version" do
|
|
expect(origin_file("lib/version.rb")).to include('STRING = "2025.12.0-latest.1"')
|
|
end
|
|
end
|
|
|
|
context "when declining the version bump" do
|
|
before do
|
|
allow(ReleaseUtils).to receive(:confirm).and_return(false)
|
|
run_task
|
|
end
|
|
|
|
it "squash-merges security fix PRs without a version bump" do
|
|
expect(origin_main_commits).to eq(
|
|
["Security fix two", "Security fix one", "Initial commit"],
|
|
)
|
|
end
|
|
|
|
it "does not modify the version" do
|
|
expect(origin_file("lib/version.rb")).to include('STRING = "2025.12.0-latest"')
|
|
end
|
|
end
|
|
|
|
context "when targeting a release branch" do
|
|
let(:base_branch) { "release/2025.6" }
|
|
let(:pr_list_json) do
|
|
[
|
|
{
|
|
"number" => 1,
|
|
"title" => "Security fix for release branch",
|
|
"body" =>
|
|
"https://github.com/discourse/discourse/security/advisories/GHSA-release-test-1234",
|
|
"headRefName" => "security-fix-for-release-branch",
|
|
},
|
|
].to_json
|
|
end
|
|
|
|
before do
|
|
ENV["SECURITY_FIX_GHSA_IDS"] = "GHSA-release-test-1234"
|
|
|
|
Dir.chdir(origin_path) do
|
|
git "checkout", "-b", base_branch
|
|
File.write("lib/version.rb", fake_version_rb("2025.6.0"))
|
|
git "add", "lib/version.rb"
|
|
git "commit", "-m", "Initial release branch commit"
|
|
git "config", "receive.denyCurrentBranch", "ignore"
|
|
git "checkout", "main"
|
|
|
|
git "checkout", "-b", "security-fix-for-release-branch"
|
|
File.write("releasefile.txt", "contents")
|
|
git "add", "releasefile.txt"
|
|
git "commit", "-m", "security fix for release branch"
|
|
end
|
|
|
|
Dir.chdir(local_path) { git "fetch", "origin" }
|
|
end
|
|
|
|
it "bumps the patch version" do
|
|
run_task
|
|
expect(origin_file("lib/version.rb")).to include('STRING = "2025.6.1"')
|
|
end
|
|
|
|
it "squash-merges security fixes and adds version bump commit" do
|
|
run_task
|
|
expect(origin_main_commits.first(3)).to eq(
|
|
[
|
|
"DEV: Bump release branch to v2025.6.1",
|
|
"Security fix for release branch",
|
|
"Initial release branch commit",
|
|
],
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "release:update_security_advisories" do
|
|
subject(:run_task) do
|
|
Dir.chdir(local_path) do
|
|
capture_stdout { invoke_rake_task("release:update_security_advisories") }
|
|
end
|
|
end
|
|
|
|
let(:draft_advisories) do
|
|
[
|
|
{ "ghsa_id" => "GHSA-1234-5678-9abc", "state" => "draft", "summary" => "Security issue 1" },
|
|
{ "ghsa_id" => "GHSA-abcd-efgh-ijkl", "state" => "draft", "summary" => "Security issue 2" },
|
|
]
|
|
end
|
|
|
|
let(:gh_api_response) { JSON.generate([draft_advisories]) }
|
|
let(:updated_advisories) { [] }
|
|
|
|
before do
|
|
allow(ReleaseUtils).to receive(:gh) do |*args, **kwargs|
|
|
if args[0..3] ==
|
|
%w[api repos/discourse/discourse/security-advisories?state=draft --paginate --slurp]
|
|
gh_api_response
|
|
elsif args[0] == "api" && args[1].match?(%r{security-advisories/GHSA-}) &&
|
|
args[2] == "--method"
|
|
updated_advisories << JSON.parse(kwargs[:input])
|
|
"{}"
|
|
else
|
|
true
|
|
end
|
|
end
|
|
|
|
Dir.chdir(origin_path) do
|
|
git "checkout", "-b", "release/2025.5"
|
|
File.write("lib/version.rb", fake_version_rb("2025.5.2"))
|
|
git "add", "lib/version.rb"
|
|
git "commit", "-m", "version 2025.5.2"
|
|
|
|
git "checkout", "-b", "release/2025.6"
|
|
File.write("lib/version.rb", fake_version_rb("2025.6.0"))
|
|
git "add", "lib/version.rb"
|
|
git "commit", "-m", "version 2025.6.0"
|
|
|
|
git "checkout", "main"
|
|
end
|
|
|
|
update_versions_json(
|
|
{
|
|
"2025.5" => {
|
|
"released" => true,
|
|
"supported" => true,
|
|
},
|
|
"2025.6" => {
|
|
"released" => true,
|
|
"supported" => true,
|
|
},
|
|
"2025.12" => {
|
|
"released" => false,
|
|
"supported" => true,
|
|
},
|
|
},
|
|
)
|
|
end
|
|
|
|
context "when choosing intermediate release for latest" do
|
|
before do
|
|
prompt = instance_double(TTY::Prompt)
|
|
allow(TTY::Prompt).to receive(:new).and_return(prompt)
|
|
allow(prompt).to receive(:select).and_return(:intermediate)
|
|
end
|
|
|
|
it "updates advisories with correct patched versions" do
|
|
run_task
|
|
|
|
expect(updated_advisories.size).to eq(2)
|
|
|
|
vulnerabilities = updated_advisories.first["vulnerabilities"]
|
|
expect(vulnerabilities.size).to eq(3)
|
|
|
|
expect(vulnerabilities[0]).to include(
|
|
"vulnerable_version_range" => ">= 0",
|
|
"patched_versions" => "2025.5.3",
|
|
)
|
|
expect(vulnerabilities[1]).to include(
|
|
"vulnerable_version_range" => ">= 2025.6.0-latest",
|
|
"patched_versions" => "2025.6.1",
|
|
)
|
|
expect(vulnerabilities[2]).to include(
|
|
"vulnerable_version_range" => ">= 2025.12.0-latest",
|
|
"patched_versions" => "2025.12.0-latest.1",
|
|
)
|
|
end
|
|
end
|
|
|
|
context "when choosing monthly release for latest" do
|
|
before do
|
|
prompt = instance_double(TTY::Prompt)
|
|
allow(TTY::Prompt).to receive(:new).and_return(prompt)
|
|
allow(prompt).to receive(:select).and_return(:monthly)
|
|
end
|
|
|
|
it "uses the current patch version for latest" do
|
|
run_task
|
|
|
|
vulnerabilities = updated_advisories.first["vulnerabilities"]
|
|
expect(vulnerabilities[2]).to include(
|
|
"vulnerable_version_range" => ">= 2025.12.0-latest",
|
|
"patched_versions" => "2025.12.0",
|
|
)
|
|
end
|
|
end
|
|
|
|
context "when there are no draft advisories" do
|
|
let(:gh_api_response) { JSON.generate([[]]) }
|
|
|
|
it "outputs a message and does nothing" do
|
|
output = run_task
|
|
expect(output).to include("No draft advisories to update")
|
|
expect(updated_advisories).to be_empty
|
|
end
|
|
end
|
|
|
|
context "when advisories have DRAFT summary prefix" do
|
|
let(:draft_advisories) do
|
|
[
|
|
{
|
|
"ghsa_id" => "GHSA-1234-5678-9abc",
|
|
"state" => "draft",
|
|
"summary" => "DRAFT - placeholder",
|
|
},
|
|
]
|
|
end
|
|
|
|
it "skips advisories with DRAFT summary prefix" do
|
|
output = run_task
|
|
expect(output).to include("No draft advisories to update")
|
|
expect(updated_advisories).to be_empty
|
|
end
|
|
end
|
|
end
|
|
end
|