如何使用 Capistrano 有条件地清理版本?

How do I conditionally cleanup releases using Capistrano?

我知道我可以使用 keep_releases 来保留特定 数量 的版本,但我有一系列具有指向它们的符号链接的版本。例如,我有:

http://www.example.com/version/1.0.0 这是某个版本的符号链接,比如 /var/www/example.com/releases/2019050101。我还有一系列我称之为 "transient" 的版本,它们使用 /current/ 链接。当部署其中一个 'transient' 版本时,/current 符号链接将被覆盖到最新版本。这意味着有些版本没有指向它们的符号链接。

我想做的是指定 Capistrano 只保留 keep_releasestransient 版本。换句话说,应该始终保留从根目录建立符号链接的所有版本。

有人可以帮我用 Capistrano 方法来完成这个吗?

我最终使用了以下配方,它主要是 the cleanup recipe in the Capistrano source 的副本,除了一些额外的逻辑来确定和跳过符号链接目录:

desc "Clean up old releases"
  task :cleanup do
    on release_roles :all do |host|
      releases = capture(:ls, "-x", releases_path).split
      kept_paths = []
      within release_path.parent.parent do
        root_path = release_path.parent.parent
        links = capture(:ls, "-l", "|", "grep", "^l").split("\n")
        links.each { |x|
          next_link_target = x.split("->")[1]
          next_link_target = next_link_target.gsub("/build", "")
          target_components = next_link_target.split("/")
          next_link_target = target_components[target_components.size - 1]
          kept_paths.push(next_link_target)
        }
      end

      valid, invalid = releases.partition { |e| /^\d{14}$/ =~ e }

      warn t(:skip_cleanup, host: host.to_s) if invalid.any?

      valid, invalid = valid.partition { |v|
        split_path = v.split("/")
        !kept_paths.include? split_path[split_path.size - 1]
      }

      if invalid.any?
        info "Skipping cleanup of releases: #{invalid} because they are symlinked in the root directory"
      end

      if valid.count >= fetch(:keep_releases)
        info t(:keeping_releases, host: host.to_s, keep_releases: fetch(:keep_releases), releases: valid.count)
        directories = (valid - valid.last(fetch(:keep_releases))).map do |release|
          releases_path.join(release).to_s
        end
        if test("[ -d #{current_path} ]")
          current_release = capture(:readlink, current_path).to_s
          if directories.include?(current_release)
            warn t(:wont_delete_current_release, host: host.to_s)
            directories.delete(current_release)
          end
        else
          debug t(:no_current_release, host: host.to_s)
        end
        if directories.any?
          execute :rm, "-rf", *directories
        else
          info t(:no_old_releases, host: host.to_s, keep_releases: fetch(:keep_releases))
        end
      end
    end
  end