")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/example.atlas.hcl b/example.atlas.hcl
deleted file mode 100644
index 7e69ee9..0000000
--- a/example.atlas.hcl
+++ /dev/null
@@ -1,10 +0,0 @@
-# The "dev" environment represents our local testings.
-env "local" {
- url = "postgres://user:password@:5432/database?search_path=public&sslmode=disable"
- migration {
- dir = "file://migrations"
- format = golang-migrate
- }
- dev = "docker://postgres/16/dev?search_path=public"
- src = "file://DB/initdb/01_schema.sql"
-}
From b614049d037a74814ec088a63ba5ecfcf8a2daa1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Wed, 13 Aug 2025 15:50:11 +0200
Subject: [PATCH 06/39] added tests for db and user
---
.gitignore | 1 +
Backend/database.go | 30 ++--------
Backend/endpoints/team.go | 2 +-
Backend/endpoints/time.go | 2 +-
Backend/endpoints/user-session.go | 2 +-
Backend/endpoints/user-settings.go | 2 +-
Backend/main.go | 1 -
Backend/models/booking.go | 7 ++-
Backend/models/db_test.go | 38 +++++++++++++
Backend/models/user.go | 6 +-
Backend/models/user_test.go | 56 +++++++++++++++++++
...{03_sample_data.sql => 02_sample_data.sql} | 2 +-
.../{02_create_user.sh => 03_create_user.sh} | 0
Docker/docker-compose.test.yml | 13 +++++
14 files changed, 126 insertions(+), 36 deletions(-)
create mode 100644 Backend/models/db_test.go
create mode 100644 Backend/models/user_test.go
rename DB/initdb/{03_sample_data.sql => 02_sample_data.sql} (82%)
rename DB/initdb/{02_create_user.sh => 03_create_user.sh} (100%)
create mode 100644 Docker/docker-compose.test.yml
diff --git a/.gitignore b/.gitignore
index 11a8757..4e80b98 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,3 +37,4 @@ DB/pg_data
node_modules
atlas.hcl
+.scannerwork
diff --git a/Backend/database.go b/Backend/database.go
index f814974..24b7dd6 100644
--- a/Backend/database.go
+++ b/Backend/database.go
@@ -7,39 +7,17 @@ import (
"fmt"
)
-func OpenDatabase() (*sql.DB, error) {
+func OpenDatabase() (models.IDatabase, error) {
dbHost := helper.GetEnv("POSTGRES_HOST", "localhost")
dbName := helper.GetEnv("POSTGRES_DB", "arbeitszeitmessung")
dbUser := helper.GetEnv("POSTGRES_API_USER", "api_nutzer")
dbPassword := helper.GetEnv("POSTGRES_API_PASS", "password")
connStr := fmt.Sprintf("postgres://%s:%s@%s:5432/%s?sslmode=disable&TimeZone=Europe/Berlin", dbUser, dbPassword, dbHost, dbName)
- return sql.Open("postgres", connStr)
-}
-
-func GetBookingsByCardID(db *sql.DB, card_id string) ([]models.Booking, error) {
- qStr, err := db.Prepare((`SELECT * FROM anwesenheit WHERE card_id = $1`))
+ db, err := sql.Open("postgres", connStr)
if err != nil {
return nil, err
}
- var bookings []models.Booking
- rows, err := qStr.Query(card_id)
- if err == sql.ErrNoRows {
- return bookings, err
- }
- if err != nil {
- return nil, err
- }
- defer rows.Close()
- for rows.Next() {
- var booking models.Booking
- if err := rows.Scan(&booking.CounterId, &booking.Timestamp, &booking.CardUID, &booking.GeraetID, &booking.CheckInOut); err != nil {
- return bookings, err
- }
- bookings = append(bookings, booking)
- }
- if err = rows.Err(); err != nil {
- return bookings, err
- }
- return bookings, nil
+ defer db.Close()
+ return db, err
}
diff --git a/Backend/endpoints/team.go b/Backend/endpoints/team.go
index 3526085..b93585e 100644
--- a/Backend/endpoints/team.go
+++ b/Backend/endpoints/team.go
@@ -33,7 +33,7 @@ func submitReport(w http.ResponseWriter, r *http.Request) {
userPN, _ := strconv.Atoi(r.FormValue("user"))
_weekTs := r.FormValue("week")
weekTs, err := time.Parse(time.DateOnly, _weekTs)
- user, err := (*models.User).GetByPersonalNummer(nil, userPN)
+ user, err := models.GetUserByPersonalNr(userPN)
workWeek := (*models.WorkWeek).GetWeek(nil, user, weekTs, false)
if err != nil {
diff --git a/Backend/endpoints/time.go b/Backend/endpoints/time.go
index eef7537..0172b4c 100644
--- a/Backend/endpoints/time.go
+++ b/Backend/endpoints/time.go
@@ -178,7 +178,7 @@ func getBookingsAPI(w http.ResponseWriter, r *http.Request) {
return
}
- user, err := (*models.User).GetByPersonalNummer(nil, user_pn)
+ user, err := models.GetUserByPersonalNr(user_pn)
if err != nil {
log.Println("No user found with the given personal number!")
http.Error(w, "No user found", http.StatusNotFound)
diff --git a/Backend/endpoints/user-session.go b/Backend/endpoints/user-session.go
index 9b9084c..ffed8b9 100644
--- a/Backend/endpoints/user-session.go
+++ b/Backend/endpoints/user-session.go
@@ -53,7 +53,7 @@ func loginUser(w http.ResponseWriter, r *http.Request) {
return
}
- user, err := (*models.User).GetByPersonalNummer(nil, personal_nummer)
+ user, err := models.GetUserByPersonalNr(personal_nummer)
if err != nil {
log.Println("No user found under this personal number!")
http.Error(w, "No user found!", http.StatusNotFound)
diff --git a/Backend/endpoints/user-settings.go b/Backend/endpoints/user-settings.go
index d8509a0..889267d 100644
--- a/Backend/endpoints/user-settings.go
+++ b/Backend/endpoints/user-settings.go
@@ -21,7 +21,7 @@ func changePassword(w http.ResponseWriter, r *http.Request) {
showUserPage(w, r, http.StatusBadRequest)
return
}
- user, err := (*models.User).GetByPersonalNummer(nil, Session.GetInt(r.Context(), "user"))
+ user, err := models.GetUserByPersonalNr(Session.GetInt(r.Context(), "user"))
if err != nil {
log.Println("Error getting user!", err)
showUserPage(w, r, http.StatusBadRequest)
diff --git a/Backend/main.go b/Backend/main.go
index 3d2aee2..272eb6f 100644
--- a/Backend/main.go
+++ b/Backend/main.go
@@ -35,7 +35,6 @@ func main() {
if err != nil {
log.Fatal(err)
}
- defer models.DB.Close()
fs := http.FileServer(http.Dir("./static"))
endpoints.CreateSessionManager(24 * time.Hour)
diff --git a/Backend/models/booking.go b/Backend/models/booking.go
index 9265808..a739f5b 100644
--- a/Backend/models/booking.go
+++ b/Backend/models/booking.go
@@ -30,7 +30,12 @@ type Booking struct {
CounterId int `json:"counter_id"`
}
-var DB *sql.DB
+type IDatabase interface {
+ Prepare(query string) (*sql.Stmt, error)
+ Exec(query string, args ...any) (sql.Result, error)
+}
+
+var DB IDatabase
func (b *Booking) New(card_uid string, geraet_id int16, check_in_out int16) Booking {
return Booking{
diff --git a/Backend/models/db_test.go b/Backend/models/db_test.go
new file mode 100644
index 0000000..21d25f5
--- /dev/null
+++ b/Backend/models/db_test.go
@@ -0,0 +1,38 @@
+package models_test
+
+import (
+ "arbeitszeitmessung/models"
+ "database/sql"
+ "testing"
+
+ _ "github.com/lib/pq"
+)
+
+type DBFixture struct {
+ Database models.IDatabase
+ TX *sql.Tx
+}
+
+func SetupDBFixture(t *testing.T) *DBFixture {
+ t.Helper()
+
+ db, err := sql.Open("postgres", "postgres://postgres:password@localhost:5433/arbeitszeitmessung?sslmode=disable")
+ if err != nil {
+ t.Fatalf("failed to connect to database: %v", err)
+ }
+
+ tx, err := db.Begin()
+ if err != nil {
+ t.Fatalf("Failed to start transaction: %v", err)
+ }
+
+ t.Cleanup(func() {
+ tx.Rollback()
+ db.Close()
+ })
+
+ return &DBFixture{
+ Database: tx,
+ TX: tx,
+ }
+}
diff --git a/Backend/models/user.go b/Backend/models/user.go
index 2f181a2..5bd9ded 100644
--- a/Backend/models/user.go
+++ b/Backend/models/user.go
@@ -24,13 +24,13 @@ func (u *User) GetUserFromSession(Session *scs.SessionManager, ctx context.Conte
var user User
var err error
if helper.GetEnv("GO_ENV", "production") == "debug" {
- user, err = (*User).GetByPersonalNummer(nil, 123)
+ user, err = GetUserByPersonalNr(123)
} else {
if !Session.Exists(ctx, "user") {
log.Println("No user in session storage!")
return user, errors.New("No user in session storage!")
}
- user, err = (*User).GetByPersonalNummer(nil, Session.GetInt(ctx, "user"))
+ user, err = GetUserByPersonalNr(Session.GetInt(ctx, "user"))
}
if err != nil {
log.Println("Cannot get user from session!")
@@ -95,7 +95,7 @@ func (u *User) CheckOut() error {
return nil
}
-func (u *User) GetByPersonalNummer(personalNummer int) (User, error) {
+func GetUserByPersonalNr(personalNummer int) (User, error) {
var user User
qStr, err := DB.Prepare((`SELECT personal_nummer, card_uid, vorname, nachname, arbeitszeit_per_tag FROM s_personal_daten WHERE personal_nummer = $1;`))
diff --git a/Backend/models/user_test.go b/Backend/models/user_test.go
new file mode 100644
index 0000000..dd9ccf4
--- /dev/null
+++ b/Backend/models/user_test.go
@@ -0,0 +1,56 @@
+package models_test
+
+import (
+ "arbeitszeitmessung/models"
+ "database/sql"
+ "testing"
+)
+
+var testUser models.User = models.User{Vorname: "Kim", Name: "Mustermensch", PersonalNummer: 456, CardUID: "aaaa-aaaa", ArbeitszeitPerTag: 8}
+
+func SetupUserFixture(t *testing.T, db models.IDatabase) {
+ t.Helper()
+ db.Exec(`INSERT INTO "s_personal_daten" ("personal_nummer", "aktiv_beschaeftigt", "vorname", "nachname", "geburtsdatum", "plz", "adresse", "geschlecht", "card_uid", "hauptbeschaeftigungs_ort", "arbeitszeit_per_tag", "arbeitszeit_min_start", "arbeitszeit_max_ende", "vorgesetzter_pers_nr") VALUES
+(456, 't', 'Kim', 'Mustermensch', '2003-02-01', '08963', 'Altenburger Str. 44A', 1, 'aaaa-aaaa', 1, 8, '07:00:00', '20:00:00', 0);`)
+}
+
+func TestGetUserByPersonalNr(t *testing.T) {
+ tc := SetupDBFixture(t)
+ SetupUserFixture(t, tc.Database)
+
+ models.DB = tc.Database
+
+ user, err := models.GetUserByPersonalNr(testUser.PersonalNummer)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if user != testUser {
+ t.Error("Retrieved user not the same as testUser!")
+ }
+
+ _, err = models.GetUserByPersonalNr(000)
+ if err != sql.ErrNoRows {
+ t.Error("Wrong error handling, when retrieving wrong personalnummer")
+ }
+}
+
+func TestCheckAnwesenheit(t *testing.T) {
+ tc := SetupDBFixture(t)
+ models.DB = tc.Database
+ SetupUserFixture(t, tc.Database)
+
+ var actual bool
+
+ if actual = testUser.CheckAnwesenheit(); actual != false {
+ t.Errorf("Checkabwesenheit with no booking should be false but is %t", actual)
+ }
+ tc.Database.Exec("INSERT INTO anwesenheit (timestamp, card_uid, check_in_out, geraet_id) VALUES (NOW() - INTERVAL '2 hour', 'aaaa-aaaa', 1, 1);")
+ if actual = testUser.CheckAnwesenheit(); actual != true {
+ t.Errorf("Checkabwesenheit with 'kommen' booking should be true but is %t", actual)
+ }
+
+ tc.Database.Exec("INSERT INTO anwesenheit (timestamp, card_uid, check_in_out, geraet_id) VALUES (NOW() - INTERVAL '1 hour', 'aaaa-aaaa', 2, 1);")
+ if actual = testUser.CheckAnwesenheit(); actual != false {
+ t.Errorf("Checkabwesenheit with 'gehen' booking should be false but is %t", actual)
+ }
+}
diff --git a/DB/initdb/03_sample_data.sql b/DB/initdb/02_sample_data.sql
similarity index 82%
rename from DB/initdb/03_sample_data.sql
rename to DB/initdb/02_sample_data.sql
index 6d84496..44c2cb6 100644
--- a/DB/initdb/03_sample_data.sql
+++ b/DB/initdb/02_sample_data.sql
@@ -1,5 +1,5 @@
INSERT INTO "s_personal_daten" ("personal_nummer", "aktiv_beschaeftigt", "vorname", "nachname", "geburtsdatum", "plz", "adresse", "geschlecht", "card_uid", "hauptbeschaeftigungs_ort", "arbeitszeit_per_tag", "arbeitszeit_min_start", "arbeitszeit_max_ende", "vorgesetzter_pers_nr") VALUES
-(123, 't', 'Max', 'Mustermann', '2003-02-01', '08963', 'Altenburger Str. 44A', 1, 'acde-edca', 1, 7.5, '07:00:00', '20:00:00', 0);
+(123, 't', 'Kim', 'Mustermensch', '2003-02-01', '08963', 'Altenburger Str. 44A', 1, 'aaaa-aaaa', 1, 8, '07:00:00', '20:00:00', 0);
INSERT INTO "user_password" ("personal_nummer", "pass_hash") VALUES
(123, crypt('max_pass', gen_salt('bf')));
diff --git a/DB/initdb/02_create_user.sh b/DB/initdb/03_create_user.sh
similarity index 100%
rename from DB/initdb/02_create_user.sh
rename to DB/initdb/03_create_user.sh
diff --git a/Docker/docker-compose.test.yml b/Docker/docker-compose.test.yml
new file mode 100644
index 0000000..fbfeb50
--- /dev/null
+++ b/Docker/docker-compose.test.yml
@@ -0,0 +1,13 @@
+name: arbeitszeitmessung-test
+services:
+ db:
+ image: postgres:16
+ restart: unless-stopped
+ env_file:
+ - .env.test
+ environment:
+ PGDATA: /var/lib/postgresql/data/pg_data
+ volumes:
+ - ${POSTGRES_PATH}/initdb:/docker-entrypoint-initdb.d
+ ports:
+ - 5433:5432
From 60c91c1ce688b67ad74c9aa27f2b3ceb37154e89 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Wed, 13 Aug 2025 16:10:24 +0200
Subject: [PATCH 07/39] working on sonarcube-test converage
---
Backend/sonar-project.properties | 8 ++++++++
1 file changed, 8 insertions(+)
create mode 100644 Backend/sonar-project.properties
diff --git a/Backend/sonar-project.properties b/Backend/sonar-project.properties
new file mode 100644
index 0000000..7b20983
--- /dev/null
+++ b/Backend/sonar-project.properties
@@ -0,0 +1,8 @@
+sonar.token=sqp_d5e23f24eb2725b03bb8055771cd8c4b48e788cc
+sonar.projectKey=Arbeitszeitmessung
+sonar.sources=.
+sonar.exclusions=**/*_test.go
+
+sonar.tests=.
+sonar.test.inclusions=**/*_test.go
+sonar.go.coverage.reportPaths=.test/coverage.out
From 33185150cc45f19dee950bc371d60ca46b78159b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Wed, 20 Aug 2025 15:53:59 +0200
Subject: [PATCH 08/39] readied jenkinsfile for build
---
Backend/helper/time_test.go | 1 +
Backend/sonar-project.properties | 2 +-
Jenkinsfile | 4 ++--
Makefile | 16 ++++++++++------
4 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/Backend/helper/time_test.go b/Backend/helper/time_test.go
index d106e7f..9593ab6 100644
--- a/Backend/helper/time_test.go
+++ b/Backend/helper/time_test.go
@@ -25,6 +25,7 @@ func TestFormatDuration(t *testing.T) {
{"30min", time.Duration(30 * time.Minute)},
{"1h 30min", time.Duration(90 * time.Minute)},
{"-1h 30min", time.Duration(-90 * time.Minute)},
+ {"", 0},
}
for _, d := range durations {
t.Run(d.name, func(t *testing.T) {
diff --git a/Backend/sonar-project.properties b/Backend/sonar-project.properties
index 7b20983..d859e77 100644
--- a/Backend/sonar-project.properties
+++ b/Backend/sonar-project.properties
@@ -1,8 +1,8 @@
-sonar.token=sqp_d5e23f24eb2725b03bb8055771cd8c4b48e788cc
sonar.projectKey=Arbeitszeitmessung
sonar.sources=.
sonar.exclusions=**/*_test.go
sonar.tests=.
sonar.test.inclusions=**/*_test.go
+sonar.go.tests.reportPaths=.test/report.json
sonar.go.coverage.reportPaths=.test/coverage.out
diff --git a/Jenkinsfile b/Jenkinsfile
index ee0171f..5e68d30 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -1,7 +1,7 @@
pipeline {
environment {
- DOCKER_USERNAME = 'tom'
- DOCKER_PASSWORD = credentials('dgitea_tom')
+ DOCKER_USERNAME = 'jenkins'
+ DOCKER_PASSWORD = credentials('gitea_jenkins')
}
agent any
diff --git a/Makefile b/Makefile
index 210097e..ccd2917 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,5 @@
DOCKER_USERNAME ?= tom
+PACKAGE_OWNER ?= tom
DOCKER_PASSWORD ?= $(shell echo "YOUR_DEFAULT_PASSWORD")
IMAGE_REGISTRY ?= git.letsstein.de
APPLICATION_NAME ?= arbeitszeit
@@ -16,12 +17,12 @@ ifdef JENKINS_HOME
endif
_builder:
- docker build --tag ${IMAGE_REGISTRY}/${DOCKER_USERNAME}/${APPLICATION_NAME}-${_BUILD_ARGS_APP_PART}:${GIT_COMMIT} -f $(call capitalize, ${_BUILD_ARGS_APP_PART})/Dockerfile $(call capitalize, ${_BUILD_ARGS_APP_PART})
+ docker build --tag ${IMAGE_REGISTRY}/${PACKAGE_OWNER}/${APPLICATION_NAME}-${_BUILD_ARGS_APP_PART}:${GIT_COMMIT} -f $(call capitalize, ${_BUILD_ARGS_APP_PART})/Dockerfile $(call capitalize, ${_BUILD_ARGS_APP_PART})
_pusher: login_registry
- docker push ${IMAGE_REGISTRY}/${DOCKER_USERNAME}/${APPLICATION_NAME}-${_BUILD_ARGS_APP_PART}:${GIT_COMMIT}
- docker tag ${IMAGE_REGISTRY}/${DOCKER_USERNAME}/${APPLICATION_NAME}-${_BUILD_ARGS_APP_PART}:${GIT_COMMIT} ${IMAGE_REGISTRY}/${DOCKER_USERNAME}/${APPLICATION_NAME}-${_BUILD_ARGS_APP_PART}:${_BUILD_ARGS_TAG}
- docker push ${IMAGE_REGISTRY}/${DOCKER_USERNAME}/${APPLICATION_NAME}-${_BUILD_ARGS_APP_PART}:${_BUILD_ARGS_TAG}
+ docker push ${IMAGE_REGISTRY}/${PACKAGE_OWNER}/${APPLICATION_NAME}-${_BUILD_ARGS_APP_PART}:${GIT_COMMIT}
+ docker tag ${IMAGE_REGISTRY}/${PACKAGE_OWNER}/${APPLICATION_NAME}-${_BUILD_ARGS_APP_PART}:${GIT_COMMIT} ${IMAGE_REGISTRY}/${PACKAGE_OWNER}/${APPLICATION_NAME}-${_BUILD_ARGS_APP_PART}:${_BUILD_ARGS_TAG}
+ docker push ${IMAGE_REGISTRY}/${PACKAGE_OWNER}/${APPLICATION_NAME}-${_BUILD_ARGS_APP_PART}:${_BUILD_ARGS_TAG}
build_%:
@@ -43,5 +44,8 @@ generateFrontend:
backend: generateFrontend login_registry
- docker buildx build --platform linux/amd64,linux/arm64 -t git.letsstein.de/tom/arbeitszeit-backend:latest Backend --push
- docker buildx build --platform linux/amd64,linux/arm64 -t git.letsstein.de/tom/arbeitszeit-backend:${GIT_COMMIT} Backend --push
+ docker buildx build --platform linux/amd64,linux/arm64 -t ${IMAGE_REGISTRY}/${PACKAGE_OWNER}/arbeitszeit-backend:latest Backend --push
+ docker buildx build --platform linux/amd64,linux/arm64 -t ${IMAGE_REGISTRY}/${PACKAGE_OWNER}/arbeitszeit-backend:${GIT_COMMIT} Backend --push
+
+scan:
+ $(MAKE) -C Backend scan
From 3475e6d7c95a3dadbecc1b3e041a1bff4ed117af Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Wed, 20 Aug 2025 18:55:47 +0200
Subject: [PATCH 09/39] experimenting with Jenkinsbuild
---
Backend/.dockerignore | 1 +
Backend/Makefile | 6 +
Backend/static/css/styles.css | 104 ++++--
Jenkinsfile | 25 +-
Makefile | 7 +-
package.json | 6 +
pnpm-lock.yaml | 655 ++++++++++++++++++++++++++++++++++
7 files changed, 762 insertions(+), 42 deletions(-)
create mode 100644 Backend/Makefile
create mode 100644 package.json
create mode 100644 pnpm-lock.yaml
diff --git a/Backend/.dockerignore b/Backend/.dockerignore
index 7ab2ceb..c389270 100644
--- a/Backend/.dockerignore
+++ b/Backend/.dockerignore
@@ -1,2 +1,3 @@
db
Dockerfile
+templates/*.go
diff --git a/Backend/Makefile b/Backend/Makefile
new file mode 100644
index 0000000..23da1d0
--- /dev/null
+++ b/Backend/Makefile
@@ -0,0 +1,6 @@
+test:
+ mkdir -p .test
+ go test ./... -coverprofile=.test/coverage.out -json > .test/report.json
+
+scan:
+ sonar-scanner
diff --git a/Backend/static/css/styles.css b/Backend/static/css/styles.css
index f67f5de..e822525 100644
--- a/Backend/static/css/styles.css
+++ b/Backend/static/css/styles.css
@@ -1,4 +1,5 @@
-/*! tailwindcss v4.0.8 | MIT License | https://tailwindcss.com */
+/*! tailwindcss v4.1.12 | MIT License | https://tailwindcss.com */
+@layer properties;
@layer theme, base, components, utilities;
@layer theme {
:root, :host {
@@ -6,18 +7,18 @@
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
"Courier New", monospace;
- --color-red-500: oklch(0.637 0.237 25.331);
- --color-red-600: oklch(0.577 0.245 27.325);
- --color-orange-500: oklch(0.705 0.213 47.604);
- --color-purple-600: oklch(0.558 0.288 302.321);
- --color-neutral-100: oklch(0.97 0 0);
- --color-neutral-200: oklch(0.922 0 0);
- --color-neutral-300: oklch(0.87 0 0);
- --color-neutral-400: oklch(0.708 0 0);
- --color-neutral-500: oklch(0.556 0 0);
- --color-neutral-700: oklch(0.371 0 0);
- --color-neutral-800: oklch(0.269 0 0);
- --color-neutral-900: oklch(0.205 0 0);
+ --color-red-500: oklch(63.7% 0.237 25.331);
+ --color-red-600: oklch(57.7% 0.245 27.325);
+ --color-orange-500: oklch(70.5% 0.213 47.604);
+ --color-purple-600: oklch(55.8% 0.288 302.321);
+ --color-neutral-100: oklch(97% 0 0);
+ --color-neutral-200: oklch(92.2% 0 0);
+ --color-neutral-300: oklch(87% 0 0);
+ --color-neutral-400: oklch(70.8% 0 0);
+ --color-neutral-500: oklch(55.6% 0 0);
+ --color-neutral-700: oklch(37.1% 0 0);
+ --color-neutral-800: oklch(26.9% 0 0);
+ --color-neutral-900: oklch(20.5% 0 0);
--color-black: #000;
--color-white: #fff;
--spacing: 0.25rem;
@@ -30,17 +31,7 @@
--default-transition-duration: 150ms;
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
--default-font-family: var(--font-sans);
- --default-font-feature-settings: var(--font-sans--font-feature-settings);
- --default-font-variation-settings: var(
- --font-sans--font-variation-settings
- );
--default-mono-font-family: var(--font-mono);
- --default-mono-font-feature-settings: var(
- --font-mono--font-feature-settings
- );
- --default-mono-font-variation-settings: var(
- --font-mono--font-variation-settings
- );
--color-accent: #0eaf23;
}
}
@@ -55,14 +46,11 @@
line-height: 1.5;
-webkit-text-size-adjust: 100%;
tab-size: 4;
- font-family: var( --default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" );
+ font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");
font-feature-settings: var(--default-font-feature-settings, normal);
- font-variation-settings: var( --default-font-variation-settings, normal );
+ font-variation-settings: var(--default-font-variation-settings, normal);
-webkit-tap-highlight-color: transparent;
}
- body {
- line-height: inherit;
- }
hr {
height: 0;
color: inherit;
@@ -85,9 +73,9 @@
font-weight: bolder;
}
code, kbd, samp, pre {
- font-family: var( --default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace );
- font-feature-settings: var( --default-mono-font-feature-settings, normal );
- font-variation-settings: var( --default-mono-font-variation-settings, normal );
+ font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);
+ font-feature-settings: var(--default-mono-font-feature-settings, normal);
+ font-variation-settings: var(--default-mono-font-variation-settings, normal);
font-size: 1em;
}
small {
@@ -151,7 +139,14 @@
}
::placeholder {
opacity: 1;
- color: color-mix(in oklab, currentColor 50%, transparent);
+ }
+ @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {
+ ::placeholder {
+ color: currentcolor;
+ @supports (color: color-mix(in lab, red, red)) {
+ color: color-mix(in oklab, currentcolor 50%, transparent);
+ }
+ }
}
textarea {
resize: vertical;
@@ -172,6 +167,9 @@
::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {
padding-block: 0;
}
+ ::-webkit-calendar-picker-indicator {
+ line-height: 1;
+ }
:-moz-ui-invalid {
box-shadow: none;
}
@@ -186,9 +184,6 @@
}
}
@layer utilities {
- .static {
- position: static;
- }
.col-span-2 {
grid-column: span 2 / span 2;
}
@@ -425,7 +420,7 @@
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
}
.transition {
- transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter;
+ transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events;
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
transition-duration: var(--tw-duration, var(--default-transition-duration));
}
@@ -714,7 +709,44 @@
syntax: "*";
inherits: false;
}
+@property --tw-drop-shadow-color {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-drop-shadow-alpha {
+ syntax: "";
+ inherits: false;
+ initial-value: 100%;
+}
+@property --tw-drop-shadow-size {
+ syntax: "*";
+ inherits: false;
+}
@property --tw-duration {
syntax: "*";
inherits: false;
}
+@layer properties {
+ @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
+ *, ::before, ::after, ::backdrop {
+ --tw-divide-x-reverse: 0;
+ --tw-border-style: solid;
+ --tw-divide-y-reverse: 0;
+ --tw-font-weight: initial;
+ --tw-blur: initial;
+ --tw-brightness: initial;
+ --tw-contrast: initial;
+ --tw-grayscale: initial;
+ --tw-hue-rotate: initial;
+ --tw-invert: initial;
+ --tw-opacity: initial;
+ --tw-saturate: initial;
+ --tw-sepia: initial;
+ --tw-drop-shadow: initial;
+ --tw-drop-shadow-color: initial;
+ --tw-drop-shadow-alpha: 100%;
+ --tw-drop-shadow-size: initial;
+ --tw-duration: initial;
+ }
+ }
+}
diff --git a/Jenkinsfile b/Jenkinsfile
index 5e68d30..bfdfc52 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -2,14 +2,32 @@ pipeline {
environment {
DOCKER_USERNAME = 'jenkins'
DOCKER_PASSWORD = credentials('gitea_jenkins')
- }
+ SONAR_TOKEN = credentials('sonarcube_token')
+ }
agent any
stages {
- stage ("Building image arbeitszeit-backend"){
+ stage('Test') {
+ agent {
+ docker {
+ image 'golang:alpine'
+ }
+ }
+ steps {
+ sh 'cd Backend && go mod download && go mod verify'
+ sh 'make test'
+ }
+ }
+ stage('SonarCube Analysis') {
+ steps {
+ sh 'make scan'
+ }
+ }
+ }
+ stage('Building image arbeitszeit-backend') {
when {
- anyOf{
+ anyOf {
changeset 'Jenkinsfile'
changeset 'Makefile'
changeset 'Backend/**'
@@ -18,7 +36,6 @@ pipeline {
steps {
sh 'make backend'
}
-
}
}
}
diff --git a/Makefile b/Makefile
index ccd2917..8ad2736 100644
--- a/Makefile
+++ b/Makefile
@@ -47,5 +47,8 @@ backend: generateFrontend login_registry
docker buildx build --platform linux/amd64,linux/arm64 -t ${IMAGE_REGISTRY}/${PACKAGE_OWNER}/arbeitszeit-backend:latest Backend --push
docker buildx build --platform linux/amd64,linux/arm64 -t ${IMAGE_REGISTRY}/${PACKAGE_OWNER}/arbeitszeit-backend:${GIT_COMMIT} Backend --push
-scan:
- $(MAKE) -C Backend scan
+test:
+ $(MAKE) -C Backend test
+
+scan: test
+ $(MAKE) -C Backend scan
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..dc47876
--- /dev/null
+++ b/package.json
@@ -0,0 +1,6 @@
+{
+ "dependencies": {
+ "tailwindcss": "^4.1.12",
+ "@tailwindcss/cli": "^4.1.12"
+ }
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
new file mode 100644
index 0000000..18cb121
--- /dev/null
+++ b/pnpm-lock.yaml
@@ -0,0 +1,655 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ dependencies:
+ '@tailwindcss/cli':
+ specifier: ^4.1.12
+ version: 4.1.12
+ tailwindcss:
+ specifier: ^4.1.12
+ version: 4.1.12
+
+packages:
+
+ '@isaacs/fs-minipass@4.0.1':
+ resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==}
+ engines: {node: '>=18.0.0'}
+
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+ '@jridgewell/remapping@2.3.5':
+ resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.5':
+ resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
+
+ '@jridgewell/trace-mapping@0.3.30':
+ resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==}
+
+ '@parcel/watcher-android-arm64@2.5.1':
+ resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [android]
+
+ '@parcel/watcher-darwin-arm64@2.5.1':
+ resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@parcel/watcher-darwin-x64@2.5.1':
+ resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@parcel/watcher-freebsd-x64@2.5.1':
+ resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@parcel/watcher-linux-arm-glibc@2.5.1':
+ resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ '@parcel/watcher-linux-arm-musl@2.5.1':
+ resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ '@parcel/watcher-linux-arm64-glibc@2.5.1':
+ resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@parcel/watcher-linux-arm64-musl@2.5.1':
+ resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@parcel/watcher-linux-x64-glibc@2.5.1':
+ resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ '@parcel/watcher-linux-x64-musl@2.5.1':
+ resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ '@parcel/watcher-win32-arm64@2.5.1':
+ resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@parcel/watcher-win32-ia32@2.5.1':
+ resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@parcel/watcher-win32-x64@2.5.1':
+ resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ '@parcel/watcher@2.5.1':
+ resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==}
+ engines: {node: '>= 10.0.0'}
+
+ '@tailwindcss/cli@4.1.12':
+ resolution: {integrity: sha512-2PyJ5MGh/6JPS+cEaAq6MGDx3UemkX/mJt+/phm7/VOpycpecwNnHuFZbbgx6TNK/aIjvFOhhTVlappM7tmqvQ==}
+ hasBin: true
+
+ '@tailwindcss/node@4.1.12':
+ resolution: {integrity: sha512-3hm9brwvQkZFe++SBt+oLjo4OLDtkvlE8q2WalaD/7QWaeM7KEJbAiY/LJZUaCs7Xa8aUu4xy3uoyX4q54UVdQ==}
+
+ '@tailwindcss/oxide-android-arm64@4.1.12':
+ resolution: {integrity: sha512-oNY5pq+1gc4T6QVTsZKwZaGpBb2N1H1fsc1GD4o7yinFySqIuRZ2E4NvGasWc6PhYJwGK2+5YT1f9Tp80zUQZQ==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [android]
+
+ '@tailwindcss/oxide-darwin-arm64@4.1.12':
+ resolution: {integrity: sha512-cq1qmq2HEtDV9HvZlTtrj671mCdGB93bVY6J29mwCyaMYCP/JaUBXxrQQQm7Qn33AXXASPUb2HFZlWiiHWFytw==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@tailwindcss/oxide-darwin-x64@4.1.12':
+ resolution: {integrity: sha512-6UCsIeFUcBfpangqlXay9Ffty9XhFH1QuUFn0WV83W8lGdX8cD5/+2ONLluALJD5+yJ7k8mVtwy3zMZmzEfbLg==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@tailwindcss/oxide-freebsd-x64@4.1.12':
+ resolution: {integrity: sha512-JOH/f7j6+nYXIrHobRYCtoArJdMJh5zy5lr0FV0Qu47MID/vqJAY3r/OElPzx1C/wdT1uS7cPq+xdYYelny1ww==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.12':
+ resolution: {integrity: sha512-v4Ghvi9AU1SYgGr3/j38PD8PEe6bRfTnNSUE3YCMIRrrNigCFtHZ2TCm8142X8fcSqHBZBceDx+JlFJEfNg5zQ==}
+ engines: {node: '>= 10'}
+ cpu: [arm]
+ os: [linux]
+
+ '@tailwindcss/oxide-linux-arm64-gnu@4.1.12':
+ resolution: {integrity: sha512-YP5s1LmetL9UsvVAKusHSyPlzSRqYyRB0f+Kl/xcYQSPLEw/BvGfxzbH+ihUciePDjiXwHh+p+qbSP3SlJw+6g==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@tailwindcss/oxide-linux-arm64-musl@4.1.12':
+ resolution: {integrity: sha512-V8pAM3s8gsrXcCv6kCHSuwyb/gPsd863iT+v1PGXC4fSL/OJqsKhfK//v8P+w9ThKIoqNbEnsZqNy+WDnwQqCA==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@tailwindcss/oxide-linux-x64-gnu@4.1.12':
+ resolution: {integrity: sha512-xYfqYLjvm2UQ3TZggTGrwxjYaLB62b1Wiysw/YE3Yqbh86sOMoTn0feF98PonP7LtjsWOWcXEbGqDL7zv0uW8Q==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+
+ '@tailwindcss/oxide-linux-x64-musl@4.1.12':
+ resolution: {integrity: sha512-ha0pHPamN+fWZY7GCzz5rKunlv9L5R8kdh+YNvP5awe3LtuXb5nRi/H27GeL2U+TdhDOptU7T6Is7mdwh5Ar3A==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+
+ '@tailwindcss/oxide-wasm32-wasi@4.1.12':
+ resolution: {integrity: sha512-4tSyu3dW+ktzdEpuk6g49KdEangu3eCYoqPhWNsZgUhyegEda3M9rG0/j1GV/JjVVsj+lG7jWAyrTlLzd/WEBg==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+ bundledDependencies:
+ - '@napi-rs/wasm-runtime'
+ - '@emnapi/core'
+ - '@emnapi/runtime'
+ - '@tybys/wasm-util'
+ - '@emnapi/wasi-threads'
+ - tslib
+
+ '@tailwindcss/oxide-win32-arm64-msvc@4.1.12':
+ resolution: {integrity: sha512-iGLyD/cVP724+FGtMWslhcFyg4xyYyM+5F4hGvKA7eifPkXHRAUDFaimu53fpNg9X8dfP75pXx/zFt/jlNF+lg==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@tailwindcss/oxide-win32-x64-msvc@4.1.12':
+ resolution: {integrity: sha512-NKIh5rzw6CpEodv/++r0hGLlfgT/gFN+5WNdZtvh6wpU2BpGNgdjvj6H2oFc8nCM839QM1YOhjpgbAONUb4IxA==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [win32]
+
+ '@tailwindcss/oxide@4.1.12':
+ resolution: {integrity: sha512-gM5EoKHW/ukmlEtphNwaGx45fGoEmP10v51t9unv55voWh6WrOL19hfuIdo2FjxIaZzw776/BUQg7Pck++cIVw==}
+ engines: {node: '>= 10'}
+
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
+ chownr@3.0.0:
+ resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
+ engines: {node: '>=18'}
+
+ detect-libc@1.0.3:
+ resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
+ engines: {node: '>=0.10'}
+ hasBin: true
+
+ detect-libc@2.0.4:
+ resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==}
+ engines: {node: '>=8'}
+
+ enhanced-resolve@5.18.3:
+ resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==}
+ engines: {node: '>=10.13.0'}
+
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
+ graceful-fs@4.2.11:
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
+ is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
+ is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ jiti@2.5.1:
+ resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==}
+ hasBin: true
+
+ lightningcss-darwin-arm64@1.30.1:
+ resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ lightningcss-darwin-x64@1.30.1:
+ resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ lightningcss-freebsd-x64@1.30.1:
+ resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ lightningcss-linux-arm-gnueabihf@1.30.1:
+ resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ lightningcss-linux-arm64-gnu@1.30.1:
+ resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ lightningcss-linux-arm64-musl@1.30.1:
+ resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ lightningcss-linux-x64-gnu@1.30.1:
+ resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ lightningcss-linux-x64-musl@1.30.1:
+ resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ lightningcss-win32-arm64-msvc@1.30.1:
+ resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ lightningcss-win32-x64-msvc@1.30.1:
+ resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ lightningcss@1.30.1:
+ resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==}
+ engines: {node: '>= 12.0.0'}
+
+ magic-string@0.30.17:
+ resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
+
+ micromatch@4.0.8:
+ resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+ engines: {node: '>=8.6'}
+
+ minipass@7.1.2:
+ resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
+ minizlib@3.0.2:
+ resolution: {integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==}
+ engines: {node: '>= 18'}
+
+ mkdirp@3.0.1:
+ resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ mri@1.2.0:
+ resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
+ engines: {node: '>=4'}
+
+ node-addon-api@7.1.1:
+ resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ tailwindcss@4.1.12:
+ resolution: {integrity: sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==}
+
+ tapable@2.2.2:
+ resolution: {integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==}
+ engines: {node: '>=6'}
+
+ tar@7.4.3:
+ resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==}
+ engines: {node: '>=18'}
+
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
+ yallist@5.0.0:
+ resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
+ engines: {node: '>=18'}
+
+snapshots:
+
+ '@isaacs/fs-minipass@4.0.1':
+ dependencies:
+ minipass: 7.1.2
+
+ '@jridgewell/gen-mapping@0.3.13':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@jridgewell/trace-mapping': 0.3.30
+
+ '@jridgewell/remapping@2.3.5':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.30
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/sourcemap-codec@1.5.5': {}
+
+ '@jridgewell/trace-mapping@0.3.30':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ '@parcel/watcher-android-arm64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-darwin-arm64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-darwin-x64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-freebsd-x64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm-glibc@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm-musl@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm64-glibc@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm64-musl@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-x64-glibc@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-x64-musl@2.5.1':
+ optional: true
+
+ '@parcel/watcher-win32-arm64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-win32-ia32@2.5.1':
+ optional: true
+
+ '@parcel/watcher-win32-x64@2.5.1':
+ optional: true
+
+ '@parcel/watcher@2.5.1':
+ dependencies:
+ detect-libc: 1.0.3
+ is-glob: 4.0.3
+ micromatch: 4.0.8
+ node-addon-api: 7.1.1
+ optionalDependencies:
+ '@parcel/watcher-android-arm64': 2.5.1
+ '@parcel/watcher-darwin-arm64': 2.5.1
+ '@parcel/watcher-darwin-x64': 2.5.1
+ '@parcel/watcher-freebsd-x64': 2.5.1
+ '@parcel/watcher-linux-arm-glibc': 2.5.1
+ '@parcel/watcher-linux-arm-musl': 2.5.1
+ '@parcel/watcher-linux-arm64-glibc': 2.5.1
+ '@parcel/watcher-linux-arm64-musl': 2.5.1
+ '@parcel/watcher-linux-x64-glibc': 2.5.1
+ '@parcel/watcher-linux-x64-musl': 2.5.1
+ '@parcel/watcher-win32-arm64': 2.5.1
+ '@parcel/watcher-win32-ia32': 2.5.1
+ '@parcel/watcher-win32-x64': 2.5.1
+
+ '@tailwindcss/cli@4.1.12':
+ dependencies:
+ '@parcel/watcher': 2.5.1
+ '@tailwindcss/node': 4.1.12
+ '@tailwindcss/oxide': 4.1.12
+ enhanced-resolve: 5.18.3
+ mri: 1.2.0
+ picocolors: 1.1.1
+ tailwindcss: 4.1.12
+
+ '@tailwindcss/node@4.1.12':
+ dependencies:
+ '@jridgewell/remapping': 2.3.5
+ enhanced-resolve: 5.18.3
+ jiti: 2.5.1
+ lightningcss: 1.30.1
+ magic-string: 0.30.17
+ source-map-js: 1.2.1
+ tailwindcss: 4.1.12
+
+ '@tailwindcss/oxide-android-arm64@4.1.12':
+ optional: true
+
+ '@tailwindcss/oxide-darwin-arm64@4.1.12':
+ optional: true
+
+ '@tailwindcss/oxide-darwin-x64@4.1.12':
+ optional: true
+
+ '@tailwindcss/oxide-freebsd-x64@4.1.12':
+ optional: true
+
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.12':
+ optional: true
+
+ '@tailwindcss/oxide-linux-arm64-gnu@4.1.12':
+ optional: true
+
+ '@tailwindcss/oxide-linux-arm64-musl@4.1.12':
+ optional: true
+
+ '@tailwindcss/oxide-linux-x64-gnu@4.1.12':
+ optional: true
+
+ '@tailwindcss/oxide-linux-x64-musl@4.1.12':
+ optional: true
+
+ '@tailwindcss/oxide-wasm32-wasi@4.1.12':
+ optional: true
+
+ '@tailwindcss/oxide-win32-arm64-msvc@4.1.12':
+ optional: true
+
+ '@tailwindcss/oxide-win32-x64-msvc@4.1.12':
+ optional: true
+
+ '@tailwindcss/oxide@4.1.12':
+ dependencies:
+ detect-libc: 2.0.4
+ tar: 7.4.3
+ optionalDependencies:
+ '@tailwindcss/oxide-android-arm64': 4.1.12
+ '@tailwindcss/oxide-darwin-arm64': 4.1.12
+ '@tailwindcss/oxide-darwin-x64': 4.1.12
+ '@tailwindcss/oxide-freebsd-x64': 4.1.12
+ '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.12
+ '@tailwindcss/oxide-linux-arm64-gnu': 4.1.12
+ '@tailwindcss/oxide-linux-arm64-musl': 4.1.12
+ '@tailwindcss/oxide-linux-x64-gnu': 4.1.12
+ '@tailwindcss/oxide-linux-x64-musl': 4.1.12
+ '@tailwindcss/oxide-wasm32-wasi': 4.1.12
+ '@tailwindcss/oxide-win32-arm64-msvc': 4.1.12
+ '@tailwindcss/oxide-win32-x64-msvc': 4.1.12
+
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
+ chownr@3.0.0: {}
+
+ detect-libc@1.0.3: {}
+
+ detect-libc@2.0.4: {}
+
+ enhanced-resolve@5.18.3:
+ dependencies:
+ graceful-fs: 4.2.11
+ tapable: 2.2.2
+
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
+ graceful-fs@4.2.11: {}
+
+ is-extglob@2.1.1: {}
+
+ is-glob@4.0.3:
+ dependencies:
+ is-extglob: 2.1.1
+
+ is-number@7.0.0: {}
+
+ jiti@2.5.1: {}
+
+ lightningcss-darwin-arm64@1.30.1:
+ optional: true
+
+ lightningcss-darwin-x64@1.30.1:
+ optional: true
+
+ lightningcss-freebsd-x64@1.30.1:
+ optional: true
+
+ lightningcss-linux-arm-gnueabihf@1.30.1:
+ optional: true
+
+ lightningcss-linux-arm64-gnu@1.30.1:
+ optional: true
+
+ lightningcss-linux-arm64-musl@1.30.1:
+ optional: true
+
+ lightningcss-linux-x64-gnu@1.30.1:
+ optional: true
+
+ lightningcss-linux-x64-musl@1.30.1:
+ optional: true
+
+ lightningcss-win32-arm64-msvc@1.30.1:
+ optional: true
+
+ lightningcss-win32-x64-msvc@1.30.1:
+ optional: true
+
+ lightningcss@1.30.1:
+ dependencies:
+ detect-libc: 2.0.4
+ optionalDependencies:
+ lightningcss-darwin-arm64: 1.30.1
+ lightningcss-darwin-x64: 1.30.1
+ lightningcss-freebsd-x64: 1.30.1
+ lightningcss-linux-arm-gnueabihf: 1.30.1
+ lightningcss-linux-arm64-gnu: 1.30.1
+ lightningcss-linux-arm64-musl: 1.30.1
+ lightningcss-linux-x64-gnu: 1.30.1
+ lightningcss-linux-x64-musl: 1.30.1
+ lightningcss-win32-arm64-msvc: 1.30.1
+ lightningcss-win32-x64-msvc: 1.30.1
+
+ magic-string@0.30.17:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ micromatch@4.0.8:
+ dependencies:
+ braces: 3.0.3
+ picomatch: 2.3.1
+
+ minipass@7.1.2: {}
+
+ minizlib@3.0.2:
+ dependencies:
+ minipass: 7.1.2
+
+ mkdirp@3.0.1: {}
+
+ mri@1.2.0: {}
+
+ node-addon-api@7.1.1: {}
+
+ picocolors@1.1.1: {}
+
+ picomatch@2.3.1: {}
+
+ source-map-js@1.2.1: {}
+
+ tailwindcss@4.1.12: {}
+
+ tapable@2.2.2: {}
+
+ tar@7.4.3:
+ dependencies:
+ '@isaacs/fs-minipass': 4.0.1
+ chownr: 3.0.0
+ minipass: 7.1.2
+ minizlib: 3.0.2
+ mkdirp: 3.0.1
+ yallist: 5.0.0
+
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+
+ yallist@5.0.0: {}
From 690a2e48f57fa58da6248b55e9c283508e8b6a6e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Wed, 20 Aug 2025 18:57:05 +0200
Subject: [PATCH 10/39] fixed Jenkins Syntax
---
Jenkinsfile | 1 -
1 file changed, 1 deletion(-)
diff --git a/Jenkinsfile b/Jenkinsfile
index bfdfc52..868f7ec 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -24,7 +24,6 @@ pipeline {
sh 'make scan'
}
}
- }
stage('Building image arbeitszeit-backend') {
when {
anyOf {
From d4330fa193a88160427e92a8b525559e9910b53c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 07:11:12 +0200
Subject: [PATCH 11/39] testing gitea actions
---
.gitea/workflows/demo.yaml | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
create mode 100644 .gitea/workflows/demo.yaml
diff --git a/.gitea/workflows/demo.yaml b/.gitea/workflows/demo.yaml
new file mode 100644
index 0000000..c537cc6
--- /dev/null
+++ b/.gitea/workflows/demo.yaml
@@ -0,0 +1,19 @@
+name: Gitea Actions Demo
+run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀
+on: [push]
+
+jobs:
+ Explore-Gitea-Actions:
+ runs-on: ubuntu-latest
+ steps:
+ - run: echo "🎉 The job was automatically triggered by a ${{ gitea.event_name }} event."
+ - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!"
+ - run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
+ - name: Check out repository code
+ uses: actions/checkout@v4
+ - run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
+ - run: echo "🖥️ The workflow is now ready to test your code on the runner."
+ - name: List files in the repository
+ run: |
+ ls ${{ gitea.workspace }}
+ - run: echo "🍏 This job's status is ${{ job.status }}."
From 17cb3b327c842125a43220273e4bf6ac28db4fb6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 07:14:54 +0200
Subject: [PATCH 12/39] Create testing.yaml
---
.gitea/workflows/testing.yaml | 10 ++++++++++
1 file changed, 10 insertions(+)
create mode 100644 .gitea/workflows/testing.yaml
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
new file mode 100644
index 0000000..43fc95c
--- /dev/null
+++ b/.gitea/workflows/testing.yaml
@@ -0,0 +1,10 @@
+name: GoLang Tests
+run-name: ${{ gitea.actor }} is testing golang Code
+on: [push]
+
+jobs:
+ Run-Go-Test:
+ runs-on: golang-alpine
+ steps:
+ - run: go version
+ - run: go test ./...
From 61635dff6df0b599716774525cbb9f8a40472d81 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 07:21:45 +0200
Subject: [PATCH 13/39] Update testing.yaml
---
.gitea/workflows/testing.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index 43fc95c..1a22a7f 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -4,7 +4,7 @@ on: [push]
jobs:
Run-Go-Test:
- runs-on: golang-alpine
+ runs-on: ubuntu-latest:docker://golang:alpine
steps:
- run: go version
- run: go test ./...
From 8fa5eafd80aa39f7b83f55bbd2d0e5275687c99a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 07:46:22 +0200
Subject: [PATCH 14/39] Update testing.yaml
---
.gitea/workflows/testing.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index 1a22a7f..56ee08c 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -4,7 +4,7 @@ on: [push]
jobs:
Run-Go-Test:
- runs-on: ubuntu-latest:docker://golang:alpine
+ runs-on: golang
steps:
- run: go version
- run: go test ./...
From 8f8f67398b144b6f8f6381058af08261e14b221e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 07:59:41 +0200
Subject: [PATCH 15/39] Update testing.yaml
---
.gitea/workflows/testing.yaml | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index 56ee08c..6a318b3 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -3,8 +3,25 @@ run-name: ${{ gitea.actor }} is testing golang Code
on: [push]
jobs:
- Run-Go-Test:
- runs-on: golang
+ test:
+ runs-on: docker
+ container:
+ image: golang:1.22
steps:
- - run: go version
- - run: go test ./...
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Set up Go cache
+ uses: actions/cache@v3
+ with:
+ path: |
+ ~/go/pkg/mod
+ ~/.cache/go-build
+ key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
+ restore-keys: |
+ ${{ runner.os }}-go-
+
+ - name: Run tests
+ run: |
+ go mod tidy
+ go test ./... -v
From c813ba62d4fc52c00defb42e2d30cfcf0b8d3f1c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 08:01:17 +0200
Subject: [PATCH 16/39] Update testing.yaml
---
.gitea/workflows/testing.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index 6a318b3..4db6fa5 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -22,6 +22,7 @@ jobs:
${{ runner.os }}-go-
- name: Run tests
+ shell: sh
run: |
go mod tidy
go test ./... -v
From e94942181d0acfa2588f4e21bad59a2d35f0cea5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 08:05:40 +0200
Subject: [PATCH 17/39] Update testing.yaml
---
.gitea/workflows/testing.yaml | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index 4db6fa5..386f633 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -8,21 +8,15 @@ jobs:
container:
image: golang:1.22
steps:
- - name: Checkout code
- uses: actions/checkout@v4
+ - name: Checkout repository
+ uses: https://gitea.com/actions/checkout@v4
- - name: Set up Go cache
- uses: actions/cache@v3
- with:
- path: |
- ~/go/pkg/mod
- ~/.cache/go-build
- key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
- restore-keys: |
- ${{ runner.os }}-go-
+ - name: Go dependencies
+ shell: sh
+ run: |
+ go mod tidy
- name: Run tests
shell: sh
run: |
- go mod tidy
go test ./... -v
From a521377f7fcab4738d98a681a8a4816dbb260980 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 08:12:40 +0200
Subject: [PATCH 18/39] Update testing.yaml
---
.gitea/workflows/testing.yaml | 43 +++++++++++++++++++++++------------
1 file changed, 28 insertions(+), 15 deletions(-)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index 386f633..c077009 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -3,20 +3,33 @@ run-name: ${{ gitea.actor }} is testing golang Code
on: [push]
jobs:
- test:
- runs-on: docker
- container:
- image: golang:1.22
+ testing:
+ name: check and test
+ runs-on: ubuntu-latest
steps:
- - name: Checkout repository
- uses: https://gitea.com/actions/checkout@v4
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0 # all history for all branches and tags
- - name: Go dependencies
- shell: sh
- run: |
- go mod tidy
-
- - name: Run tests
- shell: sh
- run: |
- go test ./... -v
+ - name: Setup go
+ uses: actions/setup-go@v5
+ with:
+ go-version-file: Backend/go.mod
+ check-latest: true
+ - uses: https://gitea.com/actions/go-hashfiles@v0.0.1
+ id: hash-go
+ with:
+ patterns: |
+ go.mod
+ go.sum
+ - name: cache go
+ id: cache-go
+ uses: actions/cache@v4
+ with:
+ path: |
+ /go_path
+ /go_cache
+ key: go_path-${{ steps.hash-go.outputs.hash }}
+ - name: test
+ run: make test
From dd8df1059e050dff6652a2f5502d8030d6f7a640 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 08:38:57 +0200
Subject: [PATCH 19/39] added db
---
.gitea/workflows/demo.yaml | 19 -------------------
.gitea/workflows/testing.yaml | 11 +++++++++++
2 files changed, 11 insertions(+), 19 deletions(-)
delete mode 100644 .gitea/workflows/demo.yaml
diff --git a/.gitea/workflows/demo.yaml b/.gitea/workflows/demo.yaml
deleted file mode 100644
index c537cc6..0000000
--- a/.gitea/workflows/demo.yaml
+++ /dev/null
@@ -1,19 +0,0 @@
-name: Gitea Actions Demo
-run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀
-on: [push]
-
-jobs:
- Explore-Gitea-Actions:
- runs-on: ubuntu-latest
- steps:
- - run: echo "🎉 The job was automatically triggered by a ${{ gitea.event_name }} event."
- - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!"
- - run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
- - name: Check out repository code
- uses: actions/checkout@v4
- - run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
- - run: echo "🖥️ The workflow is now ready to test your code on the runner."
- - name: List files in the repository
- run: |
- ls ${{ gitea.workspace }}
- - run: echo "🍏 This job's status is ${{ job.status }}."
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index c077009..6b3e195 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -6,6 +6,10 @@ jobs:
testing:
name: check and test
runs-on: ubuntu-latest
+ env:
+ POSTGRES_USER: root
+ POSTGRES_PASSWORD: password
+ POSTGRES_DB: arbeitszeitmessung
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -31,5 +35,12 @@ jobs:
/go_path
/go_cache
key: go_path-${{ steps.hash-go.outputs.hash }}
+ - name: Setup DB
+ uses: harmon758/postgresql-action@v1
+ with:
+ postgresql version: "16"
+ postgresql user: $POSTGRES_USER
+ postgresql password: $POSTGRES_PASSWORD
+ postgresql db: $POSTGRES_DB
- name: test
run: make test
From cbdd82b72542765f4c9fc19891c009e8298d3aa7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 08:46:20 +0200
Subject: [PATCH 20/39] Update testing.yaml
---
.gitea/workflows/testing.yaml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index 6b3e195..d38d99b 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -39,8 +39,8 @@ jobs:
uses: harmon758/postgresql-action@v1
with:
postgresql version: "16"
- postgresql user: $POSTGRES_USER
- postgresql password: $POSTGRES_PASSWORD
- postgresql db: $POSTGRES_DB
+ postgresql user: ${{ env.POSTGRES_USER }}
+ postgresql password: ${{ env.POSTGRES_PASSWORD }}
+ postgresql db: ${{ env.POSTGRES_DB }}
- name: test
run: make test
From 5c243e45e118cb7e6cb97b8737d3b40618fbdea8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 15:00:25 +0200
Subject: [PATCH 21/39] added Migrate Function for tests
---
.gitea/workflows/testing.yaml | 1 +
Backend/go.mod | 11 ++++++++++-
Backend/go.sum | 20 ++++++++++++++++++++
Backend/models/db_test.go | 33 ++++++++++++++++++++++++++++++++-
4 files changed, 63 insertions(+), 2 deletions(-)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index d38d99b..d142795 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -10,6 +10,7 @@ jobs:
POSTGRES_USER: root
POSTGRES_PASSWORD: password
POSTGRES_DB: arbeitszeitmessung
+ POSTGRES_PORT: 5432
steps:
- name: Checkout
uses: actions/checkout@v4
diff --git a/Backend/go.mod b/Backend/go.mod
index f680c35..53b8b2a 100644
--- a/Backend/go.mod
+++ b/Backend/go.mod
@@ -10,4 +10,13 @@ require github.com/a-h/templ v0.3.924
require github.com/alexedwards/scs/v2 v2.8.0
-require github.com/joho/godotenv v1.5.1
+require (
+ github.com/golang-migrate/migrate/v4 v4.18.3
+ github.com/joho/godotenv v1.5.1
+)
+
+require (
+ github.com/hashicorp/errwrap v1.1.0 // indirect
+ github.com/hashicorp/go-multierror v1.1.1 // indirect
+ go.uber.org/atomic v1.7.0 // indirect
+)
diff --git a/Backend/go.sum b/Backend/go.sum
index 58f050d..4d25b7c 100644
--- a/Backend/go.sum
+++ b/Backend/go.sum
@@ -2,9 +2,29 @@ github.com/a-h/templ v0.3.924 h1:t5gZqTneXqvehpNZsgtnlOscnBboNh9aASBH2MgV/0k=
github.com/a-h/templ v0.3.924/go.mod h1:FFAu4dI//ESmEN7PQkJ7E7QfnSEMdcnu7QrAY8Dn334=
github.com/alexedwards/scs/v2 v2.8.0 h1:h31yUYoycPuL0zt14c0gd+oqxfRwIj6SOjHdKRZxhEw=
github.com/alexedwards/scs/v2 v2.8.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/golang-migrate/migrate/v4 v4.18.3 h1:EYGkoOsvgHHfm5U/naS1RP/6PL/Xv3S4B/swMiAmDLs=
+github.com/golang-migrate/migrate/v4 v4.18.3/go.mod h1:99BKpIi6ruaaXRM1A77eqZ+FWPQ3cfRa+ZVy5bmWMaY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
+go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/Backend/models/db_test.go b/Backend/models/db_test.go
index 21d25f5..56ec4a5 100644
--- a/Backend/models/db_test.go
+++ b/Backend/models/db_test.go
@@ -1,10 +1,17 @@
package models_test
import (
+ "arbeitszeitmessung/helper"
"arbeitszeitmessung/models"
"database/sql"
+ "fmt"
+ "log"
"testing"
+ "github.com/golang-migrate/migrate/v4"
+ "github.com/golang-migrate/migrate/v4/database/postgres"
+ _ "github.com/golang-migrate/migrate/v4/database/postgres"
+ _ "github.com/golang-migrate/migrate/v4/source/file"
_ "github.com/lib/pq"
)
@@ -16,11 +23,24 @@ type DBFixture struct {
func SetupDBFixture(t *testing.T) *DBFixture {
t.Helper()
- db, err := sql.Open("postgres", "postgres://postgres:password@localhost:5433/arbeitszeitmessung?sslmode=disable")
+ dbHost := helper.GetEnv("POSTGRES_HOST", "localhost")
+ dbPort := helper.GetEnv("POSTGRES_PORT", "5433")
+ dbName := helper.GetEnv("POSTGRES_DB", "arbeitszeitmessung")
+ dbUser := helper.GetEnv("POSTGRES_USER", "postgres")
+ dbPassword := helper.GetEnv("POSTGRES_PASSWORD", "password")
+
+ connStr := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable&TimeZone=Europe/Berlin", dbUser, dbPassword, dbHost, dbPort, dbName)
+
+ db, err := sql.Open("postgres", connStr)
if err != nil {
t.Fatalf("failed to connect to database: %v", err)
}
+ err = MigrateDB(db, "file://../../migrations")
+ if err != nil && err != migrate.ErrNoChange {
+ t.Fatalf("Failed to migrate database: %v", err)
+ }
+
tx, err := db.Begin()
if err != nil {
t.Fatalf("Failed to start transaction: %v", err)
@@ -36,3 +56,14 @@ func SetupDBFixture(t *testing.T) *DBFixture {
TX: tx,
}
}
+
+func MigrateDB(db *sql.DB, fileUrl string) error {
+ driver, err := postgres.WithInstance(db, &postgres.Config{})
+ if err != nil {
+ log.Fatalln("Error starting migration", err)
+ }
+ m, err := migrate.NewWithDatabaseInstance(
+ fileUrl,
+ "postgres", driver)
+ return m.Up()
+}
From 945f97ef3233790399bfb65edc783d4371b13c32 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 15:04:44 +0200
Subject: [PATCH 22/39] Update testing.yaml
---
.gitea/workflows/testing.yaml | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index d142795..96c1d17 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -12,6 +12,12 @@ jobs:
POSTGRES_DB: arbeitszeitmessung
POSTGRES_PORT: 5432
steps:
+ - uses: harmon758/postgresql-action@v1
+ with:
+ postgresql version: "16"
+ postgresql user: ${{ env.POSTGRES_USER }}
+ postgresql password: ${{ env.POSTGRES_PASSWORD }}
+ postgresql db: ${{ env.POSTGRES_DB }}
- name: Checkout
uses: actions/checkout@v4
with:
@@ -36,12 +42,5 @@ jobs:
/go_path
/go_cache
key: go_path-${{ steps.hash-go.outputs.hash }}
- - name: Setup DB
- uses: harmon758/postgresql-action@v1
- with:
- postgresql version: "16"
- postgresql user: ${{ env.POSTGRES_USER }}
- postgresql password: ${{ env.POSTGRES_PASSWORD }}
- postgresql db: ${{ env.POSTGRES_DB }}
- - name: test
+ - name: Run Go Test
run: make test
From ccc82527d34d840aeb9707da152b8abbe6e661de Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 15:17:52 +0200
Subject: [PATCH 23/39] Update testing.yaml
---
.gitea/workflows/testing.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index 96c1d17..75a1d8e 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -43,4 +43,4 @@ jobs:
/go_cache
key: go_path-${{ steps.hash-go.outputs.hash }}
- name: Run Go Test
- run: make test
+ run: go test ./...
From 4974aa981556b1121e0bf20ab6aaed63973135c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 15:20:46 +0200
Subject: [PATCH 24/39] Update testing.yaml
---
.gitea/workflows/testing.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index 75a1d8e..86cdd5d 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -43,4 +43,4 @@ jobs:
/go_cache
key: go_path-${{ steps.hash-go.outputs.hash }}
- name: Run Go Test
- run: go test ./...
+ run: cd Backend && go test ./...
From 6c544174d0fcbc4bd7c7accdd526344fe2b55532 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 15:22:49 +0200
Subject: [PATCH 25/39] Update testing.yaml
---
.gitea/workflows/testing.yaml | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index 86cdd5d..94b24e1 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -12,12 +12,6 @@ jobs:
POSTGRES_DB: arbeitszeitmessung
POSTGRES_PORT: 5432
steps:
- - uses: harmon758/postgresql-action@v1
- with:
- postgresql version: "16"
- postgresql user: ${{ env.POSTGRES_USER }}
- postgresql password: ${{ env.POSTGRES_PASSWORD }}
- postgresql db: ${{ env.POSTGRES_DB }}
- name: Checkout
uses: actions/checkout@v4
with:
@@ -42,5 +36,10 @@ jobs:
/go_path
/go_cache
key: go_path-${{ steps.hash-go.outputs.hash }}
- - name: Run Go Test
- run: cd Backend && go test ./...
+ - uses: harmon758/postgresql-action@v1
+ with:
+ postgresql version: "16"
+ postgresql user: ${{ env.POSTGRES_USER }}
+ postgresql password: ${{ env.POSTGRES_PASSWORD }}
+ postgresql db: ${{ env.POSTGRES_DB }}
+ - run: cd Backend && go test ./...
From 81cdca42f9a8ab7910b70bc1a3c49dddb08b962d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 22:23:22 +0200
Subject: [PATCH 26/39] hopefully working
---
.gitea/workflows/testing.yaml | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index 94b24e1..aa94de4 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -36,10 +36,18 @@ jobs:
/go_path
/go_cache
key: go_path-${{ steps.hash-go.outputs.hash }}
- - uses: harmon758/postgresql-action@v1
- with:
- postgresql version: "16"
- postgresql user: ${{ env.POSTGRES_USER }}
- postgresql password: ${{ env.POSTGRES_PASSWORD }}
- postgresql db: ${{ env.POSTGRES_DB }}
- - run: cd Backend && go test ./...
+ - name: Setup test database
+ run: |
+ docker run -d --rm --name postgres_build_db \
+ -p $POSTGRES_PORT:5432 \
+ -e POSTGRES_USER=$POSTGRES_USER \
+ -e POSTGRES_PASSWORD=$POSTGRES_PASSWORD \
+ -e POSTGRES_DB=$POSTGRES_DB \
+ postgres:16
+ while [[ $(docker logs postgres_build_db 2>&1 | grep -c "database system is ready to accept connections") == 0 ]]; do
+ sleep 1;
+ done;
+ - name: Run Go Tests
+ run: cd Backend && go test ./...
+ - name: Shutdown Postgres DB
+ run: docker stop postgres_build_db
From e5a1ee1d0e085112a496a9433de48768c44da53c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 22:36:52 +0200
Subject: [PATCH 27/39] Update testing.yaml
---
.gitea/workflows/testing.yaml | 34 +++++++++++++++++++++-------------
1 file changed, 21 insertions(+), 13 deletions(-)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index aa94de4..fd4a4e3 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -6,7 +6,15 @@ jobs:
testing:
name: check and test
runs-on: ubuntu-latest
+ services:
+ postgres:
+ image: postgres:16
+ env:
+ POSTGRES_USER: root
+ POSTGRES_PASSWORD: password
+ POSTGRES_DB: arbeitszeitmessung
env:
+ POSTGRES_HOST: postgres
POSTGRES_USER: root
POSTGRES_PASSWORD: password
POSTGRES_DB: arbeitszeitmessung
@@ -36,18 +44,18 @@ jobs:
/go_path
/go_cache
key: go_path-${{ steps.hash-go.outputs.hash }}
- - name: Setup test database
- run: |
- docker run -d --rm --name postgres_build_db \
- -p $POSTGRES_PORT:5432 \
- -e POSTGRES_USER=$POSTGRES_USER \
- -e POSTGRES_PASSWORD=$POSTGRES_PASSWORD \
- -e POSTGRES_DB=$POSTGRES_DB \
- postgres:16
- while [[ $(docker logs postgres_build_db 2>&1 | grep -c "database system is ready to accept connections") == 0 ]]; do
- sleep 1;
- done;
+ # - name: Setup test database
+ # run: |
+ # docker run -d --rm --name postgres_build_db \
+ # -p $POSTGRES_PORT:5432 \
+ # -e POSTGRES_USER=$POSTGRES_USER \
+ # -e POSTGRES_PASSWORD=$POSTGRES_PASSWORD \
+ # -e POSTGRES_DB=$POSTGRES_DB \
+ # postgres:16
+ # while [[ $(docker logs postgres_build_db 2>&1 | grep -c "database system is ready to accept connections") == 0 ]]; do
+ # sleep 1;
+ # done;
- name: Run Go Tests
run: cd Backend && go test ./...
- - name: Shutdown Postgres DB
- run: docker stop postgres_build_db
+ # - name: Shutdown Postgres DB
+ # run: docker stop postgres_build_db
From 007d30f87442ffeadaaa79e69f9ca43a02029185 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 22:51:35 +0200
Subject: [PATCH 28/39] Added Build Step
---
.gitea/workflows/testing.yaml | 30 ++++++++++++++----------------
1 file changed, 14 insertions(+), 16 deletions(-)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index fd4a4e3..448ac95 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -4,7 +4,7 @@ on: [push]
jobs:
testing:
- name: check and test
+ name: Run Go Tests
runs-on: ubuntu-latest
services:
postgres:
@@ -22,8 +22,6 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- with:
- fetch-depth: 0 # all history for all branches and tags
- name: Setup go
uses: actions/setup-go@v5
@@ -44,18 +42,18 @@ jobs:
/go_path
/go_cache
key: go_path-${{ steps.hash-go.outputs.hash }}
- # - name: Setup test database
- # run: |
- # docker run -d --rm --name postgres_build_db \
- # -p $POSTGRES_PORT:5432 \
- # -e POSTGRES_USER=$POSTGRES_USER \
- # -e POSTGRES_PASSWORD=$POSTGRES_PASSWORD \
- # -e POSTGRES_DB=$POSTGRES_DB \
- # postgres:16
- # while [[ $(docker logs postgres_build_db 2>&1 | grep -c "database system is ready to accept connections") == 0 ]]; do
- # sleep 1;
- # done;
- name: Run Go Tests
run: cd Backend && go test ./...
- # - name: Shutdown Postgres DB
- # run: docker stop postgres_build_db
+ build:
+ needs: testing
+ name: Build Go Image and Upload
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ - name: Login to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: git.letsstein.de
+ username: ${{ gitea.actor }}
+ password: ${{ secrets.REGISTRY_TOKEN }}
From 3bd449203c579619d1a32fa0638ccea4c12427b6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 22:59:13 +0200
Subject: [PATCH 29/39] tying cache
---
.gitea/workflows/testing.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index 448ac95..26d6af4 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -42,6 +42,8 @@ jobs:
/go_path
/go_cache
key: go_path-${{ steps.hash-go.outputs.hash }}
+ restore-keys: |-
+ go_path-${{ steps.hash-go.outputs.hash }}
- name: Run Go Tests
run: cd Backend && go test ./...
build:
From 87d2dd86ebc62625995ab78d4c384c5b0767fec8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 23:10:31 +0200
Subject: [PATCH 30/39] trying build
---
.gitea/workflows/testing.yaml | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index 26d6af4..fbce127 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -41,9 +41,9 @@ jobs:
path: |
/go_path
/go_cache
- key: go_path-${{ steps.hash-go.outputs.hash }}
+ key: arbeitszeitmessung-${{ steps.hash-go.outputs.hash }}
restore-keys: |-
- go_path-${{ steps.hash-go.outputs.hash }}
+ arbeitszeitmessung-${{ steps.hash-go.outputs.hash }}
- name: Run Go Tests
run: cd Backend && go test ./...
build:
@@ -59,3 +59,13 @@ jobs:
registry: git.letsstein.de
username: ${{ gitea.actor }}
password: ${{ secrets.REGISTRY_TOKEN }}
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v3
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+ - name: Build and push
+ uses: docker/build-push-action@v6
+ with:
+ platforms: linux/amd64,linux/arm64
+ push: true
+ tags: git.letsstein.de/tom/arbeitszeitmessung:latest
From f56fde9bfdad8117ea3d02f5d922fd4f26863ba1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 23:15:22 +0200
Subject: [PATCH 31/39] Update testing.yaml
---
.gitea/workflows/testing.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index fbce127..6f2a08d 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -69,3 +69,4 @@ jobs:
platforms: linux/amd64,linux/arm64
push: true
tags: git.letsstein.de/tom/arbeitszeitmessung:latest
+ context: Docker
From 92349dc7d2db94459a6a9a9b8ae92ff75a91bd35 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 23:19:48 +0200
Subject: [PATCH 32/39] better context
---
.gitea/workflows/testing.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index 6f2a08d..2fe794f 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -47,7 +47,7 @@ jobs:
- name: Run Go Tests
run: cd Backend && go test ./...
build:
- needs: testing
+ # needs: testing
name: Build Go Image and Upload
runs-on: ubuntu-latest
steps:
@@ -69,4 +69,4 @@ jobs:
platforms: linux/amd64,linux/arm64
push: true
tags: git.letsstein.de/tom/arbeitszeitmessung:latest
- context: Docker
+ context: Backend
From 119c0c3b3391a166c4346e1fa4e293a9fd7619f5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 23:34:31 +0200
Subject: [PATCH 33/39] next try
---
Backend/.dockerignore | 1 -
Backend/database.go | 12 +++++++++++
Backend/go.mod | 2 +-
Backend/go.sum | 48 +++++++++++++++++++++++++++++++++++++++++--
4 files changed, 59 insertions(+), 4 deletions(-)
diff --git a/Backend/.dockerignore b/Backend/.dockerignore
index c389270..7ab2ceb 100644
--- a/Backend/.dockerignore
+++ b/Backend/.dockerignore
@@ -1,3 +1,2 @@
db
Dockerfile
-templates/*.go
diff --git a/Backend/database.go b/Backend/database.go
index 24b7dd6..81e9158 100644
--- a/Backend/database.go
+++ b/Backend/database.go
@@ -5,6 +5,10 @@ import (
"arbeitszeitmessung/models"
"database/sql"
"fmt"
+ "log"
+
+ "github.com/golang-migrate/migrate/v4"
+ _ "github.com/golang-migrate/migrate/v4/source/file"
)
func OpenDatabase() (models.IDatabase, error) {
@@ -21,3 +25,11 @@ func OpenDatabase() (models.IDatabase, error) {
defer db.Close()
return db, err
}
+
+func MigrateDB(db models.IDatabase, connStr string) {
+ m, err := migrate.New("file:///../migrations/", connStr)
+ if err != nil {
+ log.Fatalln("Error starting migration", err)
+ }
+ m.Up()
+}
diff --git a/Backend/go.mod b/Backend/go.mod
index 53b8b2a..6987c36 100644
--- a/Backend/go.mod
+++ b/Backend/go.mod
@@ -6,7 +6,7 @@ toolchain go1.24.5
require github.com/lib/pq v1.10.9
-require github.com/a-h/templ v0.3.924
+require github.com/a-h/templ v0.3.943
require github.com/alexedwards/scs/v2 v2.8.0
diff --git a/Backend/go.sum b/Backend/go.sum
index 4d25b7c..82a9cc4 100644
--- a/Backend/go.sum
+++ b/Backend/go.sum
@@ -1,10 +1,32 @@
-github.com/a-h/templ v0.3.924 h1:t5gZqTneXqvehpNZsgtnlOscnBboNh9aASBH2MgV/0k=
-github.com/a-h/templ v0.3.924/go.mod h1:FFAu4dI//ESmEN7PQkJ7E7QfnSEMdcnu7QrAY8Dn334=
+github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
+github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
+github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
+github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
+github.com/a-h/templ v0.3.943 h1:o+mT/4yqhZ33F3ootBiHwaY4HM5EVaOJfIshvd5UNTY=
+github.com/a-h/templ v0.3.943/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo=
github.com/alexedwards/scs/v2 v2.8.0 h1:h31yUYoycPuL0zt14c0gd+oqxfRwIj6SOjHdKRZxhEw=
github.com/alexedwards/scs/v2 v2.8.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dhui/dktest v0.4.5 h1:uUfYBIVREmj/Rw6MvgmqNAYzTiKOHJak+enB5Di73MM=
+github.com/dhui/dktest v0.4.5/go.mod h1:tmcyeHDKagvlDrz7gDKq4UAJOLIfVZYkfD5OnHDwcCo=
+github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
+github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
+github.com/docker/docker v27.2.0+incompatible h1:Rk9nIVdfH3+Vz4cyI/uhbINhEZ/oLmc+CBXmH6fbNk4=
+github.com/docker/docker v27.2.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
+github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
+github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
+github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
+github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-migrate/migrate/v4 v4.18.3 h1:EYGkoOsvgHHfm5U/naS1RP/6PL/Xv3S4B/swMiAmDLs=
github.com/golang-migrate/migrate/v4 v4.18.3/go.mod h1:99BKpIi6ruaaXRM1A77eqZ+FWPQ3cfRa+ZVy5bmWMaY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
@@ -18,13 +40,35 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
+github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
+github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
+github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
+github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
+github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
+go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
+go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
+go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
+go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
+go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
+go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
+golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
From 9f31574f3d68666e623d510e1ae9cdc982cd2844 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 23:43:10 +0200
Subject: [PATCH 34/39] testing cache
---
.gitea/workflows/testing.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index 2fe794f..99348d2 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -43,7 +43,7 @@ jobs:
/go_cache
key: arbeitszeitmessung-${{ steps.hash-go.outputs.hash }}
restore-keys: |-
- arbeitszeitmessung-${{ steps.hash-go.outputs.hash }}
+ arbeitszeitmessung-
- name: Run Go Tests
run: cd Backend && go test ./...
build:
From c1b937152bcc0c09dee571e14300549a3788f131 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 21 Aug 2025 23:49:59 +0200
Subject: [PATCH 35/39] Update testing.yaml
---
.gitea/workflows/testing.yaml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/testing.yaml
index 99348d2..62c456c 100644
--- a/.gitea/workflows/testing.yaml
+++ b/.gitea/workflows/testing.yaml
@@ -19,6 +19,7 @@ jobs:
POSTGRES_PASSWORD: password
POSTGRES_DB: arbeitszeitmessung
POSTGRES_PORT: 5432
+ RUNNER_TOOL_CACHE: /toolcache # Runner Tool Cache
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -27,7 +28,6 @@ jobs:
uses: actions/setup-go@v5
with:
go-version-file: Backend/go.mod
- check-latest: true
- uses: https://gitea.com/actions/go-hashfiles@v0.0.1
id: hash-go
with:
@@ -38,7 +38,7 @@ jobs:
id: cache-go
uses: actions/cache@v4
with:
- path: |
+ path: |-
/go_path
/go_cache
key: arbeitszeitmessung-${{ steps.hash-go.outputs.hash }}
@@ -47,7 +47,7 @@ jobs:
- name: Run Go Tests
run: cd Backend && go test ./...
build:
- # needs: testing
+ needs: testing
name: Build Go Image and Upload
runs-on: ubuntu-latest
steps:
From 34bd44db5c4668228b90b2bdb0ca8c8fee26c0a3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Fri, 22 Aug 2025 00:13:00 +0200
Subject: [PATCH 36/39] ready for action
---
.gitea/workflows/{testing.yaml => build.yaml} | 0
Backend/go.mod | 4 +-
Docker/docker-compose.dev.yml | 2 +-
Docker/docker-compose.test.yml | 3 +-
Docker/docker-compose.yml | 2 +-
Jenkinsfile | 64 +++++++++++++------
6 files changed, 49 insertions(+), 26 deletions(-)
rename .gitea/workflows/{testing.yaml => build.yaml} (100%)
diff --git a/.gitea/workflows/testing.yaml b/.gitea/workflows/build.yaml
similarity index 100%
rename from .gitea/workflows/testing.yaml
rename to .gitea/workflows/build.yaml
diff --git a/Backend/go.mod b/Backend/go.mod
index 6987c36..d5c6953 100644
--- a/Backend/go.mod
+++ b/Backend/go.mod
@@ -1,8 +1,6 @@
module arbeitszeitmessung
-go 1.23.0
-
-toolchain go1.24.5
+go 1.24.5
require github.com/lib/pq v1.10.9
diff --git a/Docker/docker-compose.dev.yml b/Docker/docker-compose.dev.yml
index 2abeb41..b1884d8 100644
--- a/Docker/docker-compose.dev.yml
+++ b/Docker/docker-compose.dev.yml
@@ -20,7 +20,7 @@ services:
- 8001:8080
backend:
build: ../Backend
- image: git.letsstein.de/tom/arbeitszeit-backend:0.1.1
+ image: git.letsstein.de/tom/arbeitszeitmessung
restart: unless-stopped
env_file:
- .env
diff --git a/Docker/docker-compose.test.yml b/Docker/docker-compose.test.yml
index fbfeb50..0d5e807 100644
--- a/Docker/docker-compose.test.yml
+++ b/Docker/docker-compose.test.yml
@@ -7,7 +7,6 @@ services:
- .env.test
environment:
PGDATA: /var/lib/postgresql/data/pg_data
- volumes:
- - ${POSTGRES_PATH}/initdb:/docker-entrypoint-initdb.d
+ # volumes: //- ${POSTGRES_PATH}/initdb:/docker-entrypoint-initdb.d
ports:
- 5433:5432
diff --git a/Docker/docker-compose.yml b/Docker/docker-compose.yml
index f484d08..272fc49 100644
--- a/Docker/docker-compose.yml
+++ b/Docker/docker-compose.yml
@@ -17,7 +17,7 @@ services:
- 5432:5432
backend:
- image: git.letsstein.de/tom/arbeitszeit-backend
+ image: git.letsstein.de/tom/arbeitszeitmessung
env_file:
- .env
environment:
diff --git a/Jenkinsfile b/Jenkinsfile
index 868f7ec..a5d5f5c 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -3,6 +3,9 @@ pipeline {
DOCKER_USERNAME = 'jenkins'
DOCKER_PASSWORD = credentials('gitea_jenkins')
SONAR_TOKEN = credentials('sonarcube_token')
+ POSTGRES_USER = 'postgres'
+ POSTGRES_PASSWORD = 'password'
+ POSTGRES_DB = 'arbeitszeitmessung'
}
agent any
@@ -11,30 +14,53 @@ pipeline {
stage('Test') {
agent {
docker {
- image 'golang:alpine'
+ image ''
+ args ''
+ args ''
}
}
steps {
- sh 'cd Backend && go mod download && go mod verify'
- sh 'make test'
- }
- }
- stage('SonarCube Analysis') {
- steps {
- sh 'make scan'
- }
- }
- stage('Building image arbeitszeit-backend') {
- when {
- anyOf {
- changeset 'Jenkinsfile'
- changeset 'Makefile'
- changeset 'Backend/**'
+ script {
+ sh '''
+ docker run -d --rm \
+ --name test-db \
+ -e POSTGRES_USER={$POSTGRES_USER} \
+ -e POSTGRES_PASSWORD={$POSTGRES_PASSWORD} \
+ -e POSTGRES_DB={$POSTGRES_DB} \
+ -v ./DB/initdb:/docker-entrypoint-initdb.d\
+ -p "5432:5432" \
+ postgres:16
+ '''
+ // docker.image('golang:1.24.5').withRun(
+ // '-u root:root --network=host'
+ // ) { go ->
+ // // wait for DB to start
+ // sh '''
+ // cd Backend \
+ // go mod download && go mod tidy \
+ // go test ./... -v
+
+ // '''
+ // }
}
}
- steps {
- sh 'make backend'
- }
}
+ stage('SonarCube Analysis') {
+ steps {
+ sh 'make scan'
+ }
+ }
+ stage('Building image arbeitszeit-backend') {
+ when {
+ anyOf {
+ changeset 'Jenkinsfile'
+ changeset 'Makefile'
+ changeset 'Backend/**'
+ }
+ }
+ steps {
+ sh 'make backend'
+ }
+ }
}
}
From 50bec238a4db2988266af6ee316698cd99bd3a5a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Fri, 22 Aug 2025 00:50:21 +0200
Subject: [PATCH 37/39] edge case at midnight
---
Backend/models/db_test.go | 8 ++++----
Backend/models/user_test.go | 4 ++--
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/Backend/models/db_test.go b/Backend/models/db_test.go
index 56ec4a5..629bd2d 100644
--- a/Backend/models/db_test.go
+++ b/Backend/models/db_test.go
@@ -36,10 +36,10 @@ func SetupDBFixture(t *testing.T) *DBFixture {
t.Fatalf("failed to connect to database: %v", err)
}
- err = MigrateDB(db, "file://../../migrations")
- if err != nil && err != migrate.ErrNoChange {
- t.Fatalf("Failed to migrate database: %v", err)
- }
+ // err = MigrateDB(db, "file://../../migrations")
+ // if err != nil && err != migrate.ErrNoChange {
+ // t.Fatalf("Failed to migrate database: %v", err)
+ // }
tx, err := db.Begin()
if err != nil {
diff --git a/Backend/models/user_test.go b/Backend/models/user_test.go
index dd9ccf4..323f925 100644
--- a/Backend/models/user_test.go
+++ b/Backend/models/user_test.go
@@ -44,12 +44,12 @@ func TestCheckAnwesenheit(t *testing.T) {
if actual = testUser.CheckAnwesenheit(); actual != false {
t.Errorf("Checkabwesenheit with no booking should be false but is %t", actual)
}
- tc.Database.Exec("INSERT INTO anwesenheit (timestamp, card_uid, check_in_out, geraet_id) VALUES (NOW() - INTERVAL '2 hour', 'aaaa-aaaa', 1, 1);")
+ tc.Database.Exec("INSERT INTO anwesenheit (timestamp, card_uid, check_in_out, geraet_id) VALUES (NOW() - INTERVAL '2 minute', 'aaaa-aaaa', 1, 1);")
if actual = testUser.CheckAnwesenheit(); actual != true {
t.Errorf("Checkabwesenheit with 'kommen' booking should be true but is %t", actual)
}
- tc.Database.Exec("INSERT INTO anwesenheit (timestamp, card_uid, check_in_out, geraet_id) VALUES (NOW() - INTERVAL '1 hour', 'aaaa-aaaa', 2, 1);")
+ tc.Database.Exec("INSERT INTO anwesenheit (timestamp, card_uid, check_in_out, geraet_id) VALUES (NOW() - INTERVAL '1 minute', 'aaaa-aaaa', 2, 1);")
if actual = testUser.CheckAnwesenheit(); actual != false {
t.Errorf("Checkabwesenheit with 'gehen' booking should be false but is %t", actual)
}
From 23e05b8cb567fc2f1b57dc4210c87b371d0e67ab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Fri, 22 Aug 2025 00:51:10 +0200
Subject: [PATCH 38/39] error in db code, closing database before usage
---
Backend/database.go | 19 ++-----------------
1 file changed, 2 insertions(+), 17 deletions(-)
diff --git a/Backend/database.go b/Backend/database.go
index 81e9158..bad1b77 100644
--- a/Backend/database.go
+++ b/Backend/database.go
@@ -5,10 +5,8 @@ import (
"arbeitszeitmessung/models"
"database/sql"
"fmt"
- "log"
- "github.com/golang-migrate/migrate/v4"
- _ "github.com/golang-migrate/migrate/v4/source/file"
+ _ "github.com/lib/pq"
)
func OpenDatabase() (models.IDatabase, error) {
@@ -18,18 +16,5 @@ func OpenDatabase() (models.IDatabase, error) {
dbPassword := helper.GetEnv("POSTGRES_API_PASS", "password")
connStr := fmt.Sprintf("postgres://%s:%s@%s:5432/%s?sslmode=disable&TimeZone=Europe/Berlin", dbUser, dbPassword, dbHost, dbName)
- db, err := sql.Open("postgres", connStr)
- if err != nil {
- return nil, err
- }
- defer db.Close()
- return db, err
-}
-
-func MigrateDB(db models.IDatabase, connStr string) {
- m, err := migrate.New("file:///../migrations/", connStr)
- if err != nil {
- log.Fatalln("Error starting migration", err)
- }
- m.Up()
+ return sql.Open("postgres", connStr)
}
From fd2c702b5fefaea854743f9702ea9960b5d9a50f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=20Tr=C3=B6ger?=
Date: Thu, 28 Aug 2025 10:55:46 +0200
Subject: [PATCH 39/39] Add LICENSE
---
LICENSE | 674 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 674 insertions(+)
create mode 100644 LICENSE
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e72bfdd
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
\ No newline at end of file