Skip to content

Commit c3c641c

Browse files
committed
fix logic + add install scripts
1 parent 3ab68fc commit c3c641c

7 files changed

Lines changed: 227 additions & 22 deletions

File tree

.github/workflows/goforge-cd.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: goforge CD
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*.*.*"
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
goreleaser:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 0
19+
20+
- name: Set up Go
21+
uses: actions/setup-go@v5
22+
with:
23+
go-version: stable
24+
25+
- name: Run GoReleaser
26+
uses: goreleaser/goreleaser-action@v6
27+
with:
28+
distribution: goreleaser
29+
version: latest
30+
args: release --clean
31+
env:
32+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,24 @@ The idea is that these are backend services (like microservices), not an entire
1010

1111
P.S. This was encountered while working on [fáfnir](https://github.com/andrearcaina/fafnir).
1212

13+
### Installation
14+
`goforge` can be installed on Windows or Linux, WSL, Git Bash:
15+
16+
Install via cURL on Linux, WSL, or Git Bash:
17+
```bash
18+
curl -fsSL https://raw.githubusercontent.com/andrearcaina/goforge/main/install.sh | sh
19+
```
20+
21+
Install via Powershell on Windows:
22+
```bash
23+
irm https://raw.githubusercontent.com/andrearcaina/goforge/main/install.ps1 | iex
24+
```
25+
26+
Or via Go (requires Go 1.24.5 or later):
27+
```bash
28+
go install github.com/andrearcaina/pathfinder@latest
29+
```
30+
1331
### TODO
1432

1533
In no particular order:
@@ -21,4 +39,4 @@ In no particular order:
2139
- [x] Add SQLc support flag
2240
- [ ] Potentially add a docker-compose file to spin up a PostgreSQL instance
2341
- [x] Interactive UI for when certain flags are not provided
24-
- [ ] Add installation scripts for both Windows and Linux
42+
- [X] Add installation scripts for both Windows and Linux

install.ps1

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
$ErrorActionPreference = "Stop" # stops the script if any error occurs (Write-Error)
2+
3+
$Repo = "andrearcaina/goforge"
4+
$BinName = "goforge"
5+
$BinNameExe = "$BinName.exe"
6+
7+
# get the latest tag from GitHub
8+
Write-Host "Fetching latest release tag..."
9+
$LatestReleaseUrl = "https://api.github.com/repos/$Repo/releases/latest"
10+
try {
11+
$Response = Invoke-RestMethod -Uri $LatestReleaseUrl -Method Get
12+
$Tag = $Response.tag_name
13+
} catch {
14+
Write-Error "Failed to fetch latest release tag."
15+
exit 1
16+
}
17+
18+
# add "v" if missing (though github usually includes it, just in case logic differs)
19+
if (-not $Tag.StartsWith("v")) {
20+
$Tag = "v$Tag"
21+
}
22+
23+
# detect architecture
24+
$ArchInput = $env:PROCESSOR_ARCHITECTURE
25+
26+
if ($ArchInput -eq "AMD64") {
27+
$Arch = "x86_64"
28+
} elseif ($ArchInput -eq "ARM64") {
29+
$Arch = "arm64"
30+
} elseif ($ArchInput -eq "x86") {
31+
if ([System.Environment]::Is64BitOperatingSystem) {
32+
$Arch = "x86_64"
33+
} else {
34+
$Arch = "i386"
35+
}
36+
} else {
37+
Write-Error "Unsupported architecture: $ArchInput"
38+
exit 1
39+
}
40+
41+
$Os = "Windows"
42+
$Ext = "zip"
43+
$DownloadName = "${BinName}_${Os}_${Arch}.${Ext}"
44+
$DownloadUrl = "https://github.com/$Repo/releases/download/$Tag/$DownloadName"
45+
46+
Write-Host "Downloading goforge $Tag for Windows ($Arch)..."
47+
$TempZip = Join-Path $env:TEMP "$BinName.zip"
48+
49+
try {
50+
Invoke-WebRequest -Uri $DownloadUrl -OutFile $TempZip
51+
} catch {
52+
Write-Error "Failed to download release from $DownloadUrl"
53+
exit 1
54+
}
55+
56+
# install directory (this is where the binary will be installed)
57+
# will be installed in $USERPROFILE/.pathfinder/bin
58+
$InstallDir = Join-Path $env:USERPROFILE ".pathfinder/bin"
59+
if (-not (Test-Path $InstallDir)) {
60+
New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
61+
}
62+
63+
# extract (extract the zip file downloaded from GitHub)
64+
Expand-Archive -Path $TempZip -DestinationPath $env:TEMP -Force
65+
$ExtractedBin = Join-Path $env:TEMP $BinNameExe
66+
67+
if (Test-Path $ExtractedBin) {
68+
Move-Item -Path $ExtractedBin -Destination (Join-Path $InstallDir $BinNameExe) -Force
69+
Write-Host "Installed to $InstallDir\$BinNameExe"
70+
} else {
71+
Write-Error "Could not find $BinNameExe after extraction."
72+
exit 1
73+
}
74+
# then cleanup (remove temp zip)
75+
Remove-Item $TempZip -Force
76+
77+
# check USER PATH and add pathfinder bin directory if not present
78+
$UserPath = [Environment]::GetEnvironmentVariable("Path", [EnvironmentVariableTarget]::User)
79+
if ($UserPath -notlike "*$InstallDir*") {
80+
Write-Host "Adding $InstallDir to User PATH..."
81+
[Environment]::SetEnvironmentVariable("Path", "$UserPath;$InstallDir", [EnvironmentVariableTarget]::User)
82+
$env:PATH = "$env:PATH;$InstallDir"
83+
Write-Host "Added to PATH. You may need to restart your shell for changes to take full effect."
84+
} else {
85+
Write-Host "$InstallDir is already in your User PATH."
86+
}
87+
88+
Write-Host "Installation complete."

install.sh

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/bin/sh
2+
set -e
3+
REPO="andrearcaina/goforge"
4+
BIN="goforge"
5+
6+
# get the latest tag from GitHub
7+
TAG=$(curl -s "https://api.github.com/repos/$REPO/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
8+
9+
# detect OS/Arch
10+
OS="$(uname -s)"
11+
ARCH="$(uname -m)"
12+
EXT="tar.gz"
13+
14+
# detects architecture for naming consistency
15+
case "$OS" in
16+
Linux*) OS="Linux" ;;
17+
Darwin*) OS="Darwin" ;;
18+
MINGW*|MSYS*) OS="Windows"; EXT="zip"; BIN="${BIN}.exe" ;;
19+
*) echo "Unsupported OS: $OS"; exit 1 ;;
20+
esac
21+
22+
# download and extract
23+
URL="https://github.com/$REPO/releases/download/$TAG/${BIN%.*}_${OS}_${ARCH}.$EXT"
24+
echo "Downloading goforge $TAG for $OS..."
25+
26+
if [ "$EXT" = "zip" ]; then
27+
# windows: download zip, unzip, install to ~/bin (no sudo needed)
28+
curl -sL "$URL" -o tmp.zip
29+
unzip -qo tmp.zip "$BIN" && rm tmp.zip
30+
mkdir -p ~/bin && mv "$BIN" ~/bin/
31+
echo "Installed to ~/bin/$BIN (Ensure ~/bin is in your PATH)"
32+
else
33+
# mac/linux: stream tar, sudo move to /usr/local/bin
34+
curl -sL "$URL" | tar xz
35+
sudo mv "$BIN" /usr/local/bin/
36+
echo "Installed to /usr/local/bin/$BIN"
37+
fi

internal/goforge/generator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ func generateRESTServer(cfg *spec.Config) error {
102102
func generateDBFiles(cfg *spec.Config) error {
103103
dbFiles := map[string]string{
104104
"base/sqlc.yaml.tmpl": "sqlc.yaml",
105-
"db/init.sql.tmpl": fmt.Sprintf("db/migrations/%s_init.sql", time.Now().Format("20060102150405")),
105+
"db/init.sql.tmpl": fmt.Sprintf("internal/db/migrations/%s_init.sql", time.Now().Format("20060102150405")),
106106
"db/user.sql.tmpl": "internal/db/queries/user.sql",
107107
"db/db.go.tmpl": "internal/db/db.go",
108108
}

internal/templates/base/Makefile.tmpl

Lines changed: 11 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/ui/success.go

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,55 @@ package ui
22

33
import (
44
"fmt"
5+
"os"
56

67
"github.com/andrearcaina/goforge/internal/spec"
78
"github.com/charmbracelet/lipgloss"
89
)
910

10-
func OutputSuccess(cfg *spec.Config) {
11-
successStyle := lipgloss.NewStyle().
12-
Foreground(lipgloss.Color("205")).
13-
Bold(true).
14-
Padding(1, 0)
11+
var (
12+
successStyle = lipgloss.NewStyle().
13+
Foreground(lipgloss.Color("205")).
14+
Bold(true).
15+
Padding(1, 0)
1516

16-
cmdStyle := lipgloss.NewStyle().
17-
Foreground(lipgloss.Color("63")).
18-
PaddingLeft(2)
17+
cmdStyle = lipgloss.NewStyle().
18+
Foreground(lipgloss.Color("63")).
19+
PaddingLeft(2)
20+
)
1921

22+
func OutputSuccess(cfg *spec.Config) {
2023
fmt.Println(successStyle.Render("🔥 Generated successfully!"))
2124
fmt.Println("Make sure to run the following commands:")
2225

2326
// base commands to run
2427
commands := []string{
2528
fmt.Sprintf("cd %s", cfg.OutputPath),
26-
"go mod tidy",
2729
}
2830

31+
if cfg.Form.MakefileFlag {
32+
if cfg.Form.DatabaseFlag {
33+
commands = appendDatabaseCommands(commands)
34+
}
35+
36+
commands = append(commands, "make")
37+
38+
printCommands(commands)
39+
}
40+
41+
commands = append(commands, "go mod tidy")
42+
2943
// add commands based on selected options
3044
if cfg.Form.ServerTypeFlag == spec.REST {
3145
commands = append(commands, "swag init -g ./cmd/server/main.go # install swag if you haven't already")
3246
}
3347

3448
// if database is selected, add sqlc generate and server run commands
3549
if cfg.Form.DatabaseFlag {
36-
commands = append(commands,
37-
"sqlc generate ./... # install sqlc if you haven't already",
38-
"goose up -dir ./db/migrations postgres \"your_db_connection_string\" # install goose and DB is running",
39-
)
50+
commands = appendDatabaseCommands(commands)
4051
}
4152

42-
if cfg.Form.MakefileFlag {
43-
commands = append(commands, "make")
44-
} else {
45-
commands = append(commands, "go run ./cmd/server/main.go")
46-
}
53+
commands = append(commands, "go run ./cmd/server/main.go")
4754

4855
// if REST server is selected, add command to view API docs
4956
if cfg.Form.ServerTypeFlag == spec.REST {
@@ -52,7 +59,21 @@ func OutputSuccess(cfg *spec.Config) {
5259
)
5360
}
5461

62+
printCommands(commands)
63+
}
64+
65+
func appendDatabaseCommands(commands []string) []string {
66+
return append(commands,
67+
"sqlc generate ./... # install sqlc if you haven't already",
68+
"goose up -dir ./db/migrations postgres \"your_db_connection_string\" # install goose and DB is running",
69+
)
70+
}
71+
72+
func printCommands(commands []string) {
5573
for _, cmd := range commands {
5674
fmt.Println(cmdStyle.Render(cmd))
5775
}
76+
77+
// exit without error
78+
os.Exit(0)
5879
}

0 commit comments

Comments
 (0)