Skip to content

Write GitHub username to Slack profile after org invite - #19

Merged
ewels merged 1 commit into
mainfrom
feature/github-profile-writeback
Jun 22, 2026
Merged

Write GitHub username to Slack profile after org invite#19
ewels merged 1 commit into
mainfrom
feature/github-profile-writeback

Conversation

@ewels

@ewels ewels commented Jun 22, 2026

Copy link
Copy Markdown
Member

What & why

When a core-team member uses the Add to GitHub org message shortcut on a #github-invitations workflow request, the bot already parses the requester's GitHub handle to send the invite — but then discards it. This PR back-fills that handle into the requester's Slack profile GitHub field, so it's stored permanently (and available to the slash-command/shortcut flows that read it).

How it works

  • New set_github_username() in checks/slack_profile.py. A bot token cannot edit another member's profile, so the write goes through an admin user token (xoxp-, users.profile:write). The custom field is set via the profile= argument.
  • Best-effort + skip-if-already-set: never clobbers a handle the member entered themselves, and a failure never affects the invite outcome.
  • Hooked into the shared invite_and_greet() success path, guarded on a resolved Slack user ID — so it naturally no-ops on the paths where the handle came from the profile in the first place.
  • New optional SLACK_ADMIN_USER_TOKEN config — unset ⇒ silent no-op, so local dev and any unconfigured workspace are unaffected.

Infra / ops

  • Added SLACK_ADMIN_USER_TOKEN to ssm_secret_names in bot_stack.py so ECS injects it.
  • SSM SecureString /nf-core-bot/SLACK_ADMIN_USER_TOKEN already created, and the stack has been deployed (ECS task rolled over).
  • Fixed a stale path in deployment.md: /nf-core//nf-core-bot/ to match what the stack actually reads.
  • Documented the user-token setup (User Token Scope + Admin/Owner reinstall + paid-plan requirement) in slack-app-setup.md.

Tests

5 new tests in test_slack_profile.py: writes-when-empty, skip-when-already-set, no-op-without-token, no-field-id, never-raises. Full suite: 546 passing; ruff + mypy clean.

🤖 Generated with Claude Code

When a core-team member uses the "Add to GitHub org" shortcut on a
#github-invitations workflow message, the bot now back-fills the
requester's GitHub handle into their Slack profile's GitHub field.

- `set_github_username()` writes via an admin user token (xoxp-), since a
  bot token cannot edit another member's profile. Best-effort and
  skip-if-already-set, so it never clobbers a handle the member entered
  and never affects the invite outcome.
- New optional `SLACK_ADMIN_USER_TOKEN` config; unset = silent no-op.
- Wired into the shared `invite_and_greet` success path, guarded on a
  resolved Slack user ID, so it no-ops on paths where the handle already
  came from the profile.
- Infra: add the token to `ssm_secret_names` so ECS injects it.
- Docs: document the user-token setup, and fix the SSM parameter path in
  deployment.md (`/nf-core/` -> `/nf-core-bot/`) to match the stack.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ewels
ewels force-pushed the feature/github-profile-writeback branch from da42d52 to 688cb1c Compare June 22, 2026 17:54
@ewels ewels closed this Jun 22, 2026
@ewels ewels reopened this Jun 22, 2026
@ewels
ewels merged commit 6bb2121 into main Jun 22, 2026
4 of 5 checks passed
@ewels
ewels deleted the feature/github-profile-writeback branch June 22, 2026 18:02
ewels added a commit that referenced this pull request Jun 22, 2026
* Fix profile write-back: target the API-managed "GitHub (auto)" field

PR #19 wrote handles into the member-editable "GitHub" field, which Slack
silently no-ops (users.profile.set only persists for fields whose Data
source is "API"). Profile write-back therefore did nothing in production.

- Write to a dedicated "GitHub (auto)" custom field (label contains
  "github" + "auto"), which has its Data source set to API. Reads/lookups
  stay on the member-editable "GitHub" field.
- Store the value as a GitHub URL with `@handle` display text (the field
  is a link type — bare handles are silently rejected).
- Populate the auto field for everyone (drop the old "skip if the member
  field is set" rule); only skip when the auto field is already populated
  (idempotent).
- Resolve the two fields separately by label; the member resolver now
  excludes the "(auto)" field.
- Document the two-field setup + the mandatory "Data source = API" step.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Apply ruff format to test_slack_profile.py

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant