feat: implement dynamic date calculation for projects
- Remove hardcoded startDate from La Porra project - Add gitRepoUrl field to Project struct for dynamic date fetching - Implement backend logic to fetch first commit date from git repositories - Add processProjectDates function to calculate dates dynamically - Update template to display computed dates and dynamic "Present/Presente" - Add support for both static and git-based project start dates When a project has a gitRepoUrl, the system automatically fetches the first commit date from the repository. For current projects, it displays "Present" (English) or "Presente" (Spanish) dynamically from the backend. The La Porra project now uses git repository path for date calculation instead of hardcoded JSON values.
This commit is contained in:
@@ -4,6 +4,9 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/juanatsap/cv-site/internal/models"
|
||||
@@ -58,6 +61,11 @@ func (h *CVHandler) Home(w http.ResponseWriter, r *http.Request) {
|
||||
)
|
||||
}
|
||||
|
||||
// Process projects for dynamic dates
|
||||
for i := range cv.Projects {
|
||||
processProjectDates(&cv.Projects[i], lang)
|
||||
}
|
||||
|
||||
// Split skills between left and right sidebars
|
||||
skillsLeft, skillsRight := splitSkills(cv.Skills.Technical)
|
||||
|
||||
@@ -122,6 +130,11 @@ func (h *CVHandler) CVContent(w http.ResponseWriter, r *http.Request) {
|
||||
)
|
||||
}
|
||||
|
||||
// Process projects for dynamic dates
|
||||
for i := range cv.Projects {
|
||||
processProjectDates(&cv.Projects[i], lang)
|
||||
}
|
||||
|
||||
// Split skills between left and right sidebars
|
||||
skillsLeft, skillsRight := splitSkills(cv.Skills.Technical)
|
||||
|
||||
@@ -325,3 +338,77 @@ func calculateDuration(startDate, endDate string, current bool, lang string) str
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// processProjectDates calculates dynamic dates for projects
|
||||
// If a project has a gitRepoUrl, it fetches the first commit date
|
||||
// For current projects, it sets the current system date
|
||||
func processProjectDates(project *models.Project, lang string) {
|
||||
now := time.Now()
|
||||
|
||||
// Set dynamic current date for ongoing projects
|
||||
if project.Current {
|
||||
if lang == "es" {
|
||||
project.DynamicDate = "Presente"
|
||||
} else {
|
||||
project.DynamicDate = "Present"
|
||||
}
|
||||
}
|
||||
|
||||
// If project has a git repository URL, fetch the first commit date
|
||||
if project.GitRepoUrl != "" {
|
||||
commitDate := getGitRepoFirstCommitDate(project.GitRepoUrl)
|
||||
if commitDate != "" {
|
||||
project.ComputedStartDate = commitDate
|
||||
}
|
||||
}
|
||||
|
||||
// If no computed date and no static date, use current date for current projects
|
||||
if project.ComputedStartDate == "" && project.StartDate == "" && project.Current {
|
||||
project.ComputedStartDate = now.Format("2006-01")
|
||||
}
|
||||
|
||||
// If we have a computed date but no static date, use the computed one
|
||||
if project.ComputedStartDate != "" && project.StartDate == "" {
|
||||
project.StartDate = project.ComputedStartDate
|
||||
}
|
||||
}
|
||||
|
||||
// getGitRepoFirstCommitDate fetches the first commit date from a git repository
|
||||
// Supports local git repository paths
|
||||
func getGitRepoFirstCommitDate(repoPath string) string {
|
||||
// Check if the path exists and is a directory
|
||||
info, err := os.Stat(repoPath)
|
||||
if err != nil || !info.IsDir() {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Execute git command to get the first commit date
|
||||
// Format: YYYY-MM (to match StartDate format)
|
||||
cmd := exec.Command("git", "-C", repoPath, "log", "--reverse", "--format=%ci", "--date=format:%Y-%m")
|
||||
cmd.Dir = repoPath
|
||||
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Parse the output to get the first commit date
|
||||
lines := strings.Split(strings.TrimSpace(string(output)), "\n")
|
||||
if len(lines) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Extract YYYY-MM from the first commit timestamp
|
||||
// Format of output: "2024-06-15 10:30:45 +0200"
|
||||
firstLine := lines[0]
|
||||
parts := strings.Fields(firstLine)
|
||||
if len(parts) > 0 {
|
||||
datePart := parts[0] // "2024-06-15"
|
||||
dateParts := strings.Split(datePart, "-")
|
||||
if len(dateParts) >= 2 {
|
||||
return dateParts[0] + "-" + dateParts[1] // "2024-06"
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -102,14 +102,19 @@ type Language struct {
|
||||
type Project struct {
|
||||
Title string `json:"title"`
|
||||
URL string `json:"url"`
|
||||
ProjectLogo string `json:"projectLogo,omitempty"` // Optional logo filename
|
||||
ProjectLogo string `json:"projectLogo,omitempty"` // Optional logo filename
|
||||
GitRepoUrl string `json:"gitRepoUrl,omitempty"` // Optional git repository URL for dynamic dates
|
||||
Location string `json:"location"`
|
||||
StartDate string `json:"startDate"`
|
||||
StartDate string `json:"startDate,omitempty"` // Optional static start date
|
||||
Current bool `json:"current"`
|
||||
MaintainedBy string `json:"maintainedBy,omitempty"` // Optional maintainer name (e.g., "SAP")
|
||||
Technologies []string `json:"technologies"`
|
||||
ShortDescription string `json:"shortDescription"`
|
||||
Responsibilities []string `json:"responsibilities"`
|
||||
|
||||
// Computed fields (not stored in JSON)
|
||||
ComputedStartDate string `json:"-"` // Dynamically calculated from git repo or system
|
||||
DynamicDate string `json:"-"` // Current date for ongoing projects
|
||||
}
|
||||
|
||||
type Award struct {
|
||||
|
||||
Reference in New Issue
Block a user