{"id":31692523,"url":"https://github.com/marcus-hooper/workflows","last_synced_at":"2026-01-20T06:01:02.879Z","repository":{"id":316664066,"uuid":"1064356111","full_name":"marcus-hooper/workflows","owner":"marcus-hooper","description":"Reusable GitHub Actions workflows for Teams notifications and CI/CD utilities (commit history, Adaptive Cards). PowerShell 7, UTF‑8 safe.","archived":false,"fork":false,"pushed_at":"2025-09-25T23:21:48.000Z","size":2,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-08T14:58:41.024Z","etag":null,"topics":["composite-action","github-actions","reusable-workflows"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marcus-hooper.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-25T23:14:45.000Z","updated_at":"2025-09-25T23:17:42.000Z","dependencies_parsed_at":"2025-09-26T01:29:05.277Z","dependency_job_id":null,"html_url":"https://github.com/marcus-hooper/workflows","commit_stats":null,"previous_names":["marcus-hooper/workflows"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/marcus-hooper/workflows","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcus-hooper%2Fworkflows","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcus-hooper%2Fworkflows/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcus-hooper%2Fworkflows/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcus-hooper%2Fworkflows/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marcus-hooper","download_url":"https://codeload.github.com/marcus-hooper/workflows/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcus-hooper%2Fworkflows/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28597087,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T02:08:49.799Z","status":"ssl_error","status_checked_at":"2026-01-20T02:08:44.148Z","response_time":117,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["composite-action","github-actions","reusable-workflows"],"created_at":"2025-10-08T14:53:37.511Z","updated_at":"2026-01-20T06:01:02.873Z","avatar_url":"https://github.com/marcus-hooper.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# workflows\n\n[![CI](https://github.com/marcus-hooper/workflows/actions/workflows/ci.yml/badge.svg)](https://github.com/marcus-hooper/workflows/actions/workflows/ci.yml)\n[![CodeQL](https://github.com/marcus-hooper/workflows/actions/workflows/codeql.yml/badge.svg)](https://github.com/marcus-hooper/workflows/actions/workflows/codeql.yml)\n[![Security](https://github.com/marcus-hooper/workflows/actions/workflows/security.yml/badge.svg)](https://github.com/marcus-hooper/workflows/actions/workflows/security.yml)\n[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/marcus-hooper/workflows/badge)](https://scorecard.dev/viewer/?uri=github.com/marcus-hooper/workflows)\n[![GitHub release](https://img.shields.io/github/v/release/marcus-hooper/workflows)](https://github.com/marcus-hooper/workflows/releases)\n[![GitHub Actions](https://img.shields.io/badge/GitHub_Actions-2088FF?logo=githubactions\u0026logoColor=white)](https://docs.github.com/en/actions)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nReusable GitHub Actions workflows for Teams notifications and CI/CD utilities.\n\n## Features\n\n- Retrieves commit history formatted for Microsoft Adaptive Cards\n- Time-ago formatting (Xs, Xm, Xh, Xd) for human-readable timestamps\n- UTF-8 safe JSON construction using `jq`\n- Designed for Microsoft Teams integration via webhooks\n- Reusable via `workflow_call` trigger\n\n## Quick Start\n\n```yaml\njobs:\n  get-commits:\n    uses: marcus-hooper/workflows/.github/workflows/get-commit-messages.yml@v1\n    with:\n      commit_count: '5'\n```\n\n## Available Workflows\n\n### Get Commit Messages\n\nRetrieves recent commit history formatted for Microsoft Adaptive Cards.\n\n#### Inputs\n\n| Input | Required | Default | Description |\n|-------|----------|---------|-------------|\n| `commit_count` | No | `10` | Number of recent commits to retrieve |\n\n#### Outputs\n\n| Output | Description |\n|--------|-------------|\n| `commit_messages` | JSON array of commit objects with `title` (time ago) and `value` (linked message with author) |\n\n#### Output Format\n\n```json\n[\n  {\"title\": \"2h ago\", \"value\": \"[Fix bug](https://github.com/owner/repo/commit/abc123) (Author Name)\"},\n  {\"title\": \"1d ago\", \"value\": \"[Add feature](https://github.com/owner/repo/commit/def456) (Author Name)\"}\n]\n```\n\n### Complete Workflow Example\n\nHere's a complete deployment workflow using `get-commit-messages` with Teams notification:\n\n```yaml\nname: Deploy and Notify\n\non:\n  push:\n    branches: [main]\n\njobs:\n  get-commits:\n    uses: marcus-hooper/workflows/.github/workflows/get-commit-messages.yml@v1\n    with:\n      commit_count: '5'\n\n  deploy:\n    runs-on: ubuntu-latest\n    needs: get-commits\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Deploy to production\n        run: |\n          # Your deployment steps here\n          echo \"Deploying application...\"\n\n      - name: Send Teams notification\n        if: ${{ always() }}\n        uses: marcus-hooper/send-teams-notification@v1\n        with:\n          job_status: ${{ job.status }}\n          environment: production\n          commit_messages: ${{ needs.get-commits.outputs.commit_messages }}\n          webhook_url: ${{ secrets.TEAMS_WEBHOOK_URL }}\n```\n\n## How It Works\n\n1. Checks out the repository with shallow clone (`fetch-depth` matching `commit_count`)\n2. Extracts commit data using `git log` (SHA, date, message, author)\n3. Calculates relative time (seconds, minutes, hours, days ago)\n4. Builds JSON array using `jq` for safe character escaping\n5. Outputs JSON via `GITHUB_OUTPUT` heredoc syntax\n\n## Sample Workflow Logs\n\nWhen the workflow runs successfully, you'll see output similar to:\n\n```\nRun git log -n 5 --format='%H|%ct|%s|%an'\nabc1234...|1737312000|Fix authentication bug|Alice\ndef5678...|1737225600|Add new feature|Bob\n...\n\nProcessing 5 commits...\nBuilding JSON array with jq...\nWriting output to GITHUB_OUTPUT\n```\n\nThe `commit_messages` output will contain:\n\n```json\n[\n  {\"title\": \"2h ago\", \"value\": \"[Fix authentication bug](https://github.com/owner/repo/commit/abc1234) (Alice)\"},\n  {\"title\": \"1d ago\", \"value\": \"[Add new feature](https://github.com/owner/repo/commit/def5678) (Bob)\"}\n]\n```\n\n## Requirements\n\n- Runs on `ubuntu-latest`\n- Uses `jq` for JSON processing (pre-installed on GitHub runners)\n- Caller must have repository access (automatic for same-repo calls)\n\n## Limitations\n\n| Limitation | Details |\n|------------|---------|\n| Linux only | Workflow runs on `ubuntu-latest`; date commands use GNU syntax |\n| Shallow clone | Only fetches commits up to `commit_count`; deeper history not available |\n| Single-line title | Only first line of commit message is included |\n| Time precision | Time-ago rounds down (e.g., 119 seconds shows as \"1m ago\") |\n\n## Troubleshooting\n\n### Common Issues\n\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| Empty `commit_messages` output | Repository has no commits or `fetch-depth: 0` in caller | Ensure commits exist and don't override `fetch-depth` |\n| Missing commits | `commit_count` too low or shallow clone in caller | Increase `commit_count` or check caller's checkout step |\n| Invalid JSON in downstream action | Special characters in commit messages | This workflow uses `jq` to escape; check downstream parsing |\n| Time shows \"0s ago\" for all commits | System clock issue on runner | Rare; retry the workflow |\n\n### Debug Tips\n\n1. **Check workflow logs** - Expand the \"Extract commit history\" step to see raw git output\n2. **Verify commit count** - Ensure `commit_count` is passed as a string (YAML type requirement)\n3. **Test JSON output** - Add a step to echo `${{ needs.get-commits.outputs.commit_messages }}`\n4. **Check repository history** - Run `git log -n 5` locally to verify commits exist\n\n## Project Structure\n\n```\nworkflows/\n├── .github/\n│   ├── dependabot.yml              # Dependency updates\n│   ├── labels.yml                  # Repository label definitions\n│   ├── ISSUE_TEMPLATE/\n│   │   ├── bug_report.yml          # Bug report form\n│   │   ├── feature_request.yml     # Feature request form\n│   │   └── config.yml              # Issue template chooser\n│   ├── PULL_REQUEST_TEMPLATE.md    # PR template\n│   └── workflows/\n│       ├── get-commit-messages.yml # Main reusable workflow\n│       ├── ci.yml                  # CI validation\n│       ├── codeql.yml              # CodeQL security analysis\n│       ├── dependabot-auto-merge.yml\n│       ├── labels.yml              # Label synchronization\n│       ├── release.yml             # Version tag management\n│       ├── schedule.yml            # Scheduled maintenance\n│       ├── scorecard.yml           # OpenSSF Scorecard\n│       └── security.yml            # Security scanning\n├── CHANGELOG.md                    # Version history\n├── CONTRIBUTING.md                 # Contribution guidelines\n├── README.md                       # This file\n└── SECURITY.md                     # Security policy\n```\n\n## Development\n\n### Requirements\n\n- `yq` - YAML parsing and validation\n- `actionlint` - GitHub Actions workflow linter (includes ShellCheck)\n\n### Validation\n\n```bash\n# Validate YAML syntax\nyq eval '.' .github/workflows/*.yml \u003e /dev/null\n\n# Lint workflows (recommended - includes ShellCheck integration)\nactionlint\n\n# Validate CHANGELOG format\ngrep -qE \"^## \\[Unreleased\\]\" CHANGELOG.md \u0026\u0026 echo \"OK\" || echo \"Missing [Unreleased]\"\n```\n\n### Local Testing\n\nFor basic local testing, use [nektos/act](https://github.com/nektos/act). Note that some features (secrets, OIDC) require a real GitHub environment.\n\n## Contributing\n\nContributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines.\n\nQuick start:\n\n1. Check existing [issues](https://github.com/marcus-hooper/workflows/issues) or open a new one\n2. Fork the repository\n3. Create a feature branch (`git checkout -b feature/my-feature`)\n4. Make your changes\n5. Ensure CI passes\n6. Submit a pull request\n\nSee the issue templates for [bug reports](.github/ISSUE_TEMPLATE/bug_report.yml) and [feature requests](.github/ISSUE_TEMPLATE/feature_request.yml).\n\n## Related Projects\n\n- [send-teams-notification](https://github.com/marcus-hooper/send-teams-notification) - Teams Adaptive Card notifications (pairs with this workflow)\n- [deployment-notification-o365](https://github.com/marcus-hooper/deployment-notification-o365) - Email notifications via Microsoft Graph API\n- [Adaptive Cards Designer](https://adaptivecards.io/designer/) - Visual card designer tool\n\n## Security\n\nSee [SECURITY.md](SECURITY.md) for security policy and reporting vulnerabilities.\n\n## Changelog\n\nSee [CHANGELOG.md](CHANGELOG.md) for version history.\n\n## License\n\nMIT License - see [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcus-hooper%2Fworkflows","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarcus-hooper%2Fworkflows","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcus-hooper%2Fworkflows/lists"}