Documentation
The GitHub CMS project presents a system for enabling content management and publication capabilities on any GitHub Repository. Content is stored as GitHub Issues, managed through GitHub Projects, published by a GitHub Action to a GitHub Repository and hosted by GitHub Pages.
- Introduction
- Design
- Architecture
- Installation
- Content Management
- Credits
Introduction
A GitHub repository has all of the ingredients for serving as a content management system.
Features
- 100% hosted on GitHub services
- Utilize advanced editing features of GitHub Issues when creating content. For example,
- Paste images and spreadsheet cells
- Keyboard shortcuts for formatting actions. eg. ctrl+B for bold, ctrl+I for italic
- Organize Issues into Projects that map to content collections
- Manage the relationships between GitHub issues and published file to any GitHub repository.
- Publish GitHub Issues as Markdown files to any GitHub repository
Design
Glossary of Terms
- Content management system is defined as a system for managing web pages and/or posts. It provides functionality that allows users to draft, publish, archive, and delete content. It represents the source of truth for all content that it manages.
- Content publication is the process of synchronizing source content with some target system based on the content’s publication state.
- Source system for all content is GitHub Issues where each issue represents one content item.
- Target system is a GitHub repository where published content items are rendered as Markdown files. This repository is rendered as a website with GitHub Pages.
- Meta system is a GitHub repository where source/target relationships are stored as JSON files. When source content is published, metadata regarding the source/target relationship is updated.
- Publication states are managed through a GitHub Project that acts as a state machine.
- Publication actions are defined with JavaScript in Node.js and executed by GitHub Actions.
Publication States
Source content can be in one of four publication states:
- Staged
- Items in this state are “staged” for a publishing action. That means, moving from this state to Published or Archived will execute that publishing action (Publish or Archive). Moving from Published or Archived to this state will produce no publishing action.
- Published
- Items in this state have a metadata record that relates the source item to a target item.
- Archived
- Items in this state have a metadata record that relates the source item to a target item.
- Unpublished
- Items in this state are not mapped to the target system. There is no metadata record for the source item. If the item is currently in a Published or Archived state, it will be removed from the target system and its metadata record will also be removed.
Publication Actions
The system supports the following actions. The general logic is described along with the action.
- Publish
- Get Issue content
- Transform content into target format
- Get metadata, if exists
- Remove target published content, if exists
- Remove target archived content, if exists
- Compute target content location and other metadata
- Publish target content to target location
- Save metadata
- Archive
- Get Issue content
- Transform content into target format
- Get metadata, if exists
- Remove target published content, if exists
- Remove target archived content, if exists
- Compute target content location and other metadata
- Publish target content to target location
- Save metadata
- Unpublish
- Get metadata for Issue
- Remove target published content, if exists
- Remove target archived content, if exists
- Remove metadata
Architecture
There are four pieces that enable publishing:
- Publication process to execute publishing actions in response to content state changes
- Content “Source of Truth”
- Location to store published content
- Publication metadata
The architecture presented here is separated by functional role within the system (and, therefore, into separate repositories). Separate repositories are not a requirement and GitHub CMS can be completely self contained in a single repository.
Publication Process
The GitHub CMS Action represents the process that executes publication actions and manages publication state. This action is used by a Source Content Repository.
Source Content Repository
The GitHub Issues in this repository represent the “Source of Truth” for all content that is published by GitHub CMS Action. A GitHub Issue and content item are used interchangeably. They are the same from our perspective.
GitHub Projects in this repository are used to organize Issues into “Collections”. These projects also represent state machines used to move Issues between Staging, Published, Unpublished, and Archived states. State changes are observed and reacted to by GitHub CMS Action.
Target Publication Repository
This GitHub Repository hosts all content published from the Source Content Repository. GitHub CMS is configured to generate Markdown formatted text files containing Jekyll front-matter. This allows instant support for hosting published content with GitHub Pages.
Metadata Repository
This GitHub Repository stores the following information content items:
- Issue Number - of the content item in the Source Content Repository.
- Publication State - whether
published
,archived
. - Target Content Location - the path to the file where the target content item resides.
- Last Updated - the timestamp of the last publication change for the content item.
Installation
This guide will show you how to setup GitHub CMS across three separate repositories aligning to the following roles:
- Source Content Repository
- Target Publication Repository
- Meta Repository
You must have an access token with the repo
scope on the three repositories above. The easiest way to do this is to make sure all of the repositories are in your account and create a Personal Access Token with the repo
scope.
See Creating a personal access token for the command line for more information.
Although separate repositories makes the components of the system very clear and flexible, it is not a requirement that you create one repository per role.
GitHub CMS can be setup in a single repository, if you wish. Simply use the same repository as you follow the setup instructions below.
Setup the Meta Repository
You can use any GitHub Repository (public or private) that you have repo
access to. For this example, a repository was created at paulkoanui/meta-repo-1
.
META_OWNER | META_REPO |
---|---|
paulkoanui | meta-repo-1 |
(in a future step, you will configure the publication workflow to use the above values)
Setup the Target Publication Repository
You can use any GitHub Repository (public or private) that you have repo
access to. For this example, a repository was created at paulkoanui/target-content-repo-1
.
TARGET_OWNER | TARGET_REPO |
---|---|
paulkoanui | target-content-repo-1 |
(in a future step, you will configure the publication workflow to use the above values)
Setup the Source Content Repository
You can use any GitHub Repository (public or private) that you have repo
access to and that has Issues you wish to publish to a Target Publication Repository. For this example, a repository was created at paulkoanui/source-content-repo-1
.
SRC_OWNER | SRC_REPO |
---|---|
paulkoanui | source-content-repo-1 |
(in a future step, you will configure the publication workflow to use the above values)
Setup GitHub CMS Publication
To complete installation and setup of publication capabilities on the Source Content Repository,
- Create a GitHub Project on the repository. It will be referred to as a Collection Project.
- For example,
paulkoanui/source-content-repo-1
has a project called “Posts”. - Issues to be published go in this project.
- For example,
- Define a Publication Workflow that uses GitHub CMS Action
GitHub CMS Action is an open source GitHub Action that executes the publication process when Issues inside of a Project change columns (state). It can be used without downloading anything. Think of it like a GitHub Repository Plugin.
Create a Collection Project
- Go to Projects.
- Create a Project and add state columns.
For example, in the video below, we create a Project called “Posts” that will be used to publish Jekyll formatted blog posts.
Define the Publication Workflow
This is a YAML file, called github-cms.yml
. It defines the publication process and how it operates. Once customized, this file will be placed in .github/workflows
in the Source Content Repository.
See the Configuring a Workflow for GitHub Actions for more info.
Copy github-cms.template.yml
Configure Repository Details
In the env
section of the workflow file, customize these values. Other values that you don’t have to change have been omitted for brevity.
# This is the source system repository
SRC_AUTH: ***
SRC_OWNER: paulkoanui
SRC_REPO: source-content-repo-1
# This is the target system repository
TARGET_AUTH: ***
TARGET_OWNER: paulkoanui
TARGET_REPO: target-content-repo-1
# This is the metadata repository
META_AUTH: ***
META_OWNER: paulkoanui
META_REPO: meta-repo-1
Setup to Observe Changes in the “Posts” Project
The “Posts” Project contains three state columns “Staging”, “Published”, “Archived”. GitHub CMS Action observes when Issues move to the “Published” or “Archived” columns.
# Collections and actions mapped to project columns
POSTS_PUBLISH_COLUMN: 8363572
POSTS_ARCHIVE_COLUMN: 8363575
You can get the project column ID by choosing “Copy Column Link”
Enable the Publication Workflow
To enable all of the GitHub CMS publication features, push github-cms.yml
to the Source Content Repository at .github/workflows/github-cms.yml
.
Try It Out: Publish a Post
With
.github/workflows/github-cms.yml
in place, content publication with GitHub CMS can begin!
- Create an Issue in the Source Content Repository with a title and body.
- Need boilerplate content? Maybe some Lorem Markdownum?
- Add the Issue to the “Posts” Project. If “awaiting triage”, move to Staging
- Move the Issue from the Staging column to the Published column.
- Wait a few seconds (or view the publication progress from the Actions tab)
- Go to the Target Publication Repository and observe the Issue has been published as a Jekyll formatted blog post in the
_posts
folder.
Content Management
Stage Content
Staged content are GitHub Issues organized in the “Staging” column of a GitHub Project. Items in this state are waiting to be published or archived.
From the Source Content Repository:
- Go to the GitHub Project where you wish to stage content
- Click “Add Cards” to bring up a list of all Issues
- Drag an Issue card into the “Staging” column
- GitHub CMS Action doesn’t perform any action when an item is moved into Staging.
“Staging” is simply an organizational state that says, “This item belongs in this collection but is not ready to be published or archived in its current form.”
Publish Content
Published content are GitHub Issues organized in the “Published” column of a GitHub Project. Items in this state are published to the Target Publication Repository.
From the Source Content Repository:
- Go to the GitHub Project where you wish to publish content
- Drag an Issue card from “Staging” or “Archived” columns into the “Published” column
- GitHub CMS Action responds to the state change and publishes the content
Archive Content
Archived content are GitHub Issues organized in the “Archived” column of a GitHub Project. Items in this state are archived to the Target Publication Repository.
The publication workflow,
github-cms.yml
, specifies theTARGET_ARCHIVE_PATH
environment variable. The default value is_archive
. So, if a published item exists at_pages/my-content-page.md
, the archived path is,_archive/_pages/my-content-page.md
.
From the Source Content Repository:
- Go to the GitHub Project where you wish to archive content
- Drag an Issue card from “Staging” or “Published” columns into the “Archived” column
- GitHub CMS Action responds to the state change and archives the content
Unpublish Content
In order to unpublish content, you must remove it from the GitHub Project that manages its publication state.
From the Source Content Repository:
- Go to the GitHub Project where you wish to unpublish content
- Open the context menu for the item you wish to unpublish and choose “Remove from Project”
- GitHub CMS Action responds to the state change and unpublishes the content
Updating Published or Archived Content
Content placed in the Target Publication Repository reflects Issue content at the time of the publication action. Therefore, subsequent updates to the published or archived issue are NOT automatically reflected in the target system.
To update Published content after changes:
- Go to the GitHub Project that manages the content publication state.
- Move the Issue from “Published” to “Staging”
- Move the Issue from “Staging” to “Published”
- GitHub CMS Action responds to the state change and publishes the updated content
To update Archived content after changes:
- Go to the GitHub Project that manages the content publication state.
- Move the Issue from “Archived” to “Staging”
- Move the Issue from “Staging” to “Archived”
- GitHub CMS Action responds to the state change and archives the updated content
Credits
- PortfolYOU A Jekyll theme by Youssef Raafat.