GitHub Actions Tutorial — String Functions
String & Type Functions
GitHub Actions provides built-in functions for string manipulation, type checking, and data conversion. These are used inside expressions to build dynamic workflows.
String Functions
contains()
Checks if a string contains a substring (case-insensitive):
if: contains(github.event.head_commit.message, '[skip ci]')
if: contains(github.event.pull_request.labels.*.name, 'urgent')
startsWith()
if: startsWith(github.ref, 'refs/tags/v')
endsWith()
if: endsWith(github.repository, '-private')
format()
String formatting with positional placeholders:
steps:
- run: echo "${{ format('Hello {0}, welcome to {1}!', github.actor, github.repository) }}"
Output: Hello octocat, welcome to my-org/my-repo!
Use {{ and }} to escape literal braces in format strings:
${{ format('JSON: {{"key": "{0}"}}', 'value') }}
join()
Join array elements into a string:
${{ join(github.event.pull_request.labels.*.name, ', ') }}
Output: bug, enhancement, priority
Type Functions
toJSON()
Convert a value to a formatted JSON string. Useful for debugging context objects:
steps:
- name: Dump github context
run: echo '${{ toJSON(github) }}'
- name: Dump matrix
run: echo '${{ toJSON(matrix) }}'
fromJSON()
Parse a JSON string into an object:
steps:
- name: Parse JSON output
id: data
run: echo 'config={"deploy":true,"env":"prod"}' >> "$GITHUB_OUTPUT"
- name: Use parsed value
if: fromJSON(steps.data.outputs.config).deploy == true
run: echo "Deploying to ${{ fromJSON(steps.data.outputs.config).env }}"
Dynamic Matrix with fromJSON()
jobs:
setup:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set.outputs.matrix }}
steps:
- id: set
run: echo 'matrix={"os":["ubuntu-latest","windows-latest"],"node":[18,20]}' >> "$GITHUB_OUTPUT"
build:
needs: setup
strategy:
matrix: ${{ fromJSON(needs.setup.outputs.matrix) }}
runs-on: ${{ matrix.os }}
steps:
- run: echo "OS=${{ matrix.os }}, Node=${{ matrix.node }}"
hashFiles()
Generate a SHA-256 hash of files — commonly used for cache keys:
- uses: actions/cache@v4
with:
path: node_modules
key: node-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
hashFiles() accepts glob patterns:
${{ hashFiles('**/package-lock.json') }} # all package-lock files
${{ hashFiles('**/*.go', 'go.sum') }} # Go source + dependencies
Function Reference
| Function | Purpose | Example |
|---|---|---|
contains(search, item) |
Substring check | contains(msg, '[skip]') |
startsWith(str, prefix) |
Prefix check | startsWith(ref, 'refs/tags/') |
endsWith(str, suffix) |
Suffix check | endsWith(repo, '-dev') |
format(fmt, args...) |
String formatting | format('{0}-{1}', os, node) |
join(array, sep) |
Join array | join(labels.*.name, ',') |
toJSON(value) |
Convert to JSON string | toJSON(github) |
fromJSON(str) |
Parse JSON string | fromJSON(output) |
hashFiles(patterns...) |
SHA-256 hash of files | hashFiles('**/lock*') |
Common Mistakes
| Mistake | Fix |
|---|---|
contains() is case-sensitive for arrays |
contains() is case-insensitive for strings, but array matching depends on exact value |
fromJSON() fails on invalid JSON |
Ensure the string is valid JSON before parsing |
hashFiles() returns empty string |
No files matched the glob pattern — check the pattern |
Using format() with unescaped braces |
Use {{ and }} to escape literal braces |
Quick Reference
| Category | Functions |
|---|---|
| String | contains(), startsWith(), endsWith(), format(), join() |
| Type | toJSON(), fromJSON() |
| Hashing | hashFiles() |
| Status | success(), failure(), always(), cancelled() |
← Previous: Status Functions
Next: Practice Exercises →