138 lines
5.4 KiB
Markdown
138 lines
5.4 KiB
Markdown
# README
|
|
|
|
upda - **Up**date **Da**shboard in Go.
|
|
|
|
The main git repository is hosted at
|
|
_[https://git.myservermanager.com/varakh/upda](https://git.myservermanager.com/varakh/upda)_.
|
|
Other repositories are mirrors and pull requests, issues, and planning are managed there.
|
|
|
|
Contributions are very welcome!
|
|
|
|
See [official documentation](./_doc/Home.md).
|
|
|
|
## Development & contribution
|
|
|
|
There's also a [embedded frontend](#embedded-frontend).
|
|
|
|
* Pay attention to `make checkstyle` (uses `go vet ./...`); pipeline fails if issues are detected.
|
|
* Each entity has its own repository
|
|
* Each entity is only used in repository and service (otherwise, mapping happens)
|
|
* Presenter layer is constructed from the entity, e.g., in REST responses and mapped
|
|
* No entity is directly returned in any REST response
|
|
* All log calls should be handled by `zap.L()`
|
|
* Configuration is bootstrapped via separated `struct` types which are given to the service which need them
|
|
* Error handling
|
|
* Always throw an error with `NewServiceError` for repositories, services and handlers
|
|
* Always throw an error wrapping the cause with `fmt.Errorf`
|
|
* Forward/bubble up the error directly, when original error is already a `NewServiceError` (most likely internal
|
|
calls)
|
|
* Always abort handler chain with `AbortWithError`
|
|
* Utils can throw any error
|
|
* Repositories, handlers and services should always properly return `error` including any `init`-like function (
|
|
best to avoid them and call in `newXXX`). **Do not abort with `Fatalf` or similar**
|
|
* `log.Fatalf` or `zap.L().Fatal` is allowed in `environment.go` or `app.go`
|
|
* Look into the `_doc/` folder for [OpenAPI specification](./_doc/api.yaml) and a Postman Collection.
|
|
* Consider reading [Effective Go](https://go.dev/doc/effective_go)
|
|
* Consider reading [100 Go Mistakes and How to Avoid Them](https://100go.co/)
|
|
|
|
## Embedded Frontend
|
|
|
|
_upda_ includes a frontend in a monorepo fashion inside `server/web/`. For production (binary and OCI), it's
|
|
embedded into the GoLang binary itself.
|
|
|
|
For _development_, no other steps are required. Simply follow the [frontend instructions](./server/web/README.md) and
|
|
start the frontend separately.
|
|
|
|
If you like to have a look on the _production_ experience, the frontend needs to be build first and you need to build
|
|
the Golang binary with `-tags prod`. How to properly build the frontend, please look into `build-web` of
|
|
the `Makefile` (additional `rm -rf` cmd).
|
|
|
|
### Getting started
|
|
|
|
Ensure to set the following environment variables for proper debug logs during development
|
|
|
|
```shell
|
|
DEVELOPMENT=true
|
|
LOGGING_ENCODING=console
|
|
LOGGING_LEVEL=debug
|
|
```
|
|
|
|
1. Run `make clean dependencies` to fetch dependencies
|
|
2. Start `git.myservermanager.com/varakh/upda/cmd/server` (or `cli`) as Go application and ensure to have _required_
|
|
environment variables set
|
|
|
|
If you like to test with PSQL and/or REDIS for task locking, here are some useful docker commands to have containers
|
|
up and running quickly. Set necessary environment variables properly.
|
|
|
|
```shell
|
|
# postgres
|
|
docker run --rm --name=upda-db \
|
|
-p 5432:5432 \
|
|
--restart=unless-stopped \
|
|
-e POSTGRES_USER=upda \
|
|
-e POSTGRES_PASSWORD=upda \
|
|
-e POSTGRES_DB=upda \
|
|
postgres:16-alpine
|
|
|
|
# redis
|
|
docker run --rm --name some-redis \
|
|
-p 6379:6379 \
|
|
redis redis-server --save 60 1 --loglevel warning
|
|
```
|
|
|
|
#### Windows hints
|
|
|
|
On Windows, you need a valid `gcc`, e.g., https://jmeubank.github.io/tdm-gcc/download/ and add the `\bin` folder to your
|
|
path.
|
|
|
|
For any `go` command you run, ensure that your `PATH` has the `gcc` binary and that you add `CGO_ENABLED=1` as
|
|
environment.
|
|
|
|
### Using the `lockService` correctly
|
|
|
|
The `lockService` can be used to lock resources. This works in-memory and also in a distributed fashion with REDIS.
|
|
|
|
Ensure to provide proper locking options when using, although in-memory ignores those.
|
|
|
|
Example:
|
|
|
|
```shell
|
|
# invoked from an endpoint
|
|
context := c.Request.Context()
|
|
|
|
var err error
|
|
var lock appLock
|
|
|
|
if lock, err = h.lockService.lockWithOptions(context, "TEST-LOCK", withAppLockOptionExpiry(5*time.Minute), withAppLockOptionInfiniteRetries(), withAppLockOptionRetryDelay(5*time.Second)); err != nil {
|
|
_ = c.AbortWithError(errToHttpStatus(err), err)
|
|
return
|
|
}
|
|
# defer to avoid leakage
|
|
defer func(lock appLock) {
|
|
_ = lock.unlock(context)
|
|
}(lock)
|
|
|
|
# simulate long running task
|
|
time.Sleep(20 * time.Second)
|
|
```
|
|
|
|
### Release
|
|
|
|
Releases are handled by the SCM platform and pipeline. Creating a **new git tag**, creates a new release in the SCM
|
|
platform, uploads produced artifacts to that release and publishes docker images automatically.
|
|
**Before** doing so, please ensure that the **commit on `master`** has the **correct version settings** and has been
|
|
built successfully:
|
|
|
|
* Adapt `commons/constants.go` and change `Version` to the correct version number
|
|
* Adapt `CHANGELOG.md` to reflect changes and ensure a date is properly set in the header, also add a reference link
|
|
in footer (link to scm git tag source)
|
|
* Adapt `api.yaml`: `version` attribute must reflect the to be released version
|
|
* Adapt `env: VERSION_*` in `.forgejo/workflows/release.yaml`
|
|
|
|
After the release has been created, ensure to change the following settings for the _next development cycle_:
|
|
|
|
* Adapt `commons/constants.go` and change `Version` to the _next_ version number
|
|
* Adapt `CHANGELOG.md` and add an _UNRELEASED_ section
|
|
* Adapt `api.yaml`: `version` attribute must reflect the _next_ version number
|
|
* Adapt `env: VERSION_*` in `.forgejo/workflows/release.yaml` to _next_ version number
|
|
|