Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 14 additions & 31 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,31 @@ name: Deploy Resume
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

env:
# These are GitHub Camo image proxy URLs.
# To obtain them: paste the raw S3 image link into a GitHub Markdown file (README, issue, etc.),
# let GitHub render it, then right-click → "Copy image address".
RESUME_IMAGE_URL: "https://camo.githubusercontent.com/19e0bf2e0d1d9b58f0bd2a4bf66b214f817d5ae7e72ff4e3684b8b15522be23f/68747470733a2f2f64616c746f6e2d63762d6172746966616374732e73332e75732d656173742d312e616d617a6f6e6177732e636f6d2f696d616765732f63762e706e67"
COVER_LETTER_IMAGE_URL: "https://camo.githubusercontent.com/31c147493e3d013bd48fcbeda87b802e2a8012a64faf6dc324f640ba7eec4f24/68747470733a2f2f64616c746f6e2d63762d6172746966616374732e73332e75732d656173742d312e616d617a6f6e6177732e636f6d2f696d616765732f636f7665725f6c65747465722e706e67"

jobs:
build-and-deploy:
runs-on: ubuntu-latest
container:
image: daluce/cv:latest
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.AWS_REGION }}

steps:
- name: Checkout source
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y make texlive-latex-base texlive-latex-extra imagemagick

- name: Build resume
run: make all

- name: Upload resume to S3
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}

- name: Copy PDF + images to S3
run: |
aws s3 cp dist/pdfs/ s3://${{ secrets.AWS_S3_BUCKET }}/pdfs/ --recursive
aws s3 cp dist/images/ s3://${{ secrets.AWS_S3_BUCKET }}/images/ --recursive

# Purge GitHub's Camo CDN cache so updated resume/cover letter images show up immediately
# Docs: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/about-anonymized-urls#removing-an-image-from-camos-cache
- name: Clear GitHub Camo cache
run: |
curl -X PURGE "${RESUME_IMAGE_URL}"
curl -X PURGE "${COVER_LETTER_IMAGE_URL}"
- name: Test
run: make test
- name: Upload PDFs and images to S3
# Only upload on pushes to main branch, not PRs
if: github.event_name == 'push'
run: make release
27 changes: 27 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Build and Push Docker Image

on:
push:
branches:
- main
paths:
- 'Dockerfile'

jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}

- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
push: true
tags: daluce/cv:latest
platforms: linux/amd64
15 changes: 15 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM python:3.11-slim

RUN apt-get update && apt-get install -y \
imagemagick \
texlive-latex-base \
texlive-latex-extra \
git \
awscli \
make \
&& apt-get clean && rm -rf /var/lib/apt/lists/*

# Install cvlint
RUN git clone https://github.com/da-luce/cvlint.git
WORKDIR /cvlint
RUN pip install .
99 changes: 53 additions & 46 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: all clean build private cover-letter images help install test
.PHONY: all clean build private cover-letter images help install test release

# Default target
all: build images
Expand All @@ -7,75 +7,82 @@ all: build images
BUILD_DIR := build
DIST_DIR := dist
SRC_DIR := src
PDF_DIR := $(DIST_DIR)/pdfs
IMG_DIR := $(DIST_DIR)/images
CV_NAME := dalton_luce_cv
COVER_LETTER_NAME := cover_letter
S3_BUCKET := dalton-cv-artifacts
AWS_REGION := us-east-1

# These are GitHub Camo image proxy URLs.
# To obtain them: paste the raw S3 image link into a GitHub Markdown file (README, issue, etc.),
# let GitHub render it, then right-click → "Copy image address".
CV_GITHUB_CACHE_URL:= https://camo.githubusercontent.com/19e0bf2e0d1d9b58f0bd2a4bf66b214f817d5ae7e72ff4e3684b8b15522be23f/68747470733a2f2f64616c746f6e2d63762d6172746966616374732e73332e75732d656173742d312e616d617a6f6e6177732e636f6d2f696d616765732f63762e706e67
COVER_GITHUB_CACHE_URL:= https://camo.githubusercontent.com/31c147493e3d013bd48fcbeda87b802e2a8012a64faf6dc324f640ba7eec4f24/68747470733a2f2f64616c746f6e2d63762d6172746966616374732e73332e75732d656173742d312e616d617a6f6e6177732e636f6d2f696d616765732f636f7665725f6c65747465722e706e67

# Help target
help:
@echo "Available targets:"
@echo " all - Build CV and cover letter, generate images"
@echo " build - Build CV (public version)"
@echo " private - Build CV (private version)"
@echo " cover-letter - Build cover letter only"
@echo " images - Generate PNG images from PDFs"
@echo " clean - Remove build directory"
@echo " install - Install Python dependencies"
@echo " test - Run tests"
@echo " all - Build CV and cover letter, then generate images"
@echo " build - Build public version of the CV"
@echo " private - Build private version of the CV"
@echo " cover-letter - Build the cover letter PDF"
@echo " images - Generate PNG images from PDFs using ImageMagick"
@echo " clean - Remove all build and distribution artifacts"
@echo " install - Install Python dependencies (not defined here)"
@echo " test - Run cvlint on the generated CV PDF"
@echo " release - Upload PDFs and images to S3, purge GitHub Camo cache"

# Create necessary directories
$(DIST_DIR)/pdfs $(DIST_DIR)/images:
$(PDF_DIR) $(IMG_DIR):
mkdir -p $@

# Build public CV
build: $(DIST_DIR)/pdfs cover-letter
mkdir -p $(BUILD_DIR)
pdflatex -output-directory=$(BUILD_DIR) -jobname=dalton_luce_cv $(SRC_DIR)/cv.tex
cp $(BUILD_DIR)/dalton_luce_cv.pdf $(DIST_DIR)/pdfs/
build: $(PDF_DIR) cover-letter
mkdir -p $(PDF_DIR)
pdflatex -output-directory=$(BUILD_DIR) -jobname=$(CV_NAME) $(SRC_DIR)/$(CV_NAME).tex
cp $(BUILD_DIR)/$(CV_NAME).pdf $(PDF_DIR)

# Build private CV
private: $(DIST_DIR)/pdfs
private: $(PDF_DIR)
mkdir -p $(BUILD_DIR)
pdflatex -output-directory=$(BUILD_DIR) -jobname=dalton_luce_cv '\def\private{} \input{$(SRC_DIR)/cv.tex}'
cp $(BUILD_DIR)/dalton_luce_cv.pdf $(DIST_DIR)/pdfs/
pdflatex -output-directory=$(BUILD_DIR) -jobname=$(CV_NAME) "\def\\private{} \input{$(SRC_DIR)/$(CV_NAME).tex}"
cp $(BUILD_DIR)/$(CV_NAME).pdf $(PDF_DIR)

# Build cover letter
cover-letter: $(DIST_DIR)/pdfs
cover-letter: $(PDF_DIR)
mkdir -p $(BUILD_DIR)
pdflatex -output-directory=$(BUILD_DIR) -jobname=cover_letter $(SRC_DIR)/cover_letter.tex
cp $(BUILD_DIR)/cover_letter.pdf $(DIST_DIR)/pdfs/
pdflatex -output-directory=$(BUILD_DIR) -jobname=cover_letter $(SRC_DIR)/$(COVER_LETTER_NAME).tex
cp $(BUILD_DIR)/$(COVER_LETTER_NAME).pdf $(PDF_DIR)

# Generate images from PDFs
# FIXME: currently using deprecated "convert" since ubuntu GitHub runners only have access to IMv6
images: $(DIST_DIR)/images
images: $(IMG_DIR)
@if command -v convert >/dev/null 2>&1; then \
convert -density 300 $(DIST_DIR)/pdfs/dalton_luce_cv.pdf -quality 100 -flatten -sharpen 0x1.0 $(DIST_DIR)/images/cv.png; \
convert -density 300 $(DIST_DIR)/pdfs/cover_letter.pdf -quality 100 -flatten -sharpen 0x1.0 $(DIST_DIR)/images/cover_letter.png; \
magick -density 300 $(DIST_DIR)/pdfs/dalton_luce_cv.pdf -quality 100 -flatten -sharpen 0x1.0 $(IMG_DIR)/$(CV_NAME).png; \
magick -density 300 $(DIST_DIR)/pdfs/cover_letter.pdf -quality 100 -flatten -sharpen 0x1.0 $(IMG_DIR)/$(COVER_LETTER_NAME).png; \
else \
echo "Imageconvert not found. Please install Imageconvert to generate images."; \
fi

# Clean build directory
clean:
rm -rf $(BUILD_DIR)


# Install Python dependencies in a venv
install:
@if [ ! -d .venv ]; then \
echo "Creating virtual environment..."; \
python3 -m venv .venv; \
fi
@echo "Installing dependencies..."
@. .venv/bin/activate; \
if [ -f pyproject.toml ]; then \
pip install --upgrade pip; \
pip install -e .; \
else \
echo "No dependency file found"; \
fi
@echo ""
@echo "✅ Next steps:"
@echo " source .venv/bin/activate"
@echo " (or run commands with .venv/bin/python, e.g. .venv/bin/python -m pytest)"
rm -rf $(BUILD_DIR) $(DIST_DIR)

# Run tests
test:
python -m pytest test/test.py
@if ! command -v cvlint >/dev/null 2>&1; then \
echo "Error: cvlint is not installed or not in PATH."; \
echo "Please install cvlint by following instructions at https://github.com/da-luce/cvlint"; \
exit 1; \
fi
cvlint check $(PDF_DIR)/$(CV_NAME).pdf

release:
aws s3 cp $(PDF_DIR)/ s3://$(S3_BUCKET)/pdfs/ --recursive --region $(AWS_REGION)
aws s3 cp $(IMG_DIR)/ s3://$(S3_BUCKET)/images/ --recursive --region $(AWS_REGION)
# Purge GitHub Camo image cache, so updated images show up in README immediately
curl -X PURGE "$(CV_GITHUB_CACHE_URL)"
curl -X PURGE "$(COVER_GITHUB_CACHE_URL)"

enter:
docker run --rm -it --pull always -v "$$(pwd)":/cv -w /cv daluce/cv:latest /bin/bash
62 changes: 20 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
# 📄 CV [![Deploy Resume](https://github.com/da-luce/cv/actions/workflows/deploy.yml/badge.svg)](https://github.com/da-luce/cv/actions/workflows/deploy.yml)

<br>
<br>

<p align="center">
<a href="https://dalton-cv-artifacts.s3.us-east-1.amazonaws.com/pdfs/dalton_luce_cv.pdf">
<img src="https://img.shields.io/badge/📄%20View_PDF-blue?style=for-the-badge&logo=&logoColor=white" alt="View PDF">
</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<a href="https://dalton-cv-artifacts.s3.us-east-1.amazonaws.com/images/cv.png">
<a href="https://dalton-cv-artifacts.s3.us-east-1.amazonaws.com/images/dalton_luce_cv.png">
<img src="https://img.shields.io/badge/🌄%20View_PNG-blue?style=for-the-badge&logo=&logoColor=white" alt="View PNG">
</a>
</p>

<br>
<br>

My [Curriculum Vitae](https://en.wikipedia.org/wiki/Curriculum_vitae) (CV) and cover letter template, written in $\LaTeX$ ([learn more](https://www.latex-project.org/)). All artifacts (PDFs and preview images) are automatically built using [GitHub Actions](https://github.com/features/actions) and uploaded to an [AWS S3](https://aws.amazon.com/s3/) bucket. A [Terraform](https://developer.hashicorp.com/terraform) configuration and [instructions](#deploying-artifacts-to-aws) are included below if you want to set it up yourself.
My [Curriculum Vitae](https://en.wikipedia.org/wiki/Curriculum_vitae) and cover letter template, written in $\LaTeX$. All artifacts (PDFs and preview images) are automatically built using GitHub Actions and uploaded to an AWS S3 bucket. A Terraform configuration and [instructions](#deploying-artifacts-to-aws) are included below if you want a similar settup for your own resume.

Is it overengineered? _For most, probably yes._ <br>
Is it perfect for automation enthusiasts? _Absolutely._ <br>
Expand All @@ -23,45 +25,28 @@ Maybe I can convince you to become one too—_[here's why](#why-this-setup)._

### Curriculum Vitae &nbsp; [![PDF](https://img.shields.io/badge/PDF-blue?style=flat)](https://dalton-cv-artifacts.s3.us-east-1.amazonaws.com/pdfs/dalton_luce_cv.pdf)

![CV Image](https://dalton-cv-artifacts.s3.us-east-1.amazonaws.com/images/cv.png)
![CV Image](https://dalton-cv-artifacts.s3.us-east-1.amazonaws.com/images/dalton_luce_cv.png)

### Cover Letter &nbsp; [![PDF](https://img.shields.io/badge/PDF-blue?style=flat)](https://dalton-cv-artifacts.s3.us-east-1.amazonaws.com/pdfs/cover_letter.pdf)

![Cover Letter Image](https://dalton-cv-artifacts.s3.us-east-1.amazonaws.com/images/cover_letter.png)

## Building

> [!NOTE]
> Requires `pdflatex` and `imagemagick` (for image generation). On macOS, you can install them with:
>
> ```shell
> brew install basictex imagemagick
> ```
>
> Then reload your terminal to ensure the binaries are in your PATH.

1. Install Python dependencies for testing:
1. Enter the development container (this requires Docker)

```shell
make install
make enter
```

```shell
source .venv/bin/activate
````

2. Build all outputs
2. Build and test all outputs

```shell
# Build everything (CV + cover letter + images)
make all
make all && make test
```

To view other available targets, run `make help`.

> [!NOTE]
> The Makefile builds PDFs and images locally. PDFs and images are uploaded to an [S3](https://aws.amazon.com/s3/) bucket via a [GitHub Action](./.github/workflows/deploy.yml) for easy access. Storage cost is extremely low: for a 2 MB resume and cover letter, it would be just over a cent for three **years**.

## Deploying Artifacts to AWS

Follow these steps to set up your AWS account and configure GitHub Actions for automatic CV deployment.
Expand Down Expand Up @@ -99,24 +84,17 @@ Follow these steps to set up your AWS account and configure GitHub Actions for a

5. See it in action

Once the secrets are added, the provided [workflow](./.github/workflows/deploy.yml) will automatically build your CV PDFs and preview images, then upload them to the configured S3 bucket whenever you push changes to the repository.

> **Note:** S3 storage is extremely cheap—effectively pennies for years of CV and cover letter artifacts.
Once the secrets are added, the provided [workflow](./.github/workflows/deploy.yml) will automatically build your CV PDFs and preview images, then upload them to the configured S3 bucket whenever you push changes to the repository.
You can also run `make release` to upload artifacts to S3.

## Why This Setup?

| Component | Why? |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Git** | Tracks every change in fine detail—much more granular than cloud-hosted solutions like Google Drive. Supports collaboration, safe experimentation, and integrates seamlessly with automation workflows. |
| **LaTeX** | Produces professional, highly customizable PDFs. Standard in math and engineering fields, and easy to track with Git. |
| **AWS S3** | Cheap, reliable hosting. Stores the latest PDFs and images outside the repo (avoiding repo bloat) and provides a stable URL accessible by anyone on the internet. |
| **Terraform** | Makes AWS setup reproducible and version-controlled. Anyone (including future you) can recreate the environment easily. |

## To be Implemented

* [ ] Improve testing and add to `deploy.yml` action
* [x] Add Terraform template for AWS setup
* [x] Add details on AWS usage in README
* [x] GitHub action to only generate new PDFs/Images on `main` to reduce repo size
* [x] A more standard build process that works on any OS (✅ Makefile added)
* [x] Migrate from requirements.txt to pyproject.toml for Python dependencies
| Component | Why? |
| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**Git**](https://git-scm.com/) | Tracks every change in fine detail—much more granular than cloud-hosted solutions like Google Drive. Supports collaboration, safe experimentation, and integrates seamlessly with automation workflows. |
| [**LaTeX**](https://www.latex-project.org/) | Produces professional, highly customizable PDFs. Standard in math and engineering fields, and easy to track with Git. |
| [**AWS S3**](https://aws.amazon.com/s3/) | Cheap (pennies for 2 MB of assets) and reliable hosting. Stores the latest PDFs and images outside the repo (avoiding repo bloat) and provides a stable URL accessible by anyone on the internet. |
| [**Terraform**](https://developer.hashicorp.com/terraform) | Makes AWS setup reproducible and version-controlled. Anyone (including future you) can recreate the environment easily. |
| [**GitHub Actions**](https://github.com/features/actions) | Automates the build, test, and deployment workflow on every push. Ensures your CV and cover letter are always up-to-date without manual intervention, seamlessly integrating with Git and AWS S3. |
| [**cvlint**](https://github.com/da-luce/cvlint) | Automatically checks your CV for formatting and content issues. |
| [**Docker**](https://www.docker.com/) | Encapsulates all dependencies and tools needed to build your CV into one portable image, guaranteeing the build runs exactly the same anywhere. |
32 changes: 0 additions & 32 deletions pyproject.toml

This file was deleted.

Loading