Skip to content

Commit 51accfc

Browse files
committed
refactor: rearrange the project structure
1 parent 8f72cd9 commit 51accfc

File tree

9 files changed

+277
-174
lines changed

9 files changed

+277
-174
lines changed

cmd/root.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package cmd
2+
3+
import (
4+
"context"
5+
"log"
6+
"os"
7+
"strconv"
8+
"time"
9+
10+
"github.com/pplmx/setup-my-action/internal/api"
11+
"github.com/pplmx/setup-my-action/internal/config"
12+
"github.com/pplmx/setup-my-action/internal/file"
13+
"github.com/pplmx/setup-my-action/internal/output"
14+
"github.com/pplmx/setup-my-action/internal/text"
15+
)
16+
17+
const contextTimeout = 15 * time.Second
18+
19+
// Execute is the main entry point for the cmd package, orchestrating the main program flow.
20+
func Execute() {
21+
configPath := os.Getenv("INPUT_CONFIG_PATH")
22+
cfg, err := config.LoadConfig(configPath)
23+
if err != nil {
24+
log.Fatalf("Failed to load configuration: %v", err)
25+
}
26+
27+
// Process text
28+
if err := processText(cfg); err != nil {
29+
log.Fatalf("Text processing error: %v", err)
30+
}
31+
32+
// Process numbers
33+
if err := processNumbers(cfg); err != nil {
34+
log.Fatalf("Number processing error: %v", err)
35+
}
36+
37+
// Process files
38+
if err := processFiles(cfg); err != nil {
39+
log.Fatalf("File processing error: %v", err)
40+
}
41+
42+
// Check API reachability
43+
if err := checkAPI(cfg); err != nil {
44+
log.Fatalf("API check error: %v", err)
45+
}
46+
}
47+
48+
func processText(cfg *config.Config) error {
49+
processedText, wordCount := text.ProcessText(cfg.InputText, cfg.FindWord, cfg.ReplaceWord)
50+
if err := output.SetOutput("processed_text", processedText); err != nil {
51+
return err
52+
}
53+
return output.SetOutput("word_count", strconv.Itoa(wordCount))
54+
}
55+
56+
func processNumbers(cfg *config.Config) error {
57+
sum, average := text.CalculateSumAndAverage(cfg.NumberList)
58+
if err := output.SetOutput("sum", strconv.FormatFloat(sum, 'f', -1, 64)); err != nil {
59+
return err
60+
}
61+
return output.SetOutput("average", strconv.FormatFloat(average, 'f', -1, 64))
62+
}
63+
64+
func processFiles(cfg *config.Config) error {
65+
return file.ReadAndAppendToFile(cfg.InputFile, cfg.OutputFile, cfg.AppendText)
66+
}
67+
68+
func checkAPI(cfg *config.Config) error {
69+
ctx, cancel := context.WithTimeout(context.Background(), contextTimeout)
70+
defer cancel()
71+
72+
if err := api.CheckAPIReachability(ctx, cfg.ApiURL); err != nil {
73+
return err
74+
}
75+
return output.SetOutput("response_field", "API Reachable")
76+
}

docs/development.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# DEVELOPMENT.md
2+
3+
## Project Overview
4+
5+
This document provides an overview of the directory structure and components of the project. The project is organized to
6+
ensure clear separation of concerns, ease of maintenance, and scalability. Below is a breakdown of each directory and
7+
its purpose.
8+
9+
## Directory Structure
10+
11+
```
12+
setup-my-action/
13+
14+
├── main.go // Entry point of the application
15+
├── cmd/
16+
│ └── root.go // Root command and setup for executing commands
17+
├── internal/
18+
│ ├── config/
19+
│ │ └── config.go // Configuration loading and validation
20+
│ ├── text/
21+
│ │ └── text.go // Text processing functions
22+
│ ├── file/
23+
│ │ └── file.go // File operations
24+
│ ├── api/
25+
│ │ └── api.go // API-related operations
26+
│ └── output/
27+
│ └── output.go // Output handling
28+
└── go.mod // Go module file
29+
```
30+
31+
## Contributing
32+
33+
When contributing to this project, please ensure that any changes are well-documented and tested. Follow the existing
34+
code style and structure for consistency.
35+
36+
## Conclusion
37+
38+
This project structure helps keep the codebase modular and maintainable. By separating different concerns into distinct
39+
packages, we ensure that each component can be developed and tested independently, making the application easier to
40+
understand and extend.

internal/.gitkeep

Whitespace-only changes.

internal/api/api.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// internal/api/api.go
2+
3+
package api
4+
5+
import (
6+
"context"
7+
"fmt"
8+
"io"
9+
"log"
10+
"net/http"
11+
"time"
12+
)
13+
14+
const httpTimeout = 10 * time.Second
15+
16+
func CheckAPIReachability(ctx context.Context, apiURL string) error {
17+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, apiURL, nil)
18+
if err != nil {
19+
return fmt.Errorf("failed to create request: %w", err)
20+
}
21+
22+
client := &http.Client{Timeout: httpTimeout}
23+
resp, err := client.Do(req)
24+
if err != nil {
25+
return fmt.Errorf("failed to make API request: %w", err)
26+
}
27+
defer func(Body io.ReadCloser) {
28+
err := Body.Close()
29+
if err != nil {
30+
log.Printf("Failed to close response body: %v", err)
31+
}
32+
}(resp.Body)
33+
34+
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
35+
return fmt.Errorf("API is not reachable, status code: %d", resp.StatusCode)
36+
}
37+
38+
return nil
39+
}

internal/config/config.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// internal/config/config.go
2+
3+
package config
4+
5+
import (
6+
"fmt"
7+
8+
"github.com/BurntSushi/toml"
9+
)
10+
11+
type Config struct {
12+
InputText string `toml:"input_text"`
13+
FindWord string `toml:"find_word"`
14+
ReplaceWord string `toml:"replace_word"`
15+
NumberList []float64 `toml:"number_list"`
16+
InputFile string `toml:"input_file"`
17+
OutputFile string `toml:"output_file"`
18+
AppendText string `toml:"append_text"`
19+
ApiURL string `toml:"api_url"`
20+
}
21+
22+
const defaultConfigPath = ".github/configs/setup-my-action.toml"
23+
24+
func LoadConfig(path string) (*Config, error) {
25+
if path == "" {
26+
path = defaultConfigPath
27+
}
28+
29+
var config Config
30+
if _, err := toml.DecodeFile(path, &config); err != nil {
31+
return nil, fmt.Errorf("failed to decode TOML file: %w", err)
32+
}
33+
34+
if err := validateConfig(&config); err != nil {
35+
return nil, fmt.Errorf("invalid configuration: %w", err)
36+
}
37+
38+
return &config, nil
39+
}
40+
41+
func validateConfig(cfg *Config) error {
42+
if cfg.InputText == "" {
43+
return fmt.Errorf("input_text is required")
44+
}
45+
if cfg.InputFile == "" || cfg.OutputFile == "" {
46+
return fmt.Errorf("input_file and output_file are required")
47+
}
48+
if cfg.ApiURL == "" {
49+
return fmt.Errorf("api_url is required")
50+
}
51+
return nil
52+
}

internal/file/file.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// internal/file/file.go
2+
3+
package file
4+
5+
import (
6+
"fmt"
7+
"os"
8+
)
9+
10+
func ReadAndAppendToFile(inputFile, outputFile, appendText string) error {
11+
content, err := os.ReadFile(inputFile)
12+
if err != nil {
13+
return fmt.Errorf("failed to read input file: %w", err)
14+
}
15+
16+
modifiedContent := string(content) + "\n" + appendText
17+
18+
return os.WriteFile(outputFile, []byte(modifiedContent), 0644)
19+
}

internal/output/output.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// internal/output/output.go
2+
3+
package output
4+
5+
import (
6+
"fmt"
7+
"log"
8+
"os"
9+
)
10+
11+
func SetOutput(name, value string) error {
12+
envFile := os.Getenv("GITHUB_OUTPUT")
13+
f, err := os.OpenFile(envFile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
14+
if err != nil {
15+
return fmt.Errorf("failed to open GITHUB_OUTPUT file: %w", err)
16+
}
17+
defer func(f *os.File) {
18+
err := f.Close()
19+
if err != nil {
20+
log.Printf("Failed to close GITHUB_OUTPUT file: %v", err)
21+
}
22+
}(f)
23+
24+
_, err = fmt.Fprintf(f, "%s=%s\n", name, value)
25+
if err != nil {
26+
return fmt.Errorf("failed to write to GITHUB_OUTPUT file: %w", err)
27+
}
28+
return nil
29+
}

internal/text/text.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// internal/text/text.go
2+
3+
package text
4+
5+
import "strings"
6+
7+
func ProcessText(inputText, findWord, replaceWord string) (string, int) {
8+
processedText := strings.ReplaceAll(inputText, findWord, replaceWord)
9+
wordCount := len(strings.Fields(inputText))
10+
return processedText, wordCount
11+
}
12+
13+
func CalculateSumAndAverage(numbers []float64) (float64, float64) {
14+
sum := 0.0
15+
for _, num := range numbers {
16+
sum += num
17+
}
18+
average := sum / float64(len(numbers))
19+
return sum, average
20+
}

0 commit comments

Comments
 (0)