add v3.1
This commit is contained in:
parent
942a0bd14e
commit
94d71a1e12
8 changed files with 1014 additions and 0 deletions
221
v3.1/main.go
Normal file
221
v3.1/main.go
Normal file
|
@ -0,0 +1,221 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Version information
|
||||
var (
|
||||
Version = "v3.1.0"
|
||||
BuildTime = "unknown"
|
||||
GitCommit = "unknown"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Print version information
|
||||
log.Printf("[MAIN] Jenkins-Cron %s (built: %s, commit: %s)", Version, BuildTime, GitCommit)
|
||||
|
||||
// Get configuration path
|
||||
configPath := GetConfigPath()
|
||||
log.Printf("[MAIN] Loading configuration from: %s", configPath)
|
||||
|
||||
// Load configuration with proper error handling
|
||||
cfg, err := LoadConfig(configPath)
|
||||
if err != nil {
|
||||
log.Fatalf("[MAIN] Failed to load configuration: %v", err)
|
||||
}
|
||||
|
||||
// Validate configuration
|
||||
if len(cfg.Jobs) == 0 {
|
||||
log.Fatalf("[MAIN] No jobs configured")
|
||||
}
|
||||
if cfg.Jenkins.URL == "" {
|
||||
log.Fatalf("[MAIN] No Jenkins URL configured")
|
||||
}
|
||||
|
||||
// Create a cancelable context
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// Setup signal handling for graceful shutdown
|
||||
setupSignalHandler(cancel)
|
||||
|
||||
// Clean Gradle caches
|
||||
if err := cleanGradleCaches(ctx, cfg); err != nil {
|
||||
log.Printf("[MAIN] Warning: Error cleaning Gradle caches: %v", err)
|
||||
}
|
||||
|
||||
// Create Jenkins client
|
||||
var jenkinsSvc JenkinsService = NewJenkinsClient(&cfg.Jenkins)
|
||||
|
||||
// Trigger Jenkins jobs
|
||||
if err := triggerJobs(ctx, jenkinsSvc, cfg); err != nil {
|
||||
log.Printf("[MAIN] Error triggering jobs: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
log.Printf("[MAIN] All operations completed successfully")
|
||||
}
|
||||
|
||||
// setupSignalHandler sets up handling of OS signals for graceful shutdown
|
||||
func setupSignalHandler(cancel context.CancelFunc) {
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||
|
||||
go func() {
|
||||
sig := <-c
|
||||
log.Printf("[MAIN] Received signal %v, shutting down gracefully", sig)
|
||||
cancel()
|
||||
|
||||
// Force exit after 5 seconds if graceful shutdown is taking too long
|
||||
time.Sleep(5 * time.Second)
|
||||
log.Printf("[MAIN] Forced shutdown after timeout")
|
||||
os.Exit(1)
|
||||
}()
|
||||
}
|
||||
|
||||
// cleanGradleCaches cleans Gradle caches in parallel
|
||||
func cleanGradleCaches(ctx context.Context, cfg *Config) error {
|
||||
if len(cfg.Gradle.Caches) == 0 {
|
||||
log.Printf("[MAIN] No Gradle caches configured, skipping cleanup")
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("[MAIN] Starting Gradle cache cleanup")
|
||||
stats := &RemoveStats{}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
var errs []error
|
||||
var mu sync.Mutex
|
||||
|
||||
for _, cache := range cfg.Gradle.Caches {
|
||||
wg.Add(1)
|
||||
go func(cachePath string) {
|
||||
defer wg.Done()
|
||||
|
||||
log.Printf("[MAIN] Cleaning cache: %s", cachePath)
|
||||
err := Remove(ctx, cachePath, RemoveOptions{
|
||||
Workers: 4,
|
||||
Retries: 3,
|
||||
Stats: stats,
|
||||
Logger: log.Printf,
|
||||
Progress: func(current int64) {
|
||||
if current > 0 && current%100 == 0 {
|
||||
log.Printf("[MAIN] Removed %d files from %s", current, cachePath)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Printf("[MAIN] Error removing cache %s: %v", cachePath, err)
|
||||
mu.Lock()
|
||||
errs = append(errs, fmt.Errorf("cache %s: %w", cachePath, err))
|
||||
mu.Unlock()
|
||||
}
|
||||
}(cache)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
log.Printf("[MAIN] Cache cleanup summary: Total=%d Success=%d Failed=%d",
|
||||
stats.Total, stats.Success, stats.Failed)
|
||||
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("encountered %d errors during cache cleanup", len(errs))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// triggerJobs triggers all configured Jenkins jobs
|
||||
func triggerJobs(ctx context.Context, js JenkinsService, cfg *Config) error {
|
||||
log.Printf("[MAIN] Starting to trigger %d Jenkins jobs", len(cfg.Jobs))
|
||||
|
||||
var wg sync.WaitGroup
|
||||
errChan := make(chan error, len(cfg.Jobs))
|
||||
|
||||
// Create a timeout context for the entire operation
|
||||
ctx, cancel := context.WithTimeout(ctx, 5*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
for _, job := range cfg.Jobs {
|
||||
wg.Add(1)
|
||||
go func(jobName string) {
|
||||
defer wg.Done()
|
||||
|
||||
if err := processJob(ctx, js, cfg, jobName); err != nil {
|
||||
log.Printf("[MAIN] Error processing job %s: %v", jobName, err)
|
||||
errChan <- fmt.Errorf("job %s: %w", jobName, err)
|
||||
}
|
||||
}(job)
|
||||
}
|
||||
|
||||
// Wait for all jobs to complete
|
||||
wg.Wait()
|
||||
close(errChan)
|
||||
|
||||
// Collect errors
|
||||
var errs []error
|
||||
for err := range errChan {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("encountered %d errors while triggering jobs", len(errs))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// processJob handles the processing of a single Jenkins job
|
||||
func processJob(ctx context.Context, js JenkinsService, cfg *Config, job string) error {
|
||||
log.Printf("[MAIN] Processing job: %s", job)
|
||||
|
||||
// Fetch build with retry
|
||||
build, err := js.FetchBuildWithRetry(ctx, job, cfg.Retries)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to fetch build: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("[MAIN] Successfully fetched build #%d for job: %s", build.Number, job)
|
||||
|
||||
// Extract and merge parameters
|
||||
latestParams := ExtractBuildParams(build)
|
||||
merged := MergeParams(latestParams, cfg.Jenkins.DefaultParameters)
|
||||
|
||||
// Trigger build with default parameters
|
||||
log.Printf("[MAIN] Triggering build with default parameters for job: %s", job)
|
||||
if err := js.TriggerBuildWithRetry(ctx, build, StringMapToInterfaceMap(merged), cfg.Retries); err != nil {
|
||||
log.Printf("[MAIN] Failed to trigger build with default parameters for job %s: %v", job, err)
|
||||
// Continue with special parameters even if default build fails
|
||||
}
|
||||
|
||||
// Process special parameters
|
||||
for _, special := range cfg.Jenkins.SpecialParameters {
|
||||
if IsSubset(latestParams, special) {
|
||||
log.Printf("[MAIN] Skipping special parameters build (subset of latest) for %s: %+v", job, special)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("[MAIN] Triggering build with special parameters for job %s: %+v", job, special)
|
||||
specialLatestParams := make(map[string]string)
|
||||
for k, v := range latestParams {
|
||||
specialLatestParams[k] = v
|
||||
}
|
||||
for k, v := range special {
|
||||
specialLatestParams[k] = fmt.Sprintf("%v", v)
|
||||
}
|
||||
|
||||
speciaMerged := MergeParams(specialLatestParams, cfg.Jenkins.DefaultParameters)
|
||||
if err := js.TriggerBuildWithRetry(ctx, build, StringMapToInterfaceMap(speciaMerged), cfg.Retries); err != nil {
|
||||
log.Printf("[MAIN] Failed to trigger build with special parameters for job %s: %v", job, err)
|
||||
// Continue with other special parameters even if one fails
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue