Add /hash/:hash endpoint

It looks up the given hash and finds the latest build producing an
artifact with this hash.
This commit is contained in:
Reynir Björnsson 2021-02-02 09:34:21 +01:00
parent 3a106342f5
commit 6b96cae318
5 changed files with 50 additions and 0 deletions

View file

@ -388,6 +388,23 @@ module Build = struct
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|}
let get_by_hash =
Caqti_request.find_opt
Rep.cstruct
(Caqti_type.tup2
Caqti_type.string
t)
{| SELECT job.name,
b.uuid, b.start_d, b.start_ps, b.finish_d, b.finish_ps,
b.result_kind, b.result_code, b.result_msg,
b.console, b.script, b.main_binary, b.job
FROM build_artifact a
INNER JOIN build b ON b.id = a.build
INNER JOIN job ON job.id = b.job
WHERE a.sha256 = ?
ORDER BY b.start_d DESC, b.start_ps DESC
LIMIT 1
|}
end
module User = struct

View file

@ -128,6 +128,8 @@ sig
(id, id * Meta.t * file option, [< `Many | `One | `Zero > `One `Zero ])
Caqti_request.t
val add : (t, unit, [< `Many | `One | `Zero > `Zero ]) Caqti_request.t
val get_by_hash :
(Cstruct.t, string * t, [< `Many | `One | `Zero > `One `Zero]) Caqti_request.t
end
module User : sig

View file

@ -199,12 +199,37 @@ let routes t =
Lwt.return (Response.of_plain_text "Internal server error\n" ~status:`Internal_server_error)
in
let hash req =
let hash_s = Router.param req "hash" in
let hash = try Some (Hex.to_cstruct (`Hex hash_s))
with Invalid_argument _ -> None
in
match hash with
| None ->
Log.debug (fun m -> m "Invalid hash hex %S" hash_s);
Response.of_plain_text "Bad request\n" ~status:`Bad_request
|> Lwt.return
| Some hash ->
let+ build = Caqti_lwt.Pool.use (Model.build_hash hash) t.pool in
match build with
| Error e ->
Log.warn (fun m -> m "Database error: %a" pp_error e);
Response.of_plain_text "Internal server error\n" ~status:`Internal_server_error
| Ok None ->
Log.debug (fun m -> m "Hash not found: %S" hash_s);
Response.of_plain_text "Artifact not found\n" ~status:`Not_found
| Ok (Some (job_name, build)) ->
Response.redirect_to (Fmt.strf "/job/%s/build/%a/" job_name
Uuidm.pp build.Builder_db.Build.uuid)
in
[
App.get "/" builder;
App.get "/job/:job/" job;
App.get "/job/:job/build/:build/" job_build;
App.get "/job/:job/build/:build/f/**" job_build_file;
App.post "/upload" (authorized t upload);
App.get "/hash/:hash" hash;
]
let add_routes t (app : App.t) =

View file

@ -49,6 +49,9 @@ let build_meta job (module Db : CONN) =
Db.find_opt Builder_db.Build.get_latest job >|=
Option.map (fun (_id, meta, file) -> (meta, file))
let build_hash hash (module Db : CONN) =
Db.find_opt Builder_db.Build.get_by_hash hash
let build_exists uuid (module Db : CONN) =
Db.find_opt Builder_db.Build.get_by_uuid uuid >|=
Option.is_some

View file

@ -14,6 +14,9 @@ val build : Uuidm.t -> Caqti_lwt.connection ->
val build_meta : Builder_db.id -> Caqti_lwt.connection ->
((Builder_db.Build.Meta.t * Builder_db.file option) option, [> error ]) result Lwt.t
val build_hash : Cstruct.t -> Caqti_lwt.connection ->
((string * Builder_db.Build.t) option, [> error ]) result Lwt.t
val build_exists : Uuidm.t -> Caqti_lwt.connection ->
(bool, [> error ]) result Lwt.t