Skip to content

Commit

Permalink
Merge pull request #6358 from openSUSE/staging-workflow
Browse files Browse the repository at this point in the history
Staging workflow -> master
  • Loading branch information
bgeuken committed Dec 12, 2018
2 parents a5a81c2 + 55641bf commit 9b63b11
Show file tree
Hide file tree
Showing 144 changed files with 27,637 additions and 116 deletions.
33 changes: 33 additions & 0 deletions docs/api/api/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1930,6 +1930,39 @@ DELETE /status_reports/repositories/<project>/<repository>/required_checks/<chec
Delete a required check
XmlResult: required_checks

== Staging
WARNING: This API is currently in beta and unstable

=== Excluded Requests

<project>: The name of the main project of a Staging, e.g. openSUSE_Tumbleweed
<request>: The number of the request, e.g. 12345
<description>: A string of text (url encoded)

POST /staging/<project>/excluded_requests/<request>?description=<description>
Exclude this request from this Staging

DELETE /staging/<project>/excluded_requests/<request>
Stop excluding this request

=== Staged Requests

<staging_workflow_project>: The name of the staging workflow project, e.g. home:user1
<staging_project>: The name of the staging project, e.g. home:user1:Staging:A

GET /staging/<staging_workflow_project>/staging_projects/<staging_project>/staged_requests
Get all staged requests of a staging project.
XmlResult: staged_requests

POST /staging/<staging_workflow_project>/staging_projects/<staging_project>/staged_requests
Add one or multiple bs_requests to the staged requests of a staging project.
XmlBody: remove_staged_requests
XmlResult: status_ok

DELETE /staging/<staging_workflow_project>/staging_projects/<staging_project>/staged_requests
Remove one or multiple bs_requests to the staged requests of a staging project.
XmlResult: status_ok

== Internal only routes

/public shall not be used in any tools, it is for OBS remote support only and may
Expand Down
4 changes: 4 additions & 0 deletions docs/api/api/remove_staged_requests.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<requests>
<number>7</number>
<number>13</number>
</requests>
4 changes: 4 additions & 0 deletions docs/api/api/staged_requests.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<staged_requests>
<request id="7" creator="tux" state="new" package="aaa_base"/>
<request id="13" creator="bob" state="review" package="ruby"/>
</staged_requests>
3 changes: 3 additions & 0 deletions docs/api/api/status_ok.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<status code="ok">
<summary>Ok</summary>
</status>
1 change: 1 addition & 0 deletions src/api/app/assets/javascripts/webui2/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@
//= require webui2/jquery-ui.min.js
//= require webui2/cm2/use-codemirror.js
//= require webui2/package-view_file.js
//= require webui2/staging_workflow.js
//= require webui2/project_monitor.js
27 changes: 27 additions & 0 deletions src/api/app/assets/javascripts/webui2/staging_workflow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
function setSpinnersForDeletion() { // jshint ignore:line
$("#staging-workflow-delete").on('ajax:beforeSend', function(){
$(this).find('.delete-spinner').removeClass('d-none');
});

$("#staging-workflow-delete").on('ajax:complete', function(){
$(this).find('.delete-spinner').addClass('d-none');
});
}

function autocompleteStagingManagersGroup() { // jshint ignore:line
$('#managers_title').autocomplete({
appendTo: '#assign-managers-group-modal-input',
source: $('#managers_title').data('autocompleteGroupsUrl'),
search: function() {
var icon = $('#assign-managers-group-search-icon i:first-child');
icon.addClass('d-none');
icon.next().removeClass('d-none');
},
response: function() {
var icon = $('#assign-managers-group-search-icon i:first-child');
icon.removeClass('d-none');
icon.next().addClass('d-none');
},
minLength: 2
});
}
13 changes: 13 additions & 0 deletions src/api/app/assets/stylesheets/webui2/collapse-component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[data-toggle="collapse"] {
&[aria-expanded="false"] {
.collapser {
display: none;
}
}

&[aria-expanded="true"] {
.expander {
display: none;
}
}
}
112 changes: 112 additions & 0 deletions src/api/app/assets/stylesheets/webui2/staging-workflow.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
.legend {
ul {
@extend .ml-2;

li {
span {
display: inline-flex;
width: 1rem;
height: 1rem;
@extend .border;
@extend .border-dark;
}
}
}
}

ul .table-list-group-item {
padding: 0.5rem 0.75rem;
background-color: transparent;
}

#staging-projects-datatable td,
#staging-project-package-list {
span.badge {
font-size: inherit;
font-weight: inherit;
}

&.project {
> span.badge {
@extend .w-100;

> span.badge {
@extend .m-1;
}
}

span.badge {
&.state-unacceptable {
@extend .badge-dark;
}

&.state-acceptable {
@extend .badge-success;
}

&.state-testing {
@extend .badge-info;
}

&.state-building {
@extend .badge-warning;

span {
@extend .text-dark;
}
}

&.state-failed {
@extend .badge-danger;
}

&.state-review {
@extend .badge-secondary;
}

&.state-empty {
@extend .badge-light;
@extend .border;

span {
@extend .text-dark;
}
}
}
}

&.requests {
@extend .w-50;

a.request {
@extend .text-white;
padding: 0 0.125rem 0.25rem;

&:hover {
text-decoration: none;
}

span.badge {
&.state-ready {
@extend .badge-success;
}

&.state-review {
@extend .badge-warning;
}

&.state-obsolete {
@extend .badge-info;
}

&.state-untracked {
@extend .badge-dark;
}
}
}

a, div.collapse, div.collapsing {
float: left;
}
}
}
2 changes: 2 additions & 0 deletions src/api/app/assets/stylesheets/webui2/webui2.css.scss
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
@import 'live_build_log';
@import 'borders';
@import 'diff';
@import 'staging-workflow';
@import 'repositories';
@import 'collapse-component';
@import 'project-package-show-grid';
@import 'user';
@import 'watchlist';
Expand Down
4 changes: 4 additions & 0 deletions src/api/app/controllers/source/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ class PutFileNoPermission < APIError

class WrongRouteForAttribute < APIError; end

class WrongRouteForStagingWorkflow < APIError
setup 403, 'Staging workflows can not be changed through the API'
end

class AttributeNotFound < APIError
setup 'not_found', 404
end
Expand Down
3 changes: 3 additions & 0 deletions src/api/app/controllers/source_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,9 @@ def check_permissions_for_file
if @file == '_attribute' && @package_name == '_project'
raise WrongRouteForAttribute, "Attributes need to be changed through #{change_attribute_path(project: params[:project])}"
end
if @file == '_staging_workflow' && @package_name == '_project'
raise WrongRouteForStagingWorkflow
end
else
# we need a local package here in any case for modifications
@pack = Package.get_by_project_and_name(@project_name, @package_name)
Expand Down
54 changes: 54 additions & 0 deletions src/api/app/controllers/staging/excluded_requests_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
class Staging::ExcludedRequestsController < ApplicationController
before_action :require_login
before_action :set_staging_workflow, only: :create
before_action :set_request_exclusion, only: :destroy

def create
request = @staging_workflow.target_of_bs_requests.find_by!(number: params[:number])
request_exclusion = @staging_workflow.request_exclusions.build(bs_request: request, description: params[:description])

authorize request_exclusion

if request_exclusion.save
render_ok
else
render_error(
status: 400,
errorcode: 'invalid_request',
message: request_exclusion.errors.full_messages.to_sentence
)
end
end

def destroy
authorize @request_exclusion

if @request_exclusion.destroy
render_ok
else
render_error(
status: 400,
errorcode: 'invalid_request',
message: "Request #{@request_exclusion.number} couldn't be unexcluded"
)
end
end

private

def set_staging_workflow
project = Project.get_by_name(params[:staging_main_project_name])
@staging_workflow = project.staging
return if @staging_workflow

raise InvalidParameterError, "Project #{params[:staging_main_project_name]} doesn't have an asociated Staging Workflow"
end

def set_request_exclusion
request = BsRequest.find_by!(number: params[:number])
@request_exclusion = request.request_exclusion
return if @request_exclusion

raise InvalidParameterError, "Request #{params[:number]} is not excluded"
end
end
82 changes: 82 additions & 0 deletions src/api/app/controllers/staging/staged_requests_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
class Staging::StagedRequestsController < ApplicationController
before_action :require_login, except: [:index]
before_action :set_staging_project
before_action :set_staging_workflow, :set_project, :set_xml_hash, only: [:create, :destroy]

def index
@requests = @staging_project.staged_requests
end

def create
authorize @staging_project, :update?

result = ::Staging::StageRequests.new(
request_numbers: request_numbers,
staging_workflow: @staging_workflow,
staging_project: @staging_project
).perform

if result.valid?
render_ok
else
render_error(
status: 400,
errorcode: 'invalid_request',
message: "Assigning requests to #{@staging_project} failed: #{result.errors.to_sentence}."
)
end
end

def destroy
authorize @staging_project, :update?
requests = @staging_project.staged_requests.where(number: request_numbers)
package_names = requests.joins(:bs_request_actions).pluck('bs_request_actions.target_package')

@staging_project.staged_requests.delete(requests)
not_unassigned_requests = request_numbers - requests.pluck(:number).map(&:to_s)

result = @staging_project.packages.where(name: package_names).destroy_all
not_deleted_packages = package_names - result.pluck(:name)

if not_unassigned_requests.empty? && not_deleted_packages.empty?
render_ok
else
message = 'Error while unassigning requests: '
message << "Requests with number #{not_unassigned_requests.to_sentence} not found. " unless not_unassigned_requests.empty?
message << "Could not delete packages #{not_deleted_packages.to_sentence}." unless not_deleted_packages.empty?
render_error(
status: 400,
errorcode: 'invalid_request',
message: message
)
end
end

private

def set_xml_hash
@xml_hash = (Xmlhash.parse(request.body.read) || {}).with_indifferent_access
end

def request_numbers
[@xml_hash[:number]].flatten
end

def set_staging_project
@staging_project = Staging::StagingProject.get_by_name(params[:staging_project_name])
end

def set_staging_workflow
@staging_workflow = @staging_project.staging_workflow
return if @staging_workflow
render_error(
status: 422,
errorcode: 'invalid_request',
message: "#{@staging_project} is not a valid staging project, can't assign requests to it."
)
end

def set_project
@project = @staging_workflow.project
end
end

0 comments on commit 9b63b11

Please sign in to comment.