You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@texera.apache.org by gi...@apache.org on 2026/05/26 10:25:15 UTC
(texera) branch gh-readonly-queue/main/pr-5222-8a7366f3b1ec18fc118a92b76326c06b92be1ff3 created (now 21cb8a57e8)
This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a change to branch gh-readonly-queue/main/pr-5222-8a7366f3b1ec18fc118a92b76326c06b92be1ff3
in repository https://gitbox.apache.org/repos/asf/texera.git
at 21cb8a57e8 feat: Welcome first-time contributors with comment commands guide (#5222)
This branch includes the following new commits:
new 21cb8a57e8 feat: Welcome first-time contributors with comment commands guide (#5222)
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(texera) 01/01: feat: Welcome first-time contributors with comment commands guide (#5222)
Posted by gi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-5222-8a7366f3b1ec18fc118a92b76326c06b92be1ff3
in repository https://gitbox.apache.org/repos/asf/texera.git
commit 21cb8a57e8503a348437742fab896c3c6cd41c24
Author: Matthew B. <mg...@uci.edu>
AuthorDate: Tue May 26 03:24:54 2026 -0700
feat: Welcome first-time contributors with comment commands guide (#5222)
### What changes were proposed in this PR?
- Add `.github/workflows/welcome-first-time-contributor.yml`, which
posts a single welcome comment listing the `/take`, `/untake`,
`/sub-issue`, `/unsub-issue`, `/parent-issue`, `/unparent-issue`,
`/request-review`, and `/unrequest-review` commands when a new
contributor opens their first issue or PR.
- Detect first-time status with the GitHub search API
(`repo:<owner>/<repo> is:issue|pr author:<login>`, treating `total_count
<= 1` as first time). This works uniformly for issues and PRs, whereas
`author_association` reports `NONE` for someone opening their first
issue, and would miss them.
- Trigger on `pull_request_target` (not `pull_request`) so PRs from
forks still receive the welcome with a write-capable token; restrict
permissions to `issues: write` and `pull-requests: write`.
- Make the workflow idempotent via a hidden HTML marker (`<!--
texera:welcome-first-time-contributor -->`) embedded in the welcome body
and checked against existing comments before posting, so workflow
re-runs and reopen races do not duplicate the welcome.
### Any related issues, documentation, or discussions?
Closes: #5166
### How was this PR tested?
- Validated the workflow YAML parses cleanly with `python3 -c "import
yaml;
yaml.safe_load(open('.github/workflows/welcome-first-time-contributor.yml'))"`.
- Reviewed logic for the known edge cases: search indexing delay (the
`<= 1` check tolerates both 0, not yet indexed, and 1, only the new
item), transient `listComments` failure (falls open rather than dropping
a genuine first-timer's welcome), and Bot guard at the job-level `if`.
- Runtime behavior cannot be exercised end-to-end locally; will be
observable on the next first-time issue or PR after merge.
### Was this PR authored or co-authored using generative AI tooling?
Co-Authored with Claude Opus 4.7 in compliance with ASF Guidelines
---
.../workflows/welcome-first-time-contributor.yml | 157 +++++++++++++++++++++
CONTRIBUTING.md | 40 ++++++
2 files changed, 197 insertions(+)
diff --git a/.github/workflows/welcome-first-time-contributor.yml b/.github/workflows/welcome-first-time-contributor.yml
new file mode 100644
index 0000000000..df67bebce0
--- /dev/null
+++ b/.github/workflows/welcome-first-time-contributor.yml
@@ -0,0 +1,157 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Welcome first-time contributors when they open an issue or pull
+# request, pointing them at the comment-driven commands defined in
+# `comment-commands.yml` (/take, /request-review, /sub-issue, etc.).
+#
+# Detection uses the search API rather than `author_association`:
+# `author_association` is FIRST_TIME_CONTRIBUTOR only on the first
+# *commit/PR*, so it misses someone opening their first issue (they
+# show up as NONE alongside any non-member who has commented before).
+# Searching `repo:<repo> is:issue author:<login>` with `total_count
+# <= 1` cleanly covers both issues and PRs, tolerating the brief
+# indexing delay where the just-opened item may not be in results yet.
+#
+# Uses `pull_request_target` so PRs from forks still get a welcome
+# comment — `pull_request` from forks runs with a read-only token.
+name: Welcome first-time contributor
+on:
+ issues:
+ types: [opened]
+ pull_request_target:
+ types: [opened]
+
+permissions:
+ issues: write
+ pull-requests: write
+
+jobs:
+ welcome:
+ if: github.event.sender.type != 'Bot'
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/github-script@v8
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ const isPR = context.eventName === 'pull_request_target';
+ const subject = isPR
+ ? context.payload.pull_request
+ : context.payload.issue;
+ const author = subject.user.login;
+ const issue_number = subject.number;
+ const { owner, repo } = context.repo;
+
+ // Hidden marker for idempotency: if a previous run already
+ // welcomed this issue/PR, the marker will be in an existing
+ // comment and we skip. Lets us survive workflow re-runs,
+ // reopen races, and future manual triggers.
+ const MARKER = '<!-- texera:welcome-first-time-contributor -->';
+ try {
+ const existing = await github.paginate(
+ github.rest.issues.listComments,
+ { owner, repo, issue_number, per_page: 100 },
+ );
+ if (existing.some((c) => (c.body || '').includes(MARKER))) {
+ core.info(`Already welcomed on #${issue_number}; skipping.`);
+ return;
+ }
+ } catch (e) {
+ core.warning(
+ `listComments on #${issue_number} failed: ${e.message}`,
+ );
+ // Fall through — better to risk a duplicate welcome than
+ // skip a genuine first-timer over a transient API error.
+ }
+
+ // Count prior items of the same kind by this author. The
+ // just-opened item may or may not be indexed yet, so we
+ // treat <=1 as "first time" (covers both 0 — not yet
+ // indexed — and 1 — only the new item).
+ const q = `repo:${owner}/${repo} is:${isPR ? 'pr' : 'issue'} author:${author}`;
+ let total = 0;
+ try {
+ const { data } = await github.rest.search.issuesAndPullRequests({
+ q, per_page: 1,
+ });
+ total = data.total_count;
+ } catch (e) {
+ core.warning(
+ `Search for prior items by ${author} failed: ${e.message}`,
+ );
+ return;
+ }
+ core.info(
+ `Author ${author} has ${total} ${isPR ? 'PR' : 'issue'}(s) ` +
+ `in ${owner}/${repo} (including this one if indexed).`,
+ );
+ if (total > 1) {
+ core.info(`${author} is not a first-time contributor; skipping.`);
+ return;
+ }
+
+ const body = [
+ MARKER,
+ `👋 Thanks for your first contribution to Texera, @${author}!`,
+ ``,
+ `You can drive common housekeeping tasks just by leaving a comment. Type the command on its own line.`,
+ ``,
+ `### On issues`,
+ ``,
+ `| Command | What it does |`,
+ `|---|---|`,
+ `| \`/take\` | Assign the issue to yourself (self-claim it) |`,
+ `| \`/untake\` | Remove yourself as assignee |`,
+ ``,
+ `To find unclaimed work, search \`is:issue is:open no:assignee\` — there's no "triage" label; the search filter *is* the triage state.`,
+ ``,
+ `### Linking sub-issues`,
+ ``,
+ `| Command | Where to run it | What it does |`,
+ `|---|---|---|`,
+ `| \`/sub-issue #12 #13\` | On the **parent** | Links #12 and #13 as children of this issue |`,
+ `| \`/unsub-issue #12 #13\` | On the **parent** | Unlinks those children |`,
+ `| \`/parent-issue #5\` | On the **child** | Sets #5 as this issue's parent |`,
+ `| \`/unparent-issue\` | On the **child** | Removes this issue's parent (auto-detected) |`,
+ `| \`/unparent-issue #5\` | On the **child** | Removes parent #5 explicitly |`,
+ ``,
+ `You can write references as \`#12\` or bare \`12\`. Cross-repo references like \`owner/repo#12\` aren't supported and are ignored.`,
+ ``,
+ `### On pull requests (author only)`,
+ ``,
+ `| Command | What it does |`,
+ `|---|---|`,
+ `| \`/request-review @user [@user ...]\` | Request reviews from those users |`,
+ `| \`/unrequest-review @user [@user ...]\` | Cancel those review requests |`,
+ ``,
+ `You can mention teams as \`@org/team\`, and \`@copilot\` works too. Only the PR **author** can use these commands.`,
+ ``,
+ `> **Note:** Commands must match exactly — \`/take this\` won't work, only \`/take\`. Bots are ignored, and you can't self-link an issue or set an issue as its own parent.`,
+ ``,
+ `For the full contribution flow, see [CONTRIBUTING.md](https://github.com/${owner}/${repo}/blob/main/CONTRIBUTING.md).`,
+ ].join('\n');
+
+ try {
+ await github.rest.issues.createComment({
+ owner, repo, issue_number, body,
+ });
+ core.info(`Posted welcome comment on #${issue_number}`);
+ } catch (e) {
+ core.warning(
+ `Failed to post welcome on #${issue_number}: ${e.message}`,
+ );
+ }
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f31b0052e0..8abbf4fc8f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -96,6 +96,46 @@ yarn format:fix
---
+## 👋 Comment commands
+
+You can drive common housekeeping tasks just by leaving a comment on an issue or pull request. Type the command on its own line.
+
+### On issues
+
+| Command | What it does |
+|---|---|
+| `/take` | Assign the issue to yourself (self-claim it) |
+| `/untake` | Remove yourself as assignee |
+
+To find unclaimed work, search `is:issue is:open no:assignee` — there's no "triage" label; the search filter *is* the triage state.
+
+### Linking sub-issues
+
+You can link from either end of the parent/child relationship:
+
+| Command | Where to run it | What it does |
+|---|---|---|
+| `/sub-issue #12 #13` | On the **parent** | Links #12 and #13 as children of this issue |
+| `/unsub-issue #12 #13` | On the **parent** | Unlinks those children |
+| `/parent-issue #5` | On the **child** | Sets #5 as this issue's parent |
+| `/unparent-issue` | On the **child** | Removes this issue's parent (auto-detected) |
+| `/unparent-issue #5` | On the **child** | Removes parent #5 explicitly |
+
+You can write references as `#12` or bare `12`. Cross-repo references like `owner/repo#12` aren't supported and are ignored.
+
+### On pull requests (author only)
+
+| Command | What it does |
+|---|---|
+| `/request-review @user [@user ...]` | Request reviews from those users |
+| `/unrequest-review @user [@user ...]` | Cancel those review requests |
+
+You can mention teams as `@org/team`, and `@copilot` works too. Only the PR **author** can use these commands.
+
+> **Note:** Commands must match exactly — `/take this` won't work, only `/take`. Bots are ignored, and you can't self-link an issue or set an issue as its own parent.
+
+---
+
## 📝 Apache License Header
All new files must include the Apache License header.