Skip to content

timothyf/resume-builder

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

195 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Resume Builder

Resume Builder is an HTML and PDF resume builder made in Ruby with Middleman. It lets you keep resume content in YAML files and render it as HTML for the web and as PDF-ready HTML for download/printing.

It has the following features:

  • YAML-based resume content with layouts and styles kept separately.
  • Thirteen resume section types and six complete screen/print themes.
  • Multiple selectable resume definitions, with explicit supported and archived lists.
  • Optional brief versions, Gravatar photos, and Markdown/HTML descriptions.
  • Schema validation before rendering, including referenced jobs, skills, links, summaries, layouts, templates, and PDF sources.
  • Static HTML and PDF-ready HTML generation, plus a downloadable PDF copied from each resume's configured source.
  • Unit, shell, full build-matrix, rendered-content, PDF-conversion, and visual regression coverage.
  • Automated GitHub Pages deployment to resume.timothyfisher.com.

Current project state

The tracked example deployment is johndoe/resume_sample, selected in data/active_resume.yml, with brief generation disabled. Supported resumes are exercised across all six themes with brief generation both enabled and disabled.

Every build writes Middleman's intermediate files to build/ and packages the selected deployable resume under dist/<user>/<resume-name>/. The packaged artifact contains the screen and PDF HTML entrypoints, stylesheets, optional brief entrypoints, and the configured downloadable PDF.

Installation

If you forked to your own repo:

 git clone https://github.com/<yourusername>/resume-builder.git
 cd resume-builder

Otherwise:

 git clone https://github.com/timothyf/resume-builder.git
 cd resume-builder

Install Ruby 3.4.9 with RVM and use the project gemset:

 rvm install 3.4.9
 rvm use 3.4.9@resume --create

Install Ruby dependencies:

 bundle install

Node.js 22, Python 3.12, and Poppler are also required to run the complete visual regression suite. Install the project-managed Node and Python packages with:

npm ci
pip install -r requirements-visual.txt

Install poppler-utils with your operating system package manager so pdftoppm is available.

Preview

See the deployed resume at resume.timothyfisher.com.

Usage

Build your resume

Build the static version of your resume

bundle exec middleman build

Or use the helper script:

./build_resume.bash

Optional profile override:

./build_resume.bash --resume-user johndoe --resume-name resume_sample

Optional theme override:

./build_resume.bash --theme theme-fern

You can also use environment variables:

ACTIVE_RESUME_USER=johndoe ACTIVE_RESUME_NAME=resume_sample ./build_resume.bash
ACTIVE_RESUME_THEME=theme-orange ./build_resume.bash

Optional brief-generation override:

ACTIVE_RESUME_GENERATE_BRIEF=true ./build_resume.bash

View current configured and effective active resume selection:

./show_active_resume.bash

With override preview:

ACTIVE_RESUME_USER=johndoe ACTIVE_RESUME_NAME=resume_sample ./show_active_resume.bash

Available themes:

theme-default, theme-fern, theme-grey, theme-orange, theme-tapestry, theme-tradewind

ATS single-column layout

data/johndoe/layouts/layout_ats.yml provides a text-first, single-column layout modeled on a conventional ATS resume. It renders a centered identity and contact header followed by summary, skills, experience, and education. The layout uses semantic HTML, standard fonts, black text, simple headings, and no sidebar, icon dependency, tables, or decorative content that could interfere with resume parsers.

Select it in a resume definition with:

layout: layout_ats
pdf:
  useicons: false

The ATS layout is independent of the selected color theme and has dedicated responsive and Letter-print rules. It is also available in the Local YAML Editor layout selector. The active deployed resume is not switched to this layout automatically.

Theme bundles are now full layout/style sets (not color-only overlays). Each theme has separate screen and PDF stylesheet bundles:

source/stylesheets/themes/_theme-default.screen.scss
source/stylesheets/themes/_theme-default.pdf.scss
...

To create a new complete layout theme:

  1. Duplicate one theme pair in source/stylesheets/themes/.
  2. Rename both files to _theme-yourname.screen.scss and _theme-yourname.pdf.scss.
  3. Update layout structure/styles in those files.
  4. Add theme-yourname to AVAILABLE_THEMES in lib/resume_selection.rb.
  5. Build with ./build_resume.bash --theme theme-yourname.

The packaged result is written to dist/<user>/<resume-name>/. Its primary entrypoints are index.html for the screen resume and pdf.html for the print layout. If brief generation is enabled, corresponding named screen and PDF brief files are included as well.

Deploy your resume

The primary deployment path is the GitHub Pages workflow in .github/workflows/static.yml. A push to main validates all supported resume definitions, runs the integration matrix, runs visual regression coverage, builds johndoe/resume_sample, and deploys its packaged artifact.

For a manual deployment using the Middleman Git deploy configuration:

./deploy_resume.bash

Optional profile override:

./deploy_resume.bash --resume-user johndoe --resume-name resume_sample

Optional theme override:

./deploy_resume.bash --theme theme-fern

The workflow sets RESUME_DEPLOYED_AT to the UTC deployment time. The screen resume converts it to America/Detroit local time and displays the correct EST or EDT abbreviation below the resume. The timestamp is intentionally omitted from the PDF entrypoint.

Launch the preview server:

bundle exec middleman

You can preview your resume at http://localhost:4567/

When using RVM, entering the project directory can pick up .ruby-version and .ruby-gemset and use ruby-3.4.9@resume.

The helper scripts resolve bundle from your PATH by default. If needed, override with:

BUNDLE_BIN=/absolute/path/to/bundle ./build_resume.bash

Testing

Install test dependencies:

bundle install

Run unit tests:

bundle exec rspec spec/lib

Validate the configured active resume without running a build:

./validate_resume.bash

Validate a selected resume with overrides:

./validate_resume.bash --resume-user johndoe --resume-name resume_sample

Validate the complete supported-resume matrix:

./validate_supported_resumes.bash

The matrix in data/resume_support.yml explicitly classifies every stored data/<user>/resume*.yml definition as either supported or archived. Supported definitions must pass the current schema validator. Archived definitions are not buildable under the current schema and must include a reason. A new resume definition must be added to one of these lists or matrix validation will fail. The tracked matrix contains the supported John Doe example.

Run shell script tests:

./spec/shell/run_shell_tests.bash

Run all tests (integration test is skipped by default):

bundle exec rspec

Run integration smoke test:

RUN_INTEGRATION=1 bundle exec rspec spec/integration/build_smoke_spec.rb

The integration suite runs the full Cartesian build matrix: every resume listed as supported in data/resume_support.yml, every theme in ResumeSelection::AVAILABLE_THEMES, and brief generation both enabled and disabled. Each build verifies the screen and PDF entrypoints, theme CSS, and brief artifact behavior. This matrix also runs in the GitHub Pages workflow before the deployed resume is built.

Run visual regression coverage after installing the Node and Python test dependencies (npm ci and pip install -r requirements-visual.txt):

RUN_VISUAL=1 bundle exec rspec spec/visual/visual_regression_spec.rb

Visual coverage compares desktop screenshots for every supported theme, a mobile-width screenshot, and the first rendered print/PDF page against the PNG baselines in spec/visual/baselines/. It also renders every generated PDF page under tmp/pdfs/visual-regression/ and checks the expected page count, text bounds, rendered content, and unexpected blank pages.

The screenshots currently render the active resume rather than a fixed test-only content fixture. Normal resume edits can therefore change wrapping, document height, or PDF pagination and cause an intentional visual failure. Review the generated images before updating baselines; do not update them automatically merely to make the test pass.

After intentionally changing layout, styles, or resume content, inspect the current images and update the committed baselines with:

RUN_VISUAL=1 UPDATE_VISUAL=1 bundle exec rspec spec/visual/visual_regression_spec.rb

Set VISUAL_CHROME_BIN, VISUAL_NODE_BIN, or VISUAL_PYTHON_BIN when those executables are not discoverable from their standard locations. Failed CI runs upload current screenshots and rendered PDF pages as diagnostic artifacts.

Local YAML editor

You can run a local-only editor UI for YAML data files (jobs, summaries, resume definitions, and the active-resume selection) without exposing data to any external service.

Install Node dependencies:

npm ci

Start the local editor:

npm run editor:start

Open in browser:

http://127.0.0.1:4310

The editor only reads/writes files inside data/ and currently lists:

  • jobs*.yml files under each user folder
  • files under each user's summaries/ folder

Editor modes:

  • Structured: form-based editing for jobs, summaries, resumes, and active selection
  • Raw YAML: direct text editing for full control

The structured resume editor uses the selected user's real catalogs to populate layouts, themes, summaries, job files and IDs, links, and skills. It edits PDF settings, contact information, ordered job references, link references, skill groups, and education entries. The active-resume form selects a valid user and resume definition and controls brief generation. Sections not represented by a form are retained unchanged during structured saves.

The structured job editor supports searching by job ID, title, or company; editing all job fields currently used by the repository (id, include, brief, title, company, location, dates, and description); duplicating jobs with a generated unique ID; reordering jobs; and guarded deletion. Optional include and brief values can be explicitly unset, blank locations are stored as null, and unrecognized job fields are retained during structured saves. Validation rejects missing required job fields and duplicate job IDs.

Before either mode saves, the editor parses the candidate YAML and validates a temporary copy against the complete supported-resume matrix. Invalid content is reported without changing the source file. A successful save first copies the previous version to .local-editor-backups/<timestamp>/ and then replaces the source atomically. Backups are local and gitignored.

The editor marks unsaved changes in the browser title and warns before file, category, or mode changes, reloads, and browser navigation. Use Validate to check without saving and Revert to reload the version currently on disk.

Run the editor API and headless-browser tests with:

npm run editor:test

Resume instructions

To create/update your resume, edit data/active_resume.yml and the selected resume file under data/<user>/ (for example data/johndoe/resume_sample.yml). All keys with a desc: | header can be Markdown formatted.

Every Middleman build and preview validates the effective active resume before rendering. Validation checks required nested fields, referenced jobs, skills, links and summaries, duplicate catalog IDs, and layout template files. All problems are reported together with their source paths. Use ./validate_resume.bash for a faster validation-only check, or ./validate_supported_resumes.bash to validate every supported definition. The GitHub Pages workflow runs the full supported-resume validation before it builds the deployed resume.

Here is what it looks like:

contact_info:
    name: Jonathan Doe
    shortdesc: Web Designer, Director
    email: example@example.com
    phone: (313) - 867-5309
    address:
        - 123 Fake Street
        - City, Country
    desc: |
        You can put Markdown in here [like this](http://daringfireball.net/projects/markdown/).

Sections

Here is a description of each of the currently supported sections of a resume. A section is a content component that can be included in the resume YAML data file.

The following section types are currently supported:

  • PDF
  • Headers
  • Contact Info
  • Links
  • Summary
  • Skills
  • Jobs
  • Education
  • Certifications
  • Projects
  • Volunteering
  • Languages
  • Interests

PDF

This project uses generatePdf.rb to generate a PDF via the FreeConvert API.

Run it with:

ruby generatePdf.rb

No API key is required for the current FreeConvert endpoint. If an API key is needed for an account or endpoint later, it can be supplied without changing the script:

export FREECONVERT_API_KEY=your_api_key

By default, the command resolves the active resume, builds its PDF HTML, sends that HTML to FreeConvert, saves the result to the resume's configured pdf.source, and runs the build again so dist/ contains the new PDF. On completion it prints the directory containing the saved source PDF.

Common environment overrides supported by the script:

FREECONVERT_SOURCE_PATH=build/pdf.html
FREECONVERT_SOURCE_URL=https://resume.timothyfisher.com/pdf.html # optional override
FREECONVERT_BUILD_BEFORE_CONVERT=true
FREECONVERT_PACKAGE_AFTER_CONVERT=true
FREECONVERT_OUTPUT_PATH=/tmp/converted-resume.pdf # optional intermediate path
FREECONVERT_POLL_INTERVAL_SECONDS=5
FREECONVERT_MAX_POLLS=120

FREECONVERT_OUTPUT_PATH is optional. When provided, the downloaded file is copied back to pdf.source before packaging. When FREECONVERT_API_KEY is set, it is sent as a bearer token; otherwise the authorization header is omitted.

GitHub Pages deployments use the committed pdf.source and do not call FreeConvert on every push. If automated conversion is added later, store the key as a GitHub Actions secret named FREECONVERT_API_KEY.

The PDF section is used to describe details of the resume PDF that will be generated.

pdf:
  filename: TimothyFisher-Resume
  source: TimothyFisher-Resume.pdf
  useicons: true
  role: developer

filename is the public path without the .pdf extension. source is resolved relative to the project root and copied into the built resume artifact at that public path. A configured source that does not exist causes validation/building to fail so a broken PDF link is not deployed. All currently supported resume definitions provide a PDF source.

Headers

The headers section allows you to specify the names of sections that will be used within the resume. For example, given the headers section shown below, the profile section will be labeled as 'Summary' and the jobs section will be labeled as "Experience".

headers:
    profile: Summary
    jobs: Experience
    education: Education
    skills: Skills
    download: Download PDF

Contact Info

This section is used to provide basic contact info for the resume user.

contact_info:
    name: Timothy Fisher
    photo: false
    email: timothyf@gmail.com
    phone: (555) 555-1234
    address:
        street: 555 Springwells
        city: Detroit
        state: MI
        postal_code: 48134

Links

links:
    github: https://github.com/timothyf
    linkedin: https://linkedin.com/in/timothyfisher/
    twitter: http://twitter.com/tfisher

Summary

summary:
  developer:
    I am a passionate developer and leader with nearly 30 years of industry experience in roles that include
    both hands-on and leadership positions across organizations that range from small startups to large enterprises.
    ...

  leader:
    I am a passionate developer and leader with 29 years of software development experience in roles
    including Chief Technology Officer, VP of Engineering, Chief Architect, and Director of Mobile Development,
    along with many years of hands-on development experience.
    ...

Skills

skills:
    - Team Leadership & Management
    - Microservices Architecture
    - Amazon Web Services (AWS), Heroku, EngineYard
    - Ruby, Rails, JavaScript, Node.js, React, ReactNative, Java, Swift, HTML, CSS

Jobs

- title: Senior Java Architect
  company: LogicaCMG
  brief: false
  include: brief
  location:
    city: Southfield
    state: MI
  dates:
      start: 2003, February
      end: 2006, May
  desc: |
    Worked on a Web-based single login project for Ford Motor Company. Responsibilities include assisting with
    architecture, analysis, design, coding, and testing. Environment consisted of Websphere Application Server
    ...

- title: Development Team Lead
  company: MedCharge
  brief: false
  location:
    city: Ann Arbor
    state: MI
  dates:
      start: 2002, February
      end: 2003, January
  desc: |
    Led the J2EE development team at MedCharge, a startup whose product was a health care application
    used within the University of Michigan Medical Center. The product allows hospital staff to capture all
    ...

Education

education:
    - name: University of Michigan
      degree: B.S. Electrical Engineering
      dates:
          start: Sept 1986
          end: May 1991

    - name: Capella University
      degree: M.S. Education
      dates:
          start: Sept 2001
          end: May 2003

Certifications

Projects

Volunteering

Languages

Interests

About

Resume builder built in Ruby using Middleman. Generates HTML and PDF resume views from resume data stored as YAML.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages