From 6b7a8c0a3c495d542453602bea3c9013353738fc Mon Sep 17 00:00:00 2001 From: Ujstor Date: Fri, 21 Jun 2024 21:26:40 +0200 Subject: [PATCH 01/10] Chi & Templ --- .air.toml | 46 --- .env | 1 - .github/workflows/go-test.yml | 17 - .gitignore | 5 +- Dockerfile | 17 +- Jenkinsfile | 12 +- Makefile | 27 +- README.md | 77 +--- cmd/api/main.go | 14 +- cmd/web/{static => assets}/css/main.css | 0 cmd/web/{static => assets}/fonts/devicon.ttf | Bin cmd/web/{static => assets}/fonts/devicon.woff | Bin .../fonts/fontawesome-webfont.ttf | Bin .../fonts/fontawesome-webfont.woff | Bin .../fonts/fontawesome-webfont.woff2 | Bin cmd/web/{static => assets}/img/favicon.ico | Bin cmd/web/{static => assets}/img/png/argo.png | Bin .../{static => assets}/img/png/blueprint.png | Bin .../{static => assets}/img/png/coolify.png | Bin cmd/web/{static => assets}/img/png/lambda.png | Bin cmd/web/{static => assets}/img/png/probit.png | Bin .../{static => assets}/img/png/s3-infra.png | Bin cmd/web/{static => assets}/img/webp/argo.webp | Bin .../img/webp/blueprint.webp | Bin .../{static => assets}/img/webp/coolify.webp | Bin .../{static => assets}/img/webp/lambda.webp | Bin .../{static => assets}/img/webp/probit.webp | Bin .../{static => assets}/img/webp/s3-infra.webp | Bin cmd/web/{static => assets}/js/main.js | 0 .../{static => assets}/js/sweet-scroll.min.js | 0 cmd/web/{static => assets}/js/typed.js | 0 cmd/web/{static => assets}/resume_24.pdf | Bin cmd/web/{static => assets}/svg/aws.svg | 0 cmd/web/{static => assets}/svg/hetzner.svg | 0 cmd/web/{static => assets}/svg/postman.svg | 0 cmd/web/{static => assets}/svg/streamlit.svg | 0 cmd/web/{static => assets}/svg/traefik.svg | 0 cmd/web/base.templ | 45 +++ cmd/web/efs.go | 6 + cmd/web/portfolio.templ | 342 ++++++++++++++++ cmd/web/templates/index.html | 377 ------------------ docker-compose-prod.yml | 6 +- docker-compose.yml | 21 +- go.mod | 25 +- go.sum | 44 +- internal/server/routes.go | 24 +- internal/server/routes_test.go | 32 -- internal/server/server.go | 25 +- internal/server/server_test.go | 16 - sitemap.xml | 22 - 50 files changed, 474 insertions(+), 727 deletions(-) delete mode 100644 .air.toml delete mode 100644 .env delete mode 100644 .github/workflows/go-test.yml rename cmd/web/{static => assets}/css/main.css (100%) rename cmd/web/{static => assets}/fonts/devicon.ttf (100%) rename cmd/web/{static => assets}/fonts/devicon.woff (100%) rename cmd/web/{static => assets}/fonts/fontawesome-webfont.ttf (100%) rename cmd/web/{static => assets}/fonts/fontawesome-webfont.woff (100%) rename cmd/web/{static => assets}/fonts/fontawesome-webfont.woff2 (100%) rename cmd/web/{static => assets}/img/favicon.ico (100%) rename cmd/web/{static => assets}/img/png/argo.png (100%) rename cmd/web/{static => assets}/img/png/blueprint.png (100%) rename cmd/web/{static => assets}/img/png/coolify.png (100%) rename cmd/web/{static => assets}/img/png/lambda.png (100%) rename cmd/web/{static => assets}/img/png/probit.png (100%) rename cmd/web/{static => assets}/img/png/s3-infra.png (100%) rename cmd/web/{static => assets}/img/webp/argo.webp (100%) rename cmd/web/{static => assets}/img/webp/blueprint.webp (100%) rename cmd/web/{static => assets}/img/webp/coolify.webp (100%) rename cmd/web/{static => assets}/img/webp/lambda.webp (100%) rename cmd/web/{static => assets}/img/webp/probit.webp (100%) rename cmd/web/{static => assets}/img/webp/s3-infra.webp (100%) rename cmd/web/{static => assets}/js/main.js (100%) rename cmd/web/{static => assets}/js/sweet-scroll.min.js (100%) rename cmd/web/{static => assets}/js/typed.js (100%) rename cmd/web/{static => assets}/resume_24.pdf (100%) rename cmd/web/{static => assets}/svg/aws.svg (100%) rename cmd/web/{static => assets}/svg/hetzner.svg (100%) rename cmd/web/{static => assets}/svg/postman.svg (100%) rename cmd/web/{static => assets}/svg/streamlit.svg (100%) rename cmd/web/{static => assets}/svg/traefik.svg (100%) create mode 100644 cmd/web/base.templ create mode 100644 cmd/web/efs.go create mode 100644 cmd/web/portfolio.templ delete mode 100644 cmd/web/templates/index.html delete mode 100644 internal/server/routes_test.go delete mode 100644 internal/server/server_test.go delete mode 100644 sitemap.xml diff --git a/.air.toml b/.air.toml deleted file mode 100644 index 99fcc72..0000000 --- a/.air.toml +++ /dev/null @@ -1,46 +0,0 @@ -root = "." -testdata_dir = "testdata" -tmp_dir = "tmp" - -[build] - args_bin = [] - bin = "./tmp/main" - cmd = "make run" - delay = 1000 - exclude_dir = ["assets", "tmp", "vendor", "testdata"] - exclude_file = [] - exclude_regex = ["_test.go"] - exclude_unchanged = false - follow_symlink = false - full_bin = "" - include_dir = [] - include_ext = ["go", "tpl", "tmpl", "html"] - include_file = [] - kill_delay = "0s" - log = "build-errors.log" - poll = false - poll_interval = 0 - post_cmd = [] - pre_cmd = [] - rerun = false - rerun_delay = 500 - send_interrupt = false - stop_on_error = false - -[color] - app = "" - build = "yellow" - main = "magenta" - runner = "green" - watcher = "cyan" - -[log] - main_only = false - time = false - -[misc] - clean_on_exit = false - -[screen] - clear_on_rebuild = false - keep_scroll = true diff --git a/.env b/.env deleted file mode 100644 index 9a69c24..0000000 --- a/.env +++ /dev/null @@ -1 +0,0 @@ -PORT=5000 \ No newline at end of file diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml deleted file mode 100644 index 58957ba..0000000 --- a/.github/workflows/go-test.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Go-test -on: [push, pull_request] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - name: Setup Go - uses: actions/setup-go@v4 - with: - go-version: '1.22.1' - - name: Build - run: go build -v ./... - - name: Test with the Go CLI - run: go test ./... \ No newline at end of file diff --git a/.gitignore b/.gitignore index 30cfa03..73e31c5 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,4 @@ # Go workspace file go.work tmp/ - -# IDE specific files -.vscode -.idea +*templ.go diff --git a/Dockerfile b/Dockerfile index 087bea4..72a10b9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.22-alpine as base +FROM golang:1.22-alpine as build RUN apk add --no-cache make @@ -9,17 +9,12 @@ RUN go mod download COPY . . -FROM base as dev -RUN make build -EXPOSE ${PORT} -CMD [ "sh", "-c", "echo 'y' | make watch" ] - -FROM base as build +RUN go install github.com/a-h/templ/cmd/templ@latest +RUN templ generate RUN go build -o main cmd/api/main.go -FROM alpine:3.19.0 as prod +FROM alpine:3.20.1 as prod WORKDIR /app COPY --from=build /app/main /app/main -COPY cmd/web cmd/web -EXPOSE ${PORT} -CMD ["./main"] \ No newline at end of file +EXPOSE 5000 +CMD ["./main"] diff --git a/Jenkinsfile b/Jenkinsfile index 224f13a..a23e850 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -7,7 +7,7 @@ pipeline { DOCKER_HUB_USERNAME = 'ujstor' DOCKER_REPO_NAME = 'portfolio-web-go' BRANCH = 'master' - VERSION_PART = 'Minor' // Patch, Minor, Major + VERSION_PART = 'Patch' // Patch, Minor, Major DOCKER_JENKINS_CERDIDENTALS_ID = 'be9636c4-b828-41af-ad0b-46d4182dfb06' TAG = '' // Generated automatically } @@ -21,14 +21,6 @@ pipeline { } } - stage('Test') { - steps { - script { - sh "go test -v ./... ${WORKSPACE}/internal/server" - } - } - } - stage('chmod Tag sh') { steps { script { @@ -109,4 +101,4 @@ pipeline { echo "Pipeline completed successfully" } } -} \ No newline at end of file +} diff --git a/Makefile b/Makefile index 702a32b..2128a01 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,9 @@ -# Simple Makefile for a Go project - # Build the application all: build build: @echo "Building..." + @templ generate @go build -o main cmd/api/main.go docker-build: @@ -21,31 +20,9 @@ docker-run: push: @docker push ujstor/portfolio-web-go -# Test the application -test: - @echo "Testing..." - @go test ./... - # Clean the binary clean: @echo "Cleaning..." @rm -f main -# Live Reload -watch: - @if [ -x "$(GOPATH)/bin/air" ]; then \ - "$(GOPATH)/bin/air"; \ - @echo "Watching...";\ - else \ - read -p "air is not installed. Do you want to install it now? (y/n) " choice; \ - if [ "$$choice" = "y" ]; then \ - go install github.com/cosmtrek/air@latest; \ - "$(GOPATH)/bin/air"; \ - @echo "Watching...";\ - else \ - echo "You chose not to install air. Exiting..."; \ - exit 1; \ - fi; \ - fi - -.PHONY: all build docker-build run docker-run push test clea watch +.PHONY: all build docker-build run docker-run push clean diff --git a/README.md b/README.md index ba356e4..923211d 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,16 @@ # Portfolio Website -This static website is built using HTML, CSS, and JavaScript and served using a Go or Flask web server. It's designed to showcase your personal or professional projects, skills, and any other information you'd like to share with the world. - -The website is containerized using Docker Compose for easy deployment and scaling. - -## Docker Compose - -Build image and start the Docker containers using Docker Compose: - -```bash -docker compose up web-prod --build -d -``` - -This command will build the Docker image for your website and start the container. - -You can now access your portfolio website by navigating to `http://localhost:5000` in your web browser. - +This static website is built with Go and Templ. ## Jenkins Pipeline The pipeline is designed to automate the processes of testing, building, and deploying a web application using Docker. -It creates an image and pushes it to DockerHub. This simplifies deployment with Docker Compose. Additionally, -the pipeline is configured to perform these tasks when certain conditions are met, such as specific branch. +It creates an image and pushes it to DockerHub. ![](https://i.imgur.com/llEoE4e.png) - ## Deployment -Application deployment can be achieved through the utilization of either a `Go` or `Flask` server, orchestrated using docker-compose, -and hosted on the cloud self-hosting service provided by [Collify](https://coolify.io/docs/installation). Please note that the Flask server resides on a distinct branch. - +Deployment can be achieved through self-hosting service provided by [Collify](https://coolify.io/docs/installation).

@@ -38,47 +19,29 @@ and hosted on the cloud self-hosting service provided by [Collify](https://cooli ## MakeFile -run all make commands with clean tests ```bash -make all build -``` +all: build -build the application -```bash -make build -``` +build: + @echo "Building..." + @templ generate + @go build -o main cmd/api/main.go -build docker image -```bash -make docker-build -``` +docker-build: + @docker build -t ujstor/portfolio-web-go . -run the application -```bash -make run -``` +run: + @go run cmd/api/main.go -run docker image -```bash -make docker-run -``` +docker-run: + @docker run -p 5000:5000 ujstor/portfolio-web-go -push image to DockerHub -```bash -make push -``` +push: + @docker push ujstor/portfolio-web-go -live reload the application -```bash -make watch -``` +clean: + @echo "Cleaning..." + @rm -f main -run the test suite -```bash -make test +.PHONY: all build docker-build run docker-run push clean ``` - -clean up binary from the last build -```bash -make clean -``` \ No newline at end of file diff --git a/cmd/api/main.go b/cmd/api/main.go index 7bc287b..835a445 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -1,22 +1,16 @@ package main import ( - "fiber/internal/server" "fmt" - "os" - "strconv" - - _ "github.com/joho/godotenv/autoload" + "portfolio-web/internal/server" ) func main() { - server := server.New() + server := server.NewServer() - server.RegisterFiberRoutes() - port, _ := strconv.Atoi(os.Getenv("PORT")) - err := server.Listen(fmt.Sprintf(":%d", port)) + err := server.ListenAndServe() if err != nil { - panic("cannot start server") + panic(fmt.Sprintf("cannot start server: %s", err)) } } diff --git a/cmd/web/static/css/main.css b/cmd/web/assets/css/main.css similarity index 100% rename from cmd/web/static/css/main.css rename to cmd/web/assets/css/main.css diff --git a/cmd/web/static/fonts/devicon.ttf b/cmd/web/assets/fonts/devicon.ttf similarity index 100% rename from cmd/web/static/fonts/devicon.ttf rename to cmd/web/assets/fonts/devicon.ttf diff --git a/cmd/web/static/fonts/devicon.woff b/cmd/web/assets/fonts/devicon.woff similarity index 100% rename from cmd/web/static/fonts/devicon.woff rename to cmd/web/assets/fonts/devicon.woff diff --git a/cmd/web/static/fonts/fontawesome-webfont.ttf b/cmd/web/assets/fonts/fontawesome-webfont.ttf similarity index 100% rename from cmd/web/static/fonts/fontawesome-webfont.ttf rename to cmd/web/assets/fonts/fontawesome-webfont.ttf diff --git a/cmd/web/static/fonts/fontawesome-webfont.woff b/cmd/web/assets/fonts/fontawesome-webfont.woff similarity index 100% rename from cmd/web/static/fonts/fontawesome-webfont.woff rename to cmd/web/assets/fonts/fontawesome-webfont.woff diff --git a/cmd/web/static/fonts/fontawesome-webfont.woff2 b/cmd/web/assets/fonts/fontawesome-webfont.woff2 similarity index 100% rename from cmd/web/static/fonts/fontawesome-webfont.woff2 rename to cmd/web/assets/fonts/fontawesome-webfont.woff2 diff --git a/cmd/web/static/img/favicon.ico b/cmd/web/assets/img/favicon.ico similarity index 100% rename from cmd/web/static/img/favicon.ico rename to cmd/web/assets/img/favicon.ico diff --git a/cmd/web/static/img/png/argo.png b/cmd/web/assets/img/png/argo.png similarity index 100% rename from cmd/web/static/img/png/argo.png rename to cmd/web/assets/img/png/argo.png diff --git a/cmd/web/static/img/png/blueprint.png b/cmd/web/assets/img/png/blueprint.png similarity index 100% rename from cmd/web/static/img/png/blueprint.png rename to cmd/web/assets/img/png/blueprint.png diff --git a/cmd/web/static/img/png/coolify.png b/cmd/web/assets/img/png/coolify.png similarity index 100% rename from cmd/web/static/img/png/coolify.png rename to cmd/web/assets/img/png/coolify.png diff --git a/cmd/web/static/img/png/lambda.png b/cmd/web/assets/img/png/lambda.png similarity index 100% rename from cmd/web/static/img/png/lambda.png rename to cmd/web/assets/img/png/lambda.png diff --git a/cmd/web/static/img/png/probit.png b/cmd/web/assets/img/png/probit.png similarity index 100% rename from cmd/web/static/img/png/probit.png rename to cmd/web/assets/img/png/probit.png diff --git a/cmd/web/static/img/png/s3-infra.png b/cmd/web/assets/img/png/s3-infra.png similarity index 100% rename from cmd/web/static/img/png/s3-infra.png rename to cmd/web/assets/img/png/s3-infra.png diff --git a/cmd/web/static/img/webp/argo.webp b/cmd/web/assets/img/webp/argo.webp similarity index 100% rename from cmd/web/static/img/webp/argo.webp rename to cmd/web/assets/img/webp/argo.webp diff --git a/cmd/web/static/img/webp/blueprint.webp b/cmd/web/assets/img/webp/blueprint.webp similarity index 100% rename from cmd/web/static/img/webp/blueprint.webp rename to cmd/web/assets/img/webp/blueprint.webp diff --git a/cmd/web/static/img/webp/coolify.webp b/cmd/web/assets/img/webp/coolify.webp similarity index 100% rename from cmd/web/static/img/webp/coolify.webp rename to cmd/web/assets/img/webp/coolify.webp diff --git a/cmd/web/static/img/webp/lambda.webp b/cmd/web/assets/img/webp/lambda.webp similarity index 100% rename from cmd/web/static/img/webp/lambda.webp rename to cmd/web/assets/img/webp/lambda.webp diff --git a/cmd/web/static/img/webp/probit.webp b/cmd/web/assets/img/webp/probit.webp similarity index 100% rename from cmd/web/static/img/webp/probit.webp rename to cmd/web/assets/img/webp/probit.webp diff --git a/cmd/web/static/img/webp/s3-infra.webp b/cmd/web/assets/img/webp/s3-infra.webp similarity index 100% rename from cmd/web/static/img/webp/s3-infra.webp rename to cmd/web/assets/img/webp/s3-infra.webp diff --git a/cmd/web/static/js/main.js b/cmd/web/assets/js/main.js similarity index 100% rename from cmd/web/static/js/main.js rename to cmd/web/assets/js/main.js diff --git a/cmd/web/static/js/sweet-scroll.min.js b/cmd/web/assets/js/sweet-scroll.min.js similarity index 100% rename from cmd/web/static/js/sweet-scroll.min.js rename to cmd/web/assets/js/sweet-scroll.min.js diff --git a/cmd/web/static/js/typed.js b/cmd/web/assets/js/typed.js similarity index 100% rename from cmd/web/static/js/typed.js rename to cmd/web/assets/js/typed.js diff --git a/cmd/web/static/resume_24.pdf b/cmd/web/assets/resume_24.pdf similarity index 100% rename from cmd/web/static/resume_24.pdf rename to cmd/web/assets/resume_24.pdf diff --git a/cmd/web/static/svg/aws.svg b/cmd/web/assets/svg/aws.svg similarity index 100% rename from cmd/web/static/svg/aws.svg rename to cmd/web/assets/svg/aws.svg diff --git a/cmd/web/static/svg/hetzner.svg b/cmd/web/assets/svg/hetzner.svg similarity index 100% rename from cmd/web/static/svg/hetzner.svg rename to cmd/web/assets/svg/hetzner.svg diff --git a/cmd/web/static/svg/postman.svg b/cmd/web/assets/svg/postman.svg similarity index 100% rename from cmd/web/static/svg/postman.svg rename to cmd/web/assets/svg/postman.svg diff --git a/cmd/web/static/svg/streamlit.svg b/cmd/web/assets/svg/streamlit.svg similarity index 100% rename from cmd/web/static/svg/streamlit.svg rename to cmd/web/assets/svg/streamlit.svg diff --git a/cmd/web/static/svg/traefik.svg b/cmd/web/assets/svg/traefik.svg similarity index 100% rename from cmd/web/static/svg/traefik.svg rename to cmd/web/assets/svg/traefik.svg diff --git a/cmd/web/base.templ b/cmd/web/base.templ new file mode 100644 index 0000000..c287a86 --- /dev/null +++ b/cmd/web/base.templ @@ -0,0 +1,45 @@ +package web + +templ Base() { + + + + + + + + + + + + + + + + + + + Aleksandar Stipan + + + + + + { children... } + + + + + + + + + + +} diff --git a/cmd/web/efs.go b/cmd/web/efs.go new file mode 100644 index 0000000..57b9761 --- /dev/null +++ b/cmd/web/efs.go @@ -0,0 +1,6 @@ +package web + +import "embed" + +//go:embed "assets" +var Files embed.FS diff --git a/cmd/web/portfolio.templ b/cmd/web/portfolio.templ new file mode 100644 index 0000000..84d3712 --- /dev/null +++ b/cmd/web/portfolio.templ @@ -0,0 +1,342 @@ +package web + +templ Portfolio() { + @Base() { +
+
+

+ ALEKSANDAR STIPAN + Backend Coder • Automation Enthusiast • CI/CD Fanatic +

+ + +
+ +
+ + +
+ +
+

My Story

+

+ As a self-taught programmer, I am focused on backend development, CI/CD pipelines and automation. + I'm excited to apply my analytical mindset to projects requiring technical expertise and creative problem-solving. + I remain open to opportunities for growth, collaboration and addressing + real-world challenges with my skill set. +

+
+ + +
+ +
+

Languages & Tools

+
+ + + + + + + + + + + + + + +
+

Preferred programming languages and core tools for version control, CI/CD, container orchestration and deployment.

+
+
+
+ + +
+
+

Featured Projects

+
+ + +
+
+ + + blueprint + +
+
+

Go-Blueprint

+
+ +   + +
+

+ Core maintainer of the Go-Blueprint project: Go Blueprint is a CLI tool that allows users to + spin up a Go project with the corresponding structure. It also offers the option to + integrate with some of the most popular Go frameworks. Additionally, it implements database + drivers along with Docker Compose file for quick database creation, HTMx templates, GitHubAction worflows and Websockets. +

+ GitHub +   + Docs +   + YouTube +
+
+ + +
+
+ + + personal-s3-storage-infrastructure + +
+
+

Personal S3 Storage Infrastructure

+
+ +   + +   + +
+

+ Implementing MinIO, a high-performance object storage system compatible with Amazon S3, using Terraform and Ansible for management. + Configured as Multi-Node Multi-Drive (MNMD), this setup ensure robust performance and availability for enterprise applications. + It is fortified with configuration to sustain read operations even in the event of half-node or drive failures. +

+ GitHub +
+
+ + +
+
+ + + Lambda, DynamoDB & APIgw TF Modules + +
+
+

Lambda, DynamoDB & APIgw TF Modules

+
+ +   + +   + +
+

+ Terraform modules for creating Lambda functions along with associated AWS infrastructure components + like DynamoDB tables and API Gateway configurations. The repository includes modularized Terraform code + with separate modules for Lambda functions, DynamoDB tables, and API Gateway integrations, facilitating + easy deployment and management of serverless applications. +

+ GitHub +
+
+ + +
+
+ + + ArgoCD pipline + +
+
+

ArgoCD GitHub Action pipeline

+
+ +   + +   + +
+

+ GitHub Actions workflow that integrates with DockerHub and ArgoCD, enabling streamlined CI/CD pipelines. + This setup utilizes semantic versioning for Docker images and automatically updates Helm charts in + another repository upon successful commits. +

+ GitHub +
+
+ + +
+
+ + + Coolify instance on Hetzner + +
+
+

Coolify instance on Hetzner

+
+ +   + +
+

+ Deploys Coolify on Hetzner Cloud using the Terraform. Coolify is an all-in one PaaS that helps you to self-host your own applications, + databases or services without managing your servers, also known as an open-source & self-hostable + Heroku / Netlify / Vercel alternative. +

+ GitHub +   + Docs +
+
+
+ } +} diff --git a/cmd/web/templates/index.html b/cmd/web/templates/index.html deleted file mode 100644 index 06ac0a8..0000000 --- a/cmd/web/templates/index.html +++ /dev/null @@ -1,377 +0,0 @@ - - - - - - - - - - - - - - - - - - - Aleksandar Stipan - - - - - -
-
-

- ALEKSANDAR STIPAN - Backend Coder • Automation Enthusiast • CI/CD Fanatic -

- - -
- -
- - -
- -
-

My Story

-

- As a self-taught programmer, I am focused on backend development, CI/CD pipelines and automation. - I'm excited to apply my analytical mindset to projects requiring technical expertise and creative problem-solving. - I remain open to opportunities for growth, collaboration and addressing - real-world challenges with my skill set. -

-
- - -
- -
-

Languages & Tools

-
- - - - - - - - - - - - - - -
-

Preferred programming languages and core tools for version control, CI/CD, container orchestration and deployment.

-
-
-
- - -
-
-

Featured Projects

-
- - -
-
- - - blueprint - -
-
-

Go-Blueprint

-
- -   - -
-

- Core maintainer of the Go-Blueprint project: Go Blueprint is a CLI tool that allows users to - spin up a Go project with the corresponding structure. It also offers the option to - integrate with some of the most popular Go frameworks. Additionally, it implements database - drivers along with Docker Compose file for quick database creation, HTMx templates, GitHubAction worflows and Websockets. -

- GitHub -   - Docs -   - YouTube -
-
- - -
-
- - - personal-s3-storage-infrastructure - -
-
-

Personal S3 Storage Infrastructure

-
- -   - -   - -
-

- Implementing MinIO, a high-performance object storage system compatible with Amazon S3, using Terraform and Ansible for management. - Configured as Multi-Node Multi-Drive (MNMD), this setup ensure robust performance and availability for enterprise applications. - It is fortified with configuration to sustain read operations even in the event of half-node or drive failures. -

- GitHub -
-
- - -
-
- - - Lambda, DynamoDB & APIgw TF Modules - -
-
-

Lambda, DynamoDB & APIgw TF Modules

-
- -   - -   - -
-

- Terraform modules for creating Lambda functions along with associated AWS infrastructure components - like DynamoDB tables and API Gateway configurations. The repository includes modularized Terraform code - with separate modules for Lambda functions, DynamoDB tables, and API Gateway integrations, facilitating - easy deployment and management of serverless applications. -

- GitHub -
-
- - -
-
- - - ArgoCD pipline - -
-
-

ArgoCD GitHub Action pipeline

-
- -   - -   - -
-

- GitHub Actions workflow that integrates with DockerHub and ArgoCD, enabling streamlined CI/CD pipelines. - This setup utilizes semantic versioning for Docker images and automatically updates Helm charts in - another repository upon successful commits. -

- GitHub -
-
- - -
-
- - - Coolify instance on Hetzner - -
-
-

Coolify instance on Hetzner

-
- -   - -
-

- Deploys Coolify on Hetzner Cloud using the Terraform. Coolify is an all-in one PaaS that helps you to self-host your own applications, - databases or services without managing your servers, also known as an open-source & self-hostable - Heroku / Netlify / Vercel alternative. -

- GitHub -   - Docs -
-
-
- - - - - - - - - - - diff --git a/docker-compose-prod.yml b/docker-compose-prod.yml index b158310..1356e51 100644 --- a/docker-compose-prod.yml +++ b/docker-compose-prod.yml @@ -2,8 +2,6 @@ version: '3.8' services: web: - image: ujstor/portfolio-web-go:1.2.0 + image: ujstor/portfolio-web-go:1.2.1 ports: - - ${PORT}:${PORT} - environment: - - PORT=${PORT} + - 5000:5000 diff --git a/docker-compose.yml b/docker-compose.yml index 3fbbea2..8364adc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,27 +1,10 @@ version: '3.8' services: - web-dev: - build: - context: . - dockerfile: Dockerfile - target: dev - ports: - - ${PORT}:${PORT} - environment: - - PORT=${PORT} - volumes: - - ./:/app - - web-prod: + web: build: context: . dockerfile: Dockerfile target: prod ports: - - ${PORT}:${PORT} - environment: - - PORT=${PORT} - -# docker-compose up web-prod --build -# docker-compose up web-dev --build + - 5000:5000 diff --git a/go.mod b/go.mod index b2a5722..3a6ee48 100644 --- a/go.mod +++ b/go.mod @@ -1,26 +1,9 @@ -module fiber +module portfolio-web -go 1.22 +go 1.22.0 require ( - github.com/gofiber/fiber/v2 v2.51.0 + github.com/a-h/templ v0.2.707 + github.com/go-chi/chi/v5 v5.0.14 github.com/joho/godotenv v1.5.1 - github.com/stretchr/testify v1.8.4 -) - -require ( - github.com/andybalholm/brotli v1.0.6 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/google/uuid v1.4.0 // indirect - github.com/klauspost/compress v1.17.2 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rivo/uniseg v0.4.4 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.51.0 // indirect - github.com/valyala/tcplisten v1.0.0 // indirect - golang.org/x/sys v0.14.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 3dbf162..239ab57 100644 --- a/go.sum +++ b/go.sum @@ -1,40 +1,8 @@ -github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= -github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -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/gofiber/fiber/v2 v2.51.0 h1:JNACcZy5e2tGApWB2QrRpenTWn0fq0hkFm6k0C86gKQ= -github.com/gofiber/fiber/v2 v2.51.0/go.mod h1:xaQRZQJGqnKOQnbQw+ltvku3/h8QxvNi8o6JiJ7Ll0U= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/a-h/templ v0.2.707 h1:T1Gkd2ugbRglZ9rYw/VBchWOSZVKmetDbBkm4YubM7U= +github.com/a-h/templ v0.2.707/go.mod h1:5cqsugkq9IerRNucNsI4DEamdHPsoGMQy99DzydLhM8= +github.com/go-chi/chi/v5 v5.0.14 h1:PyEwo2Vudraa0x/Wl6eDRRW2NXBvekgfxyydcM0WGE0= +github.com/go-chi/chi/v5 v5.0.14/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +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/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= -github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -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/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= -github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= -github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= -github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= -github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -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/internal/server/routes.go b/internal/server/routes.go index 4eeeb43..3e34896 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -1,19 +1,21 @@ package server import ( - "github.com/gofiber/fiber/v2" + "net/http" + + "github.com/a-h/templ" + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" + "portfolio-web/cmd/web" ) -func (s *FiberServer) RegisterFiberRoutes() { - s.App.Static("/", "./cmd/web/templates") +func (s *Server) RegisterRoutes() http.Handler { + r := chi.NewRouter() + r.Use(middleware.Logger) - s.App.Static("/static", "./cmd/web/static") + fileServer := http.FileServer(http.FS(web.Files)) + r.Handle("/assets/*", fileServer) + r.Get("/", templ.Handler(web.Portfolio()).ServeHTTP) - // 404 handler for all other routes - s.App.Use(func(c *fiber.Ctx) error { - if c.Path() != "/" && c.Path() != "/static" { - return fiber.ErrNotFound - } - return c.Next() - }) + return r } diff --git a/internal/server/routes_test.go b/internal/server/routes_test.go deleted file mode 100644 index 52585c4..0000000 --- a/internal/server/routes_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package server - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/gofiber/fiber/v2" - "github.com/stretchr/testify/assert" -) - -// Creates a new FiberServer instance. -func NewFiberServer() *FiberServer { - return &FiberServer{App: fiber.New()} -} - -// Checks if routes are registered correctly in Fiber -func TestRegisterFiberRoutes(t *testing.T) { - s := NewFiberServer() - - // Temporary test route - s.App.Get("/", func(c *fiber.Ctx) error { - return c.SendStatus(http.StatusOK) - }) - - req := httptest.NewRequest(http.MethodGet, "/", nil) - resp, err := s.App.Test(req) - - assert.NoError(t, err, "Error should be nil") - assert.NotNil(t, resp, "Response should not be nil") - assert.Equal(t, http.StatusOK, resp.StatusCode, "Status code should be 200") -} diff --git a/internal/server/server.go b/internal/server/server.go index 6765e24..03f8962 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -1,14 +1,27 @@ package server -import "github.com/gofiber/fiber/v2" +import ( + "fmt" + "net/http" + "time" +) -type FiberServer struct { - *fiber.App +type Server struct { + port int } -func New() *FiberServer { - server := &FiberServer{ - App: fiber.New(), +func NewServer() *http.Server { + NewServer := &Server{ + port: 5000, + } + + // Declare Server config + server := &http.Server{ + Addr: fmt.Sprintf(":%d", NewServer.port), + Handler: NewServer.RegisterRoutes(), + IdleTimeout: time.Minute, + ReadTimeout: 10 * time.Second, + WriteTimeout: 30 * time.Second, } return server diff --git a/internal/server/server_test.go b/internal/server/server_test.go deleted file mode 100644 index b418d0d..0000000 --- a/internal/server/server_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package server - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -// Checks if a new FiberServer instance is correctly created -func TestNewFiberServer(t *testing.T) { - server := New() - - assert.NotNil(t, server, "FiberServer instance should not be nil") - assert.IsType(t, &FiberServer{}, server, "New should return an instance of *FiberServer") - assert.NotNil(t, server.App, "Fiber App in FiberServer should not be nil") -} diff --git a/sitemap.xml b/sitemap.xml deleted file mode 100644 index a756596..0000000 --- a/sitemap.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - https://astipan.com/ - 2023-09-03T11:46:48+00:00 - 1.00 - - - https://astipan.com/static/resume_24.pdf - 2023-09-03T11:46:48+00:00 - 0.80 - - - - From a2bc2f7dec6814e053c0a2a89b27152e0d0abe4c Mon Sep 17 00:00:00 2001 From: Ujstor Date: Fri, 21 Jun 2024 22:24:35 +0200 Subject: [PATCH 02/10] docker action --- .github/workflows/docker-image.yml | 47 +++++++++++++ .github/workflows/linting.yml | 17 +++-- Dockerfile | 2 +- Jenkinsfile | 104 ----------------------------- README.md | 7 -- config.yml | 5 ++ docker-compose.yml | 3 - docker_tag.sh | 19 ++++-- 8 files changed, 74 insertions(+), 130 deletions(-) create mode 100644 .github/workflows/docker-image.yml delete mode 100644 Jenkinsfile create mode 100644 config.yml diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml new file mode 100644 index 0000000..0c1fe8c --- /dev/null +++ b/.github/workflows/docker-image.yml @@ -0,0 +1,47 @@ +name: Docker image + +on: + push: + branches: + - refactor + - master +jobs: + docker: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Install yq + run: | + sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq + sudo chmod +x /usr/bin/yq + + - name: Run docker tag sh and export var from config.yml + run: | + ./docker_tag.sh + + - name: Export env variabels + uses: cardinalby/export-env-action@v2 + with: + envFile: '.env' + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ env.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_REPO_NAME }}:${{ env.NEW_TAG }} + if: ${{ env.PUSH_TO_DOCKER }} == 'true' diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 6883820..05e2021 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -1,4 +1,4 @@ -name: Linting +name: continuous integration on: push: @@ -6,10 +6,8 @@ on: - '**.go' - go.sum - go.mod - branches-ignore: - - main pull_request: - + jobs: lint: runs-on: ubuntu-latest @@ -17,13 +15,13 @@ jobs: - uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: - go-version: '1.22.1' + go-version: '1.22.2' - name: Deps cache id: cache-go-deps - uses: actions/cache@v3 + uses: actions/cache@v4 env: cache-name: go-deps-cache with: @@ -33,7 +31,7 @@ jobs: ${{ runner.os }}-build-${{ env.cache-name }}- - if: ${{ steps.cache-go-deps.outputs.cache-hit != 'true' }} - name: List the state of node modules + name: List the state of go modules continue-on-error: true run: go mod graph @@ -41,6 +39,7 @@ jobs: run: | go mod tidy go mod download + go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.57.2 - name: Run golangci-lint - uses: golangci/golangci-lint-action@v3.7.0 \ No newline at end of file + run: golangci-lint run diff --git a/Dockerfile b/Dockerfile index 72a10b9..701baae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,7 @@ RUN go install github.com/a-h/templ/cmd/templ@latest RUN templ generate RUN go build -o main cmd/api/main.go -FROM alpine:3.20.1 as prod +FROM alpine:3.20.1 WORKDIR /app COPY --from=build /app/main /app/main EXPOSE 5000 diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index a23e850..0000000 --- a/Jenkinsfile +++ /dev/null @@ -1,104 +0,0 @@ -pipeline { - agent any - - environment { - GITHUB_USER = 'ujstor' - GITHUB_REPO = 'portfolio-web' - DOCKER_HUB_USERNAME = 'ujstor' - DOCKER_REPO_NAME = 'portfolio-web-go' - BRANCH = 'master' - VERSION_PART = 'Patch' // Patch, Minor, Major - DOCKER_JENKINS_CERDIDENTALS_ID = 'be9636c4-b828-41af-ad0b-46d4182dfb06' - TAG = '' // Generated automatically - } - - stages { - stage('Checkout Code') { - steps { - script { - git(url: "https://github.com/${GITHUB_USER}/${GITHUB_REPO}/", branch: env.BRANCH_NAME) - } - } - } - - stage('chmod Tag sh') { - steps { - script { - sh "chmod 777 ${WORKSPACE}/docker_tag.sh" - } - } - } - - stage('Generate Docker Image Tag') { - when { - expression { env.BRANCH_NAME == env.BRANCH} - } - steps { - script { - TAG = sh(script: "${WORKSPACE}/docker_tag.sh $DOCKER_HUB_USERNAME $DOCKER_REPO_NAME $VERSION_PART", returnStdout: true).trim() - - if (TAG) { - echo "Docker image tag generated successfully: $TAG" - } else { - error "Failed to generate Docker image tag" - } - - env.TAG = TAG - } - } - } - - stage('Docker Login') { - when { - expression { env.BRANCH_NAME == env.BRANCH } - } - steps { - script { - - withCredentials([usernamePassword(credentialsId: env.DOCKER_JENKINS_CERDIDENTALS_ID, passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME')]) { - sh "docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD" - } - } - } - } - - stage('Build') { - when { - expression { env.BRANCH_NAME == env.BRANCH } - } - steps { - script { - sh "docker build --no-cache -t ${DOCKER_HUB_USERNAME}/${DOCKER_REPO_NAME}:${TAG} --target prod ." - } - } - } - - stage('Deploy') { - when { - expression { env.BRANCH_NAME == env.BRANCH } - } - steps { - script { - sh "docker push ${DOCKER_HUB_USERNAME}/${DOCKER_REPO_NAME}:${TAG}" - } - } - } - - stage('Environment Cleanup') { - when { - expression { env.BRANCH_NAME == env.BRANCH } - } - steps { - script { - sh "docker rmi ${DOCKER_HUB_USERNAME}/${DOCKER_REPO_NAME}:${TAG}" - } - } - } - } - - post { - success { - echo "Pipeline completed successfully" - } - } -} diff --git a/README.md b/README.md index 923211d..7fc0725 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,6 @@ This static website is built with Go and Templ. - -## Jenkins Pipeline -The pipeline is designed to automate the processes of testing, building, and deploying a web application using Docker. -It creates an image and pushes it to DockerHub. - -![](https://i.imgur.com/llEoE4e.png) - ## Deployment Deployment can be achieved through self-hosting service provided by [Collify](https://coolify.io/docs/installation). diff --git a/config.yml b/config.yml new file mode 100644 index 0000000..2aa6f9e --- /dev/null +++ b/config.yml @@ -0,0 +1,5 @@ +docker: + DOCKER_HUB_USERNAME: ujstor + DOCKER_REPO_NAME: portfolio-web-go + VERSION_PART: Patch # Patch, Minor, major + PUSH_TO_DOCKER: true diff --git a/docker-compose.yml b/docker-compose.yml index 8364adc..7fe9e4e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,10 +1,7 @@ -version: '3.8' - services: web: build: context: . dockerfile: Dockerfile - target: prod ports: - 5000:5000 diff --git a/docker_tag.sh b/docker_tag.sh index 9fffd7c..4d102bc 100644 --- a/docker_tag.sh +++ b/docker_tag.sh @@ -1,21 +1,19 @@ #!/bin/bash -DOCKER_HUB_USERNAME=$1 -DOCKER_REPO_NAME=$2 -VERSION_PART=$3 +eval $(yq e '.docker | to_entries | .[] | "export \(.key)=\(.value)"' config.yml) DOCKER_IMAGE="$DOCKER_HUB_USERNAME/$DOCKER_REPO_NAME" TAGS=$(curl -s "https://hub.docker.com/v2/repositories/$DOCKER_IMAGE/tags/?page_size=100" | jq -r '.results[].name') if [ -z "$TAGS" ]; then - DEFAULT_TAG="1.0.0" + DEFAULT_TAG="0.0.1" NEW_TAG="$DEFAULT_TAG" else LATEST_TAG=$(echo "$TAGS" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n 1) if [ -z "$LATEST_TAG" ]; then - LATEST_TAG="1.0.0" + LATEST_TAG="0.0.1" fi IFS='.' read -ra PARTS <<< "$LATEST_TAG" @@ -35,4 +33,13 @@ else fi fi -echo $NEW_TAG \ No newline at end of file +create_env_file() { + cat << EOF > .env +DOCKER_HUB_USERNAME=$DOCKER_HUB_USERNAME +DOCKER_REPO_NAME=$DOCKER_REPO_NAME +NEW_TAG=$NEW_TAG +PUSH_TO_DOCKER=$PUSH_TO_DOCKER +EOF +} + +create_env_file From 53f931a81504005cb121c4a1774ec80549066c72 Mon Sep 17 00:00:00 2001 From: Ujstor Date: Fri, 21 Jun 2024 22:33:28 +0200 Subject: [PATCH 03/10] tag +x --- .github/workflows/docker-image.yml | 1 + .github/workflows/linting.yml | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 0c1fe8c..d013159 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -31,6 +31,7 @@ jobs: - name: Run docker tag sh and export var from config.yml run: | + chmod +x ./docker_tag.sh ./docker_tag.sh - name: Export env variabels diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 05e2021..17a61e6 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -2,10 +2,6 @@ name: continuous integration on: push: - paths: - - '**.go' - - go.sum - - go.mod pull_request: jobs: From 2ffe32266715a74f78cf21246f8a35460bc7e8c0 Mon Sep 17 00:00:00 2001 From: Ujstor Date: Fri, 21 Jun 2024 22:38:21 +0200 Subject: [PATCH 04/10] test docker config --- .github/workflows/linting.yml | 2 ++ config.yml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 17a61e6..9a55183 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -36,6 +36,8 @@ jobs: go mod tidy go mod download go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.57.2 + go install github.com/a-h/templ/cmd/templ@latest + templ generate - name: Run golangci-lint run: golangci-lint run diff --git a/config.yml b/config.yml index 2aa6f9e..881af4a 100644 --- a/config.yml +++ b/config.yml @@ -2,4 +2,4 @@ docker: DOCKER_HUB_USERNAME: ujstor DOCKER_REPO_NAME: portfolio-web-go VERSION_PART: Patch # Patch, Minor, major - PUSH_TO_DOCKER: true + PUSH_TO_DOCKER: false From 1dd11402979ae6026af08f0a62ddc4f6474cae13 Mon Sep 17 00:00:00 2001 From: Ujstor Date: Fri, 21 Jun 2024 22:43:23 +0200 Subject: [PATCH 05/10] debug --- .github/workflows/docker-image.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index d013159..52b55d2 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -39,10 +39,13 @@ jobs: with: envFile: '.env' + - name: Debug - Check PUSH_TO_DOCKER value + run: echo "PUSH_TO_DOCKER is set to ${{ env.PUSH_TO_DOCKER }}" + - name: Build and push uses: docker/build-push-action@v5 with: context: . push: true tags: ${{ env.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_REPO_NAME }}:${{ env.NEW_TAG }} - if: ${{ env.PUSH_TO_DOCKER }} == 'true' + if: ${{ env.PUSH_TO_DOCKER }} == 'true' From a64ef9893ad59ff1b229b346efd418d37c4bdc62 Mon Sep 17 00:00:00 2001 From: Ujstor Date: Fri, 21 Jun 2024 22:47:38 +0200 Subject: [PATCH 06/10] debug --- .github/workflows/docker-image.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 52b55d2..aa5df54 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -39,13 +39,10 @@ jobs: with: envFile: '.env' - - name: Debug - Check PUSH_TO_DOCKER value - run: echo "PUSH_TO_DOCKER is set to ${{ env.PUSH_TO_DOCKER }}" - - name: Build and push + if: ${{ env.PUSH_TO_DOCKER == 'true' }} uses: docker/build-push-action@v5 with: context: . push: true tags: ${{ env.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_REPO_NAME }}:${{ env.NEW_TAG }} - if: ${{ env.PUSH_TO_DOCKER }} == 'true' From 8f24b89242b4cbb1b575d2477a2a4026f71daed6 Mon Sep 17 00:00:00 2001 From: Ujstor Date: Fri, 21 Jun 2024 22:49:09 +0200 Subject: [PATCH 07/10] debug --- config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.yml b/config.yml index 881af4a..1536477 100644 --- a/config.yml +++ b/config.yml @@ -2,4 +2,4 @@ docker: DOCKER_HUB_USERNAME: ujstor DOCKER_REPO_NAME: portfolio-web-go VERSION_PART: Patch # Patch, Minor, major - PUSH_TO_DOCKER: false + PUSH_TO_DOCKER: true From c92b75df31d969382a44e8ce126637e4a1f6126e Mon Sep 17 00:00:00 2001 From: Ujstor Date: Fri, 21 Jun 2024 23:17:56 +0200 Subject: [PATCH 08/10] update --- .github/workflows/docker-image.yml | 1 - README.md | 24 +++++++++++++++++++++--- docker-compose-prod.yml | 2 -- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index aa5df54..7428b61 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -3,7 +3,6 @@ name: Docker image on: push: branches: - - refactor - master jobs: docker: diff --git a/README.md b/README.md index 7fc0725..faddece 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,30 @@ This static website is built with Go and Templ. +Complete website in singe binary. + +## Docker image Workflow +Variables are defined in config.yml and can be updated upon commit for new image tag: + +```bash +docker: + DOCKER_HUB_USERNAME: ujstor + DOCKER_REPO_NAME: portfolio-web-go + VERSION_PART: Patch # Patch, Minor, major + PUSH_TO_DOCKER: true +``` +If the image does not exist, the default image tag is 0.0.1 for Patch, 0.1.0 for Minor, 1.0.0 for Major. Semantic versioning is employed upon commit, automatically incrementing the version. + +Workflow also requires DockerHub login credentials, username and password configuration in the Action secret: + +```bash +username: ${{ secrets.DOCKERHUB_USERNAME }} +password: ${{ secrets.DOCKERHUB_TOKEN }} +``` + ## Deployment Deployment can be achieved through self-hosting service provided by [Collify](https://coolify.io/docs/installation). -
-
- ![](https://i.imgur.com/pi1WaHy.png) ## MakeFile diff --git a/docker-compose-prod.yml b/docker-compose-prod.yml index 1356e51..4cd46b1 100644 --- a/docker-compose-prod.yml +++ b/docker-compose-prod.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: web: image: ujstor/portfolio-web-go:1.2.1 From 7609c1abbbb63cf720939ea29a13219dbbf4810f Mon Sep 17 00:00:00 2001 From: Ujstor Date: Sat, 22 Jun 2024 00:56:11 +0200 Subject: [PATCH 09/10] releaser, air --- .air.toml | 46 ++++++++++++++++++++++++++++++ .github/workflows/docker-image.yml | 1 + .github/workflows/goreleasaer.yml | 30 +++++++++++++++++++ .gitignore | 6 ++-- .goreleaser.yml | 42 +++++++++++++++++++++++++++ Dockerfile | 14 +++++---- Makefile | 35 +++++++++++++++++++---- README.md | 37 +++++++++++++++++++++--- docker-compose.yml | 16 ++++++++++- go.mod | 1 - go.sum | 2 -- 11 files changed, 208 insertions(+), 22 deletions(-) create mode 100644 .air.toml create mode 100644 .github/workflows/goreleasaer.yml create mode 100644 .goreleaser.yml diff --git a/.air.toml b/.air.toml new file mode 100644 index 0000000..dbc481d --- /dev/null +++ b/.air.toml @@ -0,0 +1,46 @@ +root = "." +testdata_dir = "testdata" +tmp_dir = "tmp" + +[build] + args_bin = [] + bin = "./main" + cmd = "make build" + delay = 1000 + exclude_dir = ["assets", "tmp", "vendor", "testdata"] + exclude_file = [] + exclude_regex = ["_test.go", ".*_templ.go"] + exclude_unchanged = false + follow_symlink = false + full_bin = "" + include_dir = [] + include_ext = ["go", "tpl", "tmpl", "html", "templ"] + include_file = [] + kill_delay = "0s" + log = "build-errors.log" + poll = false + poll_interval = 0 + post_cmd = [] + pre_cmd = [] + rerun = false + rerun_delay = 500 + send_interrupt = false + stop_on_error = false + +[color] + app = "" + build = "yellow" + main = "magenta" + runner = "green" + watcher = "cyan" + +[log] + main_only = false + time = false + +[misc] + clean_on_exit = false + +[screen] + clear_on_rebuild = false + keep_scroll = true diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 7428b61..0add5f0 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -45,3 +45,4 @@ jobs: context: . push: true tags: ${{ env.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_REPO_NAME }}:${{ env.NEW_TAG }} + target: prod diff --git a/.github/workflows/goreleasaer.yml b/.github/workflows/goreleasaer.yml new file mode 100644 index 0000000..cfcb88c --- /dev/null +++ b/.github/workflows/goreleasaer.yml @@ -0,0 +1,30 @@ +name: goreleaser + +on: + push: + tags: + - "v*.*.*" + +permissions: + contents: write + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.22.0' + - + name: Run GoReleaser + uses: goreleaser/goreleaser-action@v5.0.0 + with: + distribution: goreleaser + version: ${{ env.GITHUB_REF_NAME }} + args: release --clean + workdir: ./ + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + diff --git a/.gitignore b/.gitignore index 73e31c5..cd6aac4 100644 --- a/.gitignore +++ b/.gitignore @@ -11,10 +11,8 @@ # Output of the go coverage tool, specifically when used with LiteIDE *.out -# Dependency directories (remove the comment below to include it) -# vendor/ - -# Go workspace file go.work tmp/ *templ.go + +main diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..ff7a12d --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,42 @@ +before: + hooks: + - go mod tidy + +env: + - PACKAGE_PATH=github.com/ujstor/portfolio-web/cmd + +builds: +- binary: "{{ .ProjectName }}" + main: ./cmd/api + goos: + - darwin + - linux + - windows + goarch: + - amd64 + - arm64 + env: + - CGO_ENABLED=0 + ldflags: + - -s -w -X {{.Env.PACKAGE_PATH}}={{.Version}} +release: + prerelease: auto + +universal_binaries: +- replace: true + +archives: + - name_template: > + {{- .ProjectName }}_{{- .Version }}_{{- title .Os }}_{{- if eq .Arch "amd64" }}x86_64{{- else if eq .Arch "386" }}i386{{- else }}{{ .Arch }}{{ end }}{{- if .Arm }}v{{ .Arm }}{{ end -}} + format_overrides: + - goos: windows + format: zip + builds_info: + group: root + owner: root + files: + - README.md + +checksum: + name_template: 'checksums.txt' + diff --git a/Dockerfile b/Dockerfile index 701baae..10396ef 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.22-alpine as build +FROM golang:1.22-alpine as base RUN apk add --no-cache make @@ -9,11 +9,15 @@ RUN go mod download COPY . . -RUN go install github.com/a-h/templ/cmd/templ@latest -RUN templ generate -RUN go build -o main cmd/api/main.go +FROM base as dev +RUN make build +EXPOSE 5000 +CMD [ "sh", "-c", "echo 'y' | make watch" ] + +FROM base as build +RUN make build -FROM alpine:3.20.1 +FROM alpine:3.20.1 as prod WORKDIR /app COPY --from=build /app/main /app/main EXPOSE 5000 diff --git a/Makefile b/Makefile index 2128a01..c1bb24e 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,23 @@ -# Build the application -all: build +all: build docker-build docker-run build: @echo "Building..." - @templ generate + @if command -v templ > /dev/null; then \ + templ generate; \ + else \ + read -p "Go's 'templ' is not installed on your machine. Do you want to install it? [Y/n] " choice; \ + if [ "$$choice" != "n" ] && [ "$$choice" != "N" ]; then \ + go install github.com/a-h/templ/cmd/templ@latest; \ + templ generate; \ + else \ + echo "You chose not to install templ. Exiting..."; \ + exit 1; \ + fi; \ + fi @go build -o main cmd/api/main.go docker-build: - @docker build -t ujstor/portfolio-web-go . + @docker build -t ujstor/portfolio-web-go --target prod . # Run the application run: @@ -25,4 +35,19 @@ clean: @echo "Cleaning..." @rm -f main -.PHONY: all build docker-build run docker-run push clean +watch: + @if command -v air > /dev/null; then \ + air; \ + echo "Watching...";\ + else \ + read -p "Go's 'air' is not installed on your machine. Do you want to install it? [Y/n] " choice; \ + if [ "$$choice" != "n" ] && [ "$$choice" != "N" ]; then \ + go install github.com/air-verse/air@latest; \ + air; \ + echo "Watching...";\ + else \ + echo "You chose not to install air. Exiting..."; \ + exit 1; \ + fi; \ + fi +.PHONY: all build docker-build run docker-run push clean watch diff --git a/README.md b/README.md index faddece..5c6217a 100644 --- a/README.md +++ b/README.md @@ -31,28 +31,57 @@ Deployment can be achieved through self-hosting service provided by [Collify](ht ## MakeFile ```bash -all: build +all: build docker-build docker-run build: @echo "Building..." - @templ generate + @if command -v templ > /dev/null; then \ + templ generate; \ + else \ + read -p "Go's 'templ' is not installed on your machine. Do you want to install it? [Y/n] " choice; \ + if [ "$$choice" != "n" ] && [ "$$choice" != "N" ]; then \ + go install github.com/a-h/templ/cmd/templ@latest; \ + templ generate; \ + else \ + echo "You chose not to install templ. Exiting..."; \ + exit 1; \ + fi; \ + fi @go build -o main cmd/api/main.go docker-build: - @docker build -t ujstor/portfolio-web-go . + @docker build -t ujstor/portfolio-web-go --target prod . +# Run the application run: @go run cmd/api/main.go docker-run: @docker run -p 5000:5000 ujstor/portfolio-web-go +# Push app to DockerHub push: @docker push ujstor/portfolio-web-go +# Clean the binary clean: @echo "Cleaning..." @rm -f main -.PHONY: all build docker-build run docker-run push clean +watch: + @if command -v air > /dev/null; then \ + air; \ + echo "Watching...";\ + else \ + read -p "Go's 'air' is not installed on your machine. Do you want to install it? [Y/n] " choice; \ + if [ "$$choice" != "n" ] && [ "$$choice" != "N" ]; then \ + go install github.com/air-verse/air@latest; \ + air; \ + echo "Watching...";\ + else \ + echo "You chose not to install air. Exiting..."; \ + exit 1; \ + fi; \ + fi +.PHONY: all build docker-build run docker-run push clean watch ``` diff --git a/docker-compose.yml b/docker-compose.yml index 7fe9e4e..5a4fbce 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,21 @@ services: - web: + web-dev: build: context: . dockerfile: Dockerfile + target: dev ports: - 5000:5000 + volumes: + - ./:/app + + web-prod: + build: + context: . + dockerfile: Dockerfile + target: prod + ports: + - 5000:5000 + +# docker compose up web-dev --build +# docker compose up web-prod --build diff --git a/go.mod b/go.mod index 3a6ee48..411c058 100644 --- a/go.mod +++ b/go.mod @@ -5,5 +5,4 @@ go 1.22.0 require ( github.com/a-h/templ v0.2.707 github.com/go-chi/chi/v5 v5.0.14 - github.com/joho/godotenv v1.5.1 ) diff --git a/go.sum b/go.sum index 239ab57..4c91e94 100644 --- a/go.sum +++ b/go.sum @@ -4,5 +4,3 @@ github.com/go-chi/chi/v5 v5.0.14 h1:PyEwo2Vudraa0x/Wl6eDRRW2NXBvekgfxyydcM0WGE0= github.com/go-chi/chi/v5 v5.0.14/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= 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/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= From 9a103bc3a326dba0e6eb72f0235816402810ed4d Mon Sep 17 00:00:00 2001 From: Ujstor Date: Sat, 22 Jun 2024 01:06:34 +0200 Subject: [PATCH 10/10] goreleaser --- .github/workflows/goreleasaer.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/goreleasaer.yml b/.github/workflows/goreleasaer.yml index cfcb88c..d05ae4a 100644 --- a/.github/workflows/goreleasaer.yml +++ b/.github/workflows/goreleasaer.yml @@ -17,8 +17,13 @@ jobs: uses: actions/setup-go@v4 with: go-version: '1.22.0' - - - name: Run GoReleaser + + - name: Install dependencies + run: | + go install github.com/a-h/templ/cmd/templ@latest + templ generate + + - name: Run GoReleaser uses: goreleaser/goreleaser-action@v5.0.0 with: distribution: goreleaser