feat: update CV and project

Changes:

- Add Adarga employment section
- Refined Experian employment section
- Removed GitLab CI files
- Updated Dockerfile
- Updated Magefiles
This commit is contained in:
Dan Anglin 2023-02-14 07:30:27 +00:00
parent 4a2d557a52
commit 95cf8dbcd6
Signed by: dananglin
GPG key ID: 0C1D44CFBEE68638
14 changed files with 76 additions and 289 deletions

1
.gitignore vendored
View file

@ -1,2 +1 @@
__output/* __output/*
!__output/cv.pdf

View file

@ -1,15 +0,0 @@
---
stages:
- test
- build
- publish
variables:
IMAGE_NAME: ${CI_REGISTRY}/${CI_PROJECT_PATH}/cv-builder
IMAGE_TAG: ${CI_COMMIT_REF_SLUG}-${CI_COMMIT_SHORT_SHA}
RELEASE_CV_FILENAME: cv-DanAnglin-${CI_COMMIT_REF_NAME}.pdf
include:
- template: 'Workflows/MergeRequest-Pipelines.gitlab-ci.yml'
- local: '/.gitlab/ci/docker-gitlab-ci.yml'
- local: '/.gitlab/ci/cv-gitlab-ci.yml'

View file

@ -1,128 +0,0 @@
---
#--------------------------------------------#
# Hidden job templates for CV build pipeline #
#--------------------------------------------#
.use-cv-builder:
image: ${IMAGE_NAME}:master-44f2a31c
.cv-default-job-rules:
rules:
- when: always
.cv-publish-job-rules:
rules:
- if: '$CI_COMMIT_REF_NAME =~ /^[0-9]{4}(.[0-9]{2}){2}$/ && $CI_PROJECT_PATH == "dananglin/cv"'
when: always
.default-tags:
tags:
- dananglin-general
.release-tags:
tags:
- dananglin-cv-release
#------------------------------------#
# Visible jobs for CV build pipeline #
#------------------------------------#
test:spellcheck:
extends:
- .cv-default-job-rules
- .default-tags
- .use-cv-builder
script:
- cv-make spellcheck
stage: test
test:pdf:
extends:
- .cv-default-job-rules
- .default-tags
- .use-cv-builder
script:
- cv-make pdf
stage: test
build:pdf:
artifacts:
expire_in: "30 minutes"
paths:
- __output/cv.pdf
extends:
- .default-tags
- .use-cv-builder
needs:
- job: "test:spellcheck"
artifacts: false
- job: "test:pdf"
artifacts: false
rules:
- if: '$CI_MERGE_REQUEST_IID'
when: always
script:
- cv-make pdf
stage: build
build:pdf-for-publish:
artifacts:
expire_in: "1 year"
name: cv-DanAnglin-${CI_COMMIT_REF_NAME}
paths:
- ${RELEASE_CV_FILENAME}
- build_job_id
extends:
- .cv-publish-job-rules
- .default-tags
- .use-cv-builder
needs:
- job: "test:spellcheck"
artifacts: false
- job: "test:pdf"
artifacts: false
script:
- cv-make pdf
- mv __output/cv.pdf ${RELEASE_CV_FILENAME}
- echo "${CI_JOB_ID}" > build_job_id
stage: build
publish:pdf:online:
before_script:
- export BUILD_JOB_ID=$( cat build_job_id )
extends:
- .cv-publish-job-rules
- .release-tags
image: registry.gitlab.com/gitlab-org/release-cli:v0.3.0
needs:
- job: "build:pdf-for-publish"
artifacts: true
script:
- 'echo "Publishing CV for release ${CI_COMMIT_REF_NAME}"'
- >
release-cli create --name "CV - ${CI_COMMIT_REF_NAME}"
--description "CV published with the release-cli tool for version ${CI_COMMIT_REF_NAME}"
--tag-name "${CI_COMMIT_REF_NAME}"
--ref "${CI_COMMIT_REF_NAME}"
--assets-links-name "${RELEASE_CV_FILENAME}"
--assets-links-url "https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/jobs/${BUILD_JOB_ID}/artifacts/${RELEASE_CV_FILENAME}"
stage: "publish"
variables:
GIT_STRATEGY: "none"
# Private releases rebuilds the CV with the extra details.
publish:pdf:private:
extends:
- .cv-publish-job-rules
- .release-tags
- .use-cv-builder
needs:
- job: "test:spellcheck"
artifacts: false
- job: "test:pdf"
artifacts: false
script:
- cv-make pdf
- mv __output/cv.pdf ${CV_DEPLOY_DIR}/${RELEASE_CV_FILENAME}
stage: publish
variables:
CV_DEPLOY_DIR: "/CV"
CV_CONTACT_PHONE: $RELEASE_CV_CONTACT_PHONE

View file

@ -1,66 +0,0 @@
---
#--------------------------------------------------------#
# Hidden job templates for Docker build/publish pipeline #
#--------------------------------------------------------#
.docker-build-setup:
image: docker:19.03.12
services:
- docker:19.03.12-dind
before_script:
- apk add --no-cache go
.dockerfile-lint:
stage: test
image: hadolint/hadolint:v2.8.0-alpine
script:
- "hadolint docker/Dockerfile"
.dockerbuild-test:
stage: test
extends: .docker-build-setup
.docker-test-rules:
rules:
- changes:
- "docker/Dockerfile"
- "*.go"
when: always
- if: '$CI_COMMIT_REF_NAME =~ /^[0-9]{4}(.[0-9]{2}){2}$/'
when: never
.docker-publish-pre-post:
stage: publish
extends: .docker-build-setup
before_script:
- apk add --no-cache go
- docker login -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD} ${CI_REGISTRY}
after_script:
- docker logout ${CI_REGISTRY}
.docker-publish-rules:
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PROJECT_PATH == "dananglin/cv" && $CI_PIPELINE_SOURCE == "web" && $BUILD_DOCKER_IMAGE == "true"'
when: always
#------------------------------------------------#
# Visible jobs for Docker build/publish pipeline #
#------------------------------------------------#
test:dockerfile:lint:
extends:
- .dockerfile-lint
- .docker-test-rules
test:docker:build:
extends:
- .dockerbuild-test
- .docker-test-rules
script:
- go run mage.go image
publish:docker-image:
extends:
- .docker-publish-pre-post
- .docker-publish-rules
script:
- go run mage.go publishImage

View file

@ -1,18 +1,18 @@
{ {
"firstName": "Dan", "firstName": "Dan",
"lastName": "Anglin", "lastName": "Anglin",
"jobTitle": "Platform Engineer", "jobTitle": "DevOps Engineer",
"contact": { "contact": {
"email": "d.n.i.anglin@gmail.com", "email": "d.n.i.anglin@gmail.com",
"location": "Nottingham, UK" "location": "Nottingham, UK"
}, },
"links": { "links": {
"linkedin": "https://www.linkedin.com/in/dan-anglin-0174671b7", "linkedin": "https://www.linkedin.com/in/dan-anglin-0174671b7",
"gitlab": "https://gitlab.com/dananglin" "github": "https://github.com/dananglin"
}, },
"summary": [ "summary": [
"I am a strong engineering professional with over seven years of experience in Platform Automation and DevOps.", "I am a strong engineering professional with over seven years of experience in Platform Automation and DevOps.",
"I enjoy working with Go, Terraform, containerisation technologies and GNU/Linux.", "I enjoy working with Go, Kubernetes, Terraform, containerisation technologies and GNU/Linux.",
"I am particularly keen on developing my skills in Go and growing as an experienced Software Engineer." "I am particularly keen on developing my skills in Go and growing as an experienced Software Engineer."
], ],
"technologies": [ "technologies": [
@ -28,8 +28,7 @@
"category": "Cloud Hosting", "category": "Cloud Hosting",
"values": [ "values": [
"AWS", "AWS",
"Linode", "Linode"
"Openstack"
] ]
}, },
{ {
@ -41,12 +40,14 @@
] ]
}, },
{ {
"category": "Continuous Integration", "category": "CI/CD",
"values": [ "values": [
"Argo CD",
"Argo Workflows",
"Dagger",
"Git", "Git",
"GitLab/GitLab CI", "GitLab CI",
"Jenkins", "GitHub Actions"
"Nexus"
] ]
}, },
{ {
@ -79,7 +80,7 @@
"employment": [ "employment": [
{ {
"company": "Adarga", "company": "Adarga",
"location": "Remote", "location": "London (Remote)",
"jobTitle": "DevOps Engineer", "jobTitle": "DevOps Engineer",
"duration": { "duration": {
"start": { "start": {
@ -88,11 +89,15 @@
}, },
"present": "yes" "present": "yes"
}, },
"details": [] "details": [
"Designed and built the infrastructure to host an Enterprise Graph Data Platform on EKS.",
"The infrastructure was provisioned using technologies such as Terraform, Helm, Argo CD, Argo Workflows and AWS services.",
"A typical day would include activities such as deploying improvements to Production environments with Terraform and Atlantis, and deploying or updating applications on EKS using GitHub and Argo CD."
]
}, },
{ {
"company": "Experian", "company": "Experian",
"location": "Nottingham", "location": "Nottingham (Hybrid)",
"jobTitle": "Platform Engineer", "jobTitle": "Platform Engineer",
"duration": { "duration": {
"start": { "start": {
@ -105,17 +110,17 @@
} }
}, },
"details": [ "details": [
"Gained knowledge and and experience with IAC technologies such Terraform and Helm.", "Gained knowledge and experience with IAC technologies such Terraform and Helm.",
"Became a core contributor to a large Terraform project that builds EKS environments for development teams to migrate their development activities onto EKS.", "Became a core contributor to a large Terraform project to build EKS environments for development teams to migrate their development activities onto EKS.",
"Built a new EKS environment using the mentioned Terraform project and helped migrate a live production environment within a short time frame.", "Built a new EKS environment using the mentioned Terraform project and helped migrate a live production environment within a short time frame.",
"Currently providing support for development teams to improve their development experience on EKS by resolving platform/deployment issues and improving the Terraform project to make deploying EKS environments easier for DevOps practitioners and SREs.", "Provided support for development teams to improve their development experience on EKS by resolving platform/deployment issues and improving the Terraform project to make deploying EKS environments easier for DevOps practitioners and SREs.",
"Currently supporting Platform teams to build new production EKS environments.", "Supported platform teams to build new production EKS environments.",
"Currently researching new capabilities that can help reduce running costs, optimise node group configuration, and ease environment management for DevOps practitioners and SREs." "Researched new capabilities to help reduce running costs of the EKS environments and ease environment management for DevOps practitioners and SREs."
] ]
}, },
{ {
"company": "Ocado Technology", "company": "Ocado Technology",
"location": "Hatfield, Hertfordshire", "location": "Hatfield, Hertfordshire (Onsite)",
"jobTitle": "Platform Automation Engineer", "jobTitle": "Platform Automation Engineer",
"duration": { "duration": {
"start": { "start": {
@ -139,7 +144,7 @@
}, },
{ {
"company": "QA Consulting (Contracted to CACI)", "company": "QA Consulting (Contracted to CACI)",
"location": "London", "location": "London (Onsite)",
"jobTitle": "DevOps Consultant", "jobTitle": "DevOps Consultant",
"duration": { "duration": {
"start": { "start": {
@ -162,7 +167,7 @@
}, },
{ {
"company": "QA Consulting (Contracted to IBM)", "company": "QA Consulting (Contracted to IBM)",
"location": "Home Office, London", "location": "Home Office, London (Onsite)",
"jobTitle": "DevOps Consultant", "jobTitle": "DevOps Consultant",
"duration": { "duration": {
"start": { "start": {
@ -184,7 +189,7 @@
}, },
{ {
"company": "QA Consulting", "company": "QA Consulting",
"location": "Worthing", "location": "Worthing (Onsite)",
"jobTitle": "Trainee DevOps Consultant", "jobTitle": "Trainee DevOps Consultant",
"duration": { "duration": {
"start": { "start": {
@ -205,7 +210,7 @@
}, },
{ {
"company": "School of Systems Engineering, University of Reading", "company": "School of Systems Engineering, University of Reading",
"location": "Reading", "location": "Reading (Onsite)",
"jobTitle": "Undergraduate Researcher", "jobTitle": "Undergraduate Researcher",
"duration": { "duration": {
"start": { "start": {

View file

@ -1,4 +1,4 @@
FROM golang:1.17.6-buster AS builder FROM golang:1.19-buster AS builder
RUN git clone https://github.com/magefile/mage "${GOPATH}/src/mage" RUN git clone https://github.com/magefile/mage "${GOPATH}/src/mage"
@ -21,26 +21,25 @@ COPY --from=builder /usr/local/bin/cv-make /usr/local/bin
# Install dependencies # Install dependencies
RUN \ RUN \
apt-get update && \ apt-get update \
apt-get install -y \ && apt-get install -y \
fonts-crosextra-carlito=20130920-1 \ fonts-crosextra-carlito \
rsync=3.1.3-6 \ rsync \
curl=7.64.0-4+deb10u2 \ curl= \
aspell=0.60.7~20110707-6+deb10u1 \ aspell \
aspell-en=2018.04.16-0-1 \ aspell-en \
&& \ && apt-get clean autoclean \
apt-get clean autoclean && \ && apt-get autoremove -y \
apt-get autoremove -y && \ && rm -rf /var/lib/apt/lists/* /tmp/* \
rm -rf /var/lib/apt/lists/* /tmp/* && \ && mkdir /opt/context
mkdir /opt/context
WORKDIR /opt/context WORKDIR /opt/context
# Install ConTeXt standalone # Install ConTeXt standalone
RUN \ RUN \
curl -LO http://minimals.contextgarden.net/setup/first-setup.sh && \ curl -LO http://minimals.contextgarden.net/setup/first-setup.sh \
sh first-setup.sh --context=current --engine=luatex && \ && sh first-setup.sh --context=current --engine=luatex \
rm -rf /opt/context/tex/texmf-context/doc && rm -rf /opt/context/tex/texmf-context/doc
ENV PATH=${PATH}:/opt/context/tex/texmf-linux-64/bin \ ENV PATH=${PATH}:/opt/context/tex/texmf-linux-64/bin \
OSFONTDIR=/usr/share/fonts OSFONTDIR=/usr/share/fonts

4
go.mod
View file

@ -1,5 +1,5 @@
module gitlab.com/dananglin/cv module gitlab.com/dananglin/cv
go 1.12 go 1.19
require github.com/magefile/mage v1.10.0 require github.com/magefile/mage v1.14.0

4
go.sum
View file

@ -1,2 +1,2 @@
github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g= github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo=
github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=

13
mage.go
View file

@ -1,13 +0,0 @@
// +build ignore
package main
import (
"os"
"github.com/magefile/mage/mage"
)
func main() {
os.Exit(mage.Main())
}

View file

@ -1,4 +1,6 @@
package helpers //go:build mage
package main
type Cv struct { type Cv struct {
FirstName string `json:"firstName"` FirstName string `json:"firstName"`
@ -21,7 +23,7 @@ type Contact struct {
type Links struct { type Links struct {
LinkedIn string `json:"linkedin"` LinkedIn string `json:"linkedin"`
GitLab string `json:"gitlab"` GitHub string `json:"github"`
} }
type Technologies struct { type Technologies struct {

View file

@ -1,10 +1,11 @@
package helpers //go:build mage
package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"strings" "strings"
@ -17,10 +18,10 @@ const (
defaultImageTag string = "latest" defaultImageTag string = "latest"
) )
// ImageName generates the docker image name from the environment // imageName generates the docker image name from the environment
// variables IMAGE_NAME and IMAGE_TAG. Default vaules will be used // variables IMAGE_NAME and IMAGE_TAG. Default vaules will be used
// if these variables are not set or empty. // if these variables are not set or empty.
func ImageName() string { func imageName() string {
name := os.Getenv("IMAGE_NAME") name := os.Getenv("IMAGE_NAME")
if len(name) == 0 { if len(name) == 0 {
name = defaultImageName name = defaultImageName
@ -34,22 +35,24 @@ func ImageName() string {
return name + ":" + tag return name + ":" + tag
} }
// CreateCVTex generates the CV docuemnt as a Tex file. // createCVTex generates the CV docuemnt as a Tex file.
func CreateCVTex(cvJsonDataFile, cvTemplateDir, cvOutputDir, cvOutputFileName string) error { func createCVTex(cvJsonDataFile, cvTemplateDir, cvOutputDir, cvOutputFileName string) error {
fmt.Printf("INFO: Attempting to read data from %s...\n", cvJsonDataFile) fmt.Printf("INFO: Attempting to read data from %s...\n", cvJsonDataFile)
data, err := ioutil.ReadFile(cvJsonDataFile) data, err := os.ReadFile(cvJsonDataFile)
if err != nil { if err != nil {
return fmt.Errorf("ERROR: Unable to read data from file. %s\n", err.Error()) return fmt.Errorf("unable to read data from file. %w", err)
} }
fmt.Println("INFO: Successfully read data.") fmt.Println("INFO: Successfully read data.")
fmt.Println("INFO: Attempting to unmarshal JSON data...") fmt.Println("INFO: Attempting to unmarshal JSON data...")
var cv Cv var cv Cv
if err = json.Unmarshal(data, &cv); err != nil { if err = json.Unmarshal(data, &cv); err != nil {
return fmt.Errorf("ERROR: Unable to unmarshal JSON data. %s\n", err.Error()) return fmt.Errorf("unable to unmarshal JSON data; %w", err)
} }
fmt.Println("INFO: JSON unmarshalling was successful.") fmt.Println("INFO: JSON unmarshalling was successful.")
// if CV_CONTACT_PHONE is set then add it to the CV // if CV_CONTACT_PHONE is set then add it to the CV
@ -62,12 +65,12 @@ func CreateCVTex(cvJsonDataFile, cvTemplateDir, cvOutputDir, cvOutputFileName st
fmt.Printf("INFO: Attempting to create output file %s...\n", cvOutputPath) fmt.Printf("INFO: Attempting to create output file %s...\n", cvOutputPath)
if err = os.MkdirAll(cvOutputDir, 0750); err != nil { if err = os.MkdirAll(cvOutputDir, 0750); err != nil {
return fmt.Errorf("ERROR: Unable to create output directory %s. %s\n", cvOutputDir, err.Error()) return fmt.Errorf("unable to create output directory %s; %w", cvOutputDir, err)
} }
output, err := os.Create(cvOutputPath) output, err := os.Create(cvOutputPath)
if err != nil { if err != nil {
return fmt.Errorf("ERROR: Unable to create output file %s. %s\n", cvOutputPath, err.Error()) return fmt.Errorf("unable to create output file %s; %w", cvOutputPath, err)
} }
fmt.Printf("INFO: Successfully created output file %s.\n", cvOutputPath) fmt.Printf("INFO: Successfully created output file %s.\n", cvOutputPath)
defer output.Close() defer output.Close()
@ -82,17 +85,17 @@ func CreateCVTex(cvJsonDataFile, cvTemplateDir, cvOutputDir, cvOutputFileName st
t := template.Must(template.New("cv.tmpl.tex").Funcs(fmap).Delims("<<", ">>").ParseGlob(cvTemplateDir + "*.tmpl.tex")) t := template.Must(template.New("cv.tmpl.tex").Funcs(fmap).Delims("<<", ">>").ParseGlob(cvTemplateDir + "*.tmpl.tex"))
if err = t.Execute(output, cv); err != nil { if err = t.Execute(output, cv); err != nil {
return fmt.Errorf("ERROR: Unable to execute the CV template. %s\n", err.Error()) return fmt.Errorf("unable to execute the CV template. %w", err)
} }
fmt.Println("INFO: Template execution successful.") fmt.Println("INFO: Template execution successful.")
return nil return nil
} }
func SpellCheck(dataFile, aspellPersonalWordlist string) error { func spellCheck(dataFile, aspellPersonalWordlist string) error {
fmt.Printf("INFO: Reading data from %s...\n", dataFile) fmt.Printf("INFO: Reading data from %s...\n", dataFile)
data, err := ioutil.ReadFile(dataFile) data, err := os.ReadFile(dataFile)
if err != nil { if err != nil {
return fmt.Errorf("unable to read data from %s, %s", dataFile, err.Error()) return fmt.Errorf("unable to read data from %s, %s", dataFile, err.Error())
} }

View file

@ -1,4 +1,4 @@
// +build mage //go:build mage
package main package main
@ -7,7 +7,6 @@ import (
"github.com/magefile/mage/mg" "github.com/magefile/mage/mg"
"github.com/magefile/mage/sh" "github.com/magefile/mage/sh"
"gitlab.com/dananglin/cv/helpers"
) )
const ( const (
@ -27,7 +26,7 @@ var Default = Pdf
// Any error found while gathering the list is returned. // Any error found while gathering the list is returned.
// This function depends on the aspell program. // This function depends on the aspell program.
func SpellCheck() error { func SpellCheck() error {
return helpers.SpellCheck(cvJsonDataFile, aspellPersonalWordlist) return spellCheck(cvJsonDataFile, aspellPersonalWordlist)
} }
// Tex takes the CV data file and generates the output tex file from // Tex takes the CV data file and generates the output tex file from
@ -37,7 +36,7 @@ func Tex() error {
mg.Deps(Clean) mg.Deps(Clean)
return helpers.CreateCVTex(cvJsonDataFile, cvTemplateDir, cvOutputDir, cvOutputFileName) return createCVTex(cvJsonDataFile, cvTemplateDir, cvOutputDir, cvOutputFileName)
} }
// Pdf takes the output tex file generated by the Tex target and // Pdf takes the output tex file generated by the Tex target and
@ -53,7 +52,7 @@ func Pdf() error {
// Image builds the CV builder docker image. // Image builds the CV builder docker image.
func Image() error { func Image() error {
image := helpers.ImageName() image := imageName()
return sh.Run("docker", "build", "-f", dockerfile, "-t", image, ".") return sh.Run("docker", "build", "-f", dockerfile, "-t", image, ".")
} }
@ -63,7 +62,7 @@ func Image() error {
func PublishImage() error { func PublishImage() error {
mg.Deps(Image) mg.Deps(Image)
image := helpers.ImageName() image := imageName()
return sh.Run("docker", "push", image) return sh.Run("docker", "push", image)
} }

View file

@ -1,4 +1,6 @@
package helpers //go:build mage
package main
import ( import (
"fmt" "fmt"

View file

@ -10,7 +10,7 @@
{\bf Location:} <<.Contact.Location>>\blank[medium] {\bf Location:} <<.Contact.Location>>\blank[medium]
<<if .Links.LinkedIn>>{\bf LinkedIn:} <<.Links.LinkedIn>>\blank[none]<<end>> <<if .Links.LinkedIn>>{\bf LinkedIn:} <<.Links.LinkedIn>>\blank[none]<<end>>
<<if .Links.GitLab>>{\bf GitLab:} <<.Links.GitLab>>\blank[none]<<end>> <<if .Links.GitHub>>{\bf GitHub:} <<.Links.GitHub>>\blank[none]<<end>>
\stoptitleAndContact \stoptitleAndContact
\section{SUMMARY} \section{SUMMARY}