Skip to content
Permalink
Browse files

Make PREvant more rustic

- Respond with "problem detail" (see RFC7807)
- Create tickets module to serve the tickets resource
- Remove command objects
  • Loading branch information...
schrieveslaach committed Feb 21, 2019
1 parent fbb454e commit a187e72ce5b13f5fa41d721bb10e7237b797236b

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
@@ -29,9 +29,13 @@ rocket_contrib = "0.4"
rocket-cache-response = "0.5"
url = "1.7"

[dependencies.http-api-problem]
version = "0.12"
features = ["with_rocket"]

[dependencies.shiplift]
git = "https://github.com/schrieveslaach/shiplift.git"
rev = "7d1067cb71f5a619e78c967084f5e59de38fd0b7"
rev = "00df424336b919184b8d0d26a85822589577913d"
default-features = false
features = ["unix-socket"]

@@ -26,6 +26,12 @@ paths:
properties:
"^[a-zA-Z0-9_-]":
$ref: '#/components/schemas/Service'
'500':
description: Server error
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
/apps/tickets/:
get:
summary: Provides ticket information to each review app
@@ -39,6 +45,14 @@ paths:
properties:
"^[a-zA-Z0-9_-]":
$ref: '#/components/schemas/Ticket'
'204':
description: 'No ticket system configuration'
'500':
description: Server error
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
/apps/{appName}:
post:
summary: Start or update a new review app.
@@ -68,6 +82,12 @@ paths:
type: array
items:
$ref: '#/components/schemas/Service'
'500':
description: Server error
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
delete:
summary: Shutdown a review app
parameters:
@@ -92,6 +112,18 @@ paths:
type: array
items:
$ref: '#/components/schemas/Service'
'404':
description: Cannot find app
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
'500':
description: Server error
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
/webhooks/:
post:
summary: Cleans up apps when webhook triggers this resource.
@@ -106,7 +138,29 @@ paths:
required: true
content:
application/json:
$ref: '#/components/schemas/BitbucketWebHookPayload'
schema:
$ref: '#/components/schemas/BitbucketWebHookPayload'
responses:
'200':
description: 'List of deleted containers'
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Service'
'404':
description: Cannot find app
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
'500':
description: Server error
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
components:
schemas:
Service:
@@ -162,8 +216,8 @@ components:
type: string
description: Key value list of enviroment variables
example:
- MYSQL_USER=admin
- MYSQL_DATABASE=dbname
- MYSQL_USER=admin
- MYSQL_DATABASE=dbname
volumes:
type: array
items:
@@ -201,4 +255,16 @@ components:
displayId:
type: string
description: The branch name containing the ticket number `XXX-123`.
example: 'feature/XXX-123-some-feature-branch'
example: 'feature/XXX-123-some-feature-branch'
ProblemDetails:
type: object
description: Defines a "problem detail" according to [RFC 7807](https://tools.ietf.org/html/rfc7807).
properties:
type:
type: string
status:
type: integer
title:
type: string
detail:
type: string
@@ -24,57 +24,100 @@
* =========================LICENSE_END==================================
*/

use crate::commands::create_app_command::{CreateOrUpdateAppCommand, CreateOrUpdateError};
use crate::commands::delete_app_command::{DeleteAppCommand, DeleteAppError};
use crate::commands::list_apps_command::{ListAppsCommand, ListAppsError};
use crate::commands::list_tickets_command::{ListTicketsCommand, ListTicketsError};
use crate::models::service::Service;
use crate::models::ticket_info::TicketInfo;
use crate::models::request_info::RequestInfo;
use crate::models::service::{Service, ServiceConfig};
use crate::services::apps_service::AppsService;
use crate::services::config_service::Config;
use http_api_problem::HttpApiProblem;
use multimap::MultiMap;
use rocket::data::{self, FromDataSimple};
use rocket::http::RawStr;
use rocket::http::Status;
use rocket::request::Request;
use rocket::Data;
use rocket::Outcome::{Failure, Success};
use rocket::State;
use rocket_contrib::json::Json;
use std::collections::HashMap;
use std::io::Read;

#[get("/apps", format = "application/json")]
pub fn apps(
config_state: State<Config>,
list_apps_command: ListAppsCommand,
) -> Result<Json<MultiMap<String, Service>>, ListAppsError> {
let apps = list_apps_command.list_apps(&config_state)?;
Ok(Json(apps))
}
request_info: RequestInfo,
) -> Result<Json<MultiMap<String, Service>>, HttpApiProblem> {
let apps_service = AppsService::new(&config_state)?;
let mut apps = apps_service.get_apps()?;

for (_, services) in apps.iter_all_mut() {
for service in services.iter_mut() {
service.set_base_url(request_info.get_base_url());
}
}

#[get("/apps/tickets", format = "application/json")]
pub fn tickets(
config_state: State<Config>,
list_tickets_command: ListTicketsCommand,
) -> Result<Json<HashMap<String, TicketInfo>>, ListTicketsError> {
let apps = list_tickets_command.list_ticket_infos(&config_state)?;
Ok(Json(apps))
}

#[delete("/apps/<app_name>", format = "application/json")]
pub fn delete_app(
app_name: &RawStr,
config_state: State<Config>,
delete_app_command: DeleteAppCommand,
) -> Result<Json<Vec<Service>>, DeleteAppError> {
let services = delete_app_command.delete_app(&config_state, &app_name.to_string())?;
request_info: RequestInfo,
) -> Result<Json<Vec<Service>>, HttpApiProblem> {
let apps_service = AppsService::new(&config_state)?;
let mut services = apps_service.delete_app(&app_name.to_string())?;

for service in services.iter_mut() {
service.set_base_url(request_info.get_base_url());
}

Ok(Json(services))
}

#[post(
"/apps/<app_name>",
format = "application/json",
data = "<app_command>"
data = "<service_configs_data>"
)]
pub fn create_app(
app_name: &RawStr,
config_state: State<Config>,
app_command: CreateOrUpdateAppCommand,
) -> Result<Json<Vec<Service>>, CreateOrUpdateError> {
let services = app_command.create_or_update_app(&config_state, &app_name.to_string())?;
request_info: RequestInfo,
service_configs_data: ServiceConfigsData,
) -> Result<Json<Vec<Service>>, HttpApiProblem> {
let apps_service = AppsService::new(&config_state)?;
let mut services = apps_service
.create_or_update(&app_name.to_string(), &service_configs_data.service_configs)?;

for service in services.iter_mut() {
service.set_base_url(request_info.get_base_url());
}

Ok(Json(services))
}

pub struct ServiceConfigsData {
service_configs: Vec<ServiceConfig>,
}

impl FromDataSimple for ServiceConfigsData {
type Error = String;

fn from_data(_request: &Request, data: Data) -> data::Outcome<ServiceConfigsData, String> {
let mut body = String::new();
if let Err(e) = data.open().read_to_string(&mut body) {
return Failure((Status::InternalServerError, format!("{:?}", e)));
}

let service_configs = match serde_json::from_str::<Vec<ServiceConfig>>(&body) {
Ok(v) => v,
Err(err) => {
return Failure((
Status::BadRequest,
format!("Cannot read body as JSON: {:?}", err),
));
}
};

Success(ServiceConfigsData { service_configs })
}
}
Oops, something went wrong.

0 comments on commit a187e72

Please sign in to comment.
You can’t perform that action at this time.