feat: add maxSyncPeriod configuration to TFS settings
- Introduced maxSyncPeriod option in TfsConfigForm for user-defined synchronization duration. - Updated TfsService to filter pull requests based on the configured maxSyncPeriod. - Enhanced TfsPullRequest type to include 'rejected' status for better PR management. - Set default maxSyncPeriod to '90d' in user preferences and TFS configuration.
This commit is contained in:
@@ -15,6 +15,7 @@ export function TfsConfigForm() {
|
|||||||
personalAccessToken: '',
|
personalAccessToken: '',
|
||||||
repositories: [],
|
repositories: [],
|
||||||
ignoredRepositories: [],
|
ignoredRepositories: [],
|
||||||
|
maxSyncPeriod: '90d',
|
||||||
});
|
});
|
||||||
const [isPending, startTransition] = useTransition();
|
const [isPending, startTransition] = useTransition();
|
||||||
const [message, setMessage] = useState<{
|
const [message, setMessage] = useState<{
|
||||||
@@ -94,13 +95,14 @@ export function TfsConfigForm() {
|
|||||||
startTransition(async () => {
|
startTransition(async () => {
|
||||||
setMessage(null);
|
setMessage(null);
|
||||||
// Réinitialiser la config
|
// Réinitialiser la config
|
||||||
const resetConfig = {
|
const resetConfig: TfsConfig = {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
organizationUrl: '',
|
organizationUrl: '',
|
||||||
projectName: '',
|
projectName: '',
|
||||||
personalAccessToken: '',
|
personalAccessToken: '',
|
||||||
repositories: [],
|
repositories: [],
|
||||||
ignoredRepositories: [],
|
ignoredRepositories: [],
|
||||||
|
maxSyncPeriod: '90d',
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = await saveTfsConfig(resetConfig);
|
const result = await saveTfsConfig(resetConfig);
|
||||||
@@ -275,6 +277,14 @@ export function TfsConfigForm() {
|
|||||||
<span className="text-xs">Aucun</span>
|
<span className="text-xs">Aucun</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<span className="text-[var(--muted-foreground)]">
|
||||||
|
Période max de sync:
|
||||||
|
</span>{' '}
|
||||||
|
<code className="bg-[var(--background)] px-2 py-1 rounded text-xs">
|
||||||
|
{config?.maxSyncPeriod || '90d'}
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -475,6 +485,29 @@ export function TfsConfigForm() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium mb-2">
|
||||||
|
Période maximale de synchronisation
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
value={config.maxSyncPeriod || '90d'}
|
||||||
|
onChange={(e) => updateConfig('maxSyncPeriod', e.target.value)}
|
||||||
|
className="w-full px-3 py-2 border border-[var(--border)] rounded bg-[var(--background)] text-[var(--foreground)] focus:outline-none focus:ring-2 focus:ring-[var(--primary)] focus:border-transparent"
|
||||||
|
>
|
||||||
|
<option value="7d">7 jours</option>
|
||||||
|
<option value="30d">30 jours</option>
|
||||||
|
<option value="90d">90 jours (recommandé)</option>
|
||||||
|
<option value="180d">180 jours</option>
|
||||||
|
<option value="1y">1 an</option>
|
||||||
|
<option value="2y">2 ans</option>
|
||||||
|
<option value="3y">3 ans</option>
|
||||||
|
</select>
|
||||||
|
<p className="text-xs text-[var(--muted-foreground)] mt-1">
|
||||||
|
Définit la période maximale pour récupérer les Pull Requests.
|
||||||
|
Les PRs plus anciennes seront ignorées lors de la synchronisation.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ export interface TfsPullRequest {
|
|||||||
pullRequestId: number;
|
pullRequestId: number;
|
||||||
title: string;
|
title: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
status: 'active' | 'completed' | 'abandoned';
|
status: 'active' | 'completed' | 'abandoned' | 'rejected';
|
||||||
createdBy: {
|
createdBy: {
|
||||||
displayName: string;
|
displayName: string;
|
||||||
uniqueName: string; // email
|
uniqueName: string; // email
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ const DEFAULT_PREFERENCES: UserPreferences = {
|
|||||||
personalAccessToken: '',
|
personalAccessToken: '',
|
||||||
repositories: [],
|
repositories: [],
|
||||||
ignoredRepositories: [],
|
ignoredRepositories: [],
|
||||||
|
maxSyncPeriod: '90d', // Par défaut 90 jours
|
||||||
},
|
},
|
||||||
tfsAutoSync: false,
|
tfsAutoSync: false,
|
||||||
tfsSyncInterval: 'daily',
|
tfsSyncInterval: 'daily',
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export interface TfsConfig {
|
|||||||
personalAccessToken?: string;
|
personalAccessToken?: string;
|
||||||
repositories?: string[]; // Liste des repos à surveiller
|
repositories?: string[]; // Liste des repos à surveiller
|
||||||
ignoredRepositories?: string[]; // Liste des repos à ignorer
|
ignoredRepositories?: string[]; // Liste des repos à ignorer
|
||||||
|
maxSyncPeriod?: '7d' | '30d' | '90d' | '180d' | '1y' | '2y' | '3y'; // Période maximale de synchronisation
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TfsSyncAction {
|
export interface TfsSyncAction {
|
||||||
@@ -375,10 +376,10 @@ export class TfsService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Filtre les PRs par statut pertinent
|
* Filtre les PRs par statut pertinent
|
||||||
* - Garde toutes les PRs actives créées dans les 90 derniers jours
|
* - Garde toutes les PRs actives créées dans la période configurée
|
||||||
* - Garde les PRs completed récentes (moins de 30 jours)
|
* - Garde les PRs completed récentes (moins de 30 jours)
|
||||||
* - Exclut les PRs abandoned
|
* - Exclut les PRs abandoned et rejected
|
||||||
* - Exclut les PRs trop anciennes
|
* - Exclut les PRs trop anciennes selon la configuration
|
||||||
* - Exclut les PRs automatiques (Renovate, etc.)
|
* - Exclut les PRs automatiques (Renovate, etc.)
|
||||||
*/
|
*/
|
||||||
private filterByRelevantStatus(
|
private filterByRelevantStatus(
|
||||||
@@ -386,6 +387,11 @@ export class TfsService {
|
|||||||
): TfsPullRequest[] {
|
): TfsPullRequest[] {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
|
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
|
||||||
|
|
||||||
|
// Calculer la période maximale selon la configuration
|
||||||
|
const maxSyncPeriod = this.config.maxSyncPeriod || '90d';
|
||||||
|
const maxSyncPeriodMs = this.getMaxSyncPeriodMs(maxSyncPeriod);
|
||||||
|
const maxSyncDate = new Date(now.getTime() - maxSyncPeriodMs);
|
||||||
|
|
||||||
return pullRequests.filter((pr) => {
|
return pullRequests.filter((pr) => {
|
||||||
// Exclure les PRs automatiques (Renovate, Dependabot, etc.)
|
// Exclure les PRs automatiques (Renovate, Dependabot, etc.)
|
||||||
@@ -396,20 +402,20 @@ export class TfsService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filtrer d'abord par âge - exclure les PRs trop anciennes
|
// Filtrer par âge selon la configuration
|
||||||
// const createdDate = parseDate(pr.creationDate);
|
const createdDate = parseDate(pr.creationDate);
|
||||||
// if (createdDate < ninetyDaysAgo) {
|
if (createdDate < maxSyncDate) {
|
||||||
// console.log(
|
console.log(
|
||||||
// `🗺 PR ${pr.pullRequestId} (${pr.title}): Trop ancienne (${formatDateForDisplay(createdDate)}) - EXCLUE`
|
`🗺 PR ${pr.pullRequestId} (${pr.title}): Trop ancienne (${formatDateForDisplay(createdDate)}, limite: ${maxSyncPeriod}) - EXCLUE`
|
||||||
// );
|
);
|
||||||
// return false;
|
return false;
|
||||||
// }
|
}
|
||||||
|
|
||||||
switch (pr.status.toLowerCase()) {
|
switch (pr.status.toLowerCase()) {
|
||||||
case 'active':
|
case 'active':
|
||||||
// PRs actives récentes
|
// PRs actives dans la période configurée
|
||||||
console.log(
|
console.log(
|
||||||
`✅ PR ${pr.pullRequestId} (${pr.title}): Active récente - INCLUSE`
|
`✅ PR ${pr.pullRequestId} (${pr.title}): Active récente (${maxSyncPeriod}) - INCLUSE`
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -426,15 +432,52 @@ export class TfsService {
|
|||||||
|
|
||||||
case 'abandoned':
|
case 'abandoned':
|
||||||
// PRs abandonnées ne sont pas pertinentes
|
// PRs abandonnées ne sont pas pertinentes
|
||||||
|
console.log(
|
||||||
|
`❌ PR ${pr.pullRequestId} (${pr.title}): Abandonnée - EXCLUE`
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case 'rejected':
|
||||||
|
// PRs rejetées ne sont pas pertinentes
|
||||||
|
console.log(
|
||||||
|
`❌ PR ${pr.pullRequestId} (${pr.title}): Rejetée - EXCLUE`
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Statut inconnu, on l'inclut par précaution
|
// Statut inconnu, on l'inclut par précaution
|
||||||
|
console.log(
|
||||||
|
`⚠️ PR ${pr.pullRequestId} (${pr.title}): Statut inconnu "${pr.status}" - INCLUSE par précaution`
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convertit une période de synchronisation en millisecondes
|
||||||
|
*/
|
||||||
|
private getMaxSyncPeriodMs(period: string): number {
|
||||||
|
switch (period) {
|
||||||
|
case '7d':
|
||||||
|
return 7 * 24 * 60 * 60 * 1000; // 7 jours
|
||||||
|
case '30d':
|
||||||
|
return 30 * 24 * 60 * 60 * 1000; // 30 jours
|
||||||
|
case '90d':
|
||||||
|
return 90 * 24 * 60 * 60 * 1000; // 90 jours
|
||||||
|
case '180d':
|
||||||
|
return 180 * 24 * 60 * 60 * 1000; // 180 jours
|
||||||
|
case '1y':
|
||||||
|
return 365 * 24 * 60 * 60 * 1000; // 1 an
|
||||||
|
case '2y':
|
||||||
|
return 2 * 365 * 24 * 60 * 60 * 1000; // 2 ans
|
||||||
|
case '3y':
|
||||||
|
return 3 * 365 * 24 * 60 * 60 * 1000; // 3 ans
|
||||||
|
default:
|
||||||
|
return 90 * 24 * 60 * 60 * 1000; // Par défaut 90 jours
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Détermine si une PR est automatique (bot, renovate, dependabot, etc.)
|
* Détermine si une PR est automatique (bot, renovate, dependabot, etc.)
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user