Reusable GitHub Actions workflows for Teams notifications and CI/CD utilities.
- Retrieves commit history formatted for Microsoft Adaptive Cards
- Time-ago formatting (Xs, Xm, Xh, Xd) for human-readable timestamps
- UTF-8 safe JSON construction using
jq - Designed for Microsoft Teams integration via webhooks
- Reusable via
workflow_calltrigger
jobs:
get-commits:
uses: marcus-hooper/workflows/.github/workflows/get-commit-messages.yml@v1
with:
commit_count: '5'Retrieves recent commit history formatted for Microsoft Adaptive Cards.
| Input | Required | Default | Description |
|---|---|---|---|
commit_count |
No | 10 |
Number of recent commits to retrieve |
| Output | Description |
|---|---|
commit_messages |
JSON array of commit objects with title (time ago) and value (linked message with author) |
[
{"title": "2h ago", "value": "[Fix bug](https://github.com/owner/repo/commit/abc123) (Author Name)"},
{"title": "1d ago", "value": "[Add feature](https://github.com/owner/repo/commit/def456) (Author Name)"}
]Here's a complete deployment workflow using get-commit-messages with Teams notification:
name: Deploy and Notify
on:
push:
branches: [main]
jobs:
get-commits:
uses: marcus-hooper/workflows/.github/workflows/get-commit-messages.yml@v1
with:
commit_count: '5'
deploy:
runs-on: ubuntu-latest
needs: get-commits
steps:
- uses: actions/checkout@v4
- name: Deploy to production
run: |
# Your deployment steps here
echo "Deploying application..."
- name: Send Teams notification
if: ${{ always() }}
uses: marcus-hooper/send-teams-notification@v1
with:
job_status: ${{ job.status }}
environment: production
commit_messages: ${{ needs.get-commits.outputs.commit_messages }}
webhook_url: ${{ secrets.TEAMS_WEBHOOK_URL }}- Checks out the repository with shallow clone (
fetch-depthmatchingcommit_count) - Extracts commit data using
git log(SHA, date, message, author) - Calculates relative time (seconds, minutes, hours, days ago)
- Builds JSON array using
jqfor safe character escaping - Outputs JSON via
GITHUB_OUTPUTheredoc syntax
When the workflow runs successfully, you'll see output similar to:
Run git log -n 5 --format='%H|%ct|%s|%an'
abc1234...|1737312000|Fix authentication bug|Alice
def5678...|1737225600|Add new feature|Bob
...
Processing 5 commits...
Building JSON array with jq...
Writing output to GITHUB_OUTPUT
The commit_messages output will contain:
[
{"title": "2h ago", "value": "[Fix authentication bug](https://github.com/owner/repo/commit/abc1234) (Alice)"},
{"title": "1d ago", "value": "[Add new feature](https://github.com/owner/repo/commit/def5678) (Bob)"}
]- Runs on
ubuntu-latest - Uses
jqfor JSON processing (pre-installed on GitHub runners) - Caller must have repository access (automatic for same-repo calls)
| Limitation | Details |
|---|---|
| Linux only | Workflow runs on ubuntu-latest; date commands use GNU syntax |
| Shallow clone | Only fetches commits up to commit_count; deeper history not available |
| Single-line title | Only first line of commit message is included |
| Time precision | Time-ago rounds down (e.g., 119 seconds shows as "1m ago") |
| Issue | Cause | Solution |
|---|---|---|
Empty commit_messages output |
Repository has no commits or fetch-depth: 0 in caller |
Ensure commits exist and don't override fetch-depth |
| Missing commits | commit_count too low or shallow clone in caller |
Increase commit_count or check caller's checkout step |
| Invalid JSON in downstream action | Special characters in commit messages | This workflow uses jq to escape; check downstream parsing |
| Time shows "0s ago" for all commits | System clock issue on runner | Rare; retry the workflow |
- Check workflow logs - Expand the "Extract commit history" step to see raw git output
- Verify commit count - Ensure
commit_countis passed as a string (YAML type requirement) - Test JSON output - Add a step to echo
${{ needs.get-commits.outputs.commit_messages }} - Check repository history - Run
git log -n 5locally to verify commits exist
workflows/
├── .github/
│ ├── dependabot.yml # Dependency updates
│ ├── labels.yml # Repository label definitions
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.yml # Bug report form
│ │ ├── feature_request.yml # Feature request form
│ │ └── config.yml # Issue template chooser
│ ├── PULL_REQUEST_TEMPLATE.md # PR template
│ └── workflows/
│ ├── get-commit-messages.yml # Main reusable workflow
│ ├── ci.yml # CI validation
│ ├── codeql.yml # CodeQL security analysis
│ ├── dependabot-auto-merge.yml
│ ├── labels.yml # Label synchronization
│ ├── release.yml # Version tag management
│ ├── schedule.yml # Scheduled maintenance
│ ├── scorecard.yml # OpenSSF Scorecard
│ └── security.yml # Security scanning
├── CHANGELOG.md # Version history
├── CONTRIBUTING.md # Contribution guidelines
├── README.md # This file
└── SECURITY.md # Security policy
yq- YAML parsing and validationactionlint- GitHub Actions workflow linter (includes ShellCheck)
# Validate YAML syntax
yq eval '.' .github/workflows/*.yml > /dev/null
# Lint workflows (recommended - includes ShellCheck integration)
actionlint
# Validate CHANGELOG format
grep -qE "^## \[Unreleased\]" CHANGELOG.md && echo "OK" || echo "Missing [Unreleased]"For basic local testing, use nektos/act. Note that some features (secrets, OIDC) require a real GitHub environment.
Contributions are welcome! Please see CONTRIBUTING.md for detailed guidelines.
Quick start:
- Check existing issues or open a new one
- Fork the repository
- Create a feature branch (
git checkout -b feature/my-feature) - Make your changes
- Ensure CI passes
- Submit a pull request
See the issue templates for bug reports and feature requests.
- send-teams-notification - Teams Adaptive Card notifications (pairs with this workflow)
- deployment-notification-o365 - Email notifications via Microsoft Graph API
- Adaptive Cards Designer - Visual card designer tool
See SECURITY.md for security policy and reporting vulnerabilities.
See CHANGELOG.md for version history.
MIT License - see LICENSE for details.