Skip to content

Version API - Endpoint Wersji Managera

Przegląd

Endpoint /api/v2/version w Dagu API udostępnia aktualną wersję managera odczytaną z pliku .release.txt. Umożliwia to zewnętrznym systemom (np. proxy, dashboard) pobieranie informacji o wersji bez konieczności dostępu do systemu plików.


Konfiguracja

1. GitHub Workflow - Automatyczne Tworzenie .release.txt (Production)

W workflow .github/workflows/build-release.yml automatycznie tworzy plik wersji przy każdym release:

yaml
- name: Create version file
  run: |
    echo "${{ github.event.release.tag_name }}" > .release.txt
    echo "Created .release.txt with version: $(cat .release.txt)"

Działanie:

  1. Triggeruje się przy publikacji GitHub release
  2. Tworzy .release.txt z tagiem release (np. v1.2.7)
  3. Kopiuje plik do paczki deployment
  4. Paczka zawiera .release.txt gotowy do użycia na serwerze

Deployment:

bash
# Po rozpakowaniu paczki na serwerze:
tar -xzf code-generations_manager.tar.gz
cat .release.txt  # v1.2.7 (już jest w paczce!)

2. Git Hook - Lokalne Development (Optional)

Do lokalnego testowania możesz zainstalować git hook:

bash
#!/bin/bash
cd "$(git rev-parse --show-toplevel)"
VERSION=$(git describe --tags --always 2>/dev/null || echo "dev")
echo "$VERSION" > .release.txt

Instalacja (opcjonalna):

bash
cat > .git/hooks/post-commit << 'EOF'
#!/bin/bash
cd "$(git rev-parse --show-toplevel)"
VERSION=$(git describe --tags --always 2>/dev/null || echo "dev")
echo "$VERSION" > .release.txt
EOF
chmod +x .git/hooks/post-commit

Kiedy używać:

  • Lokalny development
  • Testowanie Dagu API przed release

UWAGA: Na produkcji używany jest plik z GitHub workflow!

3. Lokalizacja Pliku

Plik .release.txt znajduje się w głównym katalogu managera:

/Users/tkowalski/Projects/code-generations/manager/
├── .release.txt         # <-- tutaj
├── dags/
├── docker/
└── tasks/

Format zawartości:

v1.2.7

Modyfikacja Dagu

1. OpenAPI Spec - Dodanie Endpointu

W pliku api/v2/api.yaml dodano nowy endpoint:

yaml
/version:
  get:
    summary: "Get manager version"
    description: "Returns the current manager version from .release.txt file"
    operationId: "getManagerVersion"
    tags:
      - "system"
    responses:
      "200":
        description: "A successful response"
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/VersionResponse"
      default:
        description: "Unexpected error"

2. Response Schema

W sekcji components/schemas dodano typ odpowiedzi:

yaml
VersionResponse:
  type: object
  description: "Response object for the manager version endpoint"
  properties:
    version:
      type: string
      description: "Current manager version from .release.txt"
  required:
    - version

3. Handler Implementation

Utworzono plik internal/service/frontend/api/v2/version.go:

go
package api

import (
	"context"
	"os"
	"path/filepath"
	"strings"

	"github.com/dagu-org/dagu/api/v2"
)

func (a *API) GetManagerVersion(_ context.Context, _ api.GetManagerVersionRequestObject) (api.GetManagerVersionResponseObject, error) {
	// Read version from .release.txt in the project root (dags directory parent)
	dagsDir := a.config.Paths.DAGsDir
	projectRoot := filepath.Dir(dagsDir)
	versionFile := filepath.Join(projectRoot, ".release.txt")

	data, err := os.ReadFile(versionFile)
	if err != nil {
		// If file doesn't exist or can't be read, return "unknown"
		return &api.GetManagerVersion200JSONResponse{
			Version: "unknown",
		}, nil
	}

	version := strings.TrimSpace(string(data))
	if version == "" {
		version = "unknown"
	}

	return &api.GetManagerVersion200JSONResponse{
		Version: version,
	}, nil
}

Działanie:

  1. Odczytuje ścieżkę do katalogu dags/ z konfiguracji Dagu
  2. Wyznacza katalog główny projektu (parent od dags/)
  3. Czyta .release.txt z głównego katalogu
  4. Zwraca wersję lub "unknown" w przypadku błędu

4. Generowanie API Code

Po modyfikacji OpenAPI spec należy wygenerować kod:

bash
cd /tmp/dagu-custom
make api

To polecenie:

  • Waliduje spec OpenAPI
  • Generuje interfejsy Go (api/v2/api.gen.go)
  • Tworzy typy dla VersionResponse
  • Dodaje route /version do routera chi

5. Build Custom Dagu

Build zmodyfikowanego Dagu:

bash
cd /tmp/dagu-custom
make bin

Binary znajduje się w .local/bin/dagu.

6. Instalacja

Skopiowanie nowego binary do lokalizacji Dagu:

bash
# Backup oryginalnego
cp /Users/tkowalski/.dagu/bin/dagu /Users/tkowalski/.dagu/bin/dagu.backup

# Instalacja nowej wersji
cp /tmp/dagu-custom/.local/bin/dagu /Users/tkowalski/.dagu/bin/dagu
cp /tmp/dagu-custom/.local/bin/dagu /Users/tkowalski/bin/dagu

# Restart Dagu
cd /Users/tkowalski/Projects/code-generations/manager
./manager.sh restart

Użycie API

Podstawowe Query

bash
curl http://127.0.0.1:8080/api/v2/version

Response:

json
{
  "version": "v1.2.7"
}

Z jq Parsing

bash
VERSION=$(curl -s http://127.0.0.1:8080/api/v2/version | jq -r '.version')
echo "Manager version: $VERSION"

Output:

Manager version: v1.2.7

Check Health + Version

bash
# Health check
curl http://127.0.0.1:8080/api/v2/health

# Version check
curl http://127.0.0.1:8080/api/v2/version

Z Timeout

bash
curl --max-time 5 http://127.0.0.1:8080/api/v2/version

Integracja z Proxy

Konfiguracja Proxy

W config.yml proxy używa istniejącego ustawienia:

yaml
codegen_v2:
  dagu_api_url: "http://127.0.0.1:8080"

Service Layer

Plik internal/service/manager_version.go:

go
package service

import (
	"daily-app/internal/config"
	"encoding/json"
	"fmt"
	"net/http"
	"time"
)

type versionResponse struct {
	Version string `json:"version"`
}

func GetManagerVersion() (string, error) {
	cfg := config.Get()
	if cfg == nil || cfg.CodeGenV2.DaguAPIUrl == "" {
		return "unknown", nil
	}

	// Call Dagu API /version endpoint
	url := fmt.Sprintf("%s/api/v2/version", cfg.CodeGenV2.DaguAPIUrl)
	client := &http.Client{Timeout: 5 * time.Second}

	resp, err := client.Get(url)
	if err != nil {
		return "unknown", err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return "unknown", fmt.Errorf("dagu API returned status %d", resp.StatusCode)
	}

	var vr versionResponse
	if err := json.NewDecoder(resp.Body).Decode(&vr); err != nil {
		return "unknown", err
	}

	return vr.Version, nil
}

Handler

W internal/handler/index.go:

go
func HandleIndex(w http.ResponseWriter, r *http.Request) {
	// ... existing code ...

	// Get manager version
	managerVersion, err := service.GetManagerVersion()
	if err != nil {
		log.Printf("Error getting manager version: %v", err)
		managerVersion = "unknown"
	}

	index.Dashboard(announcements, managerVersion).Render(r.Context(), w)
}

Dashboard Template

W internal/render/index/dashboard.templ:

templ
<!-- Manager Version Card -->
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm rounded-lg border border-gray-200 dark:border-gray-700">
	<div class="p-6">
		<div class="flex items-center">
			<div class="flex-shrink-0">
				<svg class="h-8 w-8 text-indigo-600 dark:text-indigo-400" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
					<path stroke-linecap="round" stroke-linejoin="round" d="M9.568 3H5.25A2.25 2.25 0 003 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 005.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 009.568 3z" />
					<path stroke-linecap="round" stroke-linejoin="round" d="M6 6h.008v.008H6V6z" />
				</svg>
			</div>
			<div class="ml-5 w-0 flex-1">
				<dl>
					<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 truncate">Manager Version</dt>
					<dd class="text-lg font-semibold text-gray-900 dark:text-gray-100">{ managerVersion }</dd>
				</dl>
			</div>
		</div>
		<div class="mt-4">
			<p class="text-sm text-gray-600 dark:text-gray-400">Current release version</p>
		</div>
	</div>
</div>

Przepływ Danych

┌──────────────┐
│  Git Commit  │
└──────┬───────┘
       │ post-commit hook

┌──────────────────┐
│ .release.txt     │ ◄─── git describe --tags
│ v1.2.7           │
└──────┬───────────┘


┌──────────────────────────────┐
│ Dagu API                     │
│ GET /api/v2/version          │
│ - Reads .release.txt         │
│ - Returns JSON               │
└──────┬───────────────────────┘
       │ HTTP GET

┌──────────────────────────────┐
│ Proxy                        │
│ - Calls Dagu API             │
│ - Parses JSON response       │
│ - Displays on dashboard      │
└──────────────────────────────┘


┌──────────────────────────────┐
│ User Dashboard               │
│ Box: "Manager Version"       │
│ Value: "v1.2.7"             │
└──────────────────────────────┘

Monitoring

Sprawdzenie Statusu Endpointu

bash
# Check if Dagu is running
curl -s http://127.0.0.1:8080/api/v2/health | jq '.status'

# Check version endpoint
curl -s http://127.0.0.1:8080/api/v2/version | jq '.version'

Logi Dagu

bash
# Server logs
tail -f /Users/tkowalski/.dagu/dagu.log

# Grep for version requests
tail -f /Users/tkowalski/.dagu/dagu.log | grep "/version"

Sprawdzenie Pliku .release.txt

bash
# Show current version
cat /Users/tkowalski/Projects/code-generations/manager/.release.txt

# Watch for changes
watch -n 5 cat /Users/tkowalski/Projects/code-generations/manager/.release.txt

Troubleshooting

Endpoint Zwraca 404

Problem:

bash
curl http://127.0.0.1:8080/api/v2/version
# 404 page not found

Przyczyny:

  1. Dagu nie został zrestartowany po instalacji
  2. Używasz starej wersji Dagu bez custom endpointu

Rozwiązanie:

bash
# Sprawdź wersję Dagu
dagu version
# Powinno być: v1.26.6-YYMMDDHHMMSS

# Restart Dagu
cd /Users/tkowalski/Projects/code-generations/manager
./manager.sh restart

# Test ponownie
curl http://127.0.0.1:8080/api/v2/version

Endpoint Zwraca "unknown"

Problem:

json
{
  "version": "unknown"
}

Przyczyny:

  1. Brak pliku .release.txt
  2. Plik pusty
  3. Nieprawidłowa ścieżka do pliku

Rozwiązanie:

bash
# Sprawdź czy plik istnieje
ls -la /Users/tkowalski/Projects/code-generations/manager/.release.txt

# Jeśli nie istnieje, utwórz manualnie
cd /Users/tkowalski/Projects/code-generations/manager
git describe --tags --always > .release.txt

# Sprawdź zawartość
cat .release.txt

# Test API
curl http://127.0.0.1:8080/api/v2/version

Git Hook Nie Działa

Problem: .release.txt nie aktualizuje się przy commitach

Rozwiązanie:

bash
# Sprawdź czy hook istnieje
ls -la .git/hooks/post-commit

# Jeśli nie istnieje, utwórz
cat > .git/hooks/post-commit << 'EOF'
#!/bin/bash
cd "$(git rev-parse --show-toplevel)"
VERSION=$(git describe --tags --always 2>/dev/null || echo "dev")
echo "$VERSION" > .release.txt
git add .release.txt 2>/dev/null || true
EOF

# Nadaj uprawnienia
chmod +x .git/hooks/post-commit

# Test
git commit --allow-empty -m "Test version update"
cat .release.txt

Proxy Nie Może Połączyć się z Dagu

Problem: Proxy pokazuje "unknown" na dashboardzie

Diagnoza:

bash
# Test z proxy machine
curl http://127.0.0.1:8080/api/v2/version

# Sprawdź logi proxy
grep "manager version" /path/to/proxy/logs

Rozwiązanie:

bash
# Sprawdź config proxy
cat config.yml | grep dagu_api_url

# Sprawdź czy Dagu nasłuchuje na prawidłowym porcie
lsof -i :8080 | grep dagu

# Sprawdź firewall
# (jeśli proxy i manager są na różnych hostach)

Wersjonowanie

Format Wersji

System używa semantic versioning z tagami git:

v1.2.7
└─┼─┼─── Patch version (bug fixes)
  │ └──── Minor version (new features)
  └────── Major version (breaking changes)

Tworzenie Nowej Wersji

bash
# Tag nowej wersji
git tag -a v1.2.8 -m "Release v1.2.8: Add version API endpoint"

# Push taga
git push origin v1.2.8

# Commit (hook automatycznie zaktualizuje .release.txt)
git commit --allow-empty -m "Bump version to v1.2.8"

# Sprawdź
cat .release.txt
# v1.2.8

# Test API
curl http://127.0.0.1:8080/api/v2/version
# {"version":"v1.2.8"}

Historia Wersji

bash
# Lista wszystkich wersji
git tag -l | sort -V

# Ostatnie 5 wersji
git tag -l | sort -V | tail -5

# Różnice między wersjami
git log v1.2.7..v1.2.8 --oneline

Best Practices

1. Zawsze Taguj Releasy

bash
# Po merge do main
git tag -a v1.2.8 -m "Release v1.2.8"
git push origin v1.2.8

2. Utrzymuj .release.txt w Sync

bash
# Jeśli hook nie zadziałał, ręcznie:
git describe --tags --always > .release.txt
git add .release.txt
git commit -m "Update version file"

3. Monitoruj API

bash
# Dodaj healthcheck dla version endpoint
curl -f http://127.0.0.1:8080/api/v2/version || echo "Version API down!"

4. Backup Dagu Binary

bash
# Przed każdą aktualizacją
cp ~/.dagu/bin/dagu ~/.dagu/bin/dagu.backup.$(date +%Y%m%d)

Pliki i Lokalizacje

Manager (Git Repository)

/Users/tkowalski/Projects/code-generations/manager/
├── .release.txt                          # Wersja (lokalna lub z deployment)
├── .git/hooks/post-commit                # Git hook (optional, lokalny)
├── .github/workflows/build-release.yml   # GitHub workflow (production)
├── dags/                                 # Dagu DAG workflows
└── .doc/operations/version-api.md        # Ta dokumentacja

Production Deployment

/path/to/production/manager/
├── .release.txt                          # Z GitHub workflow
├── dags/
├── docker/
├── plugins/
└── workspace/

Dagu (Custom Build)

/tmp/dagu-custom/
├── api/v2/api.yaml                       # OpenAPI spec
├── api/v2/api.gen.go                     # Generated code
├── internal/service/frontend/api/v2/
│   ├── api.go                            # API setup
│   └── version.go                        # Version handler
└── .local/bin/dagu                       # Built binary

Instalacja

/Users/tkowalski/.dagu/bin/dagu          # Dagu binary (aktywny)
/Users/tkowalski/bin/dagu                # Dagu binary (symlink)

Proxy

/Users/tkowalski/Projects/code-generations/enginering-proxy/
├── config.yml                            # Konfiguracja (dagu_api_url)
├── internal/service/manager_version.go   # Service layer
├── internal/handler/index.go             # Handler
└── internal/render/index/dashboard.templ # Template

Zobacz Też