Skip to content

Commit 76466f8

Browse files
authored
Merge branch 'hiero-ledger:main' into main
2 parents b7a1311 + 264d954 commit 76466f8

60 files changed

Lines changed: 1412 additions & 1305 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.coderabbit.yaml

Lines changed: 128 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ reviews:
1010
high_level_summary: false # Do not summarise a pull request first as there is a walkthrough
1111
review_status: false # Do not state what kind of review as performed or why (spammy)
1212
commit_status: false # Do not state the review is in progress (spammy)
13-
collapse_walkthrough: true # Provide a walkthrough for reviewers, but collapse it (users shouldn't use this)
13+
collapse_walkthrough: false # Provide a walkthrough for reviewers
1414
related_issues: false # Do not suggest related issues (spammy)
1515
related_prs: false # Do not suggest related PRs (spammy)
1616
suggested_labels: false # Do not suggest labels for the PR (spammy)
@@ -19,6 +19,126 @@ reviews:
1919
poem: false # Do not write a literal poem (spammy)
2020
enable_prompt_for_ai_agents: false # Disable prompts for AI agents (spammy)
2121

22+
# QUERY REVIEW INSTRUCTIONS
23+
query_review_instructions: &query_review_instructions |
24+
You are acting as a senior maintainer reviewing the Query base class
25+
and its subclasses for the hiero-sdk-python project.
26+
27+
NOTE:
28+
- Review focus levels indicate areas that are important to check carefully.
29+
- They do NOT imply severity or urgency.
30+
- Only recommend fixes when there is a clear behavioral regression.
31+
32+
Scope is STRICTLY LIMITED to:
33+
- Changes to the base `Query` class
34+
- Changes to existing `Query` subclasses
35+
- Newly added `Query` subclasses
36+
37+
----------------------------------------------------------
38+
REVIEW FOCUS 1 — QUERY SEMANTICS & PAYMENT BEHAVIOR
39+
(CONTRACTUAL / HIGH SENSITIVITY)
40+
----------------------------------------------------------
41+
Queries do not reach consensus and use `QueryHeader` for payment and responseType.
42+
43+
The following behaviors are contractual and must remain unchanged:
44+
- `_is_payment_required()` semantics
45+
- FREE vs PAID query classification
46+
- COST_ANSWER vs ANSWER_ONLY behavior
47+
- Whether a payment transaction is attached
48+
49+
Good to check and verify that changes do NOT:
50+
- Alter FREE → PAID or PAID → FREE behavior
51+
- Attach payment to COST_ANSWER queries
52+
- Bypass `get_cost(client)` for paid queries
53+
- Hardcode fees or override payment logic
54+
55+
----------------------------------------------------------
56+
REVIEW FOCUS 2 — EXECUTION LIFECYCLE & BASE CLASS INTEGRITY
57+
----------------------------------------------------------
58+
All queries MUST:
59+
- Use the base `Query` execution flow
60+
- Delegate retries, backoff, and node selection to `_Executable`
61+
- Call `_before_execute(client)` before `_execute(client)`
62+
63+
Subclasses MUST NOT:
64+
- Override retry logic
65+
- Implement custom node selection
66+
- Manage gRPC deadlines manually
67+
- Bypass `_Executable` state handling
68+
69+
Flag deviations for review; recommend fixes only if behavior changes.
70+
71+
----------------------------------------------------------
72+
REVIEW FOCUS 3 — REQUEST CONSTRUCTION CONTRACT
73+
----------------------------------------------------------
74+
`_make_request()` MUST:
75+
- Validate all required identifiers (accountId, tokenId, topicId, etc.)
76+
- Call `_make_request_header()` exactly once
77+
- Populate protobuf fields via `_to_proto()` helpers
78+
- Avoid manual `QueryHeader` mutation
79+
80+
Subclasses MUST NOT:
81+
- Set `responseType` directly
82+
- Inject payment logic
83+
- Rebuild headers manually
84+
85+
----------------------------------------------------------
86+
REVIEW FOCUS 4 — RESPONSE EXTRACTION & DOMAIN MAPPING
87+
----------------------------------------------------------
88+
`_get_query_response()` MUST:
89+
- Return the exact protobuf response field
90+
- Perform NO data transformation
91+
- Match the expected protobuf response type
92+
93+
`execute()` MUST NOT:
94+
- Implement retries or error handling
95+
- Modify payment or execution behavior
96+
- Catch and suppress execution errors
97+
98+
----------------------------------------------------------
99+
REVIEW FOCUS 5 — NEW SUBCLASS VALIDATION
100+
----------------------------------------------------------
101+
For newly added `Query` subclasses:
102+
- Ensure they extend `Query` directly
103+
- Verify required abstract methods are implemented
104+
- Confirm payment semantics match the Hedera API
105+
- Validate protobuf service and method correctness
106+
- Ensure naming matches existing query patterns
107+
108+
Missing or incorrect semantics should be flagged clearly.
109+
110+
----------------------------------------------------------
111+
REVIEW FOCUS 6 — REGRESSION & BEHAVIOR CHANGE DETECTION
112+
----------------------------------------------------------
113+
Good to check whether any change:
114+
- Alters base `Query` behavior
115+
- Changes default responseType handling
116+
- Modifies `_make_request_header()` usage
117+
- Alters `_get_method()` behavior
118+
- Introduces side effects (logging, prints, stack traces)
119+
- Changes error propagation behavior
120+
121+
Small changes should be flagged for verification
122+
if they could affect execution flow or payment safety.
123+
124+
----------------------------------------------------------
125+
REVIEW FOCUS 7 — EXPLICIT NON-GOALS
126+
----------------------------------------------------------
127+
Do NOT:
128+
- Review query consumers
129+
- Propose refactors unless correctness is impacted
130+
- Comment on style, formatting, or naming unless misleading
131+
132+
----------------------------------------------------------
133+
FINAL OBJECTIVE
134+
----------------------------------------------------------
135+
Ensure Query code remains:
136+
- Backward-compatible
137+
- Payment-safe
138+
- Execution-consistent
139+
- Strictly aligned with Hedera query semantics
140+
141+
22142
# ============================================================
23143
# GLOBAL REVIEW INSTRUCTIONS (APPLY TO ALL FILES)
24144
# ============================================================
@@ -32,7 +152,6 @@ reviews:
32152
- Do NOT block the PR on them.
33153
- Do NOT suggest fixes inline.
34154
- Instead, aggregate all out-of-scope issues into a single comment with a list of recommendations for one or more follow-up issues that can be created.
35-
36155
path_instructions:
37156
# --- CUSTOM INSTRUCTIONS FOR EXAMPLES DIRECTORY ---
38157
- path: "examples/**/*"
@@ -423,6 +542,13 @@ reviews:
423542
- Scripts MUST NOT assume write access
424543
- Permission failures MUST be handled gracefully
425544
545+
- path: "src/hiero_sdk_python/query/**/*.py"
546+
instructions: *query_review_instructions
547+
548+
- path: "src/hiero_sdk_python/contract/**/*_query.py"
549+
instructions: *query_review_instructions
550+
551+
426552
chat:
427553
art: false # Don't draw ASCII art (false)
428554
auto_reply: false # Don't allow bot to converse (spammy)

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,5 @@
11
blank_issues_enabled: true
22

3-
# Only show specific issue templates
4-
# issue_templates:
5-
# - name: Good First Issue
6-
# filename: 01-good_first_issue.yml
7-
#- name: Bug Report
8-
# filename: 02_bug_report.yml
9-
10-
# - name: Feature Request
11-
# filename: 03_feature_request.yml
12-
13-
# Test contact links
143
contact_links:
154
- name: Hiero Discord
165
url: https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/discord.md
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
/*
2+
==============================================================================
3+
Executes When:
4+
- Triggered by GitHub Actions workflow on event: 'issue_comment' (created).
5+
- Target: Issues specifically labeled with "beginner".
6+
7+
Goal:
8+
It acts as an automated onboarding assistant for "beginner" issues. It allows
9+
contributors to self-assign using a command and nudges new contributors who
10+
express interest but forget to assign themselves, while preventing spam.
11+
12+
------------------------------------------------------------------------------
13+
Flow: Basic Idea
14+
1. Listens for comments on issues.
15+
2. Ignores Pull Requests, Bots, and issues missing the "beginner" label.
16+
3. Detects if the user typed "/assign".
17+
- If YES: Assigns the user to the issue (if currently unassigned).
18+
- If NO: Checks if the user is an external contributor expressing interest.
19+
If so, it replies with instructions on how to use the assign command.
20+
21+
------------------------------------------------------------------------------
22+
Flow: Detailed Technical Steps
23+
24+
1️⃣ Validation & filtering
25+
- Checks payload to ensure it is an Issue Comment (not a PR).
26+
- Checks if the commenter is a BOT (e.g., github-actions). If so, exits.
27+
- Checks if the issue has the specific label "beginner". If not, exits.
28+
29+
2️⃣ Collaborator Check (isRepoCollaborator)
30+
- Action: Checks if the user is a repository collaborator.
31+
- Logic:
32+
* Collaborator (204) -> Treated as Team Member (Bot ignores them).
33+
* Non-Collaborator (404) -> Treated as External Contributor (Bot helps them).
34+
35+
3️⃣ Logic Branch A: The "/assign" Command
36+
- Trigger: User comment matches regex /(^|\s)\/assign(\s|$)/i.
37+
- Check: Is the issue already assigned?
38+
* Yes -> Alert the user that it is taken.
39+
* No -> API Call: Add commenter to 'assignees'.
40+
41+
4️⃣ Logic Branch B: The Helper Reminder
42+
- Trigger: Generic comment (e.g., "I want to work on this").
43+
- Condition 1: Issue must be unassigned.
44+
- Condition 2: Commenter must NOT be a Repo Collaborator.
45+
- Condition 3: Duplicate Check.
46+
* Scans previous comments for a hidden marker: "<!-- beginner assign reminder -->".
47+
* If found -> Exits to avoid spamming the thread.
48+
- Action: Posts a comment with the hidden marker and instructions.
49+
50+
------------------------------------------------------------------------------
51+
Parameters:
52+
- { github, context }: Standard objects provided by 'actions/github-script'.
53+
==============================================================================
54+
*/
55+
module.exports = async ({ github, context }) => {
56+
try {
57+
const { payload } = context;
58+
const issue = payload.issue;
59+
const comment = payload.comment;
60+
const repo = payload.repository;
61+
62+
// 1. Basic Validation
63+
if (!issue || !comment || !repo || issue.pull_request) {
64+
console.log("[Beginner Bot] Invalid payload or PR comment. Exiting.");
65+
return;
66+
}
67+
68+
// 1.1 Bot Check (Fix 2: Defensive Check)
69+
if (comment.user?.type === "Bot") {
70+
console.log(`[Beginner Bot] Commenter @${comment.user.login} is a bot. Exiting.`);
71+
return;
72+
}
73+
74+
// 2. Label Check (Fix 2: Defensive Check)
75+
const hasBeginnerLabel = Array.isArray(issue.labels) && issue.labels.some((label) => label.name === "beginner");
76+
if (!hasBeginnerLabel) {
77+
console.log(`[Beginner Bot] Issue #${issue.number} does not have 'beginner' label. Exiting.`);
78+
return;
79+
}
80+
81+
// 3. Collaborator Check Helper
82+
async function isRepoCollaborator(username) {
83+
try {
84+
if (username === repo.owner.login) {
85+
console.log(`[Beginner Bot] User @${username} is the repo owner.`);
86+
return true;
87+
}
88+
89+
await github.rest.repos.checkCollaborator({
90+
owner: repo.owner.login,
91+
repo: repo.name,
92+
username: username,
93+
});
94+
95+
console.log(`[Beginner Bot] User @${username} is a confirmed repo collaborator.`);
96+
return true;
97+
} catch (error) {
98+
if (error.status === 404) {
99+
console.log(`[Beginner Bot] User @${username} is NOT a collaborator (External Contributor).`);
100+
return false;
101+
}
102+
console.log(`[Beginner Bot] Error checking collaborator status for @${username}: ${error.message}`);
103+
return false;
104+
}
105+
}
106+
107+
const commenter = comment.user.login;
108+
109+
// Fix 3: Validate comment body
110+
if (!comment.body) {
111+
console.log("[Beginner Bot] Comment body is empty. Exiting.");
112+
return;
113+
}
114+
115+
const commentBody = comment.body.toLowerCase();
116+
const isAssignCommand = /(^|\s)\/assign(\s|$)/i.test(commentBody);
117+
118+
// 4. Logic Branch
119+
if (isAssignCommand) {
120+
// --- ASSIGNMENT LOGIC ---
121+
if (issue.assignees && issue.assignees.length > 0) {
122+
const currentAssignee = issue.assignees[0].login;
123+
console.log(`[Beginner Bot] Issue #${issue.number} is already assigned. Ignoring /assign command.`);
124+
125+
// Fix 4: Granular Try/Catch for Comment API
126+
try {
127+
await github.rest.issues.createComment({
128+
owner: repo.owner.login,
129+
repo: repo.name,
130+
issue_number: issue.number,
131+
body: `👋 Hi @${commenter}, thanks for your interest! This issue is already assigned to @${currentAssignee}, but we'd love your help on another one. You can find more "beginner" issues [here](https://github.com/hiero-ledger/hiero-sdk-python/issues?q=is%3Aissue%20state%3Aopen%20label%3Abeginner%20no%3Aassignee).`,
132+
});
133+
} catch (error) {
134+
console.error(`[Beginner Bot] Failed to post already-assigned comment: ${error.message}`);
135+
}
136+
return; // Exit after warning
137+
}
138+
139+
console.log(`[Beginner Bot] Assigning issue #${issue.number} to @${commenter}...`);
140+
141+
// Fix 4: Granular Try/Catch for Assign API
142+
try {
143+
await github.rest.issues.addAssignees({
144+
owner: repo.owner.login,
145+
repo: repo.name,
146+
issue_number: issue.number,
147+
assignees: [commenter],
148+
});
149+
console.log(`[Beginner Bot] Successfully assigned.`);
150+
} catch (error) {
151+
console.error(`[Beginner Bot] Failed to assign issue: ${error.message}`);
152+
}
153+
154+
} else {
155+
// --- REMINDER LOGIC ---
156+
157+
if (issue.assignees && issue.assignees.length > 0) {
158+
console.log(`[Beginner Bot] Issue #${issue.number} is already assigned. Skipping reminder.`);
159+
return;
160+
}
161+
162+
if (await isRepoCollaborator(commenter)) {
163+
console.log(`[Beginner Bot] Commenter @${commenter} is a repo collaborator. Skipping reminder.`);
164+
return;
165+
}
166+
167+
// Fix 5: Updated Marker Text
168+
const REMINDER_MARKER = "<!-- beginner assign reminder -->";
169+
// FIX 6: Granular Try/Catch for List Comments API
170+
let comments;
171+
try {
172+
const { data } = await github.rest.issues.listComments({
173+
owner: repo.owner.login,
174+
repo: repo.name,
175+
issue_number: issue.number,
176+
});
177+
comments = data;
178+
} catch (error) {
179+
console.error(`[Beginner Bot] Failed to list comments: ${error.message}`);
180+
return; // Exit gracefully if we can't check for duplicates
181+
}
182+
183+
if (comments.some((c) => c.body.includes(REMINDER_MARKER))) {
184+
console.log("[Beginner Bot] Reminder already exists on this issue. Skipping.");
185+
return;
186+
}
187+
188+
console.log(`[Beginner Bot] Posting help reminder for @${commenter}...`);
189+
190+
const reminderBody = `${REMINDER_MARKER}\n👋 Hi @${commenter}! If you'd like to work on this issue, please comment \`/assign\` to get assigned.`;
191+
192+
// FIX 6: Granular Try/Catch for Create Comment API
193+
try {
194+
await github.rest.issues.createComment({
195+
owner: repo.owner.login,
196+
repo: repo.name,
197+
issue_number: issue.number,
198+
body: reminderBody,
199+
});
200+
console.log("[Beginner Bot] Reminder posted successfully.");
201+
} catch (error) {
202+
console.error(`[Beginner Bot] Failed to post reminder: ${error.message}`);
203+
}
204+
}
205+
206+
} catch (error) {
207+
// Fix 1: Top-level error handling
208+
console.error("[Beginner Bot] Unexpected error:", {
209+
message: error.message,
210+
status: error.status,
211+
issue: context.payload?.issue?.number,
212+
comment: context.payload?.comment?.id
213+
});
214+
}
215+
};

0 commit comments

Comments
 (0)