Skip to content

Guix channel for the latest Emacs from the master branch.

License

Notifications You must be signed in to change notification settings

gs-101/emacs-master

Repository files navigation

Emacs Master

Note

This channel features automation through GitHub Actions. That means bugs are to be expected.

If you want a safer experience but still close to source, check out the built-in emacs-next packages, or the ones available at the divya-lambda channel.

Guix channel featuring automated builds that run every two hours, updating the packages to the latest Savannah commit.

This channel is sort of a fork of divya-lambda1, which features a non-automated build of emacs-master, taken from guix-channel-emacs-master2.

Commit updates are made with a GitHub Actions workflow, and are automatically signed3.

Channel Definition

Use this for adding this channel to your configuration:

(cons* (channel
        (name 'emacs-master)
        (url "https://github.com/gs-101/emacs-master.git")
        (branch "main")
        (introduction
         (make-channel-introduction
          "568579841d0ca41a9d222a2cfcad9a7367f9073b"
          (openpgp-fingerprint
           "3049 BF6C 0829 94E4 38ED  4A15 3033 E0E9 F7E2 5FE4"))))
       %default-channels)

Packages

Since this takes packages from divya-lambda, the following packages are available:

emacs-master

Regular package.

emacs-master-pgtk

Package featuring a GTK build. Best suited for Wayland users.

emacs-master-lucid

Package using the Lucid (Athena) X toolkit. Best suited for those on X11.

Some recommend it over PGTK, so try both of them out and use what best suits you.

emacs-master-igc

New garbage collection method in development.

Workflow

In case I stop maintaining this and someone else becomes interested, this section details how the workflow works.

Scheduling

Scheduling is done through the use of a cron job, taken from copr-lutris-git4.

At first, it ran every hour:

on:
  workflow_dispatch:
  schedule:
    - cron: "0 * * * *"

But then I changed it to every two hours because I thought I was overloading savannah:

on:
  workflow_dispatch:
  schedule:
    - cron: "0 */2 * * *"

The Job

To allow GitHub Actions to commit to repository, you need to give the job write permissions:

jobs:
  update-emacs:
    runs-on: ubuntu-latest
    permissions:
      contents: write

Steps

Checkout

This should’ve been clear to me from the start, but, to have Actions actually work with your repository, you have to use the checkout action:

- name: Checkout Repository
  uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683

This makesthe runner clone your repository.

Dependencies

These dependencies are primarily used by the scripts. Guix is used to get the hash of the Emacs commit, in the get_hash script. Since we’re not installing anything, no extra setup for Guix is required.

- name: Install Dependencies
  run: |
    sudo apt-get update
    sudo apt-get install -y curl grep guix git gpg guile-3.0 guile-library

Get Curent Commit

This is going to be needed later. It cuts the exact space where the commit hash is found, storing it in a enviroment variable, so it can be used by the other steps.

- name: Get Current Commit
  run: |
    echo "current-commit=$(grep "(define emacs-master-commit" emacs-master.scm | awk '{print $3}' | cut -c 2-41)" >> $GITHUB_ENV

Update Emacs

This runs the scripts from guix-channel-emacs-master for getting the latest commit. update-emacs gets the commit and time, and we rely on get_hash for, well, getting the hash.

- name: Update Emacs
  run: |
    chmod +x bin/get_hash.sh
    chmod +x bin/update-emacs
    bin/update-emacs
    echo "new-commit=$(grep "(define emacs-master-commit" emacs-master.scm | awk '{print $3}' | cut -c 2-41)" >> $GITHUB_ENV

We also create another variable, new-commit, to be usd in the next step: Compare Commits.

Compare Commits

Despite what the echoed messages say, this doesn’t make the workflow exit directly. It’s a simple comparison for defining a boolean variable to be used by the other steps.

- name: Compare Commits
  id: compare-commits
  run: |
    if [ "${{ env.new-commit }}" != "${{ env.current-commit }}" ]; then
      echo "The commits are different. Continue the workflow."
      echo "different-commit='true'" >> $GITHUB_OUTPUT
    else
      echo "The commits are the same. Exiting the workflow..."
      echo "different-commit='false'" >> $GITHUB_OUTPUT
    fi

GPG Key

This is where we use those instructions from “Sign git commits with GPG in GitHub Actions”. This is the workflow’s key, not yours.

We’ll setup some repository secrets. See how repository is in bold? That indicates another mistake I made during this. I thought that GitHub Actions used enviroment secrets, so I wasted some time on this.

./images/gpg_secrets.png

In case you didn’t know how, you can generate a GPG key with:

gpg --full-generate-key
  1. When choosing a key type, you can pick a signing only one if you want. We have no need for encryption here. I always choose RSA.
  2. For the keysize, same thing, you choose. I always go for 4096 because there’s no issue in doing this.
  3. Make it not expire if you want, though, that can be insecure.
  4. Use either your real name or your GitHub username.
  5. This should be the e-mail address you use for GitHub.
  6. Add a descriptive comment here, you’ll start to make a lot of these once you get used to them. Mine is “GitHub Actions Key”.
  7. Make a password.
  8. There is no other step, that was it!

Now we’ll get to the secrets. Save them to Settings → Secrets and variables → Actions → Repository secrets with these exact names.

GPG_KEY_PASSPHRASE

This is the password you set up for the key.

GPG_KEY_ID

This is the identification of the key, you can get this with:

gpg --list-secret-keys --keyid-format=long
    
sec   something/YOU-WANT-THIS-HERE 1111-11-11 [SC] [expires: 9999-99-99]
      don't-bother-with-this
uid                 [ultimate] your-name (GitHub Actions Key) <[email protected]>
    

You’ll want the numbers and letters that are in the same position as YOU-WANT-THIS-HERE in the example above.

your-name and [email protected] are also important, but will be explained later.

GPG_KEY

THis is your key itself, exported in base64. Based on the previous variable, you’d run:

gpg --export-secret-keys YOU-WANT-THIS-HERE | base64
    

This will give you even more numbers and letters.

Note

If your terminal added newlines for the display, before adding this output to your secrets, remove the newlines and make everything a single line. I’m not sure if this is necessary, but seems like a good practice.

Import GPG Key

This just makes the runner import your base64 encoded key:

- name: Import GPG Key
  if: ${{ contains(steps.compare-commits.Outputs.different-commit, 'true') }}
  run: echo "$GPG_KEY" | base64 --decode | gpg --batch --import
  env:
    GPG_KEY: ${{ secrets.GPG_KEY }}

The if statement comes from our previous comparison step. This and the next steps only run if different-commit is true.

Custom GPG Signing Program

Used in the next step for Git. Makes it so that the runner always inputs the passphrase, to keep the process automatic. It’s not like we can access it to input the password, and even if we could, that would be a manual step.

- name: Custom GPG Signing Program
  if: ${{ contains(steps.compare-commits.Outputs.different-commit, 'true') }}
  run: |
    echo "#!/bin/bash" >> /tmp/gpg.sh
    echo "gpg --batch --pinentry-mode=loopback --passphrase \$GPG_KEY_PASSPHRASE \"\$@\"" >> /tmp/gpg.sh
    chmod +x /tmp/gpg.sh
  env:
    GPG_KEY_PASSPHRASE: ${{ secrets.GPG_KEY_PASSPHRASE }}
Setup Git

Nothing out of the ordinary. This just makes Git use our key.

- name: Setup Git
  if: ${{ contains(steps.compare-commits.Outputs.different-commit, 'true') }}
  run: |
    git config commit.gpgsign true
    git config user.signingkey $GPG_KEY_ID
    git config gpg.program /tmp/gpg.sh
  env:
    GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
Commit
- name: Commit
  if: ${{ contains(steps.compare-commits.Outputs.different-commit, 'true') }}
  run: |
    git add emacs-master.scm
    short_commit=$(grep "(define emacs-master-commit" emacs-master.scm | awk '{print $3}' | cut -c 2-8)
    git commit -m "feat (emacs-master.scm): Update Emacs to $short_commit" --gpg-sign=$GPG_KEY_ID
    git push --set-upstream origin main
  env:
   GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
   GPG_KEY_PASSPHRASE: ${{ secrets.GPG_KEY_PASSPHRASE }}
   GIT_COMMITTER_NAME: ${{ secrets.GIT_COMMITTER_NAME }}
   GIT_COMMITTER_EMAIL: ${{ secrets.GIT_COMMITTER_EMAIL }}
   GIT_AUTHOR_NAME: github-actions
   GIT_AUTHOR_EMAIL: [email protected]

Not sure if --gpg-sign=$GPG_KEY_ID is necessary, but I don’t want to change as everything is working now. Try doing a run without it to see the outcome.

Now, remember when I said that your-name and [email protected] were important? This is where they are used. Add them as GIT_COMMITTER_NAME and GIT_COMMITTER_EMAIL, respectively.

GIT_AUTHOR_NAME should preferably be the name of your workflow bot (we use GitHub Actions, so I named it github-actions here). GIT_AUTHOR_EMAIL can be anything.

And that was it for the workflow! Hope you could understand everything.

References

1 Ranjan, D. (2024) “Divya-lambda.” Available at: https://codeberg.org/divyaranjan/divya-lambda (Accessed: January 16, 2025).

2 Azmain Turja, A. (2023) “guix-channel-emacs-master.” Available at: https://codeberg.org/akib/guix-channel-emacs-master (Accessed: January 16, 2025).

3 Bakulin, S. “Sign git commits with GPG in GitHub Actions” Available at: https://gist.github.com/vansergen/88eb7e71fea2e3bdaf6aa3e752371eb7 (Accessed: January 16, 2025).

4 Greiner, J. (2025) “Projectsynchro/copr-lutris-git.” Available at: https://github.com/ProjectSynchro/copr-lutris-git (Accessed: January 18, 2025).

About

Guix channel for the latest Emacs from the master branch.

Topics

Resources

License

Stars

Watchers

Forks