Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate obs factory #5140

Merged
merged 7 commits into from
Jun 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
416 changes: 359 additions & 57 deletions .rubocop_todo.yml

Large diffs are not rendered by default.

425 changes: 425 additions & 0 deletions src/api/app/assets/stylesheets/webui/obs_factory/application.css

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module Webui::ObsFactory
class ApplicationController < ::Webui::WebuiController
layout 'webui/obs_factory/application'

rescue_from ::ObsFactory::OpenqaApi::OpenqaFailure do |ex|
render text: "failure in openQA"
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
module Webui::ObsFactory
class DistributionsController < ApplicationController
respond_to :html

before_action :require_distribution, :require_dashboard

def show
@staging_projects = ::ObsFactory::StagingProjectPresenter.sort(@distribution.staging_projects)
@versions = { source: @distribution.source_version,
totest: @distribution.totest_version,
published: @distribution.published_version }
@ring_prjs = ::ObsFactory::ObsProjectPresenter.wrap(@distribution.ring_projects)
@standard = ::ObsFactory::ObsProjectPresenter.new(@distribution.standard_project)
@live = @distribution.live_project
@live = ::ObsFactory::ObsProjectPresenter.new(@live) unless @live.nil?
@images = ::ObsFactory::ObsProjectPresenter.new(@distribution.images_project)
@openqa_jobs = @distribution.openqa_jobs_for(:totest)
calculate_reviews
# For the breadcrumbs
@project = @distribution.project
end

protected

def calculate_reviews
@reviews = {}
@reviews[:review_team] = @distribution.requests_with_reviews_for_group('opensuse-review-team').size
@reviews[:factory_auto] = @distribution.requests_with_reviews_for_group('factory-auto').size
@reviews[:legal_auto] = @distribution.requests_with_reviews_for_group('legal-auto').size
@reviews[:legal_team] = @distribution.requests_with_reviews_for_group('legal-team').size
@reviews[:repo_checker] = @distribution.requests_with_reviews_for_user('repo-checker').size
end

private

def require_distribution
@distribution = ::ObsFactory::Distribution.find(params[:project])
unless @distribution
redirect_to main_app.root_path, flash: { error: "#{params[:project]} is not a valid openSUSE distribution, can't offer dashboard" }
end
end

def require_dashboard
if @distribution.staging_projects.empty?
redirect_to main_app.root_path, flash: { error: "#{params[:project]} does not offer a dashboard" }
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
module Webui::ObsFactory
class StagingProjectsController < ApplicationController
respond_to :json, :html

before_action :require_distribution
before_action :require_project_name, only: [:show]

def index
respond_to do |format|
format.html do
@staging_projects = ::ObsFactory::StagingProjectPresenter.sort(@distribution.staging_projects_all)
@backlog_requests = ::ObsFactory::Request.with_open_reviews_for(by_group: @distribution.staging_manager, target_project: @distribution.name)
@requests_state_new = ::ObsFactory::Request.in_state_new(by_group: @distribution.staging_manager, target_project: @distribution.name)

staging_project = Project.find_by_name("#{@distribution.project}:Staging")
dashboard_package = Package.find_by_project_and_name(staging_project.name, 'dashboard')

if dashboard_package && dashboard_package.file_exists?('ignored_requests')
file = ::Backend::Api::Sources::Package.file(staging_project.name, dashboard_package.name, 'ignored_requests')
@ignored_requests = YAML.load(file)
end

if @ignored_requests
@backlog_requests_ignored = @backlog_requests.select { |req| @ignored_requests.key?(req.number) }
@backlog_requests = @backlog_requests.select { |req| !@ignored_requests.key?(req.number) }
@requests_state_new = @requests_state_new.select { |req| !@ignored_requests.key?(req.number) }
@backlog_requests_ignored.sort! { |x,y| x.package <=> y.package }
else
@backlog_requests_ignored = []
end
@backlog_requests.sort! { |x,y| x.package <=> y.package }
@requests_state_new.sort! { |x,y| x.package <=> y.package }
# For the breadcrumbs
@project = @distribution.project
end
format.json { render json: @distribution.staging_projects_all }
end
end

def show
respond_to do |format|
format.html do
@staging_project = ::ObsFactory::StagingProjectPresenter.new(@staging_project)
# For the breadcrumbs
@project = @distribution.project
end
format.json { render json: @staging_project }
end
end

private

def require_distribution
@distribution = ::ObsFactory::Distribution.find(params[:project])
unless @distribution
redirect_to main_app.root_path, flash: { error: "#{params[:project]} is not a valid openSUSE distribution, can't offer dashboard" }
end
end

def require_project_name
@staging_project = ::ObsFactory::StagingProject.find(@distribution, params[:project_name])
unless @staging_project
redirect_to main_app.root_path, flash: { error: "#{params[:project_name]} is not a valid staging project" }
end
end
end
end
5 changes: 5 additions & 0 deletions src/api/app/helpers/webui/obs_factory/application_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module Webui::ObsFactory::ApplicationHelper
def openqa_links_helper
ObsFactory::OpenqaJob.openqa_links_url
end
end
224 changes: 224 additions & 0 deletions src/api/app/models/obs_factory/distribution.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
require 'open-uri'

module ObsFactory

class UnknownDistribution < Exception
end

# A Distribution. Contains a reference to the corresponding Project object.
class Distribution
include ActiveModel::Model
extend ActiveModel::Naming
extend Forwardable

SOURCE_VERSION_FILE = { package_name: '000product', filename: 'openSUSE.product' }
RINGS_PREFIX = ":Rings"

attr_accessor :project, :strategy

def initialize(project = nil)
self.project = project
self.strategy = distribution_strategy_for_project(project)
end

def self.attributes
%w(name description staging_projects openqa_version openqa_group
source_version totest_version published_version staging_manager
standard_project live_project images_project ring_projects)
end

def attributes
Hash[self.class.attributes.map { |a| [a, nil] }]
end

def_delegators :@strategy, :root_project_name, :url_suffix, :openqa_version,
:openqa_iso, :arch, :openqa_group, :staging_manager

# Find a distribution by id
#
# @return [Distribution] the distribution
def self.find(id)
project = ::Project.find_by_name(id)
if project
begin
Distribution.new(project)
rescue UnknownDistribution
nil
end
else
nil
end
end

# Name of the associated project
#
# @return [String] name of the Project object
def name
project.name
end

# Id of the distribution
#
# @return [String] name
def id
name
end

# Description of the associated project
#
# @return [String] description of the Project object
def description
project.description
end

# Version of the distribution used as ToTest
#
# @return [String] version string
def totest_version
Rails.cache.fetch("totest_version_for_#{name}", expires_in: 10.minutes) do
strategy.totest_version
end
end

# Version of the published distribution
#
# @return [String] version string
def published_version
Rails.cache.fetch("published_version_for_#{name}", expires_in: 10.minutes) do
strategy.published_version
end
end

# Staging projects associated to the distribution
#
# @return [Array] array of StagingProject objects
def staging_projects
@staging_projects ||= StagingProject.for(self)
end

# Staging projects associated to the distribution, including non-letter
#
# @return [Array] array of StagingProject objects
def staging_projects_all
@staging_projects ||= StagingProject.for(self, false)
end

# Version of the distribution used as source
#
# @return [String] version string
def source_version
Rails.cache.fetch("source_version_for_#{name}", expires_in: 10.minutes) do
begin
p = Xmlhash.parse(Backend::Api::Sources::Package.file(name, SOURCE_VERSION_FILE[:package_name], SOURCE_VERSION_FILE[:filename]))
p.get('products').get('product').get('version')
rescue ActiveXML::Transport::NotFoundError
nil
end
end
end

# openQA jobs related with a given version of the distribution
#
# @param [#to_s] version must be :source, :totest or :published
# @return [Array] list of OpenqaJob objects
def openqa_jobs_for(version)
filter = {distri: 'opensuse', version: strategy.openqa_version, build: send(:"#{version}_version"), group: strategy.openqa_group}
OpenqaJob.find_all_by(filter, exclude_modules: true)
end

# Requests with some open review targeting the distribution, filtered by
# the group in charge of the open reviews
#
# @param [String] group name of the group
# @return [Array] list of Request objects
def requests_with_reviews_for_group(group)
Request.with_open_reviews_for(by_group: group, target_project: root_project_name)
end

# Requests with some open review targeting the distribution, filtered by
# the user in charge of the open reviews
#
# @param [String] user name of the user
# @return [Array] list of Request objects
def requests_with_reviews_for_user(user)
Request.with_open_reviews_for(by_user: user, target_project: root_project_name)
end

# Standard project
#
# @return [ObsProject] standard
def standard_project
if @standard_project.nil?
@standard_project = ObsProject.new(name, 'standard')
@standard_project.exclusive_repository = 'standard'
end
@standard_project
end

# Live project
#
# @return [ObsProject] live
def live_project
if @live_project.nil?
@live_project = ObsProject.new("#{name}:Live", 'live')
if @live_project.project.nil?
@live_project = nil
else
@live_project.exclusive_repository = 'images'
end
end
@live_project
end

# Images project
#
# @return [ObsProject] images
def images_project
if @images_project.nil?
@images_project = ObsProject.new(name, 'images')
@images_project.exclusive_repository = 'images'
end
@images_project
end

# Projects defining the distribution rings
#
# @return [Array] list of ObsProject objects nicknamed with numbers
def ring_projects
@ring_projects ||= strategy.rings.each_with_index.map do |r,idx|
ObsProject.new("#{rings_project_name}:#{idx}-#{r}", "#{idx}-#{r}")
end
end

# Name of the project used as top-level for the ring projects
#
# @return [String] project name
def rings_project_name
"#{root_project_name}#{RINGS_PREFIX}"
end

# URL parameter for openqa's /test route to be opened in view
# for given project
#
# @return [String] URL part (e.g. match=A)
def openqa_filter(project)
return strategy.openqa_filter(project)
end

private

def distribution_strategy_for_project(project)
s = case project.name
when 'openSUSE:Factory' then DistributionStrategyFactory.new
when 'openSUSE:Factory:PowerPC' then DistributionStrategyFactoryPPC.new
when /^openSUSE:.*/ then DistributionStrategyOpenSUSE.new
when /^SUSE:SLE-12-SP\d:GA/ then DistributionStrategySLE12SP1.new
when /^SUSE:SLE-15:GA/ then DistributionStrategySLE15.new
when /^SUSE:SLE-12-SP.*CASP\d*/ then DistributionStrategyCasp.new
else raise UnknownDistribution
end
s.project = project
s
end
end
end
Loading