How to render a Google Docs file in LaTeX with GitHub Actions directly from GUI of that file

Ilia Ozhmegov
12 min readJan 15, 2023

--

Introduction

During my job search, I had to update the resume that I used to keep as a simple Google Docs file, which perfectly satisfied almost all my needs until that point… it couldn’t fit any more text while being nice-looking. Before getting rid of irrelevant experience points for particular companies or positions, I was advised to try out one solution which renders your CV as one page, you just need to choose a layout of your liking and fill in certain fields. And the advised solution worked!

GIF By Author: the resulting work

However, Google Docs has some features like spellchecking, easiness of proofreading and editing for trusted 3rd parties, so I still couldn’t afford to get rid of it, which made the pipeline of updating my CV look like this:

  1. Change it in Google Docs
  2. Wait until the independent 3rd party (btw, thank you guys) makes sure that it’s okay or suggests what should be changed
  3. When it’s okay, then Copy and Paste the changed part to the proposed solution
  4. Render and Download!

For me, it became annoying after going through all these steps a couple of times. Besides, this tool has some minor lack of flexibility for my “writings” and “skills” sections. So, I migrated it to LaTeX on overleaf platform.

After making a nice-looking LaTeX layout for myself based on Awesome-CV I realized that it would be great in general if Google Docs could have this custom button “render” which would send all the content to something like Overleaf platform and then download a rendered PDF file to my Google Drive and optionally to my computer.

Well, this post is dedicated to the detailed instruction that I carefully documented for people who want to have something like that, where I completely replaced the Overleaf platform with a free GitHub Actions tool.

Nevertheless, the solution that I have mentioned earlier was creddle.io, which is a really great tool, and if you do not experience any problems with English and are confident enough to share your CV without having it proofread, there is no need to read further unless you want to know how to connect Google Docs/Sheets and GitHub Actions.

Before diving in, let me list the stack of technologies that were used to solve the problem:

  • Google Cloud Platform
  • Google Docs
  • Google Drive
  • Google App script
  • HTML/CSS
  • Google API
  • Python
  • XeLaTeX
  • Docker
  • GitHub Actions

Instruction

Step 1: Use my repository as a template

Follow here my repository and push “Use this template”, then “Create a new repository”. You can give a fancy name to a new repository (for example, “CV”). The next step is creating a personal access token.

Image by Author

Step 2: Create a personal access token

To create a personal access token, you should follow the GitHub instruction. You need to choose the “workflow” checkbox (automatically it will check all necessary options). Then you should select the Expiration duration of your liking and create it. Please don’t lose that token. We will need it later.

From Github Docs: An example of generated token

Step 3: Create a Google Docs File from a template

You can find the Template. Then choose “File” and “Make a copy”.

Image by Author

Step 4: Create a service account on the Google Cloud Platform

To create a service account on the Google Cloud Platform, you should follow the Google instruction. It has 4 steps, I can add from my side that you should do it in the following way:

  1. Follow the 1st step as is
  2. In the 2nd step of the instruction, you should enable only the following APIs: Google Docs API and Google Drive API
  3. You can completely skip the 3rd step!
  4. Follow the 4th step also as is

So in the result, you should have a service account Email something like “cv-service-account@cv-test-123456.iam.gserviceaccount.com”. Share your Google Docs file created in the previous step with your service account Email. Please also don’t lose the credentials JSON file!

Image by Author

Optionally, you can keep the service email as “Viewer”.

Step 5: Add secrets

To enable the correct work of your GitHub Action workflow, we need to create repository secrets!

Copy the entire content of your credentials JSON file from the previous step as is and insert it into the “Secret” field. Please don’t forget to name it “CREDENTIALS”!

Then add the “DOCUMENT_ID” secret with the content, like this:

{
"id": "1xX111JjJJtJdp2Toy44unJ38SVw4DBLntXD7xHquNjA"
}

You can get the id of your document out of its URL. For example, if the URL of the document you want to render looks like this:

https://docs.google.com/document/d/1xX111JjJJtJdp2Toy44unJ38SVw4DBLntXD7xHquNjA/edit

Then you should take 1xX111JjJJtJdp2Toy44unJ38SVw4DBLntXD7xHquNjA and put as value as in the example above.

Image by Author: my repository secrets

Optionally, you can add your phone number as the “MOBILE” secret with the following example content:

\mobile{+01 234 5678 9876}

Please don’t forget to replace the dummy phone number with yours.

Step 6: Update your personal data in cv.tex file

I believe the name and contact details are the type of data that does not change often, so you should change those in the “cv.tex” file, for which the file path is the following:

<your-repository-name>/my-awesome-cv/cv/cv.tex (or if you named repository “CV”, then it has the name CV/my-awesome-cv/cv/cv.tex) lines 57–79.

Image by Author: cv.tex file, lines 57–66

And you can do it right in GitHub!

As the changes are pushed into the main branch the workflow will be automatically launched (you can check the details in the “Actions” tab of your repository) and besides being green it should render your CV! You will find it as an “Artifact” under the zipped_cvname.

Since I was using an empty template, my “cv.pdf” file looks like this.

Image by Author: rendered template

Step 7: Create a Simple Apps Script

Let’s create a simple Apps Script in the Google Docs document created in Step 3. You should click “Extensions”, then “Apps Script”:

Image by Author: “Apps Script” button in the “Extensions” tab

Then insert the following code in the code space and save it:

function onOpen() {
const ui = DocumentApp.getUi();
ui.createMenu('Custom')
.addItem('Show FooBar', 'foobar')
.addToUi();
}

function foobar() {
const ui = DocumentApp.getUi();
ui.alert('FooBar');
}

Optionally, you can rename the project to “CV” and should look like in the picture below.

Image by Author: the example of how the inserted code might look like

Now, let’s get back to the document tab in your browser and reload the document page.

The rightmost tab now should become “Custom” as in the picture below. If you choose “Custom” and “Show FooBar” the script that we created earlier should be launched.

Image by Author: the appearance of “Custom” tab

You might see something like that:

Image by Author: the example of the execution of a simple script

If you have something similar, then congrats! We are almost there!

Step 8: Create a Google Drive Folder

Before triggering GitHub Actions from Apps Script, you should create or choose a folder where you would like to keep your rendered PDF files. You will need a folder id in the next step.

For example, the opened Google Drive folder in my browser has the URL:

https://drive.google.com/drive/folders/1gt00mVv3_YNw0XjKdu0oKv964c6Un-uy

which has id 1gt00mVv3_YNw0XjKdu0oKv964c6Un-uy (similar to step 5). This id will be needed in the next step, so please don’t lose it!

Step 9: Copy and Paste code.gs file

Go back to your freshly created repository (or my repository) and find the content of code.gs file in the Apps_Script folder and copy-paste the content into your Apps Script coding space. But remember that it’s important to reference your repository to keep it isolated from my repository.

Image by Author: the first lines in my “code.gs” file

After copy-pasting, please draw your attention on the beginning of the “code.gs”, there are 6 important variables:

GH_REPO_URL = "https://api.github.com/repos/<your-nickname>/<your-CV-repo>";
GH_TOKEN = "ghp_aASFOaKQ4xI65zEZu00xdLZeAn2D691QB8s9";
GD_FOLDER = "1JoGzZTUSbjzX5fRHgSYshGRzUOItPpnb";
GD_FILENAME = "ILIA_OZHMEGOV_CV.pdf"; // don't forget to rename
GD_DOC_ID = DocumentApp.getActiveDocument().getId();
GH_PURGE = true;

In GH_REPO_URL you should replace <your-nickname> with your GitHub nickname, as well as <your-CV-repo> unless you named also “CV”. GD_FOLDER is an id from the previous step. Further, you may want to download the resulting PDF file GD_FILENAME with a different name than “ILIA_OZHMEGOV_CV.pdf” so also don’t hesitate to rename it!

GH_PURGE is responsible here for removing the resulting GitHub Actions artifact named zipped_cv. If its value is “true” it will remove the artifact, making it inaccessible to 3rd parties.

Optionally, you can hide your GitHub personal token. You can do that by going to “Project Settings” (Gear Icon) then “Add script property” (at the bottom of the page). Name property “github_token” with the value of your token from the 1st step. Like in the picture below:

Image by Author: an example of pasted GitHub token to hide

Then, you can access the token with following line:

GH_TOKEN    = PropertiesService.getScriptProperties().getProperty("github_token"); 

Step 10: Launch the final script!

Go back to your Google Docs file and reload it, now under “Custom” you should see “Trigger Rendering”. Smash it! It will require “Authorization” just follow the navigation with “Continue”. There you should click “Advance” in the left bottom part of the message and then “Go to Untitled project (unsafe)”. In the picture below instead it says — “Go to ILIA_OZHMEGOV_CV (unsafe)” instead, please don’t worry I took this picture too early to replace now, but it still does the job. Then allow the required access (relax, you give permission to yourself instead of some shady 3rd party). After, “Trigger Rendering” button actually starts to render your CV! You can even go to the “Actions” tab and watch the details of that building.

Image by Author: the Authorization process

After you should see the button “Download” in green rectangular, besides, the same file appears in the Google Drive folder you referenced in the 7th step.

Congratulations now you have a relatively “simple” (hehe) way of rendering your Google Docs file in XeLaTeX for free! GitHub Actions provide every user 2000 minutes per month for free and since rendering takes approximately a minute, you can render about 2000 CVs per month or one CV 2000 times.

Recycling

Now, let us share an interesting feature. Since many companies and positions might expect you to highlight different points of your career to help a recruiter to understand that you are the perfect fit and that the company urgently needs you, we can safely say that the very same pipeline can be applied to all versions of your CV, based on the one we already created.

You would need to change/update only these things:

  1. Do “File” and then “make a copy” and check the “share with the same people” option (it is essential because of the service account)
  2. If our “Custom” tab doesn’t appear, go “Extensions” and “Apps Script” as soon as you see the familiar code, that tab also shows up where it used to be, then go back to the copy of your document and change it (for example according to the job requirement)
  3. Click already familiar “Custom” and “Trigger Rendering” and complete “Authorisation” in the same way as in the 10th Step
  4. if you followed the option of hiding the GitHub token in step 9 then again, add a GitHub token in the project properties

Additionally, you can keep different versions of your CV for different companies in the same folder (GD_FOLDER) or in other (sub)folder, it’s up to you!

Google Docs Layout

The Google Docs template has four sections: “EXPERIENCE”, “EDUCATION”, “WRITINGS”, “SKILLS”. You could already notice that the internal section structure repeats. For all section names except the section named “SKILLS” it doesn’t matter how you name your section, it will just generate a PDF file purely relying on the table right after the section name. Unfortunately, the “SKILLS” section should be highlighted by containing the word “skill” in its section name (case-insensitive) since it has a relatively unique structure. So, it means there is still some freedom, and you can name it “skill”, “SKILL”, “skillS”, “sKILLs” etc.

That is because every section table except the “SKILLS” table consists of main units (see the table below “Main unit”). In which the first row usually contains the first cell company name or University or Journal, while the second cell has the location (Berlin or New York). In the second row, the first cell contains some general information like Position/Role (Software Engineer) or Degree (B.S. in Computer Science), and the second cell contains only the range of dates, for example, “Jan 2020 — Mar 2022”. The optional third row is completely dedicated to the description, for example, experience bullet points or some short description (see Note II below).

Table by Author: Main unit

So in my template, the section named “WRITING” has two main units. “EDUCATION” section has also 2 main units with short descriptions each, while “EXPERIENCE” section consists of 2 main units with full bullet point lists.

Note I: it does parse the links and preserves them by placing them into a PDF file in the same way as it was provided in the Google Docs document. Just compare the template and the resulting PDF file.

Note II: in the case of a short description, it keeps the description and information from the first cell of the second row (Position/Role/Degree) of the main unit completely in the second row, which saves up some space. Only under the condition that the amount of explicit symbols is less than or equal to 138, which is dictated by my LaTeX layout.

Some Backend details

If you have any interest in some general explanation of the backend part. Then let us redirect you to the [repository](https://github.com/IliaOzhmegov/CV). Currently, there are 4 main parts:

  1. download-and-convert-gdocs — in general it downloads, parses, and converts the Google Docs document to TeX format, and this part consists of another three classes:
    - getter.py unit downloads JSON representation of the Google Docs document
    - parser.py unit parsers JSON file into a python dictionary (from JSON to JSON, hehe)
    - converter.py takes the parsed python dictionary and converts it into the “section.tex” file, saving it in the corresponding folder “my-awesome-cv/cv/sections.tex”
  2. my-awesome-cv originates from legendary Awesome-CV LaTeX template with a few minor amendments. It does exactly what the original template does, except using some more lightweight docker image
  3. Apps_Script contains the Apps Script code.gs and HTML files that are fetched directly from the repository. The “code.gs” script triggers GitHub Actions, downloads the resulting zipped file (also known as Artifact in GitHub Platform), and then saves it to the Google Drive folder of your choice
  4. .github/workflows can be triggered by external API call as well as by “push” into the main branch. After being triggered, it runs the 1st part (download-and-convert-gdocs) and the 2nd part (my-awesome-cv) of the current list, generating the resulting zip file that was mentioned in the previous point

Why GitHub artifact? My attempts to upload the rendered PDF file directly to a shared Google Drive Folder right from GitHub Actions workflow failed since the Google API just doesn’t allow such functionality for service accounts without using OAuth2 authentication (although I found a few bits of information that it’s possible if folder belongs a corporate account on Stack Overflow platform).

Conclusion

You could already notice that it’s an overcomplicated approach of rendering your CV since every small amendment might make you wait additional 60 seconds of rendering before applying for a job, so we might conclude that the current post might not bear much value and be created based on the pure desire to give some meaningful functionality to a custom tab in the Google Docs as well as to entertain and prevent the reader from the shown path.

Although it’s an overcomplicated waste of time, we still believe that some points from this post still might find their use in helping people to realize that there is a simpler and better way. For example, reducing the number of bullet points so that your CV still looks nice in the original Google Docs Document.

--

--