diff --git a/.github/workflows/codeowner-review-request.yml b/.github/workflows/codeowner-review-request.yml index 121619e049..ab3377365d 100644 --- a/.github/workflows/codeowner-review-request.yml +++ b/.github/workflows/codeowner-review-request.yml @@ -182,11 +182,14 @@ jobs: }); // Check for previous comments from this workflow to avoid duplicate pings - const { data: comments } = await github.rest.issues.listComments({ - owner, - repo, - issue_number: pr_number - }); + const comments = await github.paginate( + github.rest.issues.listComments, + { + owner, + repo, + issue_number: pr_number + } + ); const previouslyPingedUsers = new Set(); const previouslyPingedTeams = new Set(); @@ -194,7 +197,6 @@ jobs: // Look for comments from github-actions bot that contain our bot marker const workflowComments = comments.filter(comment => comment.user.type === 'Bot' && - comment.user.login === 'github-actions[bot]' && comment.body.includes(BOT_COMMENT_MARKER) ); diff --git a/.github/workflows/external-component-bot.yml b/.github/workflows/external-component-bot.yml index 5f5bc703ad..29103e8eee 100644 --- a/.github/workflows/external-component-bot.yml +++ b/.github/workflows/external-component-bot.yml @@ -61,7 +61,8 @@ jobs: } async function createComment(octokit, owner, repo, prNumber, esphomeChanges, componentChanges) { - const commentMarker = ""; + const commentMarker = ""; + const legacyCommentMarker = ""; let commentBody; if (esphomeChanges.length === 1) { commentBody = generateExternalComponentInstructions(prNumber, componentChanges, owner, repo); @@ -71,14 +72,23 @@ jobs: commentBody += `\n\n---\n(Added by the PR bot)\n\n${commentMarker}`; // Check for existing bot comment - const comments = await github.rest.issues.listComments({ - owner: owner, - repo: repo, - issue_number: prNumber, - }); + const comments = await github.paginate( + github.rest.issues.listComments, + { + owner: owner, + repo: repo, + issue_number: prNumber, + per_page: 100, + } + ); - const botComment = comments.data.find(comment => - comment.body.includes(commentMarker) + const sorted = comments.sort((a, b) => new Date(b.updated_at) - new Date(a.updated_at)); + + const botComment = sorted.find(comment => + ( + comment.body.includes(commentMarker) || + comment.body.includes(legacyCommentMarker) + ) && comment.user.type === "Bot" ); if (botComment && botComment.body === commentBody) { diff --git a/.github/workflows/issue-codeowner-notify.yml b/.github/workflows/issue-codeowner-notify.yml index 27976a7952..3639d346f5 100644 --- a/.github/workflows/issue-codeowner-notify.yml +++ b/.github/workflows/issue-codeowner-notify.yml @@ -29,6 +29,9 @@ jobs: console.log(`Processing issue #${issue_number} with label: ${labelName}`); + // Hidden marker to identify bot comments from this workflow + const BOT_COMMENT_MARKER = ''; + // Extract component name from label const componentName = labelName.replace('component: ', ''); console.log(`Component: ${componentName}`); @@ -93,11 +96,14 @@ jobs: ); // Check for previous comments from this workflow to avoid duplicate pings - const { data: comments } = await github.rest.issues.listComments({ - owner, - repo, - issue_number: issue_number - }); + const comments = await github.paginate( + github.rest.issues.listComments, + { + owner, + repo, + issue_number: issue_number + } + ); const previouslyPingedUsers = new Set(); const previouslyPingedTeams = new Set(); @@ -105,9 +111,8 @@ jobs: // Look for comments from github-actions bot that contain codeowner pings for this component const workflowComments = comments.filter(comment => comment.user.type === 'Bot' && - comment.user.login === 'github-actions[bot]' && - comment.body.includes(`component: ${componentName}`) && - comment.body.includes("you've been identified as a codeowner") + comment.body.includes(BOT_COMMENT_MARKER) && + comment.body.includes(`component: ${componentName}`) ); // Extract previously mentioned users and teams from workflow comments @@ -140,7 +145,7 @@ jobs: // Create comment body const mentionString = allMentions.join(', '); - const commentBody = `šŸ‘‹ Hey ${mentionString}!\n\nThis issue has been labeled with \`component: ${componentName}\` and you've been identified as a codeowner of this component. Please take a look when you have a chance!\n\nThanks for maintaining this component! šŸ™`; + const commentBody = `${BOT_COMMENT_MARKER}\nšŸ‘‹ Hey ${mentionString}!\n\nThis issue has been labeled with \`component: ${componentName}\` and you've been identified as a codeowner of this component. Please take a look when you have a chance!\n\nThanks for maintaining this component! šŸ™`; // Post comment await github.rest.issues.createComment({ diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index 873f342277..4fedd36120 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -55,6 +55,9 @@ void Application::setup() { return a->get_actual_setup_priority() > b->get_actual_setup_priority(); }); + // Initialize looping_components_ early so enable_pending_loops_() works during setup + this->calculate_looping_components_(); + for (uint32_t i = 0; i < this->components_.size(); i++) { Component *component = this->components_[i]; @@ -97,7 +100,6 @@ void Application::setup() { clear_setup_priority_overrides(); this->schedule_dump_config(); - this->calculate_looping_components_(); } void Application::loop() { uint8_t new_app_state = 0; @@ -269,24 +271,16 @@ void Application::calculate_looping_components_() { // Pre-reserve vector to avoid reallocations this->looping_components_.reserve(total_looping); - // First add all active components + // Add all components with loop override + // When called at start of setup, all components are in CONSTRUCTION state + // so none will be LOOP_DONE yet - they'll all go in the active section for (auto *obj : this->components_) { - if (obj->has_overridden_loop() && - (obj->get_component_state() & COMPONENT_STATE_MASK) != COMPONENT_STATE_LOOP_DONE) { + if (obj->has_overridden_loop()) { this->looping_components_.push_back(obj); } } this->looping_components_active_end_ = this->looping_components_.size(); - - // Then add all inactive (LOOP_DONE) components - // This handles components that called disable_loop() during setup, before this method runs - for (auto *obj : this->components_) { - if (obj->has_overridden_loop() && - (obj->get_component_state() & COMPONENT_STATE_MASK) == COMPONENT_STATE_LOOP_DONE) { - this->looping_components_.push_back(obj); - } - } } void Application::disable_component_loop_(Component *component) { diff --git a/esphome/core/lock_free_queue.h b/esphome/core/lock_free_queue.h index de07b0ebba..68e2825d09 100644 --- a/esphome/core/lock_free_queue.h +++ b/esphome/core/lock_free_queue.h @@ -29,7 +29,7 @@ namespace esphome { // Base lock-free queue without task notification template class LockFreeQueue { public: - LockFreeQueue() : head_(0), tail_(0), dropped_count_(0) {} + LockFreeQueue() : dropped_count_(0), head_(0), tail_(0) {} bool push(T *element) { bool was_empty;