DEV Community

Jeremy Friesen for The DEV Team

Posted on • Originally published at takeonrules.com on

Adding Emacs Function for my Forem Pull Requests

Automating the Repetetive while also Learning a Bit More about My Editor

In I joined Forem as the lead engineer for the content experience team. I’ve been contributing to open source software for 9 years; Hello Samvera.org; I miss you but I promise I’m in a good place.

Coming from one open source community to another, I brought with me different workflows. I favor writing verbose commit messages. I like to use that as the text for my pull requests. The benefits are that commit messages travel with the code-base. I can use git annotate to help me understand the situation around a chunk of code.

But, in an open source community with over 600 contributors, the commit message as pull request strategy is inadequate. We could use git hooks to provide commit message templating, but that’s not enough for conversations around the pull request.

Forem provides a pull request template to guide contributors through all of the considerations that go into the pull request review and acceptance.

The template provides a nice pre-amble comment to help new contributors. Then provides clear sections and instructions for a contributor to fill out:

  • What type of Pull Request
  • Description
  • Related Tasks & Documents
  • QA Instructions, Screenshots, and Recordings
  • Accessibility Concerns
  • Added/updated Tests
  • How will this change be communicated? (A Forem Core Team only section)
  • Any post deployment tasks to complete
  • A GIF that Expresses How You Feel About this Contribution

As a new contributor to Forem, I love this guidance. And as I began reviewing other pull requests, I appreciated the structure even more.

My Current Pull Request Workflow

When I’m working on the code, I continue to write verbose commit messages. Then, when I’m ready, I push up my branch and push the button to create a pull request for the branch.

By default, Github prepends the last commit message to the text of the pull request template. I focus my browser into that text area and use the editWithEmacs.spoon to copy that text and paste it into a new Emacs buffer on my machine.

In that Emacs buffer, I then go about editing the pull request text.

When I’m done, I type Ctrl+c then Ctrl+c (e.g., C-c C-c in Emacs parlance) to copy the text from my Emacs buffer and paste it back into the browser’s text area. Magit and Org Mode use that key combination for confirmation of commands.

And I submit my pull request.

Automating My Workflow

Once I started editing these pull requests in Emacs, I started to see the clean-up work that I was regularly doing before I started filling out the checkboxes. And because I was now in my text editor, I chose to write a script to do that clean-up.

Without reading the elisp code, it:

  • Removes the comment preamble
  • It adds the last commit message as the description
  • It tidies up the comments of two sections

Below is the lisp code to do the tidying up:

(defun jnf/forem-tidy-pull-request ()
  "Perform some quick tidying of the Forem PR template."
  (interactive)
  ;; Start from the beginning.
  (beginning-of-buffer)

  ;; The text before the first HTML/Markdown
  ;; comments is the commit message. Cut that
  ;; text...
  (search-forward "<!--")
  (kill-region 1 (- (point) 4))

  ;; ...and paste it inside the description
  ;; section.
  (replace-string
   "## Description\n\n"
   (concat "## Description\n\n"
           (format "%s" (car kill-ring))))

  ;; We've moved point (e.g., the cursor) so let's
  ;; jump back to the beginning of the buffer.
  (beginning-of-buffer)

  ;; Remove HTML/Markdown comments
  (replace-regexp
   "\\(\n\\)*<!--\\(.\\|\n\\)*-->\\(\n\\)*"
   "")

  ;; Clean out the comments for QA instructions;
  ;; I'll write them, but the notes are
  ;; unnecessary.
  (replace-regexp
   "QA Instructions, Screenshots, Recordings\\([^#]\\)*"
   "QA Instructions, Screenshots, Recordings\n\n")

  ;; Clean out accessibility concerns; I'll write
  ;; them, but the notes are unnecessary.
  (replace-regexp
   "UI accessibility concerns?\\([^#]\\)*"
   "UI accessibility concerns?\n\n"))

Enter fullscreen mode Exit fullscreen mode

Then comes the keyboard bindings to make this easier.

When copying from browser to Emacs, the editWithEmacs.spoon toggles on the hammerspoon-edit-minor-mode for the buffer. See the code for those details. The following code adds a new key binding Ctrl+c then t to the keyboard mappings.

(define-key
  hammerspoon-edit-minor-map
  (kbd "C-c t")
  #'jnf/forem-tidy-pull-request)

Enter fullscreen mode Exit fullscreen mode

Kind of nice. Load the content into an Emacs buffer, type Ctrl+c then t and I’m a few steps closer to completing my pull request.

What remains?

I wrote a script to build a pull request message from commit messages. Note, at my previous employer they chose to keep using—and keep choosing to use—the branch name master hence the code defaults to that.

I would like to better incorprate that conceptual script into my workflow.

And if I’m feeling up for the challenge, I’ll grab any Github links from the commit messages and add those to the related tasks and documents.

Conclusion

Since joining Forem, I’ve issued 32 pull requests. And as I started doing this task more, I started wondering, “How might I tweak my tooling to address some repetetive tasks?”

I let that question linger as I wrote several pull request messages in Emacs. And then, with a bit of time, I chose to spend a bit of time writing the above script. I don’t know how many pull requests I’ll need to write to “make up” for the time spent on the script.

But that is a lesser concern. I’m more concerned with getting comfortable understanding the interplay of the various systems I use and how I can mold them to assist in the tasks at hand.

When I start to create a pull request, I can quickly run the clean up task so that I can then focus on writing the pull request. In other words, I automated away a “distraction” so I could stay closer to the area of focus.

Discussion (0)