commit cfa8450f9db8a011452c6464ed1ef1cf63efeb62 Author: Marcus Noble Date: Sun Aug 7 13:32:43 2022 +0100 Initial release Signed-off-by: Marcus Noble diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ad062f4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,170 @@ +### Git ### +# Created by git for backups. To disable backups in Git: +# $ git config --global mergetool.keepBackup false +*.orig + +# Created by git when using merge tools for conflicts +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*_BACKUP_*.txt +*_BASE_*.txt +*_LOCAL_*.txt +*_REMOTE_*.txt + +### Go ### +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +### Go Patch ### +/vendor/ +/Godeps/ + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# rollup.js default build output +dist/ + +# Storybook build outputs +.out +.storybook-out + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# Temporary folders +tmp/ +temp/ + +# VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace +.history/ + +# MacOS +# General +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..783d93a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM golang:1.17-alpine AS builder +RUN apk update && apk add --no-cache git && apk add -U --no-cache ca-certificates +WORKDIR /app/ +ADD go.mod go.sum ./ +RUN go mod download +ADD . . +RUN GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-w -s" -o marcusnoble . + +FROM scratch +WORKDIR /app/ +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ +COPY --from=builder /app/marcusnoble /app/marcusnoble +ENTRYPOINT ["/app/marcusnoble"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7c8f474 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +MIT License Copyright (c) 2022 - present Marcus Noble + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..21f76f9 --- /dev/null +++ b/Makefile @@ -0,0 +1,61 @@ +.DEFAULT_GOAL := default + +IMAGE ?= rg.fr-par.scw.cloud/averagemarcus-private/marcusnoble:latest + +.PHONY: test # Run all tests, linting and format checks +test: lint check-format run-tests + +.PHONY: lint # Perform lint checks against code +lint: + @echo "⚠️ 'lint' unimplemented" + +.PHONY: check-format # Checks code formatting and returns a non-zero exit code if formatting errors found +check-format: + @echo "⚠️ 'check-format' unimplemented" + +.PHONY: format # Performs automatic format fixes on all code +format: + @echo "⚠️ 'format' unimplemented" + +.PHONY: run-tests # Runs all tests +run-tests: + @echo "⚠️ 'run-tests' unimplemented" + +.PHONY: fetch-deps # Fetch all project dependencies +fetch-deps: + @echo "⚠️ 'fetch-deps' unimplemented" + +.PHONY: build # Build the project +build: lint check-format fetch-deps + @echo "⚠️ 'build' unimplemented" + +.PHONY: docker-build # Build the docker image +docker-build: + @docker build -t $(IMAGE) . + +.PHONY: docker-publish # Push the docker image to the remote registry +docker-publish: + @docker push $(IMAGE) + +.PHONY: run # Run the application +run: docker-build + @docker run --rm -it -p 8080:80 -v $$(pwd)/src:/usr/share/nginx/html $(IMAGE) + +.PHONY: ci # Perform CI specific tasks to perform on a pull request +ci: + @echo "⚠️ 'ci' unimplemented" + +.PHONY: release # Release the latest version of the application +release: + @kubectl --context scaleway --namespace marcusnoble set image deployment marcusnoble web=rg.fr-par.scw.cloud/averagemarcus-private/marcusnoble:$(SHA) + +.PHONY: help # Show this list of commands +help: + @echo "marcusnoble" + @echo "Usage: make [target]" + @echo "" + @echo "target description" | expand -t20 + @echo "-----------------------------------" + @grep '^.PHONY: .* #' Makefile | sed 's/\.PHONY: \(.*\) # \(.*\)/\1 \2/' | expand -t20 + +default: test build diff --git a/README.md b/README.md new file mode 100644 index 0000000..39b0104 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Marcus Noble + +Personal profile of Marcus Noble + +Available at https://marcusnoble.com diff --git a/data.yaml b/data.yaml new file mode 100644 index 0000000..86c31aa --- /dev/null +++ b/data.yaml @@ -0,0 +1,116 @@ +intro: | + I'm a platform engineer working at Giant Swarm working on building managed Kubernetes solutions and related projects. My area of focus in recent years has been around Go, ⎈ Kubernetes, containers and DevOps but originally started out as a web developer and JavaScript enthusiast. I'm a “tinkerer” and like to dabble with 3D printing and experimenting with smart home tech. +social: + - url: https://marcusnoble.co.uk + title: My articles on my Blog + content: | + + + + Blog + - url: https://marcusnoble.co.uk + title: My articles on my Blog + content: | + + C.V. + - url: https://www.github.com/AverageMarcus + title: AverageMarcus on GitHubBlog + content: | + + GitHub + - url: https://twitter.com/Marcus_Noble_ + title: "@Marcus_Noble_ on TwitterBlog" + content: | + + Twitter + - url: https://k8s.social/@Marcus + title: "@marcus@k8s.social on MastodonBlog" + content: | + + + + + Mastodon + - url: https://www.linkedin.com/in/marcusnoble/ + title: Connect with me on LinkedinBlog + content: | + + + + + + + LinkedIn + - url: https://noti.st/averagemarcus + title: View my previous talks on NotistBlog + content: | + + + + Notist + - url: https://youtube.com/playlist?list=PLT41C0Ggz5wa66-AU5xapbOuzkUKUPLzi + title: My appearances on YouTubeBlog + content: | + + YouTube +projects: + - url: https://github.com/AverageMarcus/kube-image-prefetch + name: kube-image-prefetch + description: Pre-pull all images, on all nodes, within a Kubernetes cluster + languages: + - color: "#00ADD8" + name: Go + - url: https://github.com/AverageMarcus/tweetsvg + name: tweetsvg + description: Generate an SVG for a given Tweet ID + languages: + - color: "#e34c26" + name: HTML + - color: "#00ADD8" + name: Go + - url: https://github.com/AverageMarcus/opengraph-image-gen + name: opengraph-image-gen + description: Dynamically generate OpenGraph social share images + languages: + - color: "#e34c26" + name: HTML + - color: "#00ADD8" + name: Go + - url: https://github.com/AverageMarcus/speedtest-exporter + name: speedtest-exporter + description: A prometheus exporter for Speedtest.net results + languages: + - color: "#00ADD8" + name: Go + - url: https://github.com/AverageMarcus/feed-fetcher + name: feed-fetcher + description: Returns the RSS feed associated with the given URL + languages: + - color: "#e34c26" + name: HTML + - color: "#00ADD8" + name: Go +events: + - date: "2022-09-27" + humanDate: "September 27, 2022" + url: https://www.meetup.com/DevOps-Notts/ + eventName: DevOpsNotts + details: + - name: The Wonders and Woes of Webhooks + type: Meetup Talk + - date: "2022-09-29" + humanDate: "September 29 - 30, 2022" + url: https://devopsdays.org/events/2022-london/welcome/ + eventName: DevOpsDays London 2022 + details: + - name: What DragonBall can teach us about being engineers + type: Ignite Talk + - date: "2022-10-03" + humanDate: "October 3 - 4, 2022" + url: https://kubehuddle.com/2022/ + eventName: KubeHuddle 2022 + details: + - name: The Wonders and Woes of Webhooks + type: Presentation + - name: What DragonBall can teach us about being engineers + type: Lightning Talk diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..7a368d4 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module marcusnoble + +go 1.17 + +require gopkg.in/yaml.v2 v2.4.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..dd0bc19 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +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.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/main.go b/main.go new file mode 100644 index 0000000..1f02c24 --- /dev/null +++ b/main.go @@ -0,0 +1,87 @@ +package main + +import ( + "embed" + "fmt" + "html/template" + "log" + "net/http" + "os" + "strings" + + "gopkg.in/yaml.v2" +) + +var ( + //go:embed src data.yaml + res embed.FS + port string +) + +func init() { + var ok bool + if port, ok = os.LookupEnv("PORT"); !ok { + port = "8080" + } +} + +func main() { + dataBytes, err := res.ReadFile("data.yaml") + if err != nil { + panic(err) + } + var data map[string]interface{} + if err := yaml.Unmarshal(dataBytes, &data); err != nil { + panic(err) + } + + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + page := "src" + r.URL.Path + if strings.HasSuffix(page, "/") { + page = page + "index.html" + } + + if strings.HasSuffix(page, ".html") { + tpl, err := template.ParseFS(res, page) + if err != nil { + log.Printf("page %s (%s) not found...", r.RequestURI, page) + w.WriteHeader(http.StatusInternalServerError) + return + } + w.WriteHeader(http.StatusOK) + + tpl.Funcs(template.FuncMap(map[string]interface{}{ + "html": func(str string) template.HTML { + return template.HTML(str) + }, + })) + + if err := tpl.Execute(w, data); err != nil { + return + } + } else { + + // Serve up the best file format for image + if strings.Contains(page, "headshot-transparent.png") { + if strings.Contains(r.Header.Get("Accept"), "image/avif") { + page = strings.Replace(page, ".png", ".avif", 1) + } else if strings.Contains(r.Header.Get("Accept"), "image/webp") { + page = strings.Replace(page, ".png", ".webp", 1) + } + } + + body, err := res.ReadFile(page) + if err != nil { + log.Printf("file %s (%s) not found...", r.RequestURI, page) + w.WriteHeader(http.StatusInternalServerError) + return + } + w.Write(body) + return + } + }) + // http.FileServer(http.FS(res)) + + fmt.Println("Server started at port " + port) + log.Fatal(http.ListenAndServe(":"+port, nil)) +} diff --git a/src/fonts/OrkneyBold.ttf b/src/fonts/OrkneyBold.ttf new file mode 100644 index 0000000..f011bb2 Binary files /dev/null and b/src/fonts/OrkneyBold.ttf differ diff --git a/src/fonts/OrkneyLight.ttf b/src/fonts/OrkneyLight.ttf new file mode 100644 index 0000000..fbef6d7 Binary files /dev/null and b/src/fonts/OrkneyLight.ttf differ diff --git a/src/fonts/OrkneyRegular.ttf b/src/fonts/OrkneyRegular.ttf new file mode 100644 index 0000000..c70a5f9 Binary files /dev/null and b/src/fonts/OrkneyRegular.ttf differ diff --git a/src/headshot-transparent.avif b/src/headshot-transparent.avif new file mode 100644 index 0000000..cf2458a Binary files /dev/null and b/src/headshot-transparent.avif differ diff --git a/src/headshot-transparent.png b/src/headshot-transparent.png new file mode 100755 index 0000000..7811840 Binary files /dev/null and b/src/headshot-transparent.png differ diff --git a/src/headshot-transparent.webp b/src/headshot-transparent.webp new file mode 100644 index 0000000..4fb2038 Binary files /dev/null and b/src/headshot-transparent.webp differ diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..9673394 --- /dev/null +++ b/src/index.html @@ -0,0 +1,295 @@ + + + + + + + Marcus Noble + + + + + + +
+
+
+

Hi 👋, I'm Marcus

+ +

+ {{ .intro | html }} +

+
+ + + +
+

My Open Source Projects 💻

+ +

+ All my Open Source projects can be find on my GitHub profile (as well as my personal Gitea instance, GitLab, Codeberg and BitBucket). Below are a selection of highlights. +

+ + +
+ +
+

Upcoming Events 🗓

+ +
    + {{ range .events }} +
  • + +
    + {{ .eventName }} + {{ range .details }} +
    + {{ .name }} + {{ .type }} +
    + {{ end }} +
    +
  • + {{ end }} +
+
+
+ +