Skip to content

Commit 656db30

Browse files
committed
Handle duplicate build_ref creation by upserting on conflict
1 parent 590fa73 commit 656db30

File tree

2 files changed

+48
-17
lines changed

2 files changed

+48
-17
lines changed

src/api/build.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -439,15 +439,23 @@ async fn create_build_ref_async(
439439

440440
has_token_for_build(&req, &build)?;
441441

442-
let buildref = db
443-
.new_build_ref(NewBuildRef {
444-
build_id,
445-
ref_name: args.ref_name.clone(),
446-
commit: args.commit.clone(),
447-
build_log_url: args.build_log_url.clone(),
448-
})
442+
let existing_ref = db
443+
.lookup_build_ref_by_name(build_id, args.ref_name.clone())
449444
.await?;
450445

446+
let buildref = match existing_ref {
447+
Some(existing) if existing.commit == args.commit => existing,
448+
_ => {
449+
db.upsert_build_ref(NewBuildRef {
450+
build_id,
451+
ref_name: args.ref_name.clone(),
452+
commit: args.commit.clone(),
453+
build_log_url: args.build_log_url.clone(),
454+
})
455+
.await?
456+
}
457+
};
458+
451459
respond_with_url(
452460
&buildref,
453461
&req,

src/db.rs

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -455,16 +455,6 @@ impl Db {
455455

456456
/* Build refs */
457457

458-
pub async fn new_build_ref(&self, a_build_ref: NewBuildRef) -> Result<BuildRef, ApiError> {
459-
self.run(move |conn| {
460-
use self::schema::build_refs::dsl::*;
461-
Ok(diesel::insert_into(build_refs)
462-
.values(&a_build_ref)
463-
.get_result::<BuildRef>(conn)?)
464-
})
465-
.await
466-
}
467-
468458
pub async fn lookup_build_ref(
469459
&self,
470460
the_build_id: i32,
@@ -490,6 +480,39 @@ impl Db {
490480
.await
491481
}
492482

483+
pub async fn lookup_build_ref_by_name(
484+
&self,
485+
the_build_id: i32,
486+
the_ref_name: String,
487+
) -> Result<Option<BuildRef>, ApiError> {
488+
self.run(move |conn| {
489+
use schema::build_refs::dsl::*;
490+
Ok(build_refs
491+
.filter(build_id.eq(the_build_id))
492+
.filter(ref_name.eq(the_ref_name))
493+
.first::<BuildRef>(conn)
494+
.optional()?)
495+
})
496+
.await
497+
}
498+
499+
pub async fn upsert_build_ref(&self, a_build_ref: NewBuildRef) -> Result<BuildRef, ApiError> {
500+
self.run(move |conn| {
501+
use self::schema::build_refs::dsl::*;
502+
use diesel::pg::upsert::excluded;
503+
Ok(diesel::insert_into(build_refs)
504+
.values(&a_build_ref)
505+
.on_conflict((build_id, ref_name))
506+
.do_update()
507+
.set((
508+
commit.eq(excluded(commit)),
509+
build_log_url.eq(excluded(build_log_url)),
510+
))
511+
.get_result::<BuildRef>(conn)?)
512+
})
513+
.await
514+
}
515+
493516
/// Checks whether the given token has been revoked. If it hasn't, update its last used time.
494517
pub async fn check_token(&self, jti: String, expires_at: i64) -> Result<(), ApiError> {
495518
self.run_in_transaction(move |conn| {

0 commit comments

Comments
 (0)