Automatic latex resume with github action and gitinfo2 watermark

The problematic

A latex-written resume is always a nice thing to have: easy to update, practical to integrate .bib bibliographies, and automatic management of the look (you only provide its content). For academics, a latex resume is usually the go-to option. However, the management tools needed to keep track of the different versions, the way you communicate the result (a PDF file), etc. are usually completely suboptimal.

Using a few pieces of code, a Github repository and the right Github Actions, I present here the infrastructure I use to manage my resume. It includes version control, of course, but also automatic compilation online, which allows me to only add things into the .bib files and never touch everything else (so the comits are quite clean), and moreover the automatic release of the resume on always the same web address, which allows to pass this address to people (and not the PDF file), and still modify the resume after I send the mail.

Before jumping in, you may check the look and feel of the result at https://github.com/lrnv/cv/releases/download/latest/Laverny_Oskar_CV.pdf . Take a look at the address, and at the git watermark at the begining of the page. Looks good ? Ok, let’s dive into the details.

The tools

First, you need a latex resume. You can keep a look on overleaf, or start with a moderncv directly. You can pick one :

Mine is freely available at https://github.com/lrnv/cv , and this epo also includes everything I will discuss now, so you may take a look directly in it to see how it works.

Once you have a nice template, you may commit it to a public Github repository, and start including your stuff in it. Do not forget that this repository is public, so that everything you commit will be visible by everyone ! On the other hand, your resume is supposed to be public, right ?

You do not need to commit and push the compilations files, the .pdf file, etc: take your time to add them to your .gitignore.

Automatization of the compilations through a GitHub action.

As I already discussed on this blog, it is easy to make GitHub build your latex document for you. But it might be a little harder to have it built the document and push it as the latest release on every commit that lands on master. This is what does the GitHub action from my repo :

---
name: "Release CV"

on:
  push:
    branches:
      - "main"

jobs:
  release_cv:
    name: "Release CV"
    runs-on: ubuntu-latest
    steps:
    - name: Checkout master
      uses: actions/checkout@v1
    - name: Compile CV
      uses: xu-cheng/latex-action@master
      with:
        root_file: CV.tex
    - name: Check pdf file
      run: |
        file CV.pdf | grep -q ' PDF '
    - name: "Upload"
      uses: "marvinpinto/action-automatic-releases@latest"
      with:
        repo_token: "${{ secrets.GITHUB_TOKEN }}"
        automatic_release_tag: "latest"
        prerelease: true
        title: "Build"
        files: |
          CV.pdf

This GitHub action runs on every push on master, compiles the CV.tex file to CV.pdf and then makes a release out of it. The release is then available with a stable permanent link to the last version, for me https://github.com/lrnv/cv/releases/download/latest/Laverny_Oskar_CV.pdf , that you can then distribute to people. If you modify your resume before they click the link (because you made a typo or something), then they always get the last up-to-date version ! Which, trust me, is a convenient feature when, after you send an e-mail, you realize there is a typo in the file…

You could also tailor the previous script to do other things automatically. Namely, we will modify it to use the LaTeX package gitinfo2, which allows to include information about the git process directly on the final pdf file.

Running gitinfo2 directly on GitHub Actions, without a git hook.

The beautiful piece of code that is called gitinfo2 is given as a latex package, on CTAN, which documentation is at https://www.ctan.org/pkg/gitinfo2. It allows you to simply add to you preamble the following line:

\usepackage[mark]{gitinfo2}

And it will produce a very nice looking watermark on the footer of the PDF that gives information such as the branch and commit that corresponds to the compiled PDF. Very nice thing to have to show off your git skills directly on your CV ! Also, it helps keeping track of which version people have when they ask you questions about it.

However, it comes with a drawback. It needs you to setup a git hook in your repository. Although this solution is quite elegant, it is not possible to do so on GitHub. Git hooks can only be installed on local repos. Fortunately, there is a Perl script at https://github.com/rbarazzutti/gitinfo2-latexmk that allows to run an equivalent thing to gitinfo2 hook directly via latexmk, which is the latex compiler we used on the GitHub action.

The original GitHub hook is supposed to make a file in the .git/ repository. However, this repository might not be available on GitHub actions servers. To solve this issue, we need to add the local option to gitinfo2 :

\usepackage[local,mark]{gitinfo2}

and modify the gitinfo2.pm Perl script as follows to allow the creation of the right file (I also removed the dirty check as I did not need it. Compare with the original at https://github.com/rbarazzutti/gitinfo2-latexmk ):

sub git_info_2 {
    
    # get file content as a string
    my $get_file_content = sub {   
        my ($f)= @_;

        # do not separate the reads per line
        local $/ = undef;

        open FILE, $f or return "";
        $string = <FILE>;

        close FILE;
        return $string;
    };

    # compare two files`
    my $cmp = sub {
        my($a,$b) = @_;

        return $get_file_content->($a) ne $get_file_content->($b);
    };

    my $RELEASE_MATCHER = "[0-9]*.*";

    if(%GI2TM_OPTIONS){        
        if(exists $GI2TM_OPTIONS{"RELEASE_MATCHER"}){
            $RELEASE_MATCHER = $GI2TM_OPTIONS{"RELEASE_MATCHER"};
        }
    }

    # When running in a sub-directories of the repo
    my $REPOBASE = `git rev-parse --show-toplevel`;
    $REPOBASE =~ s/\s+$//;

    my $GITDIR = "$REPOBASE/.git";

    my $GIN = "gitHeadLocal.gin";
    my $NGIN = "$GIN.new";

    # if(length(`git status --porcelain`) == 0){
    # Get the first tag found in the history from the current HEAD
    my $FIRSTTAG = `git describe --tags --always --dirty='-*'`;
    $FIRSTTAG =~ s/\s+$//;

    # Get the first tag in history that looks like a Release
    my $RELTAG = `git describe --tags --long --always --dirty='-*' --match '$RELEASE_MATCHER'`;
    $RELTAG =~ s/\s+$//;

    # Hoover up the metadata
    my $metadata =`git --no-pager log -1 --date=short --decorate=short --pretty=format:"shash={%h}, lhash={%H}, authname={%an}, authemail={%ae}, authsdate={%ad}, authidate={%ai}, authudate={%at}, commname={%an}, commemail={%ae}, commsdate={%ad}, commidate={%ai}, commudate={%at}, refnames={%d}, firsttagdescribe={$FIRSTTAG}, reltag={$RELTAG} " HEAD`;

    open(my $fh,'>',$NGIN);
    print $fh "\\usepackage[".$metadata."]{gitexinfo}\n";
    close $fh;  
    # }else{
    #     print "GIT UNCLEAN\n";   
    # }

    $cmp->($GIN,$NGIN    );

    if((-e $GIN || -e $NGIN) && $cmp->($GIN, $NGIN)) {
            print "Status changed, request recompilation\n";
            $go_mode = 1;
            unlink($GIN);
            rename($NGIN, $GIN);
    } else {
        unlink($NGIN);
    }
    print "The gitinfo function is done working!"
}

git_info_2();

Last but not least, Putting the line running the Perl script in the .latexmkrc file won’t work on GitHub action. Indeed, this script calls git a lot, and it does not work in the docker environment that runs latexmk. Fortunately, you can put it in the GitHub action YAML itself :

...
 - name: Setup perl
      uses: shogo82148/actions-setup-perl@v1
      id: set-matrix
    - name: Run perl script
      shell: perl {0}
      run: |
        do './perl/gitinfo2.pm';
...

And this must be done before the latexmk run obviously :) It will create the gitHeadLocal.gin file that gitinfo2 require.

We are done ! Our CV now does work correctly and runs with GitHub actions and everything.

Automatization of the multibib reference management.

My CV uses multibib, and draws its information from several .bib files : articles.bib, talks.bib, etc… I do not want to count the references myself, and I want them to be displayed properly, with the year on the left… etc.

For that, I modified the plainurlrev.bst file to have the references show as I wanted, and I created a little shell script to automatically count the references and write up the latex piece that shows them automatically. If I add new .bib file into the bib/ folder, they are added automatically. If a .bib file becomes empty (like a paper moving from preprints.bib to articles.bib when it is published), the corresponding section is removed from the resume.

The simple shell script I wrote is located at https://github.com/lrnv/cv/blob/main/bib/bibcounters.tex, you can take a look at it, but it is not very pretty bash code.. Once again, it is run from GitHub actions:

...
- name: Run bibliography management
      run: |
        bash ./bib/makebibs.sh
...

Final workflow

You now have a vision of everything that make this procss of an automated CV as… automated as possible. Indeed, my final workflow when I want to add a new publication to my resume is now trivial:

  • Add an entry in a .bib file.
  • Commit & Push.

And then the permalink automatically gets updated after one to two minutes. Everyone which already has this link will get the new version. If they dont, I always can check up with them the commit hash on the watermark :)

I hope these ideas will help someone else building the same thing. Please do not hesitate to clone the repository.

Oskar Laverny
Oskar Laverny
Maître de Conférence

What would be the dependence structure between quality of code and quantity of coffee ?

comments powered by Disqus

Related