mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-06 08:01:35 +00:00
feat: receive gitlab push webhooks for instant git sync pull
This commit is contained in:
@@ -1 +1 @@
|
||||
1a7e81206e8768722f0d0acfb3838036078e70be
|
||||
9ac2ffdee130fcff7ed45d137d8606ae983da837
|
||||
|
||||
@@ -4622,7 +4622,7 @@ const GIT_CREDENTIAL_LOCK_ID: i64 = 737_483_923;
|
||||
/// expiry, so a token dies visibly (and usually not at all) rather than taking
|
||||
/// sync down on its expiry date.
|
||||
#[cfg(all(feature = "enterprise", feature = "private"))]
|
||||
pub async fn maintain_git_credentials(db: &Pool<Postgres>) {
|
||||
async fn maintain_git_credentials(db: &Pool<Postgres>) {
|
||||
use windmill_common::ee_oss::{get_license_plan, LicensePlan};
|
||||
|
||||
if !matches!(get_license_plan().await, LicensePlan::Enterprise) {
|
||||
|
||||
@@ -4117,13 +4117,10 @@ async fn edit_git_sync_config(
|
||||
// `sync_repo_webhook` writes back the webhook fields it changes itself:
|
||||
// the remote hook and the record of it have to move together, so
|
||||
// persisting them out here would let one land without the other.
|
||||
if let Err(e) = windmill_common::git_sync_ee::sync_repo_webhook(&db, &w_id, repo).await
|
||||
{
|
||||
tracing::warn!("git auto-pull: webhook sync error: {}", e);
|
||||
}
|
||||
// Check the credential while the operator is still on the settings page,
|
||||
// so a token that is short-lived or missing a scope is visible now rather
|
||||
// than when it expires.
|
||||
// Before the webhook reconcile, which decides whether this repo can have
|
||||
// one from the credential this records. Also puts a short-lived or
|
||||
// under-scoped token in front of the operator while they are still on the
|
||||
// settings page, rather than when it expires.
|
||||
if let Err(e) = windmill_common::git_sync_ee::refresh_git_credential_status(
|
||||
&db,
|
||||
&w_id,
|
||||
@@ -4133,6 +4130,10 @@ async fn edit_git_sync_config(
|
||||
{
|
||||
tracing::warn!("git credential check error: {}", e);
|
||||
}
|
||||
if let Err(e) = windmill_common::git_sync_ee::sync_repo_webhook(&db, &w_id, repo).await
|
||||
{
|
||||
tracing::warn!("git auto-pull: webhook sync error: {}", e);
|
||||
}
|
||||
}
|
||||
for (path, hook_id) in removed_webhooks {
|
||||
if let Ok(url) =
|
||||
@@ -4365,9 +4366,6 @@ async fn edit_git_sync_repository(
|
||||
.iter_mut()
|
||||
.find(|r| r.git_repo_resource_path == new_config.git_repo_resource_path)
|
||||
{
|
||||
if let Err(e) = windmill_common::git_sync_ee::sync_repo_webhook(&db, &w_id, repo).await {
|
||||
tracing::warn!("git auto-pull: webhook sync error: {}", e);
|
||||
}
|
||||
if let Err(e) = windmill_common::git_sync_ee::refresh_git_credential_status(
|
||||
&db,
|
||||
&w_id,
|
||||
@@ -4377,6 +4375,9 @@ async fn edit_git_sync_repository(
|
||||
{
|
||||
tracing::warn!("git credential check error: {}", e);
|
||||
}
|
||||
if let Err(e) = windmill_common::git_sync_ee::sync_repo_webhook(&db, &w_id, repo).await {
|
||||
tracing::warn!("git auto-pull: webhook sync error: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger git sync for individual repository update/add
|
||||
|
||||
@@ -34005,6 +34005,9 @@ components:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
token_fingerprint:
|
||||
type: string
|
||||
description: one-way digest identifying which credential this status describes
|
||||
rotatable:
|
||||
type: boolean
|
||||
checked_at:
|
||||
|
||||
@@ -958,6 +958,15 @@ pub async fn run_server(
|
||||
#[cfg(not(feature = "enterprise"))]
|
||||
Router::new()
|
||||
})
|
||||
.nest("/w/{workspace_id}/git_sync", {
|
||||
#[cfg(feature = "enterprise")]
|
||||
{
|
||||
git_sync_oss::workspaced_git_sync_service()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "enterprise"))]
|
||||
Router::new()
|
||||
})
|
||||
.nest(
|
||||
"/w/{workspace_id}/resources_u",
|
||||
public_service().layer(cors.clone()),
|
||||
|
||||
@@ -427,8 +427,13 @@ pub struct GitCredentialStatus {
|
||||
pub expires_at: Option<chrono::NaiveDate>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub scopes: Vec<String>,
|
||||
/// Which credential this status describes, as a one-way digest. Lets a later
|
||||
/// check tell "the token I know about stopped working" from "someone put a
|
||||
/// different credential here", which look identical at the API otherwise.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub token_fingerprint: Option<String>,
|
||||
/// Rotation needs both a scope that permits it (`api` or `self_rotate`) and a
|
||||
/// URL held in a variable we can write back to.
|
||||
/// URL Windmill can write back to. `scopes` says which of the two is missing.
|
||||
pub rotatable: bool,
|
||||
/// Unix timestamp (seconds) of the last check.
|
||||
pub checked_at: i64,
|
||||
|
||||
@@ -204,10 +204,16 @@
|
||||
}
|
||||
}
|
||||
if (days > 30) return undefined
|
||||
// Two different things stop a renewal, and they need opposite advice: a
|
||||
// token that may not rotate itself, or a token Windmill cannot store the
|
||||
// replacement for. Scopes say which.
|
||||
const canSelfRotate = (credential.scopes ?? []).some((s) => s === 'api' || s === 'self_rotate')
|
||||
return {
|
||||
type: days <= 7 ? ('error' as const) : days <= 14 ? ('warning' as const) : ('info' as const),
|
||||
title: `Repository token ${when}`,
|
||||
body: 'Give the token the api or self_rotate scope and Windmill will renew it on its own. Otherwise, replace it before it expires to keep sync running.'
|
||||
body: canSelfRotate
|
||||
? 'Windmill cannot renew it because it cannot write the new token back to where this URL is stored. Move the URL into a Windmill variable, or replace the token before it expires.'
|
||||
: 'Give the token the api or self_rotate scope and Windmill will renew it on its own. Otherwise, replace it before it expires to keep sync running.'
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user