Skip to content

Commit

Permalink
Merge pull request #1 from RaphSku/setup
Browse files Browse the repository at this point in the history
Setup of the synmake project for version v0.1.0
  • Loading branch information
RaphSku committed Mar 11, 2024
2 parents d84a8c8 + 638ff45 commit ae7b2e8
Show file tree
Hide file tree
Showing 30 changed files with 1,097 additions and 2 deletions.
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,14 @@

# Go workspace file
go.work

# Makefile files
Makefile
*.mk

# Yaml files
*.yaml
*.yml

# Build files
synmake
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## v0.1.0
### 😁 Features
- Print the version of synmake with `synmake version`
- Generate example config with `synmake generate config`
- Parse config and generate the Makefile with `synmake --config=<path_to_config.yaml>`
- 2 provided templates: a help template and a min version preflight check template
- currently available: PHONY, variables, targets, help
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]
Copyright [2024] [RaphSku]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
84 changes: 83 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,83 @@
# synmake
# synmake
![Version](https://img.shields.io/badge/version-v0.1.0-orange)
![CI](https://github.com/RaphSku/synmake/workflows/Go%20CI/badge.svg)
## What is synmake?
You will not need synmake, when you have to write a simple Makefiles but synmake should rather help you in times where you cannot remember, e.g. how to setup a preflight check for checking the minimum required version of a tool or how to print a help window that describes the available targets.

Nowadays, the majority of people are used to writing YAML. synmake allows you to write the specification in YAML and is doing the generation of the Makefile for you.

## How to install synmake
You can either install synmake via Go1.21+ with the following command:
```bash
go install github.com/RaphSku/synmake
```

Alternatively, check the release page and install the binary. There are binaries provided for Windows, MacOS and Linux.

## How to use synmake
If you want to check which version you are using, just check with
```bash
synmake version
```
If you want to generate an example configuration YAML, simply run:
```bash
synmake generate config
```
Adjust it to your needs and then you can simply generate your Makefile via
```bash
synmake --config=<path/to/your/config.yaml>
```
The Makefile will be created in the directory in which you ran this command.

## Understanding the config schema
The config file might look like this:
```yaml
phony:
- default
- preflight
- targetA
- targetB
- help
targets:
targetA:
helpDescription: targetA just prints an output
commands:
- echo "Hello World"
- echo "This is how you specify commands!"
display: false
targetB:
helpDescription: targetB just prints an output
preTargets:
- targetA
commands:
- echo "This is targetB!"
- echo "How are you doing?"
display: true
helpTemplate:
enabled: true
delimiter: '##'
versionTemplate:
enabled: true
library: example
minVersion: 0.1.0
```
1. Phony Targets:
The phony section lists the names of phony targets (targets that are not actual files or commands) such as default, preflight, targetA, targetB, and help.
2. Targets:
Each target (targetA, targetB) has a helpDescription field providing a brief description of what the target does.
The commands field lists the commands to be executed when the target is invoked.
The display field specifies whether the commands should be displayed when running a target. If you specify `Display` as false, the commands will be shown, as well as the resulting output.
For targetB, there is a preTargets field that specifies dependencies on other targets (targetA in this case).

3. Help and Version Templates:

The helpTemplate section configures the help template:
enabled specifies whether the help template is enabled or not (true/false).
delimiter specifies the delimiter used in the help template.
The versionTemplate section configures the version template:
enabled specifies whether the version template is enabled or not (true/false).
library specifies the library or module used for checking the version.
minVersion specifies the minimum version required for the library/module.
36 changes: 36 additions & 0 deletions cmd/generate/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package config

import (
"os"

c2 "github.com/RaphSku/synmake/internal/config"
"github.com/spf13/cobra"
"go.uber.org/zap"
)

func GetGenerateConfigCmd(logger *zap.Logger) cobra.Command {
generateConfigCmd := cobra.Command{
Use: "config",
Short: "Generate a basic config.yaml for customization.",
Long: `Generate a basic config.yaml, customize it and then apply it.`,
Run: func(cmd *cobra.Command, args []string) {
file, err := os.Create("config.yaml")
if err != nil {
logger.Error("Failed to create a config.yaml", zap.Error(err))
os.Exit(1)
}

content := "---\n"
defaultConfig := c2.GetConfigAsYamlString(logger)
content += defaultConfig

_, err = file.WriteString(content)
if err != nil {
logger.Error("Failed to write to config.yaml", zap.Error(err))
os.Exit(1)
}
},
}

return generateConfigCmd
}
26 changes: 26 additions & 0 deletions cmd/generate/config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package config

import (
"os"
"testing"

"github.com/stretchr/testify/assert"
"go.uber.org/zap"
)

func TestIfGenerateConfigCmdIsRunning(t *testing.T) {
logger, err := zap.NewDevelopment()
assert.NoError(t, err)

cmd := GetGenerateConfigCmd(logger)

err = cmd.Execute()
assert.NoError(t, err, "Expected no error")
assert.FileExists(t, "config.yaml", "Expected file to be created")

shortDescription := cmd.Short
longDescription := cmd.Long
assert.Greater(t, longDescription, shortDescription)

os.Remove("config.yaml")
}
15 changes: 15 additions & 0 deletions cmd/generate/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package generate

import (
"github.com/spf13/cobra"
)

func GetGenerateCmd() cobra.Command {
generateCmd := cobra.Command{
Use: "generate",
Short: "The command generate can be used to generate configuration files.",
Long: `The command generate can be used to generate configuration files for customization.`,
}

return generateCmd
}
18 changes: 18 additions & 0 deletions cmd/generate/generate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package generate

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestIfGenerateCmdIsRunning(t *testing.T) {
cmd := GetGenerateCmd()

err := cmd.Execute()
assert.NoError(t, err)

shortDescription := cmd.Short
longDescription := cmd.Long
assert.Greater(t, len(longDescription), len(shortDescription))
}
64 changes: 64 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package cmd

import (
"os"

"github.com/RaphSku/synmake/cmd/generate"
"github.com/RaphSku/synmake/cmd/generate/config"
"github.com/RaphSku/synmake/cmd/version"
c2 "github.com/RaphSku/synmake/internal/config"
"github.com/spf13/cobra"
"go.uber.org/zap"
)

type CLI struct {
logger *zap.Logger

rootCmd *cobra.Command
}

func NewCLI(logger *zap.Logger) *CLI {
var configFilePath string

rootCmd := &cobra.Command{
Use: "synmake",
Short: "synmake helps you with the setup of Makefiles!",
Long: `Based on a yaml config, synmake will generate a Makefile template for you!`,
Run: func(cmd *cobra.Command, args []string) {
if configFilePath != "" {
configManager := c2.NewConfigManager(logger, configFilePath)
err := configManager.Parse().Apply()
if err != nil {
logger.Error("The config file could not be parsed and applied", zap.Error(err))
os.Exit(1)
}
}
},
}

rootCmd.CompletionOptions.DisableDefaultCmd = true
rootCmd.Flags().StringVarP(&configFilePath, "config", "", "", "Specify the filepath to your config yaml.")
rootCmd.MarkFlagRequired("config")

return &CLI{
logger: logger,
rootCmd: rootCmd,
}
}

func (cli *CLI) AddSubCommands() {
versionCmd := version.GetVersionCmd(cli.logger)
cli.rootCmd.AddCommand(versionCmd)

generateCmd := generate.GetGenerateCmd()
cli.rootCmd.AddCommand(&generateCmd)
configCmd := config.GetGenerateConfigCmd(cli.logger)
generateCmd.AddCommand(&configCmd)
}

func (cli *CLI) Execute() {
if err := cli.rootCmd.Execute(); err != nil {
cli.logger.Info("CLI failed to run", zap.Error(err))
os.Exit(1)
}
}
61 changes: 61 additions & 0 deletions cmd/version/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package version

import (
"bufio"
"fmt"
"os"
"regexp"

"github.com/spf13/cobra"
"go.uber.org/zap"
)

const (
CHANGELOG_FILEPATH = "CHANGELOG.md"
)

func scanFileForVersions(scanner *bufio.Scanner) string {
var version string
pattern := `v\d+\.\d+\.\d+`
re := regexp.MustCompile(pattern)
for scanner.Scan() {
line := scanner.Text()

matches := re.FindAllString(line, -1)
matchLength := len(matches)
if matchLength != 0 {
version = matches[0]
break
}
}

return version
}

func GetVersionCmd(logger *zap.Logger) *cobra.Command {
versionCmd := &cobra.Command{
Use: "version",
Short: "Print the version number of synmake.",
Long: `This will show you the version of synmake in the format: {MAJOR}-{MINOR}-{PATCH}.`,
Run: func(cmd *cobra.Command, args []string) {
file, err := os.Open(CHANGELOG_FILEPATH)
if err != nil {
logger.Error("Could not open CHANGELOG", zap.Error(err))
os.Exit(1)
}
defer file.Close()

scanner := bufio.NewScanner(file)
version := scanFileForVersions(scanner)

fmt.Println(version)

if err := scanner.Err(); err != nil {
logger.Error("Error scanning file", zap.Error(err))
os.Exit(1)
}
},
}

return versionCmd
}
32 changes: 32 additions & 0 deletions cmd/version/version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package version

import (
"os"
"testing"

"github.com/stretchr/testify/assert"
"go.uber.org/zap"
)

func TestIfVersionCmdIsRunning(t *testing.T) {
changelog := `v0.1.0`
file, err := os.Create("CHANGELOG.md")
assert.NoError(t, err)
defer file.Close()
_, err = file.WriteString(changelog)
assert.NoError(t, err)

logger, err := zap.NewDevelopment()
assert.NoError(t, err)

cmd := GetVersionCmd(logger)

err = cmd.Execute()
assert.NoError(t, err)

shortDescription := cmd.Short
longDescription := cmd.Long
assert.Greater(t, len(longDescription), len(shortDescription))

os.Remove("CHANGELOG.md")
}
18 changes: 18 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module github.com/RaphSku/synmake

go 1.21.0

require (
github.com/spf13/cobra v1.8.0
github.com/stretchr/testify v1.9.0
go.uber.org/zap v1.27.0
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
go.uber.org/multierr v1.11.0 // indirect
)
Loading

0 comments on commit ae7b2e8

Please sign in to comment.