Skip to content

GitHub Files and Templates

Use these actions to write repository content.

Use github.template.apply when several files share the same values and commit message. Use github.file.create when one file needs a separate message, a separate source, or special handling.

When an action receives owner and repo, Forge adds repository-aware template values automatically:

ValueExample
gitHostgithub.com
gitVendorgithub
repositoryOwneradaptive-labs
repositoryNamepayments-api
repositoryFullNameadaptive-labs/payments-api
repositoryQualifiedOwnergithub.com/adaptive-labs
modulePathgithub.com/adaptive-labs/payments-api

This keeps molds portable. Prefer these built-in values over hardcoding module paths.

Applies a directory of templates from the mold repository into the target repository.

steps:
- id: apply-service-template
name: Apply service template
action: github.template.apply
inputs:
owner: "${{ inputs.owner }}"
repo: "${{ inputs.name }}"
source_path: ./skeleton
target_path: .
message: "feat: scaffold service"
template_values:
serviceName: "${{ inputs.name }}"
description: "${{ inputs.description }}"
port: "${{ inputs.port }}"
goVersion: "${{ inputs.goVersion }}"

Inputs:

InputRequiredDescription
ownerYesRepository owner or qualified owner
repoYesTarget repository name
source_pathYesTemplate directory relative to the mold file
target_pathNoDestination directory in the repository
messageNoCommit message used for written files
template_valuesNoValues available inside the templates
includeNoOnly include matching files
excludeNoSkip matching files

Files ending in .tmpl are rendered with Go template syntax and written without the .tmpl suffix. For example, skeleton/cmd/{{ .serviceName }}/main.go.tmpl becomes cmd/payments-api/main.go.

The template directory must stay inside the mold directory. This prevents a mold from reading unrelated repository files.

Example with include and exclude filters:

steps:
- id: apply-template
name: Apply template
action: github.template.apply
inputs:
owner: "${{ inputs.owner }}"
repo: "${{ inputs.name }}"
source_path: ./skeleton
include:
- "cmd/**"
- "internal/**"
- go.mod.tmpl
exclude:
- "**/*.bak"
template_values:
serviceName: "${{ inputs.name }}"

Creates or updates one file.

Inline content:

steps:
- id: add-readme
name: Add README
action: github.file.create
inputs:
owner: "${{ inputs.owner }}"
repo: "${{ inputs.name }}"
path: README.md
message: "docs: add README"
content: |
# ${{ inputs.name }}
${{ inputs.description }}

Template file from the same mold directory:

steps:
- id: add-main
name: Add main package
action: github.file.create
inputs:
owner: "${{ inputs.owner }}"
repo: "${{ inputs.name }}"
path: "cmd/${{ inputs.name }}/main.go"
message: "feat: add main package"
template_path: ./skeleton/cmd/main.go.tmpl
template_values:
serviceName: "${{ inputs.name }}"
port: "${{ inputs.port }}"

Template file from a template store:

steps:
- id: add-dockerfile
name: Add Dockerfile
action: github.file.create
inputs:
owner: "${{ inputs.owner }}"
repo: "${{ inputs.name }}"
path: Dockerfile
message: "build: add Dockerfile"
template_url: "https://raw.githubusercontent.com/shoehorn-dev/shoehorn-molds-templates/main/go-service/Dockerfile.tmpl"
template_values:
serviceName: "${{ inputs.name }}"

Inputs:

InputRequiredDescription
ownerYesRepository owner or qualified owner
repoYesTarget repository name
pathYesPath to write in the repository
messageNoCommit message
contentOne content source is requiredInline file content
template_pathOne content source is requiredTemplate path relative to the mold file
template_urlOne content source is requiredRemote template URL
template_valuesNoValues available inside templates
branchNoBranch to write to

Remote templates can be raw HTTP URLs or GitHub template URLs. Prefer a stable branch, tag, or commit SHA for shared template stores.