From 06457f64b8ee1cf95060005532b9474ac56ae197 Mon Sep 17 00:00:00 2001 From: Ali Vahdati <3798865+kavir1698@users.noreply.github.com> Date: Thu, 4 Apr 2024 16:25:55 +0200 Subject: [PATCH] Unified version control (#32) * Change version control approach * Require an update only if the major/minor version has changed * Define VERSION within each main file Otherwise, it will not be updated during build * Change the if statements * Make minor improvements * Test patch update --- .goreleaser.yaml | 20 ++++++++ cmd/datasetArchiver/main.go | 3 +- cmd/datasetCleaner/main.go | 3 +- cmd/datasetGetProposal/main.go | 3 +- cmd/datasetIngestor/main.go | 4 +- cmd/datasetIngestor/main_test.go | 6 +++ cmd/datasetPublishData/main.go | 2 +- cmd/datasetPublishDataRetrieve/main.go | 2 +- cmd/datasetRetriever/main.go | 2 +- cmd/waitForJobFinished/main.go | 3 +- datasetUtils/checkForNewVersion.go | 67 ++++++++++++++++--------- datasetUtils/checkForNewVersion_test.go | 13 ++++- 12 files changed, 92 insertions(+), 36 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 02cea67..035254c 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -22,6 +22,10 @@ before: builds: - id: "datasetIngestor" + flags: + - -trimpath + ldflags: + - -s -w -X main.VERSION={{.Version}} # This will set the VERSION variable in the binary to the github tag env: - CGO_ENABLED=0 dir: ./cmd/datasetIngestor/ @@ -35,6 +39,10 @@ builds: binary: datasetIngestor - id: "datasetArchiver" + flags: + - -trimpath + ldflags: + - -s -w -X main.VERSION={{.Version}} env: - CGO_ENABLED=0 dir: ./cmd/datasetArchiver/ @@ -48,6 +56,10 @@ builds: binary: datasetArchiver - id: "datasetRetriever" + flags: + - -trimpath + ldflags: + - -s -w -X main.VERSION={{.Version}} env: - CGO_ENABLED=0 dir: ./cmd/datasetRetriever/ @@ -61,6 +73,10 @@ builds: binary: datasetRetriever - id: "datasetCleaner" + flags: + - -trimpath + ldflags: + - -s -w -X main.VERSION={{.Version}} env: - CGO_ENABLED=0 dir: ./cmd/datasetCleaner/ @@ -74,6 +90,10 @@ builds: binary: datasetCleaner - id: "datasetGetProposal" + flags: + - -trimpath + ldflags: + - -s -w -X main.VERSION={{.Version}} env: - CGO_ENABLED=0 dir: ./cmd/datasetGetProposal/ diff --git a/cmd/datasetArchiver/main.go b/cmd/datasetArchiver/main.go index 18907af..cfeefbf 100644 --- a/cmd/datasetArchiver/main.go +++ b/cmd/datasetArchiver/main.go @@ -21,6 +21,8 @@ import ( "github.com/fatih/color" ) +var VERSION string + func main() { var client = &http.Client{ @@ -34,7 +36,6 @@ func main() { const MANUAL string = "http://melanie.gitpages.psi.ch/SciCatPages" const APP = "datasetArchiver" - const VERSION = "1.1.9" var scanner = bufio.NewScanner(os.Stdin) var APIServer string diff --git a/cmd/datasetCleaner/main.go b/cmd/datasetCleaner/main.go index 35b17bb..ebdcaf0 100644 --- a/cmd/datasetCleaner/main.go +++ b/cmd/datasetCleaner/main.go @@ -48,6 +48,8 @@ func isFlagPassed(name string) bool { return found } +var VERSION string + func main() { var client = &http.Client{ @@ -60,7 +62,6 @@ func main() { const MANUAL string = "http://melanie.gitpages.psi.ch/SciCatPages" const APP = "datasetCleaner" - const VERSION = "1.0.6" var APIServer string var env string diff --git a/cmd/datasetGetProposal/main.go b/cmd/datasetGetProposal/main.go index 0d3e78f..af0ae46 100644 --- a/cmd/datasetGetProposal/main.go +++ b/cmd/datasetGetProposal/main.go @@ -20,6 +20,8 @@ import ( "github.com/fatih/color" ) +var VERSION string + func main() { var client = &http.Client{ @@ -32,7 +34,6 @@ func main() { const MANUAL string = "http://melanie.gitpages.psi.ch/SciCatPages" const APP = "datasetGetProposal" - const VERSION = "1.1.6" var APIServer string var env string diff --git a/cmd/datasetIngestor/main.go b/cmd/datasetIngestor/main.go index eea06f4..6957798 100644 --- a/cmd/datasetIngestor/main.go +++ b/cmd/datasetIngestor/main.go @@ -68,6 +68,8 @@ func isFlagPassed(name string) bool { return found } +var VERSION string + func main() { var tooLargeDatasets = 0 var emptyDatasets = 0 @@ -96,10 +98,8 @@ func main() { const MANUAL string = "http://melanie.gitpages.psi.ch/SciCatPages" const APP = "datasetIngestor" - const VERSION = "1.1.31" var scanner = bufio.NewScanner(os.Stdin) - var APIServer string var RSYNCServer string var env string diff --git a/cmd/datasetIngestor/main_test.go b/cmd/datasetIngestor/main_test.go index 1987176..d8e2268 100644 --- a/cmd/datasetIngestor/main_test.go +++ b/cmd/datasetIngestor/main_test.go @@ -6,10 +6,16 @@ import ( "testing" ) +func init() { + os.Setenv("TEST_MODE", "true") +} + // TestMainOutput is a test function that verifies the output of the main function. // It captures the stdout, runs the main function, and checks if the output contains the expected strings. // This just checks if the main function prints the help message. func TestMainOutput(t *testing.T) { + oldTestMode := "false" + defer os.Setenv("TEST_MODE", oldTestMode) // Capture stdout // The variable 'old' stores the original value of the standard output (os.Stdout). old := os.Stdout diff --git a/cmd/datasetPublishData/main.go b/cmd/datasetPublishData/main.go index ec22382..1855c5d 100644 --- a/cmd/datasetPublishData/main.go +++ b/cmd/datasetPublishData/main.go @@ -54,7 +54,6 @@ const RETRIEVELocation string = "/data/archiveManager/retrieve/" const MANUAL string = "http://melanie.gitpages.psi.ch/SciCatPages/#sec-5" const APP = "datasetPublishData" -const VERSION = "1.0.1" var APIServer string = PROD_API_SERVER var RSYNCServer string = PROD_RSYNC_RETRIEVE_SERVER @@ -63,6 +62,7 @@ var client = &http.Client{ Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: false}}, Timeout: 10 * time.Second} var scanner = bufio.NewScanner(os.Stdin) +var VERSION string type PageData struct { Doi string diff --git a/cmd/datasetPublishDataRetrieve/main.go b/cmd/datasetPublishDataRetrieve/main.go index 7514a22..8a4e314 100644 --- a/cmd/datasetPublishDataRetrieve/main.go +++ b/cmd/datasetPublishDataRetrieve/main.go @@ -38,7 +38,6 @@ const RETRIEVELocation string = "/data/archiveManager/retrieve/" const MANUAL string = "http://melanie.gitpages.psi.ch/SciCatPages/#sec-5" const APP = "datasetPublishDataRetrieve" -const VERSION = "1.0.1" var APIServer string = PROD_API_SERVER var RSYNCServer string = PROD_RSYNC_RETRIEVE_SERVER @@ -47,6 +46,7 @@ var client = &http.Client{ Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: false}}, Timeout: 10 * time.Second} var scanner = bufio.NewScanner(os.Stdin) +var VERSION string func main() { diff --git a/cmd/datasetRetriever/main.go b/cmd/datasetRetriever/main.go index 25f6333..d4f670c 100644 --- a/cmd/datasetRetriever/main.go +++ b/cmd/datasetRetriever/main.go @@ -44,7 +44,6 @@ const MANUAL string = "http://melanie.gitpages.psi.ch/SciCatPages/#sec-5" // TODO Windows const APP = "datasetRetriever" -const VERSION = "1.1.14" var APIServer string = PROD_API_SERVER var RSYNCServer string = PROD_RSYNC_RETRIEVE_SERVER @@ -53,6 +52,7 @@ var client = &http.Client{ Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: false}}, Timeout: 10 * time.Second} var scanner = bufio.NewScanner(os.Stdin) +var VERSION string func main() { // check input parameters diff --git a/cmd/waitForJobFinished/main.go b/cmd/waitForJobFinished/main.go index e84cd4a..9e8964e 100644 --- a/cmd/waitForJobFinished/main.go +++ b/cmd/waitForJobFinished/main.go @@ -26,6 +26,8 @@ type Job struct { JobStatusMessage string } +var VERSION string + func main() { var client = &http.Client{ @@ -38,7 +40,6 @@ func main() { const MANUAL string = "http://melanie.gitpages.psi.ch/SciCatPages" const APP = "waitForJobFinished" - const VERSION = "1.0.1" var APIServer string var env string diff --git a/datasetUtils/checkForNewVersion.go b/datasetUtils/checkForNewVersion.go index 788cd84..fb46d3c 100644 --- a/datasetUtils/checkForNewVersion.go +++ b/datasetUtils/checkForNewVersion.go @@ -2,21 +2,21 @@ package datasetUtils import ( "bufio" + "encoding/json" + "fmt" "log" "net/http" "os" "runtime" "strconv" "strings" - "encoding/json" version "github.com/mcuadros/go-version" - "fmt" ) var scanner = bufio.NewScanner(os.Stdin) var ( - GitHubAPI = "https://api.github.com/repos/paulscherrerinstitute/scicat-cli/releases/latest" + GitHubAPI = "https://api.github.com/repos/paulscherrerinstitute/scicat-cli/releases/latest" DeployLocation = "https://github.com/paulscherrerinstitute/scicat-cli/releases/download" ) @@ -30,35 +30,39 @@ func fetchLatestVersion(client *http.Client) (string, error) { return "", err } defer resp.Body.Close() - + if resp.StatusCode != 200 { return "", fmt.Errorf("got %s fetching %s", resp.Status, GitHubAPI) } - + var release Release err = json.NewDecoder(resp.Body).Decode(&release) if err != nil { return "", err } - + return strings.TrimSpace(release.TagName), nil } // Make sure the version number is stripped of the 'v' prefix. That's required for `strconv.Atoi` to work. func generateDownloadURL(deployLocation, latestVersion, osName string) string { - if strings.ToLower(osName) == "windows" { - return fmt.Sprintf("%s/v%s/scicat-cli_.%s_%s_x86_64.zip", deployLocation, latestVersion, latestVersion, strings.Title(osName)) - } - return fmt.Sprintf("%s/v%s/scicat-cli_.%s_%s_x86_64.tar.gz", deployLocation, latestVersion, latestVersion, strings.Title(osName)) + if strings.ToLower(osName) == "windows" { + return fmt.Sprintf("%s/v%s/scicat-cli_.%s_%s_x86_64.zip", deployLocation, latestVersion, latestVersion, strings.Title(osName)) + } + return fmt.Sprintf("%s/v%s/scicat-cli_.%s_%s_x86_64.tar.gz", deployLocation, latestVersion, latestVersion, strings.Title(osName)) } func CheckForNewVersion(client *http.Client, APP string, VERSION string, interactiveFlag bool, userInput UserInput) error { + // avoid checking for new version in test mode + if os.Getenv("TEST_MODE") == "true" { + return nil + } latestVersion, err := fetchLatestVersion(client) if err != nil { log.Printf("Can not find info about latest version for this program: %s\n", err) return err } - + latestVersion = strings.TrimPrefix(latestVersion, "v") _, err = strconv.Atoi(strings.Split(latestVersion, ".")[0]) if err != nil { @@ -69,14 +73,25 @@ func CheckForNewVersion(client *http.Client, APP string, VERSION string, interac log.Fatalf("Illegal version number:%v", VERSION) } log.Printf("Latest version: %s", latestVersion) - + // Get the operating system name osName := runtime.GOOS - + // Generate the download URL downloadURL := generateDownloadURL(DeployLocation, latestVersion, osName) + // Split the versions into parts + currentParts := strings.Split(VERSION, ".") + latestParts := strings.Split(latestVersion, ".") + + // Convert the major and minor parts to integers + currentMajor, _ := strconv.Atoi(currentParts[0]) + currentMinor, _ := strconv.Atoi(currentParts[1]) + latestMajor, _ := strconv.Atoi(latestParts[0]) + latestMinor, _ := strconv.Atoi(latestParts[1]) + if version.Compare(latestVersion, VERSION, ">") { + // Notify an update if the version has changed log.Println("You should upgrade to a newer version") log.Println("Current Version: ", VERSION) log.Println("Latest Version: ", latestVersion) @@ -87,28 +102,30 @@ func CheckForNewVersion(client *http.Client, APP string, VERSION string, interac } else { log.Printf("Browser: %s\nCommand: curl -L -O %s; tar xzf scicat-cli_.%s_%s_x86_64.tar.gz; cd scicat-cli; chmod +x %s\n", downloadURL, downloadURL, latestVersion, strings.Title(osName), APP) } - - if interactiveFlag { - log.Print("Do you want to continue with current version (y/N) ? ") - continueyn, _ := userInput.ReadLine() - if continueyn != "y\n" { - return fmt.Errorf("Execution stopped, please update the program now.") - } - } } else { log.Println("Your version of this program is up-to-date") } + if interactiveFlag && (latestMajor > currentMajor || latestMinor > currentMinor) { + log.Print("Do you want to continue with current version (y/N) ? ") + continueyn, err := userInput.ReadLine() + if err != nil { + return fmt.Errorf("failed to read user input: %v", err) + } + if strings.TrimSpace(continueyn) != "y" { + return fmt.Errorf("Execution stopped, please update the program now.") + } + } return nil } // UserInput is an interface that defines a method to read a line of input. We use this so that we can test interactive mode. type UserInput interface { - ReadLine() (string, error) + ReadLine() (string, error) } -type StdinUserInput struct {} +type StdinUserInput struct{} func (StdinUserInput) ReadLine() (string, error) { - reader := bufio.NewReader(os.Stdin) - return reader.ReadString('\n') + reader := bufio.NewReader(os.Stdin) + return reader.ReadString('\n') } diff --git a/datasetUtils/checkForNewVersion_test.go b/datasetUtils/checkForNewVersion_test.go index 99e17b1..a130f64 100644 --- a/datasetUtils/checkForNewVersion_test.go +++ b/datasetUtils/checkForNewVersion_test.go @@ -123,6 +123,15 @@ func TestCheckForNewVersion(t *testing.T) { interactiveFlag: true, userInput: "n\n", }, + { + name: "New path available, interactive mode", + currentVersion: "0.9.0", + mockResponse: `{"tag_name": "v0.9.1"}`, + expectedLog: "You should upgrade to a newer version", + expectedError: nil, + interactiveFlag: true, + userInput: "y\n", + }, } for _, tt := range tests { @@ -144,8 +153,8 @@ func TestCheckForNewVersion(t *testing.T) { // Call CheckForNewVersion err := CheckForNewVersion(client, "test", tt.currentVersion, tt.interactiveFlag, MockUserInput{Input: tt.userInput}) - if err != nil && err.Error() != tt.expectedLog { - t.Errorf("got error %v, want %v", err, tt.expectedLog) + if err != nil && err.Error() != tt.expectedError.Error() { + t.Errorf("got error %v, want %v", err, tt.expectedLog) } // Check the log output