ci: migrate build process to Taskfile

This commit is contained in:
Bhunter 2025-01-14 19:36:59 +01:00
parent 4c5d5035f7
commit 9b25f3f676
9 changed files with 317 additions and 163 deletions

View file

@ -27,6 +27,12 @@ jobs:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Install Task
uses: arduino/setup-task@v2
with:
version: 3.x
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v6

View file

@ -5,8 +5,8 @@ env:
before:
hooks:
- make frontend
- make gen
- task ui
- task gen
builds:
- env:
@ -86,6 +86,8 @@ changelog:
exclude:
- '^README'
- '^Update'
- '^Version'
- '^ci:'
- Merge pull request
- Merge branch

View file

@ -1,24 +0,0 @@
FROM golang:alpine AS builder
RUN apk add --no-cache git unzip curl make bash
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN make build
FROM scratch
WORKDIR /
COPY --from=builder /app/bin/teldrive /teldrive
EXPOSE 8080
ENTRYPOINT ["/teldrive","run","--tg-session-file","/session.db"]

137
Makefile
View file

@ -1,137 +0,0 @@
ifdef ComSpec
SHELL := powershell.exe
IS_WINDOWS := true
else
SHELL := /bin/bash
IS_WINDOWS := false
endif
APP_NAME := teldrive
BUILD_DIR := bin
FRONTEND_DIR := ui/dist
FRONTEND_ASSET := https://github.com/tgdrive/teldrive-ui/releases/download/latest/teldrive-ui.zip
GIT_COMMIT := $(shell git rev-parse --short HEAD)
GIT_LINK := $(shell git remote get-url origin)
MODULE_PATH := $(shell go list -m)
GOOS ?= $(shell go env GOOS)
GOARCH ?= $(shell go env GOARCH)
GIT_COMMIT := $(shell git rev-parse --short HEAD)
VERSION_PACKAGE := $(MODULE_PATH)/internal/version
BINARY_EXTENSION :=
ifeq ($(IS_WINDOWS),true)
TAG_FILTER:=Sort-Object -Descending | Select-Object -First 1
else
TAG_FILTER:=head -n 1
endif
GIT_TAG := $(shell git tag -l '[0-9]*.[0-9]*.[0-9]*' --sort=-v:refname | $(TAG_FILTER))
ifeq ($(IS_WINDOWS),true)
BINARY_EXTENSION := .exe
RM := powershell -Command "Remove-Item"
RMDIR := powershell -Command "Remove-Item -Recurse -Force"
MKDIR := powershell -Command "New-Item -ItemType Directory -Force"
DOWNLOAD := powershell -Command "Invoke-WebRequest -Uri"
UNZIP := powershell -Command "Expand-Archive"
else
RM := rm -f
RMDIR := rm -rf
MKDIR := mkdir -p
DOWNLOAD := curl -sLO
UNZIP := unzip -q -d
endif
.PHONY: all build run clean frontend backend run sync-ui retag patch-version minor-version major-version gen check-semver install-semver
all: build
check-semver:
ifeq ($(IS_WINDOWS),true)
@powershell -Command "if (-not (Get-Command semver -ErrorAction SilentlyContinue)) { Write-Host 'Installing semver...'; npm install -g semver }"
else
@which semver > /dev/null || (echo "Installing semver..." && npm install -g semver)
endif
frontend:
@echo "Extract UI"
$(RMDIR) $(FRONTEND_DIR)
ifeq ($(IS_WINDOWS),true)
$(DOWNLOAD) $(FRONTEND_ASSET) -OutFile teldrive-ui.zip
$(MKDIR) $(subst /,\\,$(FRONTEND_DIR))
$(UNZIP) -Path teldrive-ui.zip -DestinationPath $(FRONTEND_DIR) -Force
$(RM) teldrive-ui.zip
else
$(DOWNLOAD) $(FRONTEND_ASSET)
$(MKDIR) $(FRONTEND_DIR)
$(UNZIP) $(FRONTEND_DIR) teldrive-ui.zip
$(RM) teldrive-ui.zip
endif
gen:
go generate ./...
backend: gen
@echo "Building backend for $(GOOS)/$(GOARCH)..."
go build -trimpath -ldflags "-s -w -X '$(VERSION_PACKAGE).Version=$(GIT_TAG)' -X '$(VERSION_PACKAGE).CommitSHA=$(GIT_COMMIT)' -extldflags=-static" -o $(BUILD_DIR)/$(APP_NAME)$(BINARY_EXTENSION)
build: frontend backend
@echo "Building complete."
run:
@echo "Running $(APP_NAME)..."
$(BUILD_DIR)/$(APP_NAME) run
clean:
@echo "Cleaning up..."
$(RMDIR) $(BUILD_DIR)
ifeq ($(IS_WINDOWS),true)
if exist "$(FRONTEND_DIR)" $(RMDIR) "$(FRONTEND_DIR)"
else
$(RMDIR) $(FRONTEND_DIR)
endif
deps:
@echo "Installing Go dependencies..."
go mod download
retag:
@echo "Retagging $(GIT_TAG)..."
-git tag -d $(GIT_TAG)
-git push --delete origin $(GIT_TAG)
git tag -a $(GIT_TAG) -m "Recreated tag $(GIT_TAG)"
git push origin $(GIT_TAG)
patch-version: check-semver
@echo "Current version: $(GIT_TAG)"
ifeq ($(GIT_TAG),)
$(eval NEW_VERSION := 1.0.0)
else
$(eval NEW_VERSION := $(shell semver -i patch $(GIT_TAG)))
endif
@echo "Creating new patch version: $(NEW_VERSION)"
git tag -a $(NEW_VERSION) -m "Release $(NEW_VERSION)"
git push origin $(NEW_VERSION)
minor-version: check-semver
@echo "Current version: $(GIT_TAG)"
ifeq ($(GIT_TAG),)
$(eval NEW_VERSION := 1.0.0)
else
$(eval NEW_VERSION := $(shell semver -i minor $(GIT_TAG)))
endif
@echo "Creating new minor version: $(NEW_VERSION)"
git tag -a $(NEW_VERSION) -m "Release $(NEW_VERSION)"
git push origin $(NEW_VERSION)
major-version: check-semver
@echo "Current version: $(GIT_TAG)"
ifeq ($(GIT_TAG),)
$(eval NEW_VERSION := 1.0.0)
else
$(eval NEW_VERSION := $(shell semver -i major $(GIT_TAG)))
endif
@echo "Creating new major version: $(NEW_VERSION)"
git tag -a $(NEW_VERSION) -m "Release $(NEW_VERSION)"
git push origin $(NEW_VERSION)

1
go.mod
View file

@ -3,6 +3,7 @@ module github.com/tgdrive/teldrive
go 1.23.3
require (
github.com/Masterminds/semver/v3 v3.3.1
github.com/WinterYukky/gorm-extra-clause-plugin v0.3.0
github.com/coocood/freecache v1.2.4
github.com/go-chi/chi/v5 v5.2.0

2
go.sum
View file

@ -4,6 +4,8 @@ github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7Oputl
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4=
github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/WinterYukky/gorm-extra-clause-plugin v0.3.0 h1:fQfTkxoRso6mlm7eOfBIk94aqamJeqxCEfU+MyLWhgo=
github.com/WinterYukky/gorm-extra-clause-plugin v0.3.0/go.mod h1:GFT8TzxeeGKYXNU/65PsiN2+zNHigm9HjybnbL1T7eg=
github.com/beevik/ntp v1.4.3 h1:PlbTvE5NNy4QHmA4Mg57n7mcFTmr1W1j3gcK7L1lqho=

104
scripts/extract.go Normal file
View file

@ -0,0 +1,104 @@
//go:build ignore
package main
import (
"archive/zip"
"flag"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
)
func main() {
urlFlag := flag.String("url", "", "URL to download from")
outputFlag := flag.String("output", "", "Output directory")
flag.Parse()
if *urlFlag == "" || *outputFlag == "" {
flag.Usage()
os.Exit(1)
}
if err := os.RemoveAll(*outputFlag); err != nil {
fmt.Printf("Error removing directory: %v\n", err)
os.Exit(1)
}
if err := os.MkdirAll(*outputFlag, 0755); err != nil {
fmt.Printf("Error creating directory: %v\n", err)
os.Exit(1)
}
resp, err := http.Get(*urlFlag)
if err != nil {
fmt.Printf("Error downloading: %v\n", err)
os.Exit(1)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
fmt.Printf("Bad status: %s\n", resp.Status)
os.Exit(1)
}
tmpFile, err := os.CreateTemp("", "download-*.zip")
if err != nil {
fmt.Printf("Error creating temp file: %v\n", err)
os.Exit(1)
}
defer os.Remove(tmpFile.Name())
defer tmpFile.Close()
_, err = io.Copy(tmpFile, resp.Body)
if err != nil {
fmt.Printf("Error saving download: %v\n", err)
os.Exit(1)
}
reader, err := zip.OpenReader(tmpFile.Name())
if err != nil {
fmt.Printf("Error opening zip: %v\n", err)
os.Exit(1)
}
defer reader.Close()
for _, file := range reader.File {
path := filepath.Join(*outputFlag, file.Name)
if file.FileInfo().IsDir() {
os.MkdirAll(path, os.ModePerm)
continue
}
if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
fmt.Printf("Error creating directory for file: %v\n", err)
os.Exit(1)
}
dstFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
if err != nil {
fmt.Printf("Error creating file: %v\n", err)
os.Exit(1)
}
srcFile, err := file.Open()
if err != nil {
dstFile.Close()
fmt.Printf("Error opening zip entry: %v\n", err)
os.Exit(1)
}
_, err = io.Copy(dstFile, srcFile)
dstFile.Close()
srcFile.Close()
if err != nil {
fmt.Printf("Error extracting file: %v\n", err)
os.Exit(1)
}
}
fmt.Println("UI Extracted successfully!")
}

90
scripts/release.go Normal file
View file

@ -0,0 +1,90 @@
package main
import (
"errors"
"fmt"
"os"
"os/exec"
"strings"
"github.com/Masterminds/semver/v3"
"github.com/spf13/pflag"
)
var (
versionFile = "VERSION"
versionFlag bool
commitFlag bool
)
func init() {
pflag.BoolVarP(&versionFlag, "version", "v", false, "resolved version number")
pflag.Parse()
}
func main() {
if err := release(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func release() error {
if len(pflag.Args()) != 1 {
return errors.New("error: expected version number")
}
version, err := getVersion()
if err != nil {
return err
}
if err := bumpVersion(version, pflag.Arg(0)); err != nil {
return err
}
if versionFlag {
fmt.Println(version)
return nil
}
if err := writeVersionFile(version); err != nil {
return fmt.Errorf("failed to write version file: %w", err)
}
return nil
}
func getVersion() (*semver.Version, error) {
cmd := exec.Command("git", "tag", "-l", "[0-9]*.[0-9]*.[0-9]*", "--sort=-v:refname")
b, err := cmd.Output()
if err != nil {
return nil, err
}
tags := strings.Split(strings.TrimSpace(string(b)), "\n")
if len(tags) == 0 || tags[0] == "" {
return nil, errors.New("error: no tags found")
}
return semver.NewVersion(tags[0])
}
func bumpVersion(version *semver.Version, verb string) error {
switch verb {
case "major":
*version = version.IncMajor()
case "minor":
*version = version.IncMinor()
case "patch":
*version = version.IncPatch()
case "current":
// do nothing
default:
*version = *semver.MustParse(verb)
}
return nil
}
func writeVersionFile(version *semver.Version) error {
return os.WriteFile(versionFile, []byte(version.String()), 0644)
}

110
taskfile.yml Normal file
View file

@ -0,0 +1,110 @@
version: '3'
vars:
APP_NAME: teldrive
BUILD_DIR: bin
FRONTEND_DIR: ui/dist
FRONTEND_ASSET: https://github.com/tgdrive/teldrive-ui/releases/download/latest/teldrive-ui.zip
GIT_COMMIT:
sh: git rev-parse --short HEAD
MODULE_PATH:
sh: go list -m
GOOS:
sh: go env GOOS
GOARCH:
sh: go env GOARCH
BINARY_EXTENSION: '{{if eq OS "windows"}}.exe{{end}}'
tasks:
default:
cmds:
- task: ui
- task: server
ui:
desc: Download UI assets
cmds:
- go run scripts/extract.go -url {{.FRONTEND_ASSET}} -output {{.FRONTEND_DIR}}
gen:
desc: Generate API code
cmds:
- go generate ./...
server:
desc: Build Server
deps: [gen]
vars:
VERSION:
sh: go run scripts/release.go --version current
cmds:
- echo "Building backend for {{.GOOS}}/{{.GOARCH}}..."
- >
go build -trimpath -ldflags "-s -w
-X '{{.MODULE_PATH}}/internal/version.Version={{.VERSION}}'
-X '{{.MODULE_PATH}}/internal/version.CommitSHA={{.GIT_COMMIT}}'
-extldflags=-static
" -o {{.BUILD_DIR}}/{{.APP_NAME}}{{.BINARY_EXTENSION}}
run:
desc: Run Server
cmds:
- ./{{.BUILD_DIR}}/{{.APP_NAME}}{{.BINARY_EXTENSION}} run
deps:
desc: Install dependencies
cmds:
- go mod download
- go mod tidy
retag:
desc: Retag a version
vars:
VERSION:
sh: go run scripts/release.go --version current
preconditions:
- sh: test $(git rev-parse --abbrev-ref HEAD) = "main"
msg: "You must be on the main branch to retag"
- sh: "[[ -z $(git diff --shortstat main) ]]"
msg: "You must have a clean working tree to retag"
prompt: "This will recreate tag {{.VERSION}}. Are you sure?"
cmds:
- echo "Retagging {{.VERSION}}..."
- cmd: git rev-list -n 1 {{.VERSION}} || true
silent: true
vars:
OLD_COMMIT: out
- git tag -d {{.VERSION}} || true
- git push --delete origin {{.VERSION}} || true
- cmd: |
if [ ! -z "{{.OLD_COMMIT}}" ]; then
if ! git cherry-pick {{.OLD_COMMIT}}; then
git cherry-pick --abort
echo "Failed to cherry-pick version commit"
exit 1
fi
fi
- git tag -a {{.VERSION}} -m "Release {{.VERSION}}"
- git push origin {{.VERSION}}
- git push origin main
release:*:
desc: Prepare for a new release
vars:
VERSION:
sh: "go run scripts/release.go --version {{index .MATCH 0}}"
preconditions:
- sh: test $(git rev-parse --abbrev-ref HEAD) = "main"
msg: "You must be on the main branch to release"
- sh: "[[ -z $(git diff --shortstat main) ]]"
msg: "You must have a clean working tree to release"
prompt: "Are you sure you want to release version {{.VERSION}}?"
cmds:
- cmd: echo "Releasing {{.VERSION}}"
silent: true
- "go run scripts/release.go {{.VERSION}}"
- "git add --all"
- 'git commit -m "Version {{.VERSION}}"'
- "git push"
- "git tag {{.VERSION}}"
- "git push origin tag {{.VERSION}}"