Skip to content

Commit

Permalink
return matched Product data to function calls
Browse files Browse the repository at this point in the history
  • Loading branch information
mr-pmillz committed Sep 11, 2024
1 parent c0c4310 commit ec4ee11
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 39 deletions.
30 changes: 21 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,25 +51,37 @@ package main

import (
"fmt"
"log"
"strings"

"github.com/mr-pmillz/eoldate"
"log"
"time"
)

func main() {
client := eoldate.NewClient()
softwareName := "php"
phpVersion := "7.4.33"
isPHPVersionSupported, latestVersion, err := client.IsSupportedSoftwareVersion(softwareName, phpVersion)
phpVersion := "7.4"
isSupported, latestVersion, product, err := client.IsSupportedSoftwareVersion(softwareName, phpVersion)
if err != nil {
log.Fatal(err)
}
latestVersionInfo := fmt.Sprintf("The latest version of %s at the time of testing was %s.", strings.ToUpper(softwareName), latestVersion)
if isPHPVersionSupported {
fmt.Printf("%s %s is Supported. %s", softwareName, phpVersion, latestVersionInfo)

latestVersionInfo := fmt.Sprintf("The latest version of %s on %v was %s.", softwareName, time.Now().Format("01-02-2006"), latestVersion)

endDate := product.GetEndDate()
if isSupported {
fmt.Printf("%s %s is Supported. %s\n", softwareName, phpVersion, latestVersionInfo)

if endDate != nil {
years, months, days := eoldate.CalculateTimeDifference(*endDate)
fmt.Printf("Support ends in %d years, %d months, and %d days (%s)\n", years, months, days, endDate.Format("01-02-2006"))
}
} else {
fmt.Printf("%s %s is no longer Supported. %s", softwareName, phpVersion, latestVersionInfo)
fmt.Printf("%s %s is no longer Supported. %s\n", softwareName, phpVersion, latestVersionInfo)

if endDate != nil {
years, months, days := eoldate.CalculateTimeDifference(*endDate)
fmt.Printf("Support ended %d years, %d months, and %d days ago (%s)\n", years, months, days, endDate.Format("01-02-2006"))
}
}
}
```
62 changes: 42 additions & 20 deletions eoldate.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import (
"io"
"net/http"
"slices"
"strings"
"time"
)

const (
CurrentVersion = `v1.0.3`
CurrentVersion = `v1.0.4`
EOLBaseURL = "https://endoflife.date/api"
NotAvailable = "N/A"
)
Expand Down Expand Up @@ -40,70 +41,68 @@ type Product struct {
AdditionalFields map[string]interface{} `json:"-"`
}

// IsSupportedSoftwareVersion checks if a given software version is supported
func (c *Client) IsSupportedSoftwareVersion(softwareName string, version string) (bool, string, error) {
softwareReleaseData, err := c.GetProduct(softwareName)
// IsSupportedSoftwareVersion checks if a given software version is supported and returns relevant information
func (c *Client) IsSupportedSoftwareVersion(softwareName string, version string) (bool, string, *Product, error) {
softwareReleaseData, err := c.GetProduct(strings.ToLower(softwareName))
if err != nil {
return false, "", LogError(err)
return false, "", nil, LogError(err)
}

isSupported, err := softwareReleaseData.IsVersionSupported(version)
isSupported, matchingProduct, err := softwareReleaseData.IsVersionSupported(version)
if err != nil {
return false, "", LogError(err)
return false, "", nil, LogError(err)
}

latestVersion, err := softwareReleaseData.GetLatestSupportedVersion()
if err != nil {
return false, "", LogError(err)
return false, "", nil, LogError(err)
}

latestVersionStr := latestVersion.String()

return isSupported, latestVersionStr, nil
return isSupported, latestVersionStr, matchingProduct, nil
}

// IsVersionSupported checks if the given version is supported in any of the product cycles
func (p Products) IsVersionSupported(versionStr string) (bool, error) {
func (p Products) IsVersionSupported(versionStr string) (bool, *Product, error) {
version, err := semver.NewVersion(versionStr)
if err != nil {
return false, fmt.Errorf("invalid version string: %s", versionStr)
return false, nil, fmt.Errorf("invalid version string: %s", versionStr)
}

// Find the lowest cycle version
var lowestCycle *semver.Version
var lowestProduct *Product

for _, product := range p {
cycleVersion, err := semver.NewVersion(product.Cycle)
if err != nil {
// If the cycle is not a valid version, skip it
continue
}
if lowestCycle == nil || cycleVersion.LessThan(lowestCycle) {
lowestCycle = cycleVersion
lowestProduct = &product
}
}

// If the version is lower than the lowest cycle, it's not supported
if lowestCycle != nil && version.LessThan(lowestCycle) {
return false, nil
return false, lowestProduct, nil
}

// Check if the version is in any of the cycles
for _, product := range p {
constraint, err := semver.NewConstraint(product.Cycle)
if err != nil {
// If the cycle is not a valid constraint, skip it
continue
}

if constraint.Check(version) {
eolDate, err := product.GetEOLDate()
if err != nil {
return false, err
return false, &product, err
}
return time.Now().Before(eolDate), nil
return time.Now().Before(eolDate), &product, nil
}
}
return false, nil
return false, nil, nil
}

// GetLatestSupportedVersion returns the latest supported version from a list of Products
Expand All @@ -127,6 +126,29 @@ func (p Products) GetLatestSupportedVersion() (*semver.Version, error) {
return latestVersion, nil
}

// GetEndDate ...
func (p *Product) GetEndDate() *time.Time {
if p == nil {
return nil
}

// Check Support field first
if support, ok := p.Support.(string); ok {
if t, err := time.Parse("2006-01-02", support); err == nil {
return &t
}
}

// If Support is not available or invalid, check EOL
if eol, ok := p.EOL.(string); ok {
if t, err := time.Parse("2006-01-02", eol); err == nil {
return &t
}
}

return nil
}

// GetEOLDate returns the end-of-life date for the product
func (p *Product) GetEOLDate() (time.Time, error) {
switch eol := p.EOL.(type) {
Expand Down
88 changes: 87 additions & 1 deletion eoldate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package eoldate

import (
"testing"
"time"
)

func TestClient_IsSupportedSoftwareVersion(t *testing.T) {
Expand All @@ -23,7 +24,7 @@ func TestClient_IsSupportedSoftwareVersion(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, _, err := c.IsSupportedSoftwareVersion(tt.args.softwareName, tt.args.version)
got, _, _, err := c.IsSupportedSoftwareVersion(tt.args.softwareName, tt.args.version)
if (err != nil) != tt.wantErr {
t.Errorf("IsSupportedSoftwareVersion() error = %v, wantErr %v", err, tt.wantErr)
return
Expand All @@ -34,3 +35,88 @@ func TestClient_IsSupportedSoftwareVersion(t *testing.T) {
})
}
}

func TestCalculateTimeDifference(t *testing.T) {
now := time.Now()
type args struct {
endDate time.Time
}
tests := []struct {
name string
args args
want int
want1 int
want2 int
}{
{
name: "One year ago",
args: args{endDate: now.AddDate(-1, 0, 0)},
want: 1,
want1: 0,
want2: 0,
},
{
name: "Six months ago",
args: args{endDate: now.AddDate(0, -6, 0)},
want: 0,
want1: 6,
want2: 0,
},
{
name: "One month and 15 days ago",
args: args{endDate: now.AddDate(0, -1, -15)},
want: 0,
want1: 1,
want2: 15,
},
{
name: "One year and one month in the future",
args: args{endDate: now.AddDate(1, 1, 0)},
want: 1,
want1: 1,
want2: 0,
},
{
name: "Six months in the future",
args: args{endDate: now.AddDate(0, 6, 0)},
want: 0,
want1: 6,
want2: 0,
},
{
name: "15 days in the future",
args: args{endDate: now.AddDate(0, 0, 15)},
want: 0,
want1: 0,
want2: 15,
},
{
name: "Current date",
args: args{endDate: now},
want: 0,
want1: 0,
want2: 0,
},
{
name: "Two years, three months, and 10 days ago",
args: args{endDate: now.AddDate(-2, -3, -10)},
want: 2,
want1: 3,
want2: 10,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got1, got2 := CalculateTimeDifference(tt.args.endDate)
if got != tt.want {
t.Errorf("CalculateTimeDifference() got = %v, want %v", got, tt.want)
}
if got1 != tt.want1 {
t.Errorf("CalculateTimeDifference() got1 = %v, want %v", got1, tt.want1)
}
if got2 != tt.want2 {
t.Errorf("CalculateTimeDifference() got2 = %v, want %v", got2, tt.want2)
}
})
}
}
30 changes: 21 additions & 9 deletions examples/is-supported/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,36 @@ package main

import (
"fmt"
"log"
"strings"

"github.com/mr-pmillz/eoldate"
"log"
"time"
)

func main() {
client := eoldate.NewClient()
softwareName := "php"
phpVersion := "7.4.33"
isPHPVersionSupported, latestVersion, err := client.IsSupportedSoftwareVersion(softwareName, phpVersion)
phpVersion := "7.4"
isSupported, latestVersion, product, err := client.IsSupportedSoftwareVersion(softwareName, phpVersion)
if err != nil {
log.Fatal(err)
}
latestVersionInfo := fmt.Sprintf("The latest version of %s at the time of testing was %s.", strings.ToUpper(softwareName), latestVersion)
if isPHPVersionSupported {
fmt.Printf("%s %s is Supported. %s", softwareName, phpVersion, latestVersionInfo)

latestVersionInfo := fmt.Sprintf("The latest version of %s on %v was %s.", softwareName, time.Now().Format("01-02-2006"), latestVersion)

endDate := product.GetEndDate()
if isSupported {
fmt.Printf("%s %s is Supported. %s\n", softwareName, phpVersion, latestVersionInfo)

if endDate != nil {
years, months, days := eoldate.CalculateTimeDifference(*endDate)
fmt.Printf("Support ends in %d years, %d months, and %d days (%s)\n", years, months, days, endDate.Format("01-02-2006"))
}
} else {
fmt.Printf("%s %s is no longer Supported. %s", softwareName, phpVersion, latestVersionInfo)
fmt.Printf("%s %s is no longer Supported. %s\n", softwareName, phpVersion, latestVersionInfo)

if endDate != nil {
years, months, days := eoldate.CalculateTimeDifference(*endDate)
fmt.Printf("Support ended %d years, %d months, and %d days ago (%s)\n", years, months, days, endDate.Format("01-02-2006"))
}
}
}
41 changes: 41 additions & 0 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"os/user"
"path/filepath"
"strings"
"time"
)

// Exists returns whether the given file or directory exists
Expand Down Expand Up @@ -157,3 +158,43 @@ func ResolveAbsPath(path string) (string, error) {

return path, nil
}

// CalculateTimeDifference calculates the difference between the current date and the given endDate
func CalculateTimeDifference(endDate time.Time) (int, int, int) {
now := time.Now()
if endDate.After(now) {
// For future dates
return diffDates(now, endDate)
}
// For past dates or current date
return diffDates(endDate, now)
}

// diffDates calculates the difference between two dates
func diffDates(start, end time.Time) (int, int, int) {
years := end.Year() - start.Year()
months := int(end.Month() - start.Month())
days := end.Day() - start.Day()

// Adjust for negative months
if months < 0 {
years--
months += 12
}

// Adjust for negative days
if days < 0 {
months--
// Get the last day of the previous month
lastMonth := end.AddDate(0, -1, 0)
days += lastMonth.AddDate(0, 1, -lastMonth.Day()).Day()
}

// Adjust for negative months again (in case day adjustment caused it)
if months < 0 {
years--
months += 12
}

return years, months, days
}

0 comments on commit ec4ee11

Please sign in to comment.