diff --git a/.github/workflows/schema.yml b/.github/workflows/schema.yml index 483ba1856..2656a6a08 100644 --- a/.github/workflows/schema.yml +++ b/.github/workflows/schema.yml @@ -13,12 +13,6 @@ jobs: with: fetch-depth: 0 - - name: Test GitHub CLI - env: - GH_TOKEN: ${{ github.token }} - run: | - gh pr view ${{ github.event.pull_request.number }} --json body -q '.body' - - name: Run schema dependency check env: GH_TOKEN: ${{ github.token }} diff --git a/app/components/alert_component.rb b/app/components/alert_component.rb index a34c6be85..81cfe1ec8 100644 --- a/app/components/alert_component.rb +++ b/app/components/alert_component.rb @@ -3,6 +3,7 @@ class AlertComponent < BaseComponent notice: "text-blue-900 bg-blue-50 dark:bg-main-800 dark:text-blue-400", error: "text-red-800 bg-red-50 dark:bg-main-800 dark:text-red-400", alert: "text-red-800 bg-red-50 dark:bg-main-800 dark:text-red-400", + timedout: "text-red-800 bg-red-50 dark:bg-main-800 dark:text-red-400", success: "text-green-800 bg-green-50 dark:bg-main-800 dark:text-green-400", info: "text-main-800 bg-main-50 dark:bg-main-800 dark:text-main-400", announce: "text-amber-800 bg-amber-50 dark:bg-amber-800 dark:text-amber-400" @@ -12,6 +13,7 @@ class AlertComponent < BaseComponent notice: "border border-blue-300 dark:border-blue-800 " + COLORS[:notice], error: "border border-red-300 dark:border-red-800 " + COLORS[:error], alert: "border border-red-300 dark:border-red-800 " + COLORS[:alert], + timedout: "border border-red-300 dark:border-red-800 " + COLORS[:alert], success: "border border-green-300 dark:border-green-800 " + COLORS[:success], info: "border border-main-300 dark:border-main-800 " + COLORS[:info], announce: "border border-amber-300 dark:border-amber-800 " + COLORS[:announce] diff --git a/app/controllers/trains_controller.rb b/app/controllers/trains_controller.rb index aeb7a1c7b..3e51f37fd 100644 --- a/app/controllers/trains_controller.rb +++ b/app/controllers/trains_controller.rb @@ -135,7 +135,8 @@ def train_params :auto_apply_patch_changes, :version_bump_enabled, :version_bump_file_paths, - :version_bump_branch_prefix + :version_bump_branch_prefix, + :version_bump_strategy ) end @@ -185,7 +186,8 @@ def train_update_params :auto_apply_patch_changes, :version_bump_enabled, :version_bump_file_paths, - :version_bump_branch_prefix + :version_bump_branch_prefix, + :version_bump_strategy ) end diff --git a/app/jobs/coordinators/pre_release_job.rb b/app/jobs/coordinators/pre_release_job.rb new file mode 100644 index 000000000..20f0172fe --- /dev/null +++ b/app/jobs/coordinators/pre_release_job.rb @@ -0,0 +1,30 @@ +class Coordinators::PreReleaseJob < ApplicationJob + RELEASE_HANDLERS = { + "almost_trunk" => Coordinators::PreRelease::AlmostTrunk, + "parallel_working" => Coordinators::PreRelease::ParallelBranches, + "release_backmerge" => Coordinators::PreRelease::ReleaseBackMerge + } + + queue_as :high + + def perform(release_id) + release = Release.find(release_id) + release_branch = release.release_branch + train = release.train + branching_strategy = train.branching_strategy + + if release.hotfix_with_existing_branch? + latest_commit = release.latest_commit_hash(sha_only: false) + return Signal.commits_have_landed!(release, latest_commit, []) + end + + begin + release.start_pre_release_phase! + RELEASE_HANDLERS[branching_strategy].call(release, release_branch).value! + rescue Triggers::Errors => ex + elog(ex, level: :warn) + release.fail_pre_release_phase! + release.event_stamp!(reason: :pre_release_failed, kind: :error, data: {error: ex.message}) + end + end +end diff --git a/app/jobs/coordinators/version_bump_job.rb b/app/jobs/coordinators/version_bump_job.rb new file mode 100644 index 000000000..2d50c0162 --- /dev/null +++ b/app/jobs/coordinators/version_bump_job.rb @@ -0,0 +1,8 @@ +class Coordinators::VersionBumpJob < ApplicationJob + queue_as :high + + def perform(release_id) + release = Release.find(release_id) + Triggers::VersionBump.call(release) + end +end diff --git a/app/jobs/releases/pre_release_job.rb b/app/jobs/releases/pre_release_job.rb deleted file mode 100644 index 6ca21f827..000000000 --- a/app/jobs/releases/pre_release_job.rb +++ /dev/null @@ -1,14 +0,0 @@ -class Releases::PreReleaseJob < ApplicationJob - queue_as :high - - def perform(release_id) - release = Release.find(release_id) - - if release.hotfix_with_existing_branch? - latest_commit = release.latest_commit_hash(sha_only: false) - return Signal.commits_have_landed!(release, latest_commit, []) - end - - Triggers::PreRelease.call(release) - end -end diff --git a/app/libs/coordinators.rb b/app/libs/coordinators.rb index 672f268d8..f01031291 100644 --- a/app/libs/coordinators.rb +++ b/app/libs/coordinators.rb @@ -43,12 +43,13 @@ module Signals def self.release_has_started!(release) Coordinators::SetupReleaseSpecificChannel.call(release) release.notify!("New release has commenced!", :release_started, release.notification_params) - Releases::PreReleaseJob.perform_async(release.id) + Coordinators::PreReleaseJob.perform_async(release.id) Releases::FetchCommitLogJob.perform_async(release.id) RefreshReportsJob.perform_async(release.hotfixed_from.id) if release.hotfix? end def self.commits_have_landed!(release, head_commit, rest_commits) + Coordinators::VersionBumpJob.perform_async(release.id) Coordinators::ProcessCommits.call(release, head_commit, rest_commits) end @@ -92,8 +93,14 @@ def self.workflow_run_trigger_failed!(workflow_run) def self.pull_request_closed!(pr) release = pr.release - Actions.complete_release!(release) if release.post_release_failed? - Releases::PreReleaseJob.perform_async(release.id) if release.pre_release? && pr.pre_release_version_bump? + + if release.post_release_failed? + Actions.complete_release!(release) + end + + if release.pre_release? && pr.pre_release_version_bump? + Releases::PreReleaseJob.perform_async(release.id) + end end end diff --git a/app/libs/coordinators/pre_release/almost_trunk.rb b/app/libs/coordinators/pre_release/almost_trunk.rb new file mode 100644 index 000000000..0c75527f7 --- /dev/null +++ b/app/libs/coordinators/pre_release/almost_trunk.rb @@ -0,0 +1,59 @@ +module Coordinators + module PreRelease + class AlmostTrunk + def self.call(release, release_branch) + new(release, release_branch).call + end + + def initialize(release, release_branch) + @release = release + @release_branch = release_branch + @pre_release_version_bump_pr = release.pull_requests.pre_release.version_bump_type.first + end + + def call + if version_bump_required? + Triggers::VersionBump.call(release).then { create_default_release_branch } + else + create_default_release_branch + end + end + + private + + attr_reader :release, :release_branch + delegate :train, :hotfix?, :hotfix_with_new_branch?, to: :release + delegate :working_branch, :version_bump_enabled?, :current_version_before_release_branch?, to: :train + + def create_default_release_branch + source = + if hotfix_with_new_branch? + { + ref: release.hotfixed_from.end_ref, + type: :tag + } + elsif version_bump_enabled? && (commit = @pre_release_version_bump_pr&.merge_commit_sha).present? + { + ref: commit, + type: :commit + } + else + { + ref: working_branch, + type: :branch + } + end + stamp_data = {working_branch: source[:ref], release_branch:} + stamp_type = :release_branch_created + Triggers::Branch.call(release, source[:ref], release_branch, source[:type], stamp_data, stamp_type) + end + + def version_bump_required? + version_bump_enabled? && + current_version_before_release_branch? && + !hotfix? && + @pre_release_version_bump_pr.blank? + end + end + end +end diff --git a/app/libs/coordinators/pre_release/parallel_branches.rb b/app/libs/coordinators/pre_release/parallel_branches.rb new file mode 100644 index 000000000..0c480d789 --- /dev/null +++ b/app/libs/coordinators/pre_release/parallel_branches.rb @@ -0,0 +1,46 @@ +module Coordinators + module PreRelease + class ParallelBranches + include ApplicationHelper + + def self.call(release, release_branch) + new(release, release_branch).call + end + + def initialize(release, release_branch) + @release = release + @release_branch = release_branch + end + + def call + create_and_merge_pr + end + + private + + attr_reader :release, :release_branch + delegate :train, to: :release + delegate :vcs_provider, :working_branch, to: :train + + def create_and_merge_pr + Triggers::PullRequest.create_and_merge!( + release: release, + new_pull_request_attrs: {phase: :pre_release, kind: :forward_merge, release_id: release.id, state: :open}, + to_branch_ref: release_branch, + from_branch_ref: working_branch, + title: pr_title, + description: pr_description, + allow_without_diff: false + ) + end + + def pr_title + "[#{version_in_progress(train.version_current)}] Pre-release merge" + end + + def pr_description + "A new release train #{train.name} is starting. The #{working_branch} branch has to be merged into #{release_branch} branch." + end + end + end +end diff --git a/app/libs/coordinators/pre_release/release_back_merge.rb b/app/libs/coordinators/pre_release/release_back_merge.rb new file mode 100644 index 000000000..f206ccb62 --- /dev/null +++ b/app/libs/coordinators/pre_release/release_back_merge.rb @@ -0,0 +1,10 @@ +module Coordinators + module PreRelease + class ReleaseBackMerge + def self.call(release, release_branch) + # ReleaseBackMerge behaves the same as AlmostTrunk while making a new release + Triggers::PreRelease::AlmostTrunk.call(release, release_branch) + end + end + end +end diff --git a/app/libs/triggers/pre_release.rb b/app/libs/triggers/pre_release.rb deleted file mode 100644 index 3f208a769..000000000 --- a/app/libs/triggers/pre_release.rb +++ /dev/null @@ -1,31 +0,0 @@ -class Triggers::PreRelease - include Memery - include Loggable - - RELEASE_HANDLERS = { - "almost_trunk" => AlmostTrunk, - "parallel_working" => ParallelBranches, - "release_backmerge" => ReleaseBackMerge - } - - def self.call(release) - new(release).call - end - - def initialize(release) - @release = release - end - - delegate :train, :release_branch, to: :release - delegate :branching_strategy, to: :train - attr_reader :release - - def call - release.start_pre_release_phase! - RELEASE_HANDLERS[branching_strategy].call(release, release_branch).value! - rescue Triggers::Errors => ex - elog(ex, level: :warn) - release.fail_pre_release_phase! - release.event_stamp!(reason: :pre_release_failed, kind: :error, data: {error: ex.message}) - end -end diff --git a/app/libs/triggers/pre_release/almost_trunk.rb b/app/libs/triggers/pre_release/almost_trunk.rb deleted file mode 100644 index 34bf0424f..000000000 --- a/app/libs/triggers/pre_release/almost_trunk.rb +++ /dev/null @@ -1,54 +0,0 @@ -class Triggers::PreRelease - class AlmostTrunk - def self.call(release, release_branch) - new(release, release_branch).call - end - - def initialize(release, release_branch) - @release = release - @release_branch = release_branch - @pre_release_version_bump_pr = release.pull_requests.pre_release.version_bump_type.first - end - - def call - if version_bump_required? - Triggers::VersionBump.call(release).then { create_default_release_branch } - else - create_default_release_branch - end - end - - private - - attr_reader :release, :release_branch - delegate :train, :hotfix?, :hotfix_with_new_branch?, to: :release - delegate :working_branch, :version_bump_enabled?, to: :train - - def create_default_release_branch - source = - if hotfix_with_new_branch? - { - ref: release.hotfixed_from.end_ref, - type: :tag - } - elsif version_bump_enabled? && (commit = @pre_release_version_bump_pr&.merge_commit_sha).present? - { - ref: commit, - type: :commit - } - else - { - ref: working_branch, - type: :branch - } - end - stamp_data = {working_branch: source[:ref], release_branch:} - stamp_type = :release_branch_created - Triggers::Branch.call(release, source[:ref], release_branch, source[:type], stamp_data, stamp_type) - end - - def version_bump_required? - version_bump_enabled? && !hotfix? && @pre_release_version_bump_pr.blank? - end - end -end diff --git a/app/libs/triggers/pre_release/parallel_branches.rb b/app/libs/triggers/pre_release/parallel_branches.rb deleted file mode 100644 index cc3b8a4b2..000000000 --- a/app/libs/triggers/pre_release/parallel_branches.rb +++ /dev/null @@ -1,44 +0,0 @@ -class Triggers::PreRelease - class ParallelBranches - include ApplicationHelper - - def self.call(release, release_branch) - new(release, release_branch).call - end - - def initialize(release, release_branch) - @release = release - @release_branch = release_branch - end - - def call - create_and_merge_pr - end - - private - - attr_reader :release, :release_branch - delegate :train, to: :release - delegate :vcs_provider, :working_branch, to: :train - - def create_and_merge_pr - Triggers::PullRequest.create_and_merge!( - release: release, - new_pull_request_attrs: {phase: :pre_release, kind: :forward_merge, release_id: release.id, state: :open}, - to_branch_ref: release_branch, - from_branch_ref: working_branch, - title: pr_title, - description: pr_description, - allow_without_diff: false - ) - end - - def pr_title - "[#{version_in_progress(train.version_current)}] Pre-release merge" - end - - def pr_description - "A new release train #{train.name} is starting. The #{working_branch} branch has to be merged into #{release_branch} branch." - end - end -end diff --git a/app/libs/triggers/pre_release/release_back_merge.rb b/app/libs/triggers/pre_release/release_back_merge.rb deleted file mode 100644 index 49a84aa99..000000000 --- a/app/libs/triggers/pre_release/release_back_merge.rb +++ /dev/null @@ -1,8 +0,0 @@ -class Triggers::PreRelease - class ReleaseBackMerge - def self.call(release, release_branch) - # ReleaseBackMerge behaves the same as AlmostTrunk while making a new release - Triggers::PreRelease::AlmostTrunk.call(release, release_branch) - end - end -end diff --git a/app/libs/triggers/version_bump.rb b/app/libs/triggers/version_bump.rb index d6feb0d74..d63db1069 100644 --- a/app/libs/triggers/version_bump.rb +++ b/app/libs/triggers/version_bump.rb @@ -6,11 +6,15 @@ class Triggers::VersionBump DEFAULT_PR_AUTHOR_EMAIL = "tramline-bot@tramline.app" def self.call(release) + return unless release.train.version_bump_enabled? new(release).call end def initialize(release) @release = release + @train = release.train + raise ArgumentError, "Version bumping is not enabled" unless @train.version_bump_enabled? + @strategy = @train.version_bump_strategy.to_sym end def call @@ -18,8 +22,7 @@ def call create_branch.then { update_files_and_create_pr } end - attr_reader :release - delegate :train, :release_version, to: :release + attr_reader :release, :train, :strategy delegate :working_branch, :version_bump_file_paths, :version_bump_branch_prefix, to: :train delegate :logger, to: Rails @@ -53,24 +56,7 @@ def update_files_and_create_pr end # create (and merge) PR - pr_title = "Bump version to #{release_version}" - pr_body = <<~BODY - 🎉 A new release #{release_version} has kicked off! - - This PR updates the version number in `#{updated_files.join(", ")}` to prepare for our #{release_version} release. - - All aboard the release train! - BODY - Triggers::PullRequest.create_and_merge!( - release: release, - new_pull_request_attrs: {phase: :pre_release, kind: :version_bump, release_id: release.id, state: :open}, - existing_pr: release.pull_requests.pre_release.version_bump_type.open.first, - to_branch_ref: working_branch, - from_branch_ref: version_bump_branch, - title: pr_title, - description: pr_body, - error_result_on_auto_merge: true - ) + Triggers::PullRequest.create_and_merge!(**pr_attributes(pr_title, pr_body(updated_files))) end # The matchers will update all instances of matches in the file (can be more than 1) @@ -123,7 +109,7 @@ def update_pubspec_version(content) def update_gradle_version(content) content .then { |c| c.gsub(/versionName\s+"[^"]*"/, "versionName \"#{release_version}\"") } # direct declaration - .then { |c| c.gsub(/("versionName"\s*:\s*)"[^"]*"/, "\\1\"#{release_version}\"") } # dictionary declaration + .then { |c| c.gsub(/("versionName"\s*:\s*)"[^"]*"/, "\\1\"#{release_version}\"") } # dictionary declaration end # The version line typically looks like: versionName = "1.0.0" @@ -147,4 +133,66 @@ def update_pbxproj_version(content) memoize def version_bump_branch [version_bump_branch_prefix, "version-bump", release_version, release.slug].compact_blank.join("-") end + + memoize def release_version + case strategy + when :current_version_before_release_branch + release.release_version + when :next_version_after_release_branch + release.next_version + end + end + + def pr_title + case strategy + when :current_version_before_release_branch + "Bump version to #{release_version}" + when :next_version_after_release_branch + "Update next version to #{release_version}" + end + end + + def pr_body(updated_files) + case strategy + when :current_version_before_release_branch + <<~BODY + 🎉 A new release #{release_version} has kicked off! + + This PR updates the version number in `#{updated_files.join(", ")}` to prepare for our #{release_version} release. + + All aboard the release train! + BODY + when :next_version_after_release_branch + <<~BODY + This PR updates the next version number in `#{updated_files.join(", ")}` to prepare for future releases. + + All aboard the release train! + BODY + end + end + + def pr_attributes(title, description) + base = {release:, title:, description:, error_result_on_auto_merge: true} + new = + case strategy + when :current_version_before_release_branch + { + new_pull_request_attrs: {phase: :pre_release, kind: :version_bump, release_id: release.id, state: :open}, + existing_pr: release.pull_requests.pre_release.version_bump_type.open.first, + to_branch_ref: working_branch, + from_branch_ref: version_bump_branch + } + when :next_version_after_release_branch + { + new_pull_request_attrs: {phase: :mid_release, kind: :version_bump, release_id: release.id, state: :open}, + existing_pr: release.pull_requests.mid_release.version_bump_type.open.first, + to_branch_ref: working_branch, + from_branch_ref: version_bump_branch + } + else + {} + end + + base.merge(new) + end end diff --git a/app/models/train.rb b/app/models/train.rb index 00a52f7d2..0e47a5fae 100644 --- a/app/models/train.rb +++ b/app/models/train.rb @@ -36,6 +36,7 @@ # version_bump_branch_prefix :string # version_bump_enabled :boolean default(FALSE) # version_bump_file_paths :string default([]), is an Array +# version_bump_strategy :string # version_current :string # version_seeded_with :string # versioning_strategy :string default("semver") @@ -68,6 +69,10 @@ class Train < ApplicationRecord pbxproj: ".pbxproj", yaml: ".yaml" }.freeze + VERSION_BUMP_STRATEGIES = { + current_version_before_release_branch: "Current Version Before Release Branch Cuts", + next_version_after_release_branch: "Next Version After Release Branch Cuts" + }.freeze belongs_to :app has_many :releases, -> { sequential }, inverse_of: :train, dependent: :destroy @@ -89,6 +94,7 @@ class Train < ApplicationRecord enum :status, {draft: "draft", active: "active", inactive: "inactive"} enum :backmerge_strategy, {continuous: "continuous", on_finalize: "on_finalize"} enum :versioning_strategy, VersioningStrategies::Semverish::STRATEGIES.keys.zip_map_self.transform_values(&:to_s) + enum :version_bump_strategy, VERSION_BUMP_STRATEGIES.keys.zip_map_self.transform_values(&:to_s) friendly_id :name, use: :slugged normalizes :name, with: ->(name) { name.squish } @@ -112,6 +118,7 @@ class Train < ApplicationRecord validates :name, format: {with: /\A[a-zA-Z0-9\s_\/-]+\z/, message: :invalid} validate :version_config_constraints validate :version_bump_config + validates :version_bump_strategy, inclusion: {in: VERSION_BUMP_STRATEGIES.keys.map(&:to_s)}, if: -> { version_bump_enabled? } after_initialize :set_branching_strategy, if: :new_record? after_initialize :set_constituent_seed_versions, if: :persisted? @@ -597,6 +604,11 @@ def version_config_constraints def version_bump_config if version_bump_enabled? + if version_bump_strategy.blank? + errors.add(:version_bump_strategy, :blank) + return + end + if version_bump_file_paths.blank? errors.add(:version_bump_file_paths, :blank) return diff --git a/app/views/trains/_form.html.erb b/app/views/trains/_form.html.erb index 757892576..33b3a9b89 100644 --- a/app/views/trains/_form.html.erb +++ b/app/views/trains/_form.html.erb @@ -322,6 +322,12 @@ <% end %> <% component.with_child do %> + <%= section.F.labeled_select :version_bump_strategy, + "Version Bump Strategy", + options_for_select(Train::VERSION_BUMP_STRATEGIES.invert, train.version_bump_strategy), + {disabled: !train.version_bump_enabled?}, + {} %> + <%= section.F.labeled_text_field :version_bump_file_paths, "Build File Paths", value: list_to_csv(section.F.object.version_bump_file_paths), diff --git a/config/locales/en.yml b/config/locales/en.yml index 869c0c861..32d92fabb 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -493,6 +493,8 @@ en: backmerge_strategy: continuous_not_allowed: "continuous backmerge only allowed for Almost Trunk branching strategy" disabled_for_bitbucket: "continuous backmerge is not allowed for Bitbucket at the moment" + version_bump_strategy: + blank: "must be picked" version_bump_file_paths: blank: "must have at least one file path" blank_file: "it should be a valid comma-separated list of files" diff --git a/db/data/20250102175116_add_new_notifications.rb b/db/data/20250102175116_add_new_notifications.rb index af18b0ef0..4e9643e0e 100644 --- a/db/data/20250102175116_add_new_notifications.rb +++ b/db/data/20250102175116_add_new_notifications.rb @@ -2,6 +2,7 @@ class AddNewNotifications < ActiveRecord::Migration[7.2] def up + return ActiveRecord::Base.transaction do Train.all.where.not(notification_channel: nil).each do |train| next if train.notification_settings.empty? diff --git a/db/data/20250305103930_convert_changelog_commits_to_commit_objects.rb b/db/data/20250305103930_convert_changelog_commits_to_commit_objects.rb index 7c798358e..87d12b29e 100644 --- a/db/data/20250305103930_convert_changelog_commits_to_commit_objects.rb +++ b/db/data/20250305103930_convert_changelog_commits_to_commit_objects.rb @@ -2,6 +2,7 @@ class ConvertChangelogCommitsToCommitObjects < ActiveRecord::Migration[7.0] def up + return commits_processed = 0 ActiveRecord::Base.transaction do ReleaseChangelog.pluck(:id, :release_id, :commits).each do |changelog_id, release_id, changelog_commits| diff --git a/db/data/20250428124117_update_new_tag_configs.rb b/db/data/20250428124117_update_new_tag_configs.rb index 74f800b6a..f57cffcb4 100644 --- a/db/data/20250428124117_update_new_tag_configs.rb +++ b/db/data/20250428124117_update_new_tag_configs.rb @@ -2,6 +2,7 @@ class UpdateNewTagConfigs < ActiveRecord::Migration[7.2] def up + return Train.all.find_each do |train| train.update(tag_end_of_release_vcs_release: train.tag_end_of_release?) end diff --git a/db/data/20250505112729_add_workflow_trigger_failed_notification.rb b/db/data/20250505112729_add_workflow_trigger_failed_notification.rb index 870d9ff87..f67f33828 100644 --- a/db/data/20250505112729_add_workflow_trigger_failed_notification.rb +++ b/db/data/20250505112729_add_workflow_trigger_failed_notification.rb @@ -2,6 +2,7 @@ class AddWorkflowTriggerFailedNotification < ActiveRecord::Migration[7.2] def up + return ActiveRecord::Base.transaction do Train.all.where.not(notification_channel: nil).find_each do |train| next if train.notification_settings.empty? diff --git a/db/data/20250509122543_update_pull_requests_to_normalize_kinds_and_phases.rb b/db/data/20250509122543_update_pull_requests_to_normalize_kinds_and_phases.rb index 0be57ac7c..d4623082b 100644 --- a/db/data/20250509122543_update_pull_requests_to_normalize_kinds_and_phases.rb +++ b/db/data/20250509122543_update_pull_requests_to_normalize_kinds_and_phases.rb @@ -2,6 +2,7 @@ class UpdatePullRequestsToNormalizeKindsAndPhases < ActiveRecord::Migration[7.2] def up + return PullRequest.transaction do PullRequest.find_each do |pull_request| if pull_request.phase == "version_bump" diff --git a/db/data/20250514142607_update_notification_settings_to_add_release_specific_channels.rb b/db/data/20250514142607_update_notification_settings_to_add_release_specific_channels.rb index b1e6bc191..9babde142 100644 --- a/db/data/20250514142607_update_notification_settings_to_add_release_specific_channels.rb +++ b/db/data/20250514142607_update_notification_settings_to_add_release_specific_channels.rb @@ -2,6 +2,7 @@ class UpdateNotificationSettingsToAddReleaseSpecificChannels < ActiveRecord::Migration[7.2] def up + return # find all trains with release-specific channels enabled Train.where(notifications_release_specific_channel_enabled: true).find_each do |train| notification_settings = train.notification_settings.release_specific_channel_allowed diff --git a/db/data/20250527062528_notifications_copy_active_flag_to_core_enabled.rb b/db/data/20250527062528_notifications_copy_active_flag_to_core_enabled.rb index 9848b07cb..08c7b5dd8 100644 --- a/db/data/20250527062528_notifications_copy_active_flag_to_core_enabled.rb +++ b/db/data/20250527062528_notifications_copy_active_flag_to_core_enabled.rb @@ -2,6 +2,7 @@ class NotificationsCopyActiveFlagToCoreEnabled < ActiveRecord::Migration[7.2] def up + return # Update core_enabled flag for notifications which are currently active NotificationSetting.where(active: true).update_all(core_enabled: true) diff --git a/db/data/20250527142253_update_version_bumping_strategies.rb b/db/data/20250527142253_update_version_bumping_strategies.rb new file mode 100644 index 000000000..81eb689ce --- /dev/null +++ b/db/data/20250527142253_update_version_bumping_strategies.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class UpdateVersionBumpingStrategies < ActiveRecord::Migration[7.2] + def up + Train.where(version_bump_enabled: true).find_each do |train| + train.version_bump_strategy = Train.version_bump_strategies[:current_version_before_release_branch] + train.save! + end + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/db/data_schema.rb b/db/data_schema.rb index 75fe7fcb9..985d51e50 100644 --- a/db/data_schema.rb +++ b/db/data_schema.rb @@ -1 +1 @@ -DataMigrate::Data.define(version: 20250514142607) +DataMigrate::Data.define(version: 20250527142253) diff --git a/db/migrate/20250521145722_add_version_bumping_strategies.rb b/db/migrate/20250521145722_add_version_bumping_strategies.rb new file mode 100644 index 000000000..f87fa274e --- /dev/null +++ b/db/migrate/20250521145722_add_version_bumping_strategies.rb @@ -0,0 +1,5 @@ +class AddVersionBumpingStrategies < ActiveRecord::Migration[7.2] + def change + add_column :trains, :version_bump_strategy, :string, null: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 987c64f21..8313d4dc7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -965,6 +965,7 @@ t.boolean "tag_end_of_release_vcs_release", default: false t.boolean "tag_store_releases_vcs_release", default: false t.boolean "notifications_release_specific_channel_enabled", default: false + t.string "version_bump_strategy" t.index ["app_id"], name: "index_trains_on_app_id" end diff --git a/lib/tasks/anonymize.rake b/lib/tasks/anonymize.rake index f00849fed..f8948861c 100644 --- a/lib/tasks/anonymize.rake +++ b/lib/tasks/anonymize.rake @@ -50,7 +50,7 @@ namespace :anonymize do "repeat_duration", "build_queue_wait_time", "build_queue_size", "backmerge_strategy", "manual_release", "tag_store_releases_with_platform_names", "tag_store_releases", "compact_build_notes", "tag_end_of_release", "build_queue_enabled", "kickoff_at", "versioning_strategy", "send_build_notes", "notifications_release_specific_channel_enabled", - "tag_end_of_release_prefix", "tag_end_of_release_suffix" + "tag_end_of_release_prefix", "tag_end_of_release_suffix", "version_bump_strategy" whitelist_timestamps anonymize("app_id") { |field| app.id } anonymize("notification_channel") { |field| {"id" => "dummy", "name" => "test", "is_private" => false} } diff --git a/spec/factories/trains.rb b/spec/factories/trains.rb index 61f0d915c..96febca38 100644 --- a/spec/factories/trains.rb +++ b/spec/factories/trains.rb @@ -59,6 +59,12 @@ build_queue_wait_time { 1.hour } end + trait :with_version_bump do + version_bump_enabled { true } + version_bump_file_paths { ["pubspec.yaml"] } + version_bump_strategy { :current_version_before_release_branch } + end + after(:build) do |train| def train.working_branch_presence = true diff --git a/spec/libs/triggers/pre_release/almost_trunk_spec.rb b/spec/libs/coordinators/pre_release/almost_trunk_spec.rb similarity index 96% rename from spec/libs/triggers/pre_release/almost_trunk_spec.rb rename to spec/libs/coordinators/pre_release/almost_trunk_spec.rb index 2c7a30965..be3b6acf3 100644 --- a/spec/libs/triggers/pre_release/almost_trunk_spec.rb +++ b/spec/libs/coordinators/pre_release/almost_trunk_spec.rb @@ -2,7 +2,7 @@ require "rails_helper" -describe Triggers::PreRelease::AlmostTrunk do +describe Coordinators::PreRelease::AlmostTrunk do describe ".call" do let(:working_branch) { "main" } let(:release_tag_name) { Faker::Lorem.word } @@ -41,7 +41,7 @@ end context "when version bump is enabled" do - let(:train) { create(:train, working_branch: working_branch, version_bump_enabled: true, version_bump_file_paths: ["pubspec.yaml"]) } + let(:train) { create(:train, :with_version_bump, working_branch: working_branch) } let(:release) { create(:release, train: train, tag_name: release_tag_name) } let(:commit) { create(:commit, release:) } let(:release_branch) { release.release_branch } diff --git a/spec/libs/triggers/version_bump_spec.rb b/spec/libs/triggers/version_bump_spec.rb index ffa3bd610..0341e18f1 100644 --- a/spec/libs/triggers/version_bump_spec.rb +++ b/spec/libs/triggers/version_bump_spec.rb @@ -24,7 +24,7 @@ def setup_mocks(train, vcs_provider_dbl, project_file, updated_contents_file) context "when a version bump PR is attempted" do let(:project_file) { "spec/fixtures/project_files/build.1.0.0.gradle" } let(:updated_contents_file) { "spec/fixtures/project_files/build.1.2.0.gradle" } - let(:train) { create(:train, version_seeded_with: "1.1.0", version_bump_enabled: true, version_bump_file_paths: [project_file]) } + let(:train) { create(:train, :with_version_bump, version_seeded_with: "1.1.0", version_bump_file_paths: [project_file]) } let(:release) { create(:release, train:) } let(:vcs_provider_dbl) { instance_double(GithubIntegration) } let(:expected_new_branch) { "version-bump-#{release.release_version}-#{release.slug}" } @@ -97,7 +97,7 @@ def setup_mocks(train, vcs_provider_dbl, project_file, updated_contents_file) project_file = "spec/fixtures/project_files/build.1.0.0.gradle" updated_contents_file = "spec/fixtures/project_files/build.1.2.0.gradle" updated_contents = File.read(updated_contents_file) - train = create(:train, version_seeded_with: "1.1.0", version_bump_enabled: true, version_bump_file_paths: [project_file]) + train = create(:train, :with_version_bump, version_seeded_with: "1.1.0", version_bump_file_paths: [project_file]) release = create(:release, train:) setup_mocks(train, vcs_provider_dbl, project_file, updated_contents_file) @@ -110,7 +110,7 @@ def setup_mocks(train, vcs_provider_dbl, project_file, updated_contents_file) project_file = "spec/fixtures/project_files/build.1.0.0.dict.gradle" updated_contents_file = "spec/fixtures/project_files/build.1.2.0.dict.gradle" updated_contents = File.read(updated_contents_file) - train = create(:train, version_seeded_with: "1.1.0", version_bump_enabled: true, version_bump_file_paths: [project_file]) + train = create(:train, :with_version_bump, version_seeded_with: "1.1.0", version_bump_file_paths: [project_file]) release = create(:release, train:) setup_mocks(train, vcs_provider_dbl, project_file, updated_contents_file) @@ -123,7 +123,7 @@ def setup_mocks(train, vcs_provider_dbl, project_file, updated_contents_file) project_file = "spec/fixtures/project_files/build.1.0.0.gradle.kts" updated_contents_file = "spec/fixtures/project_files/build.1.2.0.gradle.kts" updated_contents = File.read(updated_contents_file) - train = create(:train, version_seeded_with: "1.1.0", version_bump_enabled: true, version_bump_file_paths: [project_file]) + train = create(:train, :with_version_bump, version_seeded_with: "1.1.0", version_bump_file_paths: [project_file]) release = create(:release, train:) setup_mocks(train, vcs_provider_dbl, project_file, updated_contents_file) @@ -136,7 +136,7 @@ def setup_mocks(train, vcs_provider_dbl, project_file, updated_contents_file) project_file = "spec/fixtures/project_files/build.1.0.0.pubspec.yaml" updated_contents_file = "spec/fixtures/project_files/build.1.2.0.pubspec.yaml" updated_contents = File.read(updated_contents_file) - train = create(:train, version_seeded_with: "1.1.0", version_bump_enabled: true, version_bump_file_paths: [project_file]) + train = create(:train, :with_version_bump, version_seeded_with: "1.1.0", version_bump_file_paths: [project_file]) release = create(:release, train:) setup_mocks(train, vcs_provider_dbl, project_file, updated_contents_file) @@ -147,7 +147,8 @@ def setup_mocks(train, vcs_provider_dbl, project_file, updated_contents_file) end describe "#update_gradle_version" do - let(:release) { create(:release) } + let(:train) { create(:train, :with_version_bump) } + let(:release) { create(:release, train:) } before do allow(release).to receive(:release_version).and_return("1.2.0") @@ -176,7 +177,8 @@ def setup_mocks(train, vcs_provider_dbl, project_file, updated_contents_file) end describe "#update_gradle_kts_version" do - let(:release) { create(:release) } + let(:train) { create(:train, :with_version_bump) } + let(:release) { create(:release, train:) } before do allow(release).to receive(:release_version).and_return("1.2.0") @@ -203,7 +205,8 @@ def setup_mocks(train, vcs_provider_dbl, project_file, updated_contents_file) end describe "#update_pubspec_version" do - let(:release) { create(:release) } + let(:train) { create(:train, :with_version_bump) } + let(:release) { create(:release, train:) } before do allow(release).to receive(:release_version).and_return("1.2.0")