Greasy Fork is available in English.

GitHub Actions Filter Button

Filter Kata Containers passed or non-required checks.

  1. // ==UserScript==
  2. // @name GitHub Actions Filter Button
  3. // @namespace http://www.nxw.name
  4. // @version 1.0.10
  5. // @description Filter Kata Containers passed or non-required checks.
  6. // @author Xuewei Niu
  7. // @match *://github.com/kata-containers/kata-containers*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=github.com
  9. // @grant none
  10. // @license Apache-2.0
  11. // ==/UserScript==
  12.  
  13. var filteredItems = 0;
  14. var checkCount = 0;
  15. var filterButton;
  16.  
  17. function onFilterButtonClicked() {
  18. var checks = document.querySelectorAll('div.merge-status-list.hide-closed-list.js-updatable-content-preserve-scroll-position > div');
  19. if (checks.length == 0) {
  20. console.log('stop hiding checks: they aren\'t ready')
  21. return;
  22. }
  23.  
  24. if (checkCount === 0) {
  25. checkCount = checks.length;
  26. }
  27.  
  28. var hidden = (filteredItems === 0);
  29. if (!hidden) {
  30. // Count the number of showing checks
  31. var showingCheckCount = 0;
  32. checks.forEach(function(check) {
  33. if (!check.classList.contains('hidden-check')) {
  34. showingCheckCount += 1;
  35. }
  36. });
  37. // GitHub updates periodly to restore the hidden checks.
  38. // We need to update `hidden` to fit the above issue.
  39. if (checkCount === showingCheckCount) {
  40. console.log('checks were updated, hide checks again');
  41. hidden = true;
  42. }
  43. filteredItems = 0
  44. }
  45. checks.forEach(function(check) {
  46. if (hidden) {
  47. // There is no github icon in the case of non-gha,
  48. // so the indexes of status element and details element
  49. // are required to calculate dynamically.
  50. var elemCount = check.childElementCount;
  51. var statusElement = check.querySelector('div:nth-child('+ (elemCount-1) +')');
  52. if (!statusElement) {
  53. console.debug(statusElement, 'check status not found');
  54. return;
  55. }
  56. var detailsElement = check.querySelector('div:nth-child('+ elemCount +')');
  57. if (!detailsElement) {
  58. console.debug(detailsElement, 'check details not found');
  59. return;
  60. }
  61.  
  62. var statusText = statusElement.textContent;
  63. var requiredText = detailsElement.textContent;
  64. // 'Successful in' for GHA, 'Build finished' for Jenkins
  65. var successful = statusText.includes('Successful in') || statusText.includes('Build finished');
  66. var required = requiredText.includes('Required');
  67.  
  68. if (successful || !required) {
  69. console.debug('check item is hidden: successful: ' + successful + ', required: ' + required, check);
  70. check.classList.add('hidden-check');
  71. } else {
  72. console.info('check item isn\'t hidden: successful: ' + successful + ', required: ' + required, check);
  73. }
  74. filteredItems += 1;
  75. } else {
  76. check.classList.remove('hidden-check');
  77. }
  78. });
  79. }
  80.  
  81. function insertFilterButton() {
  82. var body = document.querySelector('body');
  83. var bodyFirstChild = document.querySelector('body div:nth-child(1)');
  84.  
  85. filterButton = document.createElement('button');
  86. filterButton.type = 'button';
  87. filterButton.textContent = 'Filter Checks';
  88. filterButton.classList.add('gha-filter-button');
  89. filterButton.classList.add('hidden-check');
  90. filterButton.addEventListener('click', onFilterButtonClicked);
  91.  
  92. body.insertBefore(filterButton, bodyFirstChild);
  93. }
  94.  
  95. function insertHiddenCheckCssStyle() {
  96. var styleElement = document.createElement('style');
  97. styleElement.type = 'text/css';
  98. var cssRule = document.createTextNode('.hidden-check { display: none !important }\n.gha-filter-button { position: fixed; bottom: 100px; right: 20px; display: block; z-index: 10000; background-color: #218bff; color: #fff; padding: 5px 16px; border: none; border-radius: 6px;}');
  99. styleElement.appendChild(cssRule);
  100. document.head.appendChild(styleElement);
  101. }
  102.  
  103. function updateFilterButton(href) {
  104. const regex = /github\.com\/kata-containers\/kata-containers\/pull\/\d+(#pullrequestreview-\d+)?(#discussion_r\d+)?(#issuecomment-\d+)?$/;
  105. if (regex.test(href)) {
  106. console.debug('show filter button', href);
  107. filterButton.classList.remove('hidden-check');
  108. } else {
  109. console.debug('hide filter button', href);
  110. filterButton.classList.add('hidden-check');
  111. }
  112. }
  113.  
  114. function listenUrlChanged(callback) {
  115. var _wr = function (type) {
  116. var orig = history[type];
  117. return function () {
  118. var rv = orig.apply(this, arguments);
  119. var e = new Event(type);
  120. e.arguments = arguments;
  121. window.dispatchEvent(e);
  122. return rv;
  123. };
  124. };
  125. history.pushState = _wr('pushState');
  126.  
  127. window.addEventListener('pushState', function (e) {
  128. console.debug('pushState: url changed', window.location.href);
  129. callback();
  130. });
  131. window.addEventListener('popstate', function (e) {
  132. console.debug('popstate: url changed', window.location.href);
  133. callback();
  134. });
  135. window.addEventListener('hashchange', function (e) {
  136. console.debug('hashchange: url changed', window.location.href);
  137. callback();
  138. });
  139. }
  140.  
  141. (function() {
  142. 'use strict';
  143.  
  144. insertHiddenCheckCssStyle();
  145. insertFilterButton();
  146.  
  147. updateFilterButton(window.location.href);
  148. listenUrlChanged(function() {
  149. updateFilterButton(window.location.href);
  150. filteredItems = 0;
  151. });
  152. })();