Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 65 additions & 1 deletion .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -824,7 +824,8 @@
"avatar_url": "https://avatars.githubusercontent.com/u/9788612?v=4",
"profile": "https://github.com/JacobStruiksma",
"contributions": [
"code"
"code",
"bug"
]
},
{
Expand Down Expand Up @@ -998,6 +999,69 @@
"contributions": [
"bug"
]
},
{
"login": "Christopherloof",
"name": "Christopherloof",
"avatar_url": "https://avatars.githubusercontent.com/u/119003550?v=4",
"profile": "https://github.com/Christopherloof",
"contributions": [
"bug"
]
},
{
"login": "haflidif",
"name": "Haflidi Fridthjofsson",
"avatar_url": "https://avatars.githubusercontent.com/u/26624010?v=4",
"profile": "https://linktr.ee/haflidif",
"contributions": [
"bug"
]
},
{
"login": "josesarsa",
"name": "josearsa",
"avatar_url": "https://avatars.githubusercontent.com/u/89536192?v=4",
"profile": "https://github.com/josesarsa",
"contributions": [
"bug"
]
},
{
"login": "sharmilamusunuru",
"name": "sharmilamusunuru",
"avatar_url": "https://avatars.githubusercontent.com/u/70754330?v=4",
"profile": "https://github.com/sharmilamusunuru",
"contributions": [
"bug"
]
},
{
"login": "xan-archera",
"name": "xan-archera",
"avatar_url": "https://avatars.githubusercontent.com/u/248541667?v=4",
"profile": "https://github.com/xan-archera",
"contributions": [
"bug"
]
},
{
"login": "bpurchell",
"name": "Brian Purchell",
"avatar_url": "https://avatars.githubusercontent.com/u/40211715?v=4",
"profile": "https://github.com/bpurchell",
"contributions": [
"code"
]
},
{
"login": "danfiedler-msft",
"name": "Dan Fiedler",
"avatar_url": "https://avatars.githubusercontent.com/u/151573964?v=4",
"profile": "https://github.com/danfiedler-msft",
"contributions": [
"code"
]
}
],
"commitType": "docs",
Expand Down
2 changes: 1 addition & 1 deletion .claude/commands/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ A draft is only visible to maintainers and doesn't create the tag, so it is safe
2. Write the body from the previous release's body (`gh release view v{N-1} --json body --jq .body`) and this version's changelog section:
- **New in {Month yyyy}**: one line per tool for new features, each with the tool emoji and a link to its page (don't link individual features).
- **Updated**: one line per tool for changes and fixes, in the same tool order as the previous release. Keep it to the notable items; don't list every change.
- **Contributors**: code contributors come from `gh api --paginate repos/microsoft/finops-toolkit/compare/v{N-1}...dev --jq '.commits[].author.login'` (drop bots; list `@MSBrett` and `@flanakin` last). Supporters are issue reporters from the milestone (`gh issue list --milestone v{N} --state all --json author`) who aren't contributors, sorted alphabetically. Tell the user these lists miss reviewers and discussion participants, so they need a final review.
- **Contributors**: code contributors come from `gh api --paginate repos/microsoft/finops-toolkit/compare/v{N-1}...dev --jq '.commits[].author.login'` (drop bots). List external contributors first, then the regular team members (`@RolandKrummenacher`, then `@MSBrett` and `@flanakin` last), so one-time and occasional contributors stand out. Cross-check against merged PR authors (`gh pr list --state merged --search "milestone:v{N}" --json author`), because a few commits have no GitHub login. Supporters are issue reporters from the milestone (`gh issue list --milestone v{N} --state all --json author`) who aren't contributors, sorted alphabetically. Everyone named in either list must also be in `.all-contributorsrc` with the right contribution types, so check each login and credit what they did, treating every type equally (see "Recognizing contributors" in `CONTRIBUTING.md`): `code` for code PRs, `doc` for documentation PRs, `bug` for issue reporters, `ideas` for feature requesters, `review` for reviewers, `question` for people who answered questions, and any other type that fits. Find missing credits with `./src/scripts/Update-Contributors.ps1 -Milestone v{N}` (a dry run that infers `code`, `doc`, `review`, `bug`, and `ideas` from merged PRs, reviews, and issues), then run `npm ci --ignore-scripts` once and rerun it with `-Apply`, which also keeps the `.all-contributorsrc` diff to the added entries. Commit the changed `.all-contributorsrc`, `README.md`, and `docs/README.md`. The weekly `update-contributors` workflow opens a PR with the same changes, so check for `automation/update-contributors` first. For types the script can't infer, or issue authors it lists as needing a human, add them with `npm run contrib -- {login} {type} [{type}...]` and put the arrays in `.all-contributorsrc` back on multiple lines. Don't skip someone because their type is unclear; credit `code` or `doc` for a merged PR and ask the user about the rest. Tell the user these lists miss reviewers and discussion participants, so they need a final review.
- **Footer**: copy the previous footer with the version updated. Keep the blog and download links commented out until the release is published.
3. Set the body with `gh api --method PATCH repos/microsoft/finops-toolkit/releases/{id} -F body=@{file}`. Find `{id}` with `gh api repos/microsoft/finops-toolkit/releases --jq '.[] | select(.draft and .tag_name=="v{N}") | .id'`.
4. After Power BI packaging, upload the remaining files with `gh release upload`. `gh` can't find a draft by its `v{N}` tag, so use the `untagged-…` name from the draft's URL: `gh release upload untagged-{hash} release/PowerBI-demo.zip --repo microsoft/finops-toolkit`.
Expand Down
198 changes: 198 additions & 0 deletions .github/workflows/update-contributors.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
name: Update contributors

# Finds contributors who are missing from .all-contributorsrc (merged PR authors, PR reviewers, and the reporters of
# fixed or accepted bugs and feature requests) and opens a pull request that adds them. Only contribution types that
# GitHub data can prove are handled; everything else (question, design, security, mentoring, promotion, leader) is
# left to humans. See "Recognizing contributors" in CONTRIBUTING.md and src/scripts/Update-Contributors.ps1.
#
# Requires the repo setting "Allow GitHub Actions to create and approve pull requests" (Settings > Actions >
# General). If it is off, or the org blocks it, the branch is still pushed and the job summary links to the
# "create pull request" page, like the open data workflows.
#
# Pull requests opened with GITHUB_TOKEN don't start other workflows, so close and reopen the PR to run its checks.
#
# Two ways to run:
# - On every pull request from this repo, the author (code, doc) and reviewers (review) of that PR are credited with a
# commit on the PR branch, like the ms.date workflow. Pull requests from forks can't be pushed to, so they are
# skipped here.
# - Weekly (and on demand), everything from the last 60 days is checked, which catches fork PRs, reviews added after
# the PR was last updated, and fixed or accepted bugs and feature requests.

on:
pull_request:
types: [opened, synchronize, reopened]
schedule:
- cron: '0 7 * * 1' # Every Monday at 07:00 UTC
Comment on lines +24 to +25

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better would be per PR, so on PR open or update, if we want to account for reviewers (which is rare)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [AI][Claude] ✅ Implemented

Added a per-PR job: on open/update of a same-repo PR it credits the author and reviewers with a commit on the PR branch (like the ms.date workflow). Kept the weekly run as a catch-all, because fork PRs (most external contributors) can't be pushed to, and it covers bugs and feature requests. Note: two open PRs crediting different people can conflict in .all-contributorsrc.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [AI][Claude] ❓ Question

Related to Roland's thread above (conflicts and extra commits from per-PR commits). Which do you want: per-PR commits or a weekly/on-push-to-dev job only? Recommendation: on-push-to-dev plus the weekly schedule, no per-PR job.

workflow_dispatch:
inputs:
since:
description: 'Credit contributions since this date (YYYY-MM-DD). Default is 60 days ago.'
required: false
type: string

# Each job asks for only what it needs
permissions: {}

jobs:
credit-pr:
name: Credit pull request contributors
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write
Comment thread
flanakin marked this conversation as resolved.
Resolved
# Same-repo pull requests only (forks have a read-only token). Skip the weekly PR, which is already the credit.
if: >-

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per-PR commits to .all-contributorsrc and the README tables conflict between parallel PRs and with the weekly PR. Should the weekly job also run on push to dev, with no per-PR job?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [AI][Claude] ❓ Question

Escalating to Michael Flanakin (@flanakin): this is a design decision, so I'm not changing it yet. Per-PR commits to .all-contributorsrc and the README tables will conflict between parallel PRs and with the weekly PR, and add an extra head commit per PR that needs checks and approval. Recommendation: drop the per-PR credit-pr job and run the existing weekly job on push to dev (plus the schedule and manual runs). That serves fork PRs too, avoids conflicts, and removes the bot commit on PRs. Trade-off: credits show up in a follow-up PR after merge rather than in the PR itself.

github.event_name == 'pull_request'
&& github.event.pull_request.head.repo.full_name == github.repository
&& github.head_ref != 'automation/update-contributors'
concurrency:
group: update-contributors-pr-${{ github.event.pull_request.number }}
cancel-in-progress: true
env:
GH_TOKEN: ${{ github.token }}
steps:
- name: Checkout PR branch
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.head_ref }}
token: ${{ secrets.GITHUB_TOKEN }}

# all-contributors-cli needs Node 22.22 or later
- name: Set up Node.js
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: '22.22'
Comment thread
flanakin marked this conversation as resolved.
Resolved

- name: Install all-contributors-cli
Comment thread
flanakin marked this conversation as resolved.
Resolved
run: npm ci --ignore-scripts

- name: Add missing credits for this pull request
shell: pwsh
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
run: ./src/scripts/Update-Contributors.ps1 -PullRequest ([int]$env:PR_NUMBER) -Apply

- name: Commit and push changes
env:
HEAD_REF: ${{ github.head_ref }}
run: |
if git diff --quiet -- .all-contributorsrc README.md docs/README.md; then
echo "No missing credits."
exit 0
fi
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add .all-contributorsrc README.md docs/README.md
git commit -m "docs: Credit contributors"

# Other workflows (like ms.date) push to the same branch on the same event, so rebase onto theirs and retry
for attempt in 1 2 3 4; do
if git push; then exit 0; fi
echo "Push failed (attempt $attempt). Rebasing onto the remote branch and retrying."
sleep $((attempt * 5))
git pull --rebase origin "$HEAD_REF"
Comment thread
flanakin marked this conversation as resolved.
Resolved
done
echo "::error::Could not push the contributor credits after 4 attempts."
exit 1

update:
name: Credit new contributors
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: write
pull-requests: write
concurrency:
group: update-contributors
cancel-in-progress: false
# Scheduled workflows also run in forks, where there is nothing to credit and no permission to push. Only run in
# the upstream repo, from dev, so manual runs from other branches can't push their commits into the PR.
if: github.repository == 'microsoft/finops-toolkit' && github.ref == 'refs/heads/dev'
env:
GH_TOKEN: ${{ github.token }}
BRANCH: automation/update-contributors
steps:
- name: Checkout dev
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

# The repo's own devDependency (all-contributors-cli). Scripts are not run during install.
# all-contributors-cli needs Node 22.22 or later
- name: Set up Node.js
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: '22.22'

- name: Install all-contributors-cli
run: npm ci --ignore-scripts

# The default window is long on purpose: the script only adds what is missing, so re-checking recent work is
# harmless, and an unmerged PR from a previous week keeps its entries when the branch is rebuilt from dev.
- name: Add missing contributors

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just use npm run contrib directly? PR author can be for code, issue author for bug (?) (or feature depending on context?), issue commenters for ???

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [AI][Claude] 🤔 Needs discussion

The script already wraps npm run contrib (-Apply runs the CLI per login and keeps the diff small), so I kept it for detection and dedupe. Mapping: PR author = code/doc, issue author = bug/ideas, PR reviewers = review. I did not credit commenters: comments don't prove a contribution, and question is added by hand (@allcontributors please add @user for question). Want a threshold (e.g. 3+ answered issues) instead?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [AI][Claude] ❓ Question

Your call on whether the script should stay or the workflow should call npm run contrib directly. Recommendation: keep the script. The CLI alone can't find who is missing or which type applies (PR author = code/doc, issue author = bug/ideas, reviewer = review), and it can't dedupe against the existing list. The script already runs npm run contrib's CLI per login for the actual write. Commenters stay manual.

id: update
shell: pwsh
env:
SINCE_INPUT: ${{ inputs.since }}
run: |
$since = if ($env:SINCE_INPUT) { $env:SINCE_INPUT } else { (Get-Date).AddDays(-60).ToString('yyyy-MM-dd') }
"since=$since" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
./src/scripts/Update-Contributors.ps1 -Since $since -Apply -SummaryPath "$env:RUNNER_TEMP/contributors.md"
# A failure for one login shouldn't lose the credits that worked. The last step fails the job afterwards.
continue-on-error: true

- name: Check for changes
id: changes
run: |
if git diff --quiet -- .all-contributorsrc README.md docs/README.md; then
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "No missing contributors."
else
echo "changed=true" >> "$GITHUB_OUTPUT"
git diff --stat -- .all-contributorsrc README.md docs/README.md
fi

- name: Push branch and open pull request
if: steps.changes.outputs.changed == 'true'
env:
SINCE: ${{ steps.update.outputs.since }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git checkout -b "$BRANCH"
git add .all-contributorsrc README.md docs/README.md
git commit -m "docs: Credit new contributors"

# The branch is rebuilt from dev every run, so an open PR is updated in place
git push --force origin "$BRANCH"

{
echo "Adds contributor credits found by [\`Update-Contributors.ps1\`](https://github.com/${GITHUB_REPOSITORY}/blob/dev/src/scripts/Update-Contributors.ps1) for work since $SINCE."
echo ""
cat "$RUNNER_TEMP/contributors.md"
echo ""
echo "Review before merging: credits come from GitHub data only (merged PRs, reviews, and fixed or accepted bugs and feature requests). Other types, like question, design, security, mentoring, and promotion, are added by hand. See [Recognizing contributors](https://github.com/${GITHUB_REPOSITORY}/blob/dev/CONTRIBUTING.md#-recognizing-contributors)."
echo ""
echo "_Opened by the [Update contributors](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}) workflow. Close and reopen this PR to run its checks._"
} > "$RUNNER_TEMP/pr-body.md"
cat "$RUNNER_TEMP/pr-body.md" >> "$GITHUB_STEP_SUMMARY"

PR_NUMBER=$(gh pr list --head "$BRANCH" --base dev --state open --json number --jq '.[0].number // empty')
if [ -n "$PR_NUMBER" ]; then
gh pr edit "$PR_NUMBER" --body-file "$RUNNER_TEMP/pr-body.md"
echo "Updated PR #$PR_NUMBER"
elif ! gh pr create --base dev --head "$BRANCH" --title "[Docs] Credit new contributors" --body-file "$RUNNER_TEMP/pr-body.md"; then
# Creating PRs from Actions is a repo/org setting. Don't lose the work if it is off.
PR_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/compare/dev...${BRANCH}?expand=1"
echo "::warning::Could not open the pull request (is \"Allow GitHub Actions to create and approve pull requests\" off?). The branch $BRANCH was pushed."
{
echo ""
echo "GitHub Actions could not open the pull request. Branch \`$BRANCH\` was pushed, so open it manually:"
echo ""
echo "[**Create pull request**]($PR_URL)"
} >> "$GITHUB_STEP_SUMMARY"
fi

- name: Fail if credits could not be added
if: steps.update.outcome == 'failure'
run: |
echo "::error::Update-Contributors.ps1 failed. See the 'Add missing contributors' step."
exit 1
20 changes: 20 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,26 @@ Want to stay connected with the team? Join our [weekly contributor sync](https:/
For details about contributing code changes and submitting pull requests, see [How to contribute](../../wiki/How-to-contribute).
-->

## 🏅 Recognizing contributors

We recognize every kind of contribution equally with the [all-contributors](https://allcontributors.org) list in the [README](./README.md#contributing). Anyone who contributes in any of the ways below should be listed. If we missed you, let us know.

| Type | Emoji | Credit for |
| ---- | ----- | ---------- |
| `code` | 💻 | Code changes in a merged pull request |
| `doc` | 📖 | Documentation changes in a merged pull request |
| `bug` | 🐛 | Reporting a bug that was confirmed or fixed |
| `ideas` | 🤔 | Suggesting a feature or idea that shaped the product |
| `review` | 👀 | Reviewing pull requests |
| `question` | 💬 | Answering questions in issues and discussions |
| `design` | 🎨 | Design work, like report layouts and visuals |
| `security` | 🛡️ | Finding or fixing security issues |
| `mentoring` | 🧑‍🏫 | Mentoring other contributors |
| `promotion` | 📣 | Promoting the toolkit in blogs, talks, and events |
| `leader` | 🌟 | Serving on the governing board |

The `code`, `doc`, `review`, `bug`, and `ideas` credits are found automatically. The [update-contributors](.github/workflows/update-contributors.yml) workflow adds a commit crediting the author and reviewers to every pull request from this repo, and a weekly run opens a pull request with whatever else is missing (fork pull requests, bugs, and feature requests), and you can check any time with `./src/scripts/Update-Contributors.ps1 -Since 2026-01-01` (add `-Apply` to update the list). Other types are added by hand: comment `@allcontributors please add @username for question, design` on any issue or pull request in this repo, or run `npm ci --ignore-scripts` once and then `npm run contrib -- username question,design`.
Comment thread
flanakin marked this conversation as resolved.
Resolved

<br>

# 🙏 Thank you! <!-- markdownlint-disable-line single-h1 -->
Expand Down
Loading
Loading