diff --git a/.github/workflows/build&release.yml b/.github/workflows/build&release.yml index d6a4c544..f3d34608 100644 --- a/.github/workflows/build&release.yml +++ b/.github/workflows/build&release.yml @@ -36,17 +36,15 @@ jobs: - name: Prepare Build Variables id: vars run: | - repo_name=${GITHUB_REPOSITORY##*/} + # Prepare version information + VERSION=$(git describe --tags --always --dirty 2>/dev/null || echo "dev") + GIT_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown") + BUILD_TIME=$(date -u '+%Y-%m-%d_%H:%M:%S') - # For non-tag builds, use commit SHA as identifier - build_id=${GITHUB_SHA::7} - echo "build_id=$build_id" >> $GITHUB_OUTPUT + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "git_commit=$GIT_COMMIT" >> $GITHUB_OUTPUT + echo "build_time=$BUILD_TIME" >> $GITHUB_OUTPUT echo "binary_name=supernode-linux-amd64" >> $GITHUB_OUTPUT - - # Debug output - echo "Output variables:" - echo "- build_id: $build_id" - echo "- binary_name: supernode-linux-amd64" - name: Build binary run: | @@ -57,17 +55,15 @@ jobs: GOARCH=amd64 \ go build \ -trimpath \ - -ldflags="-s -w" \ + -ldflags="-s -w \ + -X github.com/LumeraProtocol/supernode/supernode/cmd.Version=${{ steps.vars.outputs.version }} \ + -X github.com/LumeraProtocol/supernode/supernode/cmd.GitCommit=${{ steps.vars.outputs.git_commit }} \ + -X github.com/LumeraProtocol/supernode/supernode/cmd.BuildTime=${{ steps.vars.outputs.build_time }}" \ -o release/${{ steps.vars.outputs.binary_name }} \ - ./supernode/main.go + ./supernode - # Make binary executable chmod +x release/${{ steps.vars.outputs.binary_name }} - - # Show build results - ls -la release/ - # Fix permissions - name: Fix Release Directory Permissions run: | sudo chown -R $USER:$USER release/ @@ -88,25 +84,17 @@ jobs: - name: Get tag information id: tag_info run: | - # Get the tag name TAG_NAME=${GITHUB_REF#refs/tags/} echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT - # Get the tag message TAG_MESSAGE=$(git tag -l --format='%(contents)' $TAG_NAME) - # If tag message is empty, use the tag name as message if [ -z "$TAG_MESSAGE" ]; then TAG_MESSAGE="Release $TAG_NAME" fi - # Handle multiline tag messages TAG_MESSAGE="${TAG_MESSAGE//'%'/'%25'}" TAG_MESSAGE="${TAG_MESSAGE//$'\n'/'%0A'}" TAG_MESSAGE="${TAG_MESSAGE//$'\r'/'%0D'}" echo "tag_message=$TAG_MESSAGE" >> $GITHUB_OUTPUT - - # Get the annotated tag commit - TAG_COMMIT=$(git rev-list -n 1 $TAG_NAME) - echo "tag_commit=$TAG_COMMIT" >> $GITHUB_OUTPUT - name: Configure Git Safe Directory run: git config --global --add safe.directory $GITHUB_WORKSPACE @@ -117,7 +105,13 @@ jobs: - name: Prepare Release Variables id: vars run: | - repo_name=${GITHUB_REPOSITORY##*/} + VERSION=${{ steps.tag_info.outputs.tag_name }} + GIT_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown") + BUILD_TIME=$(date -u '+%Y-%m-%d_%H:%M:%S') + + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "git_commit=$GIT_COMMIT" >> $GITHUB_OUTPUT + echo "build_time=$BUILD_TIME" >> $GITHUB_OUTPUT echo "binary_name=supernode-linux-amd64" >> $GITHUB_OUTPUT - name: Build Release Version @@ -129,17 +123,15 @@ jobs: GOARCH=amd64 \ go build \ -trimpath \ - -ldflags="-s -w" \ + -ldflags="-s -w \ + -X github.com/LumeraProtocol/supernode/supernode/cmd.Version=${{ steps.vars.outputs.version }} \ + -X github.com/LumeraProtocol/supernode/supernode/cmd.GitCommit=${{ steps.vars.outputs.git_commit }} \ + -X github.com/LumeraProtocol/supernode/supernode/cmd.BuildTime=${{ steps.vars.outputs.build_time }}" \ -o release/${{ steps.vars.outputs.binary_name }} \ - ./supernode/main.go + ./supernode - # Make binary executable chmod +x release/${{ steps.vars.outputs.binary_name }} - - # Show build results - ls -la release/ - # Fix permissions - name: Fix Release Directory Permissions run: | sudo chown -R $USER:$USER release/ @@ -155,11 +147,12 @@ jobs: body: | ${{ steps.tag_info.outputs.tag_message }} - Tag: ${{ steps.tag_info.outputs.tag_name }} - Commit: ${{ steps.tag_info.outputs.tag_commit }} + Version: ${{ steps.vars.outputs.version }} + Git Commit: ${{ steps.vars.outputs.git_commit }} + Build Time: ${{ steps.vars.outputs.build_time }} Installation: - 1. Download the binary - 2. Make it executable: `chmod +x supernode-linux-amd64` - 3. Run the binary: `./supernode-linux-amd64` + 1. Download: `supernode-linux-amd64` + 2. Make executable: `chmod +x supernode-linux-amd64` + 3. Run: `./supernode-linux-amd64` token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/Makefile b/Makefile index fbebcefe..0d20d887 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,31 @@ -.PHONY: test-unit test-integration test-system install-lumera setup-supernodes system-test-setup +.PHONY: test-unit test-integration test-system install-lumera setup-supernodes system-test-setup build build-release + +# Build variables +VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev") +GIT_COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown") +BUILD_TIME ?= $(shell date -u '+%Y-%m-%d_%H:%M:%S') + +# Linker flags for version information +LDFLAGS = -X github.com/LumeraProtocol/supernode/supernode/cmd.Version=$(VERSION) \ + -X github.com/LumeraProtocol/supernode/supernode/cmd.GitCommit=$(GIT_COMMIT) \ + -X github.com/LumeraProtocol/supernode/supernode/cmd.BuildTime=$(BUILD_TIME) + +# Development build +build: + go build -ldflags "$(LDFLAGS)" -o supernode ./supernode + +# Release build (matches GitHub workflow) +build-release: + @mkdir -p release + CGO_ENABLED=1 \ + GOOS=linux \ + GOARCH=amd64 \ + go build \ + -trimpath \ + -ldflags="-s -w $(LDFLAGS)" \ + -o release/supernode-linux-amd64 \ + ./supernode + @chmod +x release/supernode-linux-amd64 # Run unit tests (regular tests with code) test-unit: diff --git a/supernode/cmd/root.go b/supernode/cmd/root.go index 12baefa0..2dc9bc4a 100644 --- a/supernode/cmd/root.go +++ b/supernode/cmd/root.go @@ -15,52 +15,42 @@ var ( appConfig *config.Config ) +const ( + DefaultConfigFile = "config.yaml" + DefaultBaseDir = ".supernode" +) + // fileExists checks if a file exists at the given path func fileExists(path string) bool { _, err := os.Stat(path) return err == nil } -// findConfigFile searches for config files in multiple locations -func findConfigFile() string { +// findConfigFile searches for config files in base directory only +func findConfigFile(baseDirPath string) string { // If config file is explicitly specified, use it if cfgFile != "" { return cfgFile } - // Try current working directory first (for go run) - workingDir, err := os.Getwd() - if err == nil { - yamlPath := filepath.Join(workingDir, "config.yaml") - ymlPath := filepath.Join(workingDir, "config.yml") - - if fileExists(yamlPath) { - return yamlPath - } - if fileExists(ymlPath) { - return ymlPath + // Only search in base directory as default + if baseDirPath != "" { + searchPaths := []string{ + filepath.Join(baseDirPath, DefaultConfigFile), + filepath.Join(baseDirPath, "config.yml"), } - } - - // Then try executable directory (for binary) - execPath, err := os.Executable() - if err == nil { - execDir := filepath.Dir(execPath) - yamlPath := filepath.Join(execDir, "config.yaml") - ymlPath := filepath.Join(execDir, "config.yml") - if fileExists(yamlPath) { - return yamlPath - } - if fileExists(ymlPath) { - return ymlPath + // Return first existing config file + for _, path := range searchPaths { + if fileExists(path) { + return path + } } } return "" } -// setupBaseDir configures the base directory if not specified func setupBaseDir() (string, error) { if baseDir != "" { return baseDir, nil @@ -71,20 +61,18 @@ func setupBaseDir() (string, error) { return "", fmt.Errorf("failed to get home directory: %w", err) } - return filepath.Join(homeDir, ".supernode"), nil + return filepath.Join(homeDir, DefaultBaseDir), nil } // logConfig logs information about config and base directory func logConfig(configPath, baseDirPath string) { // For config file - absPath, err := filepath.Abs(configPath) - if err == nil { + if absPath, err := filepath.Abs(configPath); err == nil { fmt.Printf("Using config file: %s\n", absPath) } else { fmt.Printf("Using config file: %s\n", configPath) } - // For base directory fmt.Printf("Using base directory: %s\n", baseDirPath) } @@ -100,16 +88,16 @@ This application allows you to create and recover keys using mnemonics.`, } // Setup base directory - setupDir, err := setupBaseDir() + var err error + baseDir, err = setupBaseDir() if err != nil { return err } - baseDir = setupDir - // Find config file - cfgFile = findConfigFile() + // Find config file (only searches in base directory by default) + cfgFile = findConfigFile(baseDir) if cfgFile == "" { - return fmt.Errorf("no config file found in working directory or executable directory") + return fmt.Errorf("no config file found in base directory (%s)", baseDir) } // Log configuration @@ -134,7 +122,9 @@ func Execute() { } func init() { - // Allow user to override config file location with --config flag - rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "Config file path (default is ./config.yaml or ./config.yml)") - rootCmd.PersistentFlags().StringVarP(&baseDir, "basedir", "d", "", "Base directory for all data (default is ~/.supernode)") + // Use default values in flag descriptions + rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", + fmt.Sprintf("Config file path (default is ~/%s/%s)", DefaultBaseDir, DefaultConfigFile)) + rootCmd.PersistentFlags().StringVarP(&baseDir, "basedir", "d", "", + fmt.Sprintf("Base directory for all data (default is ~/%s)", DefaultBaseDir)) } diff --git a/supernode/cmd/version.go b/supernode/cmd/version.go new file mode 100644 index 00000000..517a0c13 --- /dev/null +++ b/supernode/cmd/version.go @@ -0,0 +1,28 @@ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +var ( + // Build-time variables set by go build -ldflags + Version = "dev" + GitCommit = "unknown" + BuildTime = "unknown" +) + +// versionCmd represents the version command +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Show version information", + Long: `Display version information for the supernode.`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println(Version) + }, +} + +func init() { + rootCmd.AddCommand(versionCmd) +} diff --git a/supernode/main.go b/supernode/main.go index 4d4febe1..45f03fff 100644 --- a/supernode/main.go +++ b/supernode/main.go @@ -1,22 +1,12 @@ package main import ( - "context" - "github.com/LumeraProtocol/supernode/pkg/keyring" - "github.com/LumeraProtocol/supernode/pkg/logtrace" "github.com/LumeraProtocol/supernode/supernode/cmd" ) func main() { - // Create initial context with correlation ID - ctx := logtrace.CtxWithCorrelationID(context.Background(), "supernode-main") - // Initialize Cosmos SDK configuration - logtrace.Info(ctx, "Initializing Cosmos SDK configuration", logtrace.Fields{}) keyring.InitSDKConfig() - - // Execute root command - logtrace.Info(ctx, "Executing CLI command", logtrace.Fields{}) cmd.Execute() }