From e6d34c730acaa26a3ddfaa46132f98d05fd401e6 Mon Sep 17 00:00:00 2001 From: Jamie Banks Date: Fri, 12 Jun 2026 14:38:57 +0100 Subject: [PATCH] feat: add application versioning to UI and implement automated release workflow via Gitea Actions --- .gitea/workflows/build.yml | 44 ----------------------- .gitea/workflows/release.yml | 68 ++++++++++++++++++++++++++++++++++++ cmd/goencode/main.go | 6 ++-- internal/web/server.go | 16 +++++++-- web/templates/layout.html | 1 + 5 files changed, 87 insertions(+), 48 deletions(-) delete mode 100644 .gitea/workflows/build.yml create mode 100644 .gitea/workflows/release.yml diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml deleted file mode 100644 index 036cedc..0000000 --- a/.gitea/workflows/build.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Build -on: - push: - branches: [ main ] - workflow_dispatch: - -jobs: - build-and-push: - name: Build and Push Docker Image - runs-on: build-htz-01 - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Build and push Docker image - run: | - docker build -t cr.jdbnet.co.uk/public/goencode:latest . - docker push cr.jdbnet.co.uk/public/goencode:latest - - build-binary: - name: Build and Upload Binary - runs-on: build-htz-01 - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version-file: go.mod - - - name: Build - run: | - go mod tidy - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o goencode ./cmd/goencode - - - name: Upload to Cloudflare R2 - env: - AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }} - AWS_DEFAULT_REGION: auto - R2_ENDPOINT: ${{ secrets.R2_ENDPOINT_URL }} - run: | - aws s3 cp goencode s3://apps/goencode --endpoint-url "$R2_ENDPOINT" \ No newline at end of file diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 0000000..2b03913 --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,68 @@ +name: Release + +on: + pull_request: + branches: + - main + types: [closed] + +jobs: + release: + if: github.event.pull_request.merged == true && startsWith(github.head_ref, 'v') + runs-on: build-htz-01 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Extract Version + id: get_version + run: | + RAW_VERSION=${{ github.head_ref }} + CLEAN_VERSION=${RAW_VERSION#v} + echo "VERSION=${RAW_VERSION}" >> $GITHUB_OUTPUT + echo "CLEAN_VERSION=${CLEAN_VERSION}" >> $GITHUB_OUTPUT + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Build Binary + run: | + go mod tidy + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w -X main.Version=${{ steps.get_version.outputs.VERSION }}" -o goencode ./cmd/goencode + + - name: Build and push Docker image + run: | + docker build -t cr.jdbnet.co.uk/public/goencode:${{ steps.get_version.outputs.CLEAN_VERSION }} . + docker push cr.jdbnet.co.uk/public/goencode:${{ steps.get_version.outputs.CLEAN_VERSION }} + docker tag cr.jdbnet.co.uk/public/goencode:${{ steps.get_version.outputs.CLEAN_VERSION }} cr.jdbnet.co.uk/public/goencode:latest + docker push cr.jdbnet.co.uk/public/goencode:latest + + # - name: Generate Changelog + # id: changelog + # uses: https://github.com/metcalfc/changelog-generator@v4.6.2 + # with: + # myToken: ${{ secrets.GITHUB_TOKEN }} + + - name: Create Gitea Release + uses: https://gitea.com/actions/gitea-release-action@v1 + with: + tag_name: ${{ steps.get_version.outputs.VERSION }} + name: ${{ steps.get_version.outputs.VERSION }} + body: ${{ steps.changelog.outputs.changelog }} + draft: false + prerelease: false + files: | + goencode + + - name: Upload to Cloudflare R2 + env: + AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: auto + R2_ENDPOINT: ${{ secrets.R2_ENDPOINT_URL }} + run: | + aws s3 cp goencode s3://apps/goencode --endpoint-url "$R2_ENDPOINT" diff --git a/cmd/goencode/main.go b/cmd/goencode/main.go index 867859b..8e8997b 100644 --- a/cmd/goencode/main.go +++ b/cmd/goencode/main.go @@ -15,6 +15,8 @@ import ( "goencode/internal/web" ) +var Version string = "dev" + func main() { configPath := flag.String("config", "goencode.yaml", "Path to configuration file") flag.Parse() @@ -44,10 +46,10 @@ func main() { wm.Start() defer wm.Stop() - server := web.NewServer(cfg, qm, wm, sseServer) + server := web.NewServer(cfg, qm, wm, sseServer, Version) go func() { - log.Printf("Starting GoEncode Web UI on %s:%d", cfg.Server.ListenAddr, cfg.Server.Port) + log.Printf("Starting GoEncode Web UI (v%s) on %s:%d", Version, cfg.Server.ListenAddr, cfg.Server.Port) if err := server.Start(); err != nil { log.Fatalf("Server failed: %v", err) } diff --git a/internal/web/server.go b/internal/web/server.go index 230fa5c..d1af357 100644 --- a/internal/web/server.go +++ b/internal/web/server.go @@ -26,9 +26,10 @@ type Server struct { sse *SSEServer mux *http.ServeMux sessionToken string + version string } -func NewServer(cfg *config.Config, qm *queue.Manager, wm *watcher.Manager, sse *SSEServer) *Server { +func NewServer(cfg *config.Config, qm *queue.Manager, wm *watcher.Manager, sse *SSEServer, version string) *Server { b := make([]byte, 32) rand.Read(b) token := hex.EncodeToString(b) @@ -40,6 +41,7 @@ func NewServer(cfg *config.Config, qm *queue.Manager, wm *watcher.Manager, sse * sse: sse, mux: http.NewServeMux(), sessionToken: token, + version: version, } s.routes() return s @@ -246,11 +248,13 @@ func (s *Server) handleDashboard(w http.ResponseWriter, r *http.Request) { FilesEncoded int QueueLength int SavedSpace string + Version string }{ AuthEnabled: s.cfg.Auth.Username != "", FilesEncoded: stats.FilesEncoded, QueueLength: stats.QueueLength, SavedSpace: formatBytes(stats.TotalSavedSpace), + Version: s.version, } tmpl, err := template.New("layout").Funcs(template.FuncMap{ @@ -270,7 +274,13 @@ func (s *Server) handlePage(tmplName string) http.HandlerFunc { http.Error(w, err.Error(), http.StatusInternalServerError) return } - data := struct{ AuthEnabled bool }{AuthEnabled: s.cfg.Auth.Username != ""} + data := struct { + AuthEnabled bool + Version string + }{ + AuthEnabled: s.cfg.Auth.Username != "", + Version: s.version, + } if err := tmpl.ExecuteTemplate(w, "layout", data); err != nil { log.Printf("Template execution error: %v", err) } @@ -334,6 +344,7 @@ func (s *Server) handleHistory(w http.ResponseWriter, r *http.Request) { FilterFolder int Folders []db.WatchFolder Limit int + Version string }{ AuthEnabled: s.cfg.Auth.Username != "", Reports: reports, @@ -348,6 +359,7 @@ func (s *Server) handleHistory(w http.ResponseWriter, r *http.Request) { FilterFolder: folderFilterID, Folders: folders, Limit: limit, + Version: s.version, } tmpl, err := template.New("layout").Funcs(template.FuncMap{ diff --git a/web/templates/layout.html b/web/templates/layout.html index 3f06412..5e2089e 100644 --- a/web/templates/layout.html +++ b/web/templates/layout.html @@ -24,6 +24,7 @@