Repository: hub4j/github-api
Pull request #1903 (2024-08-01 02:06:59)

Chore(deps): Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.7.0 to 3.8.0
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.7.0 to 3.8.0.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/apache/maven-javadoc-plugin/commit/621cba66b6aee068a370806b1619cf1d87e9c582"><code>621cba6</code></a> [maven-release-plugin] prepare release maven-javadoc-plugin-3.8.0</li>
<li><a href="https://github.com/apache/maven-javadoc-plugin/commit/eab964ca3f7df4c5bc94ef78a2547729bbcb1c88"><code>eab964c</code></a> [MJAVADOC-603] javadoc:fix failure on JDK10: java.lang.ClassNotFoundException...</li>
<li><a href="https://github.com/apache/maven-javadoc-plugin/commit/0a26a7e048e1b0ddb1951983e33e8f3453e87f17"><code>0a26a7e</code></a> Update since tags</li>
<li><a href="https://github.com/apache/maven-javadoc-plugin/commit/08205b187e976bb7d9266df3b8e7865dae755105"><code>08205b1</code></a> Add compile step for MJAVADOC-365 IT</li>
<li><a href="https://github.com/apache/maven-javadoc-plugin/commit/4c8ca8ede6517cc34a7a1a38ba113d0fac351e4d"><code>4c8ca8e</code></a> [MJAVADOC-804] Remove temporary directories created by tests</li>
<li><a href="https://github.com/apache/maven-javadoc-plugin/commit/91369fabe400ea6c2d91a36d90885d36b447d3ec"><code>91369fa</code></a> [MJAVADOC-775] Option 'taglets/taglet/tagletpath' ignored when pointing to a JAR</li>
<li><a href="https://github.com/apache/maven-javadoc-plugin/commit/be2fa208674c781b08658878ae375f2c058992fc"><code>be2fa20</code></a> [MJAVADOC-783] Invalid path when using TagletArtifact and TagletPath</li>
<li><a href="https://github.com/apache/maven-javadoc-plugin/commit/3eb47c5081bf6f4158333bd378641bc9b7c9a25f"><code>3eb47c5</code></a> [MJAVADOC-791] maven-javadoc-plugin not working correctly together with maven...</li>
<li><a href="https://github.com/apache/maven-javadoc-plugin/commit/d3afd39f63f730f5018e8bb00bbf4226dd0f482f"><code>d3afd39</code></a> [MJAVADOC-803] Add default parameter to force root locale</li>
<li><a href="https://github.com/apache/maven-javadoc-plugin/commit/4904e0825ae265f5d152a9f0d7eebbcc038c55c9"><code>4904e08</code></a> [MJAVADOC-802] Set default value of defaultAuthor parameter in fix goals to $...</li>
<li>Additional commits viewable in <a href="https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.7.0...maven-javadoc-plugin-3.8.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.apache.maven.plugins:maven-javadoc-plugin&package-manager=maven&previous-version=3.7.0&new-version=3.8.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

You can trigger a rebase of this PR by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/pom.xml b/pom.xml
index a438bc091..80aaf5225 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.kohsuke</groupId>
   <artifactId>github-api</artifactId>
-  <version>1.324-SNAPSHOT</version>
+  <version>1.325-SNAPSHOT</version>
   <name>GitHub API for Java</name>
   <url>https://github-api.kohsuke.org/</url>
   <description>GitHub API for Java</description>
@@ -84,7 +84,7 @@
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>versions-maven-plugin</artifactId>
-          <version>2.16.2</version>
+          <version>2.17.1</version>
         </plugin>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
@@ -222,7 +222,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-javadoc-plugin</artifactId>
-          <version>3.7.0</version>
+          <version>3.8.0</version>
           <configuration>
             <release>8</release>
             <failOnWarnings>true</failOnWarnings>
diff --git a/src/main/java/org/kohsuke/github/AbuseLimitHandler.java b/src/main/java/org/kohsuke/github/AbuseLimitHandler.java
index d6894adf9..09084080a 100644
--- a/src/main/java/org/kohsuke/github/AbuseLimitHandler.java
+++ b/src/main/java/org/kohsuke/github/AbuseLimitHandler.java
@@ -5,6 +5,9 @@ import org.kohsuke.github.connector.GitHubConnectorResponse;
 import java.io.IOException;
 import java.io.InterruptedIOException;
 import java.net.HttpURLConnection;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
 
 import javax.annotation.Nonnull;
 
@@ -86,13 +89,6 @@ public abstract class AbuseLimitHandler extends GitHubAbuseLimitHandler {
             }
         }
 
-        private long parseWaitTime(HttpURLConnection uc) {
-            String v = uc.getHeaderField("Retry-After");
-            if (v == null)
-                return 60 * 1000; // can't tell, return 1 min
-
-            return Math.max(1000, Long.parseLong(v) * 1000);
-        }
     };
 
     /**
@@ -105,4 +101,25 @@ public abstract class AbuseLimitHandler extends GitHubAbuseLimitHandler {
             throw e;
         }
     };
+
+    /*
+     * Exposed for testability. Given an http response, find the retry-after header field and parse it as either a
+     * number or a date (the spec allows both). If no header is found, wait for a reasonably amount of time.
+     */
+    long parseWaitTime(HttpURLConnection uc) {
+        String v = uc.getHeaderField("Retry-After");
+        if (v == null) {
+            // can't tell, wait for unambiguously over one minute per GitHub guidance
+            return 61 * 1000;
+        }
+
+        try {
+            return Math.max(1000, Long.parseLong(v) * 1000);
+        } catch (NumberFormatException nfe) {
+            // The retry-after header could be a number in seconds, or an http-date
+            ZonedDateTime zdt = ZonedDateTime.parse(v, DateTimeFormatter.RFC_1123_DATE_TIME);
+            return ChronoUnit.MILLIS.between(ZonedDateTime.now(), zdt);
+        }
+    }
+
 }
diff --git a/src/main/java/org/kohsuke/github/GHBranchSync.java b/src/main/java/org/kohsuke/github/GHBranchSync.java
new file mode 100644
index 000000000..d03f4a79b
--- /dev/null
+++ b/src/main/java/org/kohsuke/github/GHBranchSync.java
@@ -0,0 +1,90 @@
+package org.kohsuke.github;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+/**
+ * The type Gh branch sync.
+ */
+public class GHBranchSync extends GitHubInteractiveObject {
+
+    /**
+     * The Repository that this branch is in.
+     */
+    private GHRepository owner;
+
+    /**
+     * The message.
+     */
+    private String message;
+
+    /**
+     * The merge type.
+     */
+    private String mergeType;
+
+    /**
+     * The base branch.
+     */
+    private String baseBranch;
+
+    /**
+     * Gets owner.
+     *
+     * @return the repository that this branch is in.
+     */
+    @SuppressFBWarnings(value = { "EI_EXPOSE_REP" }, justification = "Expected behavior")
+    public GHRepository getOwner() {
+        return owner;
+    }
+
+    /**
+     * Gets message.
+     *
+     * @return the message
+     */
+    public String getMessage() {
+        return message;
+    }
+
+    /**
+     * Gets merge type.
+     *
+     * @return the merge type
+     */
+    public String getMergeType() {
+        return mergeType;
+    }
+
+    /**
+     * Gets base branch.
+     *
+     * @return the base branch
+     */
+    public String getBaseBranch() {
+        return baseBranch;
+    }
+
+    /**
+     * To string.
+     *
+     * @return the string
+     */
+    @Override
+    public String toString() {
+        return "GHBranchSync{" + "message='" + message + '\'' + ", mergeType='" + mergeType + '\'' + ", baseBranch='"
+                + baseBranch + '\'' + '}';
+    }
+
+    /**
+     * Wrap.
+     *
+     * @param repo
+     *            the repo
+     * @return the GH branch sync
+     */
+    GHBranchSync wrap(GHRepository repo) {
+        this.owner = repo;
+        return this;
+    }
+
+}
diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java
index e854e618e..44bf41d30 100644
--- a/src/main/java/org/kohsuke/github/GHRepository.java
+++ b/src/main/java/org/kohsuke/github/GHRepository.java
@@ -1007,7 +1007,7 @@ public class GHRepository extends GHObject {
 
     /**
      * Lists all
-     * <a href="https://help.github.com/articles/assigning-issues-and-pull-requests-to-other-github-users/">the
+     * <a href= "https://help.github.com/articles/assigning-issues-and-pull-requests-to-other-github-users/">the
      * available assignees</a> to which issues may be assigned.
      *
      * @return the paged iterable
@@ -1614,6 +1614,24 @@ public class GHRepository extends GHObject {
         throw new IOException(this + " was forked but can't find the new repository");
     }
 
+    /**
+     * Sync this repository fork branch
+     *
+     * @param branch
+     *            the branch to sync
+     * @return The current repository
+     * @throws IOException
+     *             the io exception
+     */
+    public GHBranchSync sync(String branch) throws IOException {
+        return root().createRequest()
+                .method("POST")
+                .with("branch", branch)
+                .withUrlPath(getApiTailUrl("merge-upstream"))
+                .fetch(GHBranchSync.class)
+                .wrap(this);
+    }
+
     /**
      * Forks this repository into an organization.
      *
@@ -2222,7 +2240,7 @@ public class GHRepository extends GHObject {
      * @return check runs for given ref
      * @throws IOException
      *             the io exception
-     * @see <a href="https://developer.github.com/v3/checks/runs/#list-check-runs-for-a-specific-ref">List check runs
+     * @see <a href= "https://developer.github.com/v3/checks/runs/#list-check-runs-for-a-specific-ref">List check runs
      *      for a specific ref</a>
      */
     public PagedIterable<GHCheckRun> getCheckRuns(String ref) throws IOException {
@@ -2242,7 +2260,7 @@ public class GHRepository extends GHObject {
      * @return check runs for the given ref
      * @throws IOException
      *             the io exception
-     * @see <a href="https://developer.github.com/v3/checks/runs/#list-check-runs-for-a-specific-ref">List check runs
+     * @see <a href= "https://developer.github.com/v3/checks/runs/#list-check-runs-for-a-specific-ref">List check runs
      *      for a specific ref</a>
      */
     public PagedIterable<GHCheckRun> getCheckRuns(String ref, Map<String, Object> params) throws IOException {
@@ -3568,7 +3586,8 @@ public class GHRepository extends GHObject {
 
         // We don't use the URL provided in the JSON because it is not reliable:
         // 1. There is bug in Push event payloads that returns the wrong url.
-        // For Push event repository records, they take the form "https://github.com/{fullName}".
+        // For Push event repository records, they take the form
+        // "https://github.com/{fullName}".
         // All other occurrences of "url" take the form "https://api.github.com/...".
         // 2. For Installation event payloads, the URL is not provided at all.
 
@@ -3649,6 +3668,23 @@ public class GHRepository extends GHObject {
                 .fetch(GHRepositoryTrafficTopReferralSources[].class));
     }
 
+    /**
+     * Get all active rules that apply to the specified branch
+     * (https://docs.github.com/en/rest/repos/rules?apiVersion=2022-11-28#get-rules-for-a-branch).
+     *
+     * @param branch
+     *            the branch
+     * @return the rules for branch
+     * @throws IOException
+     *             the io exception
+     */
+    public PagedIterable<GHRepositoryRule> listRulesForBranch(String branch) throws IOException {
+        return root().createRequest()
+                .method("GET")
+                .withUrlPath(getApiTailUrl("/rules/branches/" + branch))
+                .toIterable(GHRepositoryRule[].class, null);
+    }
+
     /**
      * A {@link GHRepositoryBuilder} that allows multiple properties to be updated per request.
      *
diff --git a/src/main/java/org/kohsuke/github/GHRepositoryRule.java b/src/main/java/org/kohsuke/github/GHRepositoryRule.java
new file mode 100644
index 000000000..0c1b9c5d5
--- /dev/null
+++ b/src/main/java/org/kohsuke/github/GHRepositoryRule.java
@@ -0,0 +1,610 @@
+package org.kohsuke.github;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.kohsuke.github.internal.EnumUtils;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * Represents a repository rule.
+ */
+@SuppressFBWarnings(value = { "UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD" },
+        justification = "JSON API")
+public class GHRepositoryRule extends GitHubInteractiveObject {
+    private String type;
+    private String rulesetSourceType;
+    private String rulesetSource;
+    private long rulesetId;
+    private Map<String, JsonNode> parameters;
+
+    /**
+     * Gets the type.
+     *
+     * @return the type
+     */
+    public Type getType() {
+        return EnumUtils.getEnumOrDefault(Type.class, this.type, Type.UNKNOWN);
+    }
+
+    /**
+     * Gets the ruleset source type.
+     *
+     * @return the ruleset source type
+     */
+    public RulesetSourceType getRulesetSourceType() {
+        return EnumUtils.getEnumOrDefault(RulesetSourceType.class, this.rulesetSourceType, RulesetSourceType.UNKNOWN);
+    }
+
+    /**
+     * Gets the ruleset source.
+     *
+     * @return the ruleset source
+     */
+    public String getRulesetSource() {
+        return this.rulesetSource;
+    }
+
+    /**
+     * Gets the ruleset id.
+     *
+     * @return the ruleset id
+     */
+    public long getRulesetId() {
+        return this.rulesetId;
+    }
+
+    /**
+     * Gets a parameter. ({@link GHRepositoryRule.Parameters Parameters} provides a list of available parameters.)
+     *
+     * @param parameter
+     *            the parameter
+     * @param <T>
+     *            the type of the parameter
+     * @return the parameters
+     * @throws IOException
+     *             if an I/O error occurs
+     */
+    public <T> Optional<T> getParameter(Parameter<T> parameter) throws IOException {
+        if (this.parameters == null) {
+            return Optional.empty();
+        }
+        JsonNode jsonNode = this.parameters.get(parameter.getKey());
+        if (jsonNode == null) {
+            return Optional.empty();
+        }
+        return Optional.ofNullable(parameter.apply(jsonNode, root()));
+    }
+
+    /**
+     * The type of the ruleset.
+     */
+    public static enum Type {
+        /**
+         * unknown
+         */
+        UNKNOWN,
+
+        /**
+         * creation
+         */
+        CREATION,
+
+        /**
+         * update
+         */
+        UPDATE,
+
+        /**
+         * deletion
+         */
+        DELETION,
+
+        /**
+         * required_linear_history
+         */
+        REQUIRED_LINEAR_HISTORY,
+
+        /**
+         * required_deployments
+         */
+        REQUIRED_DEPLOYMENTS,
+
+        /**
+         * required_signatures
+         */
+        REQUIRED_SIGNATURES,
+
+        /**
+         * pull_request
+         */
+        PULL_REQUEST,
+
+        /**
+         * required_status_checks
+         */
+        REQUIRED_STATUS_CHECKS,
+
+        /**
+         * non_fast_forward
+         */
+        NON_FAST_FORWARD,
+
+        /**
+         * commit_message_pattern
+         */
+        COMMIT_MESSAGE_PATTERN,
+
+        /**
+         * commit_author_email_pattern
+         */
+        COMMIT_AUTHOR_EMAIL_PATTERN,
+
+        /**
+         * committer_email_pattern
+         */
+        COMMITTER_EMAIL_PATTERN,
+
+        /**
+         * branch_name_pattern
+         */
+        BRANCH_NAME_PATTERN,
+
+        /**
+         * tag_name_pattern
+         */
+        TAG_NAME_PATTERN,
+
+        /**
+         * workflows
+         */
+        WORKFLOWS,
+
+        /**
+         * code_scanning
+         */
+        CODE_SCANNING
+    }
+
+    /**
+     * The source of the ruleset type.
+     */
+    public enum RulesetSourceType {
+        /**
+         * unknown
+         */
+        UNKNOWN,
+
+        /**
+         * Repository
+         */
+        REPOSITORY,
+
+        /**
+         * Organization
+         */
+        ORGANIZATION
+    }
+
+    /**
+     * Available parameters for a ruleset.
+     */
+    public interface Parameters {
+        /**
+         * update_allows_fetch_and_merge parameter
+         */
+        public static final BooleanParameter UPDATE_ALLOWS_FETCH_AND_MERGE = new BooleanParameter(
+                "update_allows_fetch_and_merge");
+        /**
+         * required_deployment_environments parameter
+         */
+        public static final ListParameter<String> REQUIRED_DEPLOYMENT_ENVIRONMENTS = new ListParameter<String>(
+                "required_deployment_environments") {
+            @Override
+            TypeReference<List<String>> getType() {
+                return new TypeReference<List<String>>() {
+                };
+            }
+        };
+        /**
+         * dismiss_stale_reviews_on_push parameter
+         */
+        public static final BooleanParameter DISMISS_STALE_REVIEWS_ON_PUSH = new BooleanParameter(
+                "dismiss_stale_reviews_on_push");
+        /**
+         * require_code_owner_review parameter
+         */
+        public static final BooleanParameter REQUIRE_CODE_OWNER_REVIEW = new BooleanParameter(
+                "require_code_owner_review");
+        /**
+         * require_last_push_approval parameter
+         */
+        public static final BooleanParameter REQUIRE_LAST_PUSH_APPROVAL = new BooleanParameter(
+                "require_last_push_approval");
+        /**
+         * required_approving_review_count parameter
+         */
+        public static final IntegerParameter REQUIRED_APPROVING_REVIEW_COUNT = new IntegerParameter(
+                "required_approving_review_count");
+        /**
+         * required_review_thread_resolution parameter
+         */
+        public static final BooleanParameter REQUIRED_REVIEW_THREAD_RESOLUTION = new BooleanParameter(
+                "required_review_thread_resolution");
+        /**
+         * required_status_checks parameter
+         */
+        public static final ListParameter<StatusCheckConfiguration> REQUIRED_STATUS_CHECKS = new ListParameter<StatusCheckConfiguration>(
+                "required_status_checks") {
+            @Override
+            TypeReference<List<StatusCheckConfiguration>> getType() {
+                return new TypeReference<List<StatusCheckConfiguration>>() {
+                };
+            }
+        };
+        /**
+         * strict_required_status_checks_policy parameter
+         */
+        public static final BooleanParameter STRICT_REQUIRED_STATUS_CHECKS_POLICY = new BooleanParameter(
+                "strict_required_status_checks_policy");
+        /**
+         * name parameter
+         */
+        public static final StringParameter NAME = new StringParameter("name");
+        /**
+         * negate parameter
+         */
+        public static final BooleanParameter NEGATE = new BooleanParameter("negate");
+        /**
+         * operator parameter
+         */
+        public static final Parameter<Operator> OPERATOR = new Parameter<Operator>("operator") {
+            @Override
+            TypeReference<Operator> getType() {
+                return new TypeReference<Operator>() {
+                };
+            }
+        };
+        /**
+         * regex parameter
+         */
+        public static final StringParameter REGEX = new StringParameter("regex");
+        /**
+         * workflows parameter
+         */
+        public static final ListParameter<WorkflowFileReference> WORKFLOWS = new ListParameter<WorkflowFileReference>(
+                "workflows") {
+            @Override
+            TypeReference<List<WorkflowFileReference>> getType() {
+                return new TypeReference<List<WorkflowFileReference>>() {
+                };
+            }
+        };
+        /**
+         * code_scanning_tools parameter
+         */
+        public static final ListParameter<CodeScanningTool> CODE_SCANNING_TOOLS = new ListParameter<CodeScanningTool>(
+                "code_scanning_tools") {
+            @Override
+            TypeReference<List<CodeScanningTool>> getType() {
+                return new TypeReference<List<CodeScanningTool>>() {
+                };
+            }
+        };
+    }
+
+    /**
+     * Basic parameter for a ruleset.
+     *
+     * @param <T>
+     *            the type of the parameter
+     */
+    public abstract static class Parameter<T> {
+
+        private final String key;
+
+        /**
+         * Get the parameter type reference for type mapping.
+         */
+        abstract TypeReference<T> getType();
+
+        /**
+         * Instantiates a new parameter.
+         *
+         * @param key
+         *            the key
+         */
+        protected Parameter(String key) {
+            this.key = key;
+        }
+
+        /**
+         * Gets the key.
+         *
+         * @return the key
+         */
+        String getKey() {
+            return this.key;
+        }
+
+        T apply(JsonNode jsonNode, GitHub root) throws IOException {
+            if (jsonNode == null) {
+                return null;
+            }
+            return GitHubClient.getMappingObjectReader(root).forType(this.getType()).readValue(jsonNode);
+        }
+    }
+
+    /**
+     * String parameter for a ruleset.
+     */
+    public static class StringParameter extends Parameter<String> {
+        /**
+         * Instantiates a new string parameter.
+         *
+         * @param key
+         *            the key
+         */
+        public StringParameter(String key) {
+            super(key);
+        }
+
+        @Override
+        TypeReference<String> getType() {
+            return new TypeReference<String>() {
+            };
+        }
+    }
+
+    /**
+     * Boolean parameter for a ruleset.
+     */
+    public static class BooleanParameter extends Parameter<Boolean> {
+        /**
+         * Instantiates a new boolean parameter.
+         *
+         * @param key
+         *            the key
+         */
+        public BooleanParameter(String key) {
+            super(key);
+        }
+
+        @Override
+        TypeReference<Boolean> getType() {
+            return new TypeReference<Boolean>() {
+            };
+        }
+    }
+
+    /**
+     * Integer parameter for a ruleset.
+     */
+    public static class IntegerParameter extends Parameter<Integer> {
+        /**
+         * Instantiates a new integer parameter.
+         *
+         * @param key
+         *            the key
+         */
+        public IntegerParameter(String key) {
+            super(key);
+        }
+
+        @Override
+        TypeReference<Integer> getType() {
+            return new TypeReference<Integer>() {
+            };
+        }
+    }
+
+    /**
+     * List parameter for a ruleset.
+     *
+     * @param <T>
+     *            the type of the list
+     */
+    public abstract static class ListParameter<T> extends Parameter<List<T>> {
+        /**
+         * Instantiates a new list parameter.
+         *
+         * @param key
+         *            the key
+         */
+        public ListParameter(String key) {
+            super(key);
+        }
+    }
+
+    /**
+     * Status check configuration parameter.
+     */
+    public static class StatusCheckConfiguration {
+        private String context;
+        private Integer integrationId;
+
+        /**
+         * Gets the context.
+         *
+         * @return the context
+         */
+        public String getContext() {
+            return this.context;
+        }
+
+        /**
+         * Gets the integration id.
+         *
+         * @return the integration id
+         */
+        public Integer getIntegrationId() {
+            return this.integrationId;
+        }
+    }
+
+    /**
+     * Operator parameter.
+     */
+    public static enum Operator {
+        /**
+         * starts_with
+         */
+        STARTS_WITH,
+
+        /**
+         * ends_with
+         */
+        ENDS_WITH,
+
+        /**
+         * contains
+         */
+        CONTAINS,
+
+        /**
+         * regex
+         */
+        REGEX
+    }
+
+    /**
+     * Workflow file reference parameter.
+     */
+    public static class WorkflowFileReference {
+        private String path;
+        private String ref;
+        private long repositoryId;
+        private String sha;
+
+        /**
+         * Gets the path.
+         *
+         * @return the path
+         */
+        public String getPath() {
+            return this.path;
+        }
+
+        /**
+         * Gets the ref.
+         *
+         * @return the ref
+         */
+        public String getRef() {
+            return this.ref;
+        }
+
+        /**
+         * Gets the repository id.
+         *
+         * @return the repository id
+         */
+        public long getRepositoryId() {
+            return this.repositoryId;
+        }
+
+        /**
+         * Gets the sha.
+         *
+         * @return the sha
+         */
+        public String getSha() {
+            return this.sha;
+        }
+    }
+
+    /**
+     * Code scanning tool parameter.
+     */
+    public static class CodeScanningTool {
+        private AlertsThreshold alertsThreshold;
+        private SecurityAlertsThreshold securityAlertsThreshold;
+        private String tool;
+
+        /**
+         * Gets the alerts threshold.
+         *
+         * @return the alerts threshold
+         */
+        public AlertsThreshold getAlertsThreshold() {
+            return this.alertsThreshold;
+        }
+
+        /**
+         * Gets the security alerts threshold.
+         *
+         * @return the security alerts threshold
+         */
+        public SecurityAlertsThreshold getSecurityAlertsThreshold() {
+            return this.securityAlertsThreshold;
+        }
+
+        /**
+         * Gets the tool.
+         *
+         * @return the tool
+         */
+        public String getTool() {
+            return this.tool;
+        }
+    }
+
+    /**
+     * Alerts threshold parameter.
+     */
+    public static enum AlertsThreshold {
+        /**
+         * none
+         */
+        NONE,
+
+        /**
+         * errors
+         */
+        ERRORS,
+
+        /**
+         * errors_and_warnings
+         */
+        ERRORS_AND_WARNINGS,
+
+        /**
+         * all
+         */
+        ALL
+    }
+
+    /**
+     * Security alerts threshold parameter.
+     */
+    public static enum SecurityAlertsThreshold {
+        /**
+         * none
+         */
+        NONE,
+
+        /**
+         * critical
+         */
+        CRITICAL,
+
+        /**
+         * high_or_higher
+         */
+        HIGH_OR_HIGHER,
+
+        /**
+         * medium_or_higher
+         */
+        MEDIUM_OR_HIGHER,
+
+        /**
+         * all
+         */
+        ALL
+    }
+}
diff --git a/src/main/java/org/kohsuke/github/GHUser.java b/src/main/java/org/kohsuke/github/GHUser.java
index d28ab697d..b072fc52c 100644
--- a/src/main/java/org/kohsuke/github/GHUser.java
+++ b/src/main/java/org/kohsuke/github/GHUser.java
@@ -39,6 +39,9 @@ public class GHUser extends GHPerson {
     /** The ldap dn. */
     protected String ldap_dn;
 
+    /** The suspended_at */
+    private String suspendedAt;
+
     /**
      * Gets keys.
      *
@@ -264,6 +267,17 @@ public class GHUser extends GHPerson {
         return Optional.ofNullable(ldap_dn);
     }
 
+    /**
+     * When was this user suspended?.
+     *
+     * @return updated date
+     * @throws IOException
+     *             on error
+     */
+    public Date getSuspendedAt() throws IOException {
+        return GitHubClient.parseDate(suspendedAt);
+    }
+
     /**
      * Hash code.
      *
diff --git a/src/main/java/org/kohsuke/github/GitHubAbuseLimitHandler.java b/src/main/java/org/kohsuke/github/GitHubAbuseLimitHandler.java
index 0555ead23..e76960452 100644
--- a/src/main/java/org/kohsuke/github/GitHubAbuseLimitHandler.java
+++ b/src/main/java/org/kohsuke/github/GitHubAbuseLimitHandler.java
@@ -29,7 +29,19 @@ public abstract class GitHubAbuseLimitHandler extends GitHubConnectorResponseErr
      */
     @Override
     boolean isError(@Nonnull GitHubConnectorResponse connectorResponse) {
-        return isForbidden(connectorResponse) && hasRetryOrLimitHeader(connectorResponse);
+        return isTooManyRequests(connectorResponse)
+                || (isForbidden(connectorResponse) && hasRetryOrLimitHeader(connectorResponse));
+    }
+
+    /**
+     * Checks if the response status code is TOO_MANY_REQUESTS (429).
+     *
+     * @param connectorResponse
+     *            the response from the GitHub connector
+     * @return true if the status code is TOO_MANY_REQUESTS
+     */
+    private boolean isTooManyRequests(GitHubConnectorResponse connectorResponse) {
+        return connectorResponse.statusCode() == TOO_MANY_REQUESTS;
     }
 
     /**
diff --git a/src/main/java/org/kohsuke/github/GitHubConnectorResponseErrorHandler.java b/src/main/java/org/kohsuke/github/GitHubConnectorResponseErrorHandler.java
index e71e81921..0a7f7fa9f 100644
--- a/src/main/java/org/kohsuke/github/GitHubConnectorResponseErrorHandler.java
+++ b/src/main/java/org/kohsuke/github/GitHubConnectorResponseErrorHandler.java
@@ -23,6 +23,17 @@ import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
  */
 abstract class GitHubConnectorResponseErrorHandler {
 
+    /**
+     * The HTTP 429 Too Many Requests response status code indicates the user has sent too many requests in a given
+     * amount of time ("rate limiting").
+     *
+     * A Retry-After header might be included to this response indicating how long to wait before making a new request.
+     *
+     * Why is this hardcoded here? The HttpURLConnection class is missing the status codes above 415, so the constant
+     * needs to be sourced from elsewhere.
+     */
+    public static final int TOO_MANY_REQUESTS = 429;
+
     /**
      * Called to detect an error handled by this handler.
      *


Test patch:
diff --git a/src/test/java/org/kohsuke/github/AbuseLimitHandlerTest.java b/src/test/java/org/kohsuke/github/AbuseLimitHandlerTest.java
index 004ba305e..5736146c4 100644
--- a/src/test/java/org/kohsuke/github/AbuseLimitHandlerTest.java
+++ b/src/test/java/org/kohsuke/github/AbuseLimitHandlerTest.java
@@ -16,6 +16,7 @@ import java.util.Map;
 
 import static org.hamcrest.CoreMatchers.*;
 import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.Matchers.greaterThan;
 import static org.hamcrest.core.IsInstanceOf.instanceOf;
 
 // TODO: Auto-generated Javadoc
@@ -98,22 +99,14 @@ public class AbuseLimitHandlerTest extends AbstractGitHubWireMockTest {
                         // getting an input stream in an error case should throw
                         IOException ioEx = Assert.assertThrows(IOException.class, () -> uc.getInputStream());
 
-                        try (InputStream errorStream = uc.getErrorStream()) {
-                            assertThat(errorStream, notNullValue());
-                            String errorString = IOUtils.toString(errorStream, StandardCharsets.UTF_8);
-                            assertThat(errorString, containsString("Must have push access to repository"));
-                        }
+                        checkErrorMessageMatches(uc, "Must have push access to repository");
 
                         // calling again should still error
                         ioEx = Assert.assertThrows(IOException.class, () -> uc.getInputStream());
 
                         // calling again on a GitHubConnectorResponse should yield the same value
                         if (uc.toString().contains("GitHubConnectorResponseHttpUrlConnectionAdapter")) {
-                            try (InputStream errorStream = uc.getErrorStream()) {
-                                assertThat(errorStream, notNullValue());
-                                String errorString = IOUtils.toString(errorStream, StandardCharsets.UTF_8);
-                                assertThat(errorString, containsString("Must have push access to repository"));
-                            }
+                            checkErrorMessageMatches(uc, "Must have push access to repository");
                         } else {
                             try (InputStream errorStream = uc.getErrorStream()) {
                                 assertThat(errorStream, notNullValue());
@@ -126,7 +119,7 @@ public class AbuseLimitHandlerTest extends AbstractGitHubWireMockTest {
                         }
 
                         assertThat(uc.getHeaderFields(), instanceOf(Map.class));
-                        assertThat(uc.getHeaderFields().size(), Matchers.greaterThan(25));
+                        assertThat(uc.getHeaderFields().size(), greaterThan(25));
                         assertThat(uc.getHeaderField("Status"), equalTo("403 Forbidden"));
 
                         String key = uc.getHeaderFieldKey(1);
@@ -349,16 +342,203 @@ public class AbuseLimitHandlerTest extends AbstractGitHubWireMockTest {
                         assertThat(uc.getContentType(), equalTo("application/json; charset=utf-8"));
                         assertThat(uc.getContentLength(), equalTo(-1));
                         assertThat(uc.getHeaderFields(), instanceOf(Map.class));
-                        assertThat(uc.getHeaderFields().size(), Matchers.greaterThan(25));
+                        assertThat(uc.getHeaderFields().size(), greaterThan(25));
                         assertThat(uc.getHeaderField("Status"), equalTo("403 Forbidden"));
 
-                        try (InputStream errorStream = uc.getErrorStream()) {
-                            assertThat(errorStream, notNullValue());
-                            String errorString = IOUtils.toString(errorStream, StandardCharsets.UTF_8);
-                            assertThat(errorString,
-                                    containsString(
-                                            "You have exceeded a secondary rate limit. Please wait a few minutes before you try again"));
-                        }
+                        checkErrorMessageMatches(uc,
+                                "You have exceeded a secondary rate limit. Please wait a few minutes before you try again");
+                        AbuseLimitHandler.FAIL.onError(e, uc);
+                    }
+                })
+                .build();
+
+        gitHub.getMyself();
+        assertThat(mockGitHub.getRequestCount(), equalTo(1));
+        try {
+            getTempRepository();
+            fail();
+        } catch (Exception e) {
+            assertThat(e, instanceOf(HttpException.class));
+            assertThat(e.getMessage(), equalTo("Abuse limit reached"));
+        }
+        assertThat(mockGitHub.getRequestCount(), equalTo(2));
+    }
+
+    /**
+     * This is making an assertion about the behaviour of the mock, so it's useful for making sure we're on the right
+     * mock, but should not be used to validate assumptions about the behaviour of the actual GitHub API.
+     */
+    private static void checkErrorMessageMatches(HttpURLConnection uc, String substring) throws IOException {
+        try (InputStream errorStream = uc.getErrorStream()) {
+            assertThat(errorStream, notNullValue());
+            String errorString = IOUtils.toString(errorStream, StandardCharsets.UTF_8);
+            assertThat(errorString, containsString(substring));
+        }
+    }
+
+    /**
+     * Tests the behavior of the GitHub API client when the abuse limit handler is set to WAIT then the handler waits
+     * appropriately when secondary rate limits are encountered.
+     *
+     * @throws Exception
+     *             if any error occurs during the test execution.
+     */
+    @Test
+    public void testHandler_Wait_Secondary_Limits_Too_Many_Requests() throws Exception {
+        // Customized response that templates the date to keep things working
+        snapshotNotAllowed();
+        final HttpURLConnection[] savedConnection = new HttpURLConnection[1];
+        gitHub = getGitHubBuilder().withEndpoint(mockGitHub.apiServer().baseUrl())
+                .withAbuseLimitHandler(new AbuseLimitHandler() {
+                    /**
+                     * Overriding method because the actual method will wait for one minute causing slowness in unit
+                     * tests
+                     */
+                    @Override
+                    public void onError(IOException e, HttpURLConnection uc) throws IOException {
+                        savedConnection[0] = uc;
+                        // Verify the test data is what we expected it to be for this test case
+                        assertThat(uc.getDate(), Matchers.greaterThanOrEqualTo(new Date().getTime() - 10000));
+                        assertThat(uc.getExpiration(), equalTo(0L));
+                        assertThat(uc.getIfModifiedSince(), equalTo(0L));
+                        assertThat(uc.getLastModified(), equalTo(1581014017000L));
+                        assertThat(uc.getRequestMethod(), equalTo("GET"));
+                        assertThat(uc.getResponseCode(), equalTo(429));
+                        assertThat(uc.getResponseMessage(), containsString("Many"));
+                        assertThat(uc.getURL().toString(),
+                                endsWith(
+                                        "/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests"));
+                        assertThat(uc.getContentLength(), equalTo(-1));
+                        assertThat(uc.getHeaderFields(), instanceOf(Map.class));
+                        assertThat(uc.getHeaderField("Status"), equalTo("429 Too Many Requests"));
+                        assertThat(uc.getHeaderField("Retry-After"), equalTo("42"));
+
+                        checkErrorMessageMatches(uc,
+                                "You have exceeded a secondary rate limit. Please wait a few minutes before you try again");
+                        // Because we've overridden onError to bypass the wait, we don't cover the wait calculation
+                        // logic
+                        // Manually invoke it to make sure it's what we intended
+                        long waitTime = parseWaitTime(uc);
+                        assertThat(waitTime, equalTo(42 * 1000l));
+
+                        AbuseLimitHandler.FAIL.onError(e, uc);
+                    }
+                })
+                .build();
+
+        gitHub.getMyself();
+        assertThat(mockGitHub.getRequestCount(), equalTo(1));
+        try {
+            getTempRepository();
+            fail();
+        } catch (Exception e) {
+            assertThat(e, instanceOf(HttpException.class));
+            assertThat(e.getMessage(), equalTo("Abuse limit reached"));
+        }
+        assertThat(mockGitHub.getRequestCount(), equalTo(2));
+    }
+
+    /**
+     * Tests the behavior of the GitHub API client when the abuse limit handler with a date retry.
+     *
+     * @throws Exception
+     *             if any error occurs during the test execution.
+     */
+    @Test
+    public void testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After() throws Exception {
+        // Customized response that templates the date to keep things working
+        snapshotNotAllowed();
+        final HttpURLConnection[] savedConnection = new HttpURLConnection[1];
+        gitHub = getGitHubBuilder().withEndpoint(mockGitHub.apiServer().baseUrl())
+                .withAbuseLimitHandler(new AbuseLimitHandler() {
+                    /**
+                     * Overriding method because the actual method will wait for one minute causing slowness in unit
+                     * tests
+                     */
+                    @Override
+                    public void onError(IOException e, HttpURLConnection uc) throws IOException {
+                        savedConnection[0] = uc;
+                        // Verify the test data is what we expected it to be for this test case
+                        assertThat(uc.getRequestMethod(), equalTo("GET"));
+                        assertThat(uc.getResponseCode(), equalTo(429));
+                        assertThat(uc.getResponseMessage(), containsString("Many"));
+                        assertThat(uc.getURL().toString(),
+                                endsWith(
+                                        "/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After"));
+                        assertThat(uc.getContentLength(), equalTo(-1));
+                        assertThat(uc.getHeaderField("Status"), equalTo("429 Too Many Requests"));
+                        assertThat(uc.getHeaderField("Retry-After"), startsWith("Mon"));
+
+                        checkErrorMessageMatches(uc,
+                                "You have exceeded a secondary rate limit. Please wait a few minutes before you try again");
+
+                        // Because we've overridden onError to bypass the wait, we don't cover the wait calculation
+                        // logic
+                        // Manually invoke it to make sure it's what we intended
+                        long waitTime = parseWaitTime(uc);
+                        // The exact value here will depend on when the test is run, but it should be positive, and huge
+                        assertThat(waitTime, greaterThan(1000 * 1000l));
+
+                        AbuseLimitHandler.FAIL.onError(e, uc);
+                    }
+                })
+                .build();
+
+        gitHub.getMyself();
+        assertThat(mockGitHub.getRequestCount(), equalTo(1));
+        try {
+            getTempRepository();
+            fail();
+        } catch (Exception e) {
+            assertThat(e, instanceOf(HttpException.class));
+            assertThat(e.getMessage(), equalTo("Abuse limit reached"));
+        }
+        assertThat(mockGitHub.getRequestCount(), equalTo(2));
+    }
+
+    /**
+     * Tests the behavior of the GitHub API client when the abuse limit handler with a no retry after header.
+     *
+     * @throws Exception
+     *             if any error occurs during the test execution.
+     */
+    @Test
+    public void testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After() throws Exception {
+        // Customized response that templates the date to keep things working
+        snapshotNotAllowed();
+        final HttpURLConnection[] savedConnection = new HttpURLConnection[1];
+        gitHub = getGitHubBuilder().withEndpoint(mockGitHub.apiServer().baseUrl())
+                .withAbuseLimitHandler(new AbuseLimitHandler() {
+                    /**
+                     * Overriding method because the actual method will wait for one minute causing slowness in unit
+                     * tests
+                     */
+                    @Override
+                    public void onError(IOException e, HttpURLConnection uc) throws IOException {
+                        savedConnection[0] = uc;
+                        // Verify the test data is what we expected it to be for this test case
+                        assertThat(uc.getRequestMethod(), equalTo("GET"));
+                        assertThat(uc.getResponseCode(), equalTo(429));
+                        assertThat(uc.getResponseMessage(), containsString("Many"));
+                        assertThat(uc.getURL().toString(),
+                                endsWith(
+                                        "/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After"));
+                        assertThat(uc.getContentEncoding(), nullValue());
+                        assertThat(uc.getContentType(), equalTo("application/json; charset=utf-8"));
+                        assertThat(uc.getContentLength(), equalTo(-1));
+                        assertThat(uc.getHeaderFields(), instanceOf(Map.class));
+                        assertThat(uc.getHeaderField("Status"), equalTo("429 Too Many Requests"));
+                        assertThat(uc.getHeaderField("Retry-After"), nullValue());
+
+                        checkErrorMessageMatches(uc,
+                                "You have exceeded a secondary rate limit. Please wait a few minutes before you try again");
+
+                        // Because we've overridden onError to bypass the wait, we don't cover the wait calculation
+                        // logic
+                        // Manually invoke it to make sure it's what we intended
+                        long waitTime = parseWaitTime(uc);
+                        assertThat(waitTime, greaterThan(60000l));
+
                         AbuseLimitHandler.FAIL.onError(e, uc);
                     }
                 })
diff --git a/src/test/java/org/kohsuke/github/GHRepositoryRuleTest.java b/src/test/java/org/kohsuke/github/GHRepositoryRuleTest.java
new file mode 100644
index 000000000..9f176883e
--- /dev/null
+++ b/src/test/java/org/kohsuke/github/GHRepositoryRuleTest.java
@@ -0,0 +1,107 @@
+package org.kohsuke.github;
+
+import org.junit.Test;
+import org.kohsuke.github.GHRepositoryRule.AlertsThreshold;
+import org.kohsuke.github.GHRepositoryRule.CodeScanningTool;
+import org.kohsuke.github.GHRepositoryRule.Operator;
+import org.kohsuke.github.GHRepositoryRule.Parameter;
+import org.kohsuke.github.GHRepositoryRule.Parameters;
+import org.kohsuke.github.GHRepositoryRule.SecurityAlertsThreshold;
+import org.kohsuke.github.GHRepositoryRule.StatusCheckConfiguration;
+import org.kohsuke.github.GHRepositoryRule.StringParameter;
+import org.kohsuke.github.GHRepositoryRule.WorkflowFileReference;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+
+/**
+ * Test class for GHRepositoryRule.
+ */
+public class GHRepositoryRuleTest {
+    /**
+     * Test to cover the constructor of the Parameters class.
+     */
+    @Test
+    public void testParameters() {
+        assertThat(Parameters.REQUIRED_DEPLOYMENT_ENVIRONMENTS.getType(), is(notNullValue()));
+        assertThat(Parameters.REQUIRED_STATUS_CHECKS.getType(), is(notNullValue()));
+        assertThat(Parameters.OPERATOR.getType(), is(notNullValue()));
+        assertThat(Parameters.WORKFLOWS.getType(), is(notNullValue()));
+        assertThat(Parameters.CODE_SCANNING_TOOLS.getType(), is(notNullValue()));
+        assertThat(new StringParameter("any").getType(), is(notNullValue()));
+    }
+
+    /**
+     * Tests to cover StatusCheckConfiguration class.
+     */
+    @Test
+    public void testStatusCheckConfiguration() {
+        StatusCheckConfiguration statusCheckConfiguration = new StatusCheckConfiguration();
+        statusCheckConfiguration = new StatusCheckConfiguration();
+        assertThat(statusCheckConfiguration.getContext(), is(nullValue()));
+        assertThat(statusCheckConfiguration.getIntegrationId(), is(nullValue()));
+    }
+
+    /**
+     * Tests to cover WorkflowFileReference class.
+     */
+    @Test
+    public void testWorkflowFileReference() {
+        WorkflowFileReference workflowFileReference = new WorkflowFileReference();
+        assertThat(workflowFileReference.getPath(), is(nullValue()));
+        assertThat(workflowFileReference.getRef(), is(nullValue()));
+        assertThat(workflowFileReference.getRepositoryId(), is(equalTo(0L)));
+        assertThat(workflowFileReference.getSha(), is(nullValue()));
+    }
+
+    /**
+     * Tests to cover CodeScanningTool class.
+     */
+    @Test
+    public void testCodeScanningTool() {
+        CodeScanningTool codeScanningTool = new CodeScanningTool();
+        codeScanningTool = new CodeScanningTool();
+        assertThat(codeScanningTool.getAlertsThreshold(), is(nullValue()));
+        assertThat(codeScanningTool.getSecurityAlertsThreshold(), is(nullValue()));
+        assertThat(codeScanningTool.getTool(), is(nullValue()));
+    }
+
+    /**
+     * Tests to cover AlertsThreshold enum.
+     */
+    @Test
+    public void testAlertsThreshold() {
+        assertThat(AlertsThreshold.ERRORS, is(notNullValue()));
+    }
+
+    /**
+     * Tests to cover SecurityAlertsThreshold enum.
+     */
+    @Test
+    public void testSecurityAlertsThreshold() {
+        assertThat(SecurityAlertsThreshold.HIGH_OR_HIGHER, is(notNullValue()));
+    }
+
+    /**
+     * Tests to cover Operator enum.
+     */
+    @Test
+    public void testOperator() {
+        assertThat(Operator.ENDS_WITH, is(notNullValue()));
+    }
+
+    /**
+     * Tests that apply on null JsonNode returns null.
+     *
+     * @throws Exception
+     *             if something goes wrong.
+     */
+    @Test
+    public void testParameterReturnsNullOnNullArg() throws Exception {
+        Parameter<String> parameter = new StringParameter("any");
+        assertThat(parameter.apply(null, null), is(nullValue()));
+    }
+}
diff --git a/src/test/java/org/kohsuke/github/GHRepositoryTest.java b/src/test/java/org/kohsuke/github/GHRepositoryTest.java
index 5e1626bec..bb737dbb8 100644
--- a/src/test/java/org/kohsuke/github/GHRepositoryTest.java
+++ b/src/test/java/org/kohsuke/github/GHRepositoryTest.java
@@ -47,6 +47,36 @@ public class GHRepositoryTest extends AbstractGitHubWireMockTest {
         return gitHub.getOrganization("hub4j-test-org").getRepository("github-api");
     }
 
+    /**
+     * Test sync of fork
+     *
+     * @throws IOException
+     *             Signals that an I/O exception has occurred.
+     */
+    @Test
+    public void sync() throws IOException {
+        GHRepository r = getRepository();
+        GHBranchSync sync = r.sync("main");
+        assertThat(sync.getOwner().getFullName(), equalTo("hub4j-test-org/github-api"));
+        assertThat(sync.getMessage(), equalTo("Successfully fetched and fast-forwarded from upstream github-api:main"));
+        assertThat(sync.getMergeType(), equalTo("fast-forward"));
+        assertThat(sync.getBaseBranch(), equalTo("github-api:main"));
+    }
+
+    /**
+     * Test sync of repository not a fork
+     *
+     * @throws IOException
+     *             Signals that an I/O exception has occurred.
+     */
+    @Test(expected = HttpException.class)
+    public void syncNoFork() throws IOException {
+        GHRepository r = getRepository();
+        GHBranchSync sync = r.sync("main");
+        fail("Should have thrown an exception");
+
+    }
+
     /**
      * Test zipball.
      *
@@ -493,7 +523,8 @@ public class GHRepositoryTest extends AbstractGitHubWireMockTest {
         }
 
         if (false) {
-            // can't easily test this; there's no private repository visible to the test user
+            // can't easily test this; there's no private repository visible to the test
+            // user
             r = gitHub.getOrganization("cloudbees").getRepository("private-repo-not-writable-by-me");
             try {
                 r.getPermission("jglick");
@@ -1159,7 +1190,8 @@ public class GHRepositoryTest extends AbstractGitHubWireMockTest {
         assertThat(ghRefsWithPrefix.get(0).getRef(), equalTo(ghRefs.get(0).getRef()));
 
         // git/refs/heads/gh-pages
-        // passing a specific ref to listRefs will fail to parse due to returning a single item not an array
+        // passing a specific ref to listRefs will fail to parse due to returning a
+        // single item not an array
         try {
             ghRefs = repo.listRefs("heads/gh-pages").toList();
             fail();
@@ -1849,6 +1881,45 @@ public class GHRepositoryTest extends AbstractGitHubWireMockTest {
         assertThat(referralSources.size(), greaterThan(0));
     }
 
+    /**
+     * Test getRulesForBranch.
+     *
+     * @throws Exception
+     *             the exception
+     */
+    @Test
+    public void testGetRulesForBranch() throws Exception {
+        GHRepository repository = gitHub.getRepository("ihrigb/node-doorbird");
+        List<GHRepositoryRule> rules = repository.listRulesForBranch("main").toList();
+        assertThat(rules.size(), equalTo(3));
+
+        GHRepositoryRule rule = rules.get(0);
+        assertThat(rule.getType(), is(equalTo(GHRepositoryRule.Type.DELETION)));
+        assertThat(rule.getRulesetSourceType(), is(equalTo(GHRepositoryRule.RulesetSourceType.REPOSITORY)));
+        assertThat(rule.getRulesetSource(), is(equalTo("ihrigb/node-doorbird")));
+        assertThat(rule.getRulesetId(), is(equalTo(1170520L)));
+
+        rule = rules.get(1);
+        assertThat(rule.getType(), is(equalTo(GHRepositoryRule.Type.NON_FAST_FORWARD)));
+        assertThat(rule.getRulesetSourceType(), is(equalTo(GHRepositoryRule.RulesetSourceType.REPOSITORY)));
+        assertThat(rule.getRulesetSource(), is(equalTo("ihrigb/node-doorbird")));
+        assertThat(rule.getRulesetId(), is(equalTo(1170520L)));
+
+        rule = rules.get(2);
+        assertThat(rule.getType(), is(equalTo(GHRepositoryRule.Type.PULL_REQUEST)));
+        assertThat(rule.getRulesetSourceType(), is(equalTo(GHRepositoryRule.RulesetSourceType.REPOSITORY)));
+        assertThat(rule.getRulesetSource(), is(equalTo("ihrigb/node-doorbird")));
+        assertThat(rule.getRulesetId(), is(equalTo(1170520L)));
+
+        // check parameters
+        assertThat(rule.getParameter(GHRepositoryRule.Parameters.NEGATE).isPresent(), is(equalTo(false)));
+        assertThat(rule.getParameter(GHRepositoryRule.Parameters.REQUIRED_APPROVING_REVIEW_COUNT).get(),
+                is(equalTo(1)));
+        assertThat(rule.getParameter(GHRepositoryRule.Parameters.DISMISS_STALE_REVIEWS_ON_PUSH).get(),
+                is(equalTo(true)));
+        assertThat(rule.getParameter(GHRepositoryRule.Parameters.REQUIRE_CODE_OWNER_REVIEW).get(), is(equalTo(false)));
+    }
+
     private void verifyEmptyResult(PagedSearchIterable<GHPullRequest> searchResult) {
         assertThat(searchResult.getTotalCount(), is(0));
     }
diff --git a/src/test/java/org/kohsuke/github/GHUserTest.java b/src/test/java/org/kohsuke/github/GHUserTest.java
index 61a89a238..5e67bf645 100644
--- a/src/test/java/org/kohsuke/github/GHUserTest.java
+++ b/src/test/java/org/kohsuke/github/GHUserTest.java
@@ -3,6 +3,7 @@ package org.kohsuke.github;
 import org.junit.Test;
 
 import java.io.IOException;
+import java.time.Instant;
 import java.util.*;
 
 import static org.hamcrest.CoreMatchers.*;
@@ -227,4 +228,20 @@ public class GHUserTest extends AbstractGitHubWireMockTest {
         GHUser u = gitHub.getUser("kartikpatodi");
         assertThat(u.getLdapDn().orElse(""), not(emptyString()));
     }
+
+    /**
+     * Verify suspended_at.
+     *
+     * @throws IOException
+     *             Signals that an I/O exception has occurred.
+     */
+    @Test
+    public void verifySuspendedAt() throws IOException {
+        GHUser normal = gitHub.getUser("normal");
+        assertThat(normal.getSuspendedAt(), is(nullValue()));
+
+        GHUser suspended = gitHub.getUser("suspended");
+        Date suspendedAt = new Date(Instant.parse("2024-08-08T00:00:00Z").toEpochMilli());
+        assertThat(suspended.getSuspendedAt(), equalTo(suspendedAt));
+    }
 }
diff --git a/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests/__files/1-user.json b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests/__files/1-user.json
new file mode 100644
index 000000000..467313f14
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests/__files/1-user.json
@@ -0,0 +1,45 @@
+{
+  "login": "bitwiseman",
+  "id": 1958953,
+  "node_id": "MDQ6VXNlcjE5NTg5NTM=",
+  "avatar_url": "https://avatars3.githubusercontent.com/u/1958953?v=4",
+  "gravatar_id": "",
+  "url": "https://api.github.com/users/bitwiseman",
+  "html_url": "https://github.com/bitwiseman",
+  "followers_url": "https://api.github.com/users/bitwiseman/followers",
+  "following_url": "https://api.github.com/users/bitwiseman/following{/other_user}",
+  "gists_url": "https://api.github.com/users/bitwiseman/gists{/gist_id}",
+  "starred_url": "https://api.github.com/users/bitwiseman/starred{/owner}{/repo}",
+  "subscriptions_url": "https://api.github.com/users/bitwiseman/subscriptions",
+  "organizations_url": "https://api.github.com/users/bitwiseman/orgs",
+  "repos_url": "https://api.github.com/users/bitwiseman/repos",
+  "events_url": "https://api.github.com/users/bitwiseman/events{/privacy}",
+  "received_events_url": "https://api.github.com/users/bitwiseman/received_events",
+  "type": "User",
+  "site_admin": false,
+  "name": "Liam Newman",
+  "company": "Cloudbees, Inc.",
+  "blog": "",
+  "location": "Seattle, WA, USA",
+  "email": "bitwiseman@gmail.com",
+  "hireable": null,
+  "bio": "https://twitter.com/bitwiseman",
+  "public_repos": 181,
+  "public_gists": 7,
+  "followers": 146,
+  "following": 9,
+  "created_at": "2012-07-11T20:38:33Z",
+  "updated_at": "2020-02-06T17:29:39Z",
+  "private_gists": 8,
+  "total_private_repos": 10,
+  "owned_private_repos": 0,
+  "disk_usage": 33697,
+  "collaborators": 0,
+  "two_factor_authentication": true,
+  "plan": {
+    "name": "free",
+    "space": 976562499,
+    "collaborators": 0,
+    "private_repos": 10000
+  }
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests/__files/3-r_h_t_fail.json b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests/__files/3-r_h_t_fail.json
new file mode 100644
index 000000000..4cb1b145a
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests/__files/3-r_h_t_fail.json
@@ -0,0 +1,126 @@
+{
+  "id": 238757196,
+  "node_id": "MDEwOlJlcG9zaXRvcnkyMzg3NTcxOTY=",
+  "name": "temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests",
+  "full_name": "hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests",
+  "private": false,
+  "owner": {
+    "login": "hub4j-test-org",
+    "id": 7544739,
+    "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=",
+    "avatar_url": "https://avatars3.githubusercontent.com/u/7544739?v=4",
+    "gravatar_id": "",
+    "url": "https://api.github.com/users/hub4j-test-org",
+    "html_url": "https://github.com/hub4j-test-org",
+    "followers_url": "https://api.github.com/users/hub4j-test-org/followers",
+    "following_url": "https://api.github.com/users/hub4j-test-org/following{/other_user}",
+    "gists_url": "https://api.github.com/users/hub4j-test-org/gists{/gist_id}",
+    "starred_url": "https://api.github.com/users/hub4j-test-org/starred{/owner}{/repo}",
+    "subscriptions_url": "https://api.github.com/users/hub4j-test-org/subscriptions",
+    "organizations_url": "https://api.github.com/users/hub4j-test-org/orgs",
+    "repos_url": "https://api.github.com/users/hub4j-test-org/repos",
+    "events_url": "https://api.github.com/users/hub4j-test-org/events{/privacy}",
+    "received_events_url": "https://api.github.com/users/hub4j-test-org/received_events",
+    "type": "Organization",
+    "site_admin": false
+  },
+  "html_url": "https://github.com/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests",
+  "description": "A test repository for testing the github-api project: temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests",
+  "fork": false,
+  "url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests",
+  "forks_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/forks",
+  "keys_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/keys{/key_id}",
+  "collaborators_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/collaborators{/collaborator}",
+  "teams_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/teams",
+  "hooks_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/hooks",
+  "issue_events_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/issues/events{/number}",
+  "events_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/events",
+  "assignees_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/assignees{/user}",
+  "branches_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/branches{/branch}",
+  "tags_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/tags",
+  "blobs_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/git/blobs{/sha}",
+  "git_tags_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/git/tags{/sha}",
+  "git_refs_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/git/refs{/sha}",
+  "trees_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/git/trees{/sha}",
+  "statuses_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/statuses/{sha}",
+  "languages_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/languages",
+  "stargazers_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/stargazers",
+  "contributors_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/contributors",
+  "subscribers_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/subscribers",
+  "subscription_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/subscription",
+  "commits_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/commits{/sha}",
+  "git_commits_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/git/commits{/sha}",
+  "comments_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/comments{/number}",
+  "issue_comment_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/issues/comments{/number}",
+  "contents_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/contents/{+path}",
+  "compare_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/compare/{base}...{head}",
+  "merges_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/merges",
+  "archive_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/{archive_format}{/ref}",
+  "downloads_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/downloads",
+  "issues_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/issues{/number}",
+  "pulls_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/pulls{/number}",
+  "milestones_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/milestones{/number}",
+  "notifications_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/notifications{?since,all,participating}",
+  "labels_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/labels{/name}",
+  "releases_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/releases{/id}",
+  "deployments_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/deployments",
+  "created_at": "2020-02-06T18:33:39Z",
+  "updated_at": "2020-02-06T18:33:43Z",
+  "pushed_at": "2020-02-06T18:33:41Z",
+  "git_url": "git://github.com/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests.git",
+  "ssh_url": "git@github.com:hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests.git",
+  "clone_url": "https://github.com/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests.git",
+  "svn_url": "https://github.com/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests",
+  "homepage": "http://github-api.kohsuke.org/",
+  "size": 0,
+  "stargazers_count": 0,
+  "watchers_count": 0,
+  "language": null,
+  "has_issues": true,
+  "has_projects": true,
+  "has_downloads": true,
+  "has_wiki": true,
+  "has_pages": false,
+  "forks_count": 0,
+  "mirror_url": null,
+  "archived": false,
+  "disabled": false,
+  "open_issues_count": 0,
+  "license": null,
+  "forks": 0,
+  "open_issues": 0,
+  "watchers": 0,
+  "default_branch": "main",
+  "permissions": {
+    "admin": true,
+    "push": true,
+    "pull": true
+  },
+  "temp_clone_token": "",
+  "allow_squash_merge": true,
+  "allow_merge_commit": true,
+  "allow_rebase_merge": true,
+  "delete_branch_on_merge": false,
+  "organization": {
+    "login": "hub4j-test-org",
+    "id": 7544739,
+    "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=",
+    "avatar_url": "https://avatars3.githubusercontent.com/u/7544739?v=4",
+    "gravatar_id": "",
+    "url": "https://api.github.com/users/hub4j-test-org",
+    "html_url": "https://github.com/hub4j-test-org",
+    "followers_url": "https://api.github.com/users/hub4j-test-org/followers",
+    "following_url": "https://api.github.com/users/hub4j-test-org/following{/other_user}",
+    "gists_url": "https://api.github.com/users/hub4j-test-org/gists{/gist_id}",
+    "starred_url": "https://api.github.com/users/hub4j-test-org/starred{/owner}{/repo}",
+    "subscriptions_url": "https://api.github.com/users/hub4j-test-org/subscriptions",
+    "organizations_url": "https://api.github.com/users/hub4j-test-org/orgs",
+    "repos_url": "https://api.github.com/users/hub4j-test-org/repos",
+    "events_url": "https://api.github.com/users/hub4j-test-org/events{/privacy}",
+    "received_events_url": "https://api.github.com/users/hub4j-test-org/received_events",
+    "type": "Organization",
+    "site_admin": false
+  },
+  "network_count": 0,
+  "subscribers_count": 6
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests/mappings/1-user.json b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests/mappings/1-user.json
new file mode 100644
index 000000000..413354685
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests/mappings/1-user.json
@@ -0,0 +1,48 @@
+{
+  "id": "a60baf84-5b5c-4f86-af3d-cab0d609c7b2",
+  "name": "user",
+  "request": {
+    "url": "/user",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 200,
+    "bodyFileName": "1-user.json",
+    "headers": {
+      "Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
+      "Content-Type": "application/json; charset=utf-8",
+      "Server": "GitHub.com",
+      "Status": "200 OK",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4930",
+      "X-RateLimit-Reset": "{{now offset='3 seconds' format='unix'}}",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": [
+        "Accept, Authorization, Cookie, X-GitHub-OTP",
+        "Accept-Encoding"
+      ],
+      "ETag": "W/\"1cb30f031c67c499473b3aad01c7f7a5\"",
+      "Last-Modified": "Thu, 06 Feb 2020 17:29:39 GMT",
+      "X-OAuth-Scopes": "admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion",
+      "X-Accepted-OAuth-Scopes": "",
+      "X-GitHub-Media-Type": "unknown, github.v3",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "1; mode=block",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "X-GitHub-Request-Id": "CC37:2605:3F884:4E941:5E3C5BFC"
+    }
+  },
+  "uuid": "a60baf84-5b5c-4f86-af3d-cab0d609c7b2",
+  "persistent": true,
+  "insertionIndex": 1
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests/mappings/2-r_h_t_fail.json b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests/mappings/2-r_h_t_fail.json
new file mode 100644
index 000000000..d1127227f
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests/mappings/2-r_h_t_fail.json
@@ -0,0 +1,52 @@
+{
+  "id": "79fb1092-8bf3-4274-bc8e-ca126c9d9261",
+  "name": "repos_hub4j-test-org_temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests",
+  "request": {
+    "url": "/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 403,
+    "body": "{\"message\":\"You have exceeded a secondary rate limit. Please wait a few minutes before you try again\"}",
+    "headers": {
+      "Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
+      "Content-Type": "application/json; charset=utf-8",
+      "Server": "GitHub.com",
+      "Status": "403 Forbidden",
+      "gh-limited-by": "search-elapsed-time-shared-grouped",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4000",
+      "X-RateLimit-Reset": "{{testStartDate offset='3 seconds' format='unix'}}",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": [
+        "Accept, Authorization, Cookie, X-GitHub-OTP",
+        "Accept-Encoding"
+      ],
+      "ETag": "W/\"7ff3c96399f7ddf6129622d675ca9935\"",
+      "Last-Modified": "Thu, 06 Feb 2020 18:33:37 GMT",
+      "X-OAuth-Scopes": "admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion",
+      "X-Accepted-OAuth-Scopes": "repo",
+      "X-GitHub-Media-Type": "unknown, github.v3",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, gh-limited-by, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "1; mode=block",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "X-GitHub-Request-Id": "CC37:2605:3F982:4E949:5E3C5BFC"
+    }
+  },
+  "uuid": "79fb1092-8bf3-4274-bc8e-ca126c9d9261",
+  "persistent": true,
+  "scenarioName": "scenario-1-repos-hub4j-test-org-temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests",
+  "requiredScenarioState": "Started",
+  "newScenarioState": "scenario-1-repos-hub4j-test-org-temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests-2",
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests/mappings/3-r_h_t_fail.json b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests/mappings/3-r_h_t_fail.json
new file mode 100644
index 000000000..a2dc66b59
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests/mappings/3-r_h_t_fail.json
@@ -0,0 +1,49 @@
+{
+  "id": "79fb1092-8bf3-4274-bc8e-ca126c9d9261",
+  "name": "repos_hub4j-test-org_temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests",
+  "request": {
+    "url": "/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 429,
+    "body": "{\"message\":\"You have exceeded a secondary rate limit. Please wait a few minutes before you try again\"}",
+    "headers": {
+      "Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
+      "Content-Type": "application/json; charset=utf-8",
+      "Server": "GitHub.com",
+      "Status": "429 Too Many Requests",
+      "Retry-After": "42",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": [
+        "Accept, Authorization, Cookie, X-GitHub-OTP",
+        "Accept-Encoding"
+      ],
+      "ETag": "W/\"7ff3c96399f7ddf6129622d675ca9935\"",
+      "Last-Modified": "Thu, 06 Feb 2020 18:33:37 GMT",
+      "X-OAuth-Scopes": "admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion",
+      "X-Accepted-OAuth-Scopes": "repo",
+      "X-GitHub-Media-Type": "unknown, github.v3",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, gh-limited-by, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "1; mode=block",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "X-GitHub-Request-Id": "CC37:2605:3F982:4E949:5E3C5BFC"
+    }
+  },
+  "uuid": "79fb1092-8bf3-4274-bc8e-ca126c9d9261",
+  "persistent": true,
+  "scenarioName": "scenario-4-repos-hub4j-test-org-temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests",
+  "requiredScenarioState": "Started",
+  "newScenarioState": "scenario-4-repos-hub4j-test-org-temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests-2",
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/__files/1-user.json b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/__files/1-user.json
new file mode 100644
index 000000000..467313f14
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/__files/1-user.json
@@ -0,0 +1,45 @@
+{
+  "login": "bitwiseman",
+  "id": 1958953,
+  "node_id": "MDQ6VXNlcjE5NTg5NTM=",
+  "avatar_url": "https://avatars3.githubusercontent.com/u/1958953?v=4",
+  "gravatar_id": "",
+  "url": "https://api.github.com/users/bitwiseman",
+  "html_url": "https://github.com/bitwiseman",
+  "followers_url": "https://api.github.com/users/bitwiseman/followers",
+  "following_url": "https://api.github.com/users/bitwiseman/following{/other_user}",
+  "gists_url": "https://api.github.com/users/bitwiseman/gists{/gist_id}",
+  "starred_url": "https://api.github.com/users/bitwiseman/starred{/owner}{/repo}",
+  "subscriptions_url": "https://api.github.com/users/bitwiseman/subscriptions",
+  "organizations_url": "https://api.github.com/users/bitwiseman/orgs",
+  "repos_url": "https://api.github.com/users/bitwiseman/repos",
+  "events_url": "https://api.github.com/users/bitwiseman/events{/privacy}",
+  "received_events_url": "https://api.github.com/users/bitwiseman/received_events",
+  "type": "User",
+  "site_admin": false,
+  "name": "Liam Newman",
+  "company": "Cloudbees, Inc.",
+  "blog": "",
+  "location": "Seattle, WA, USA",
+  "email": "bitwiseman@gmail.com",
+  "hireable": null,
+  "bio": "https://twitter.com/bitwiseman",
+  "public_repos": 181,
+  "public_gists": 7,
+  "followers": 146,
+  "following": 9,
+  "created_at": "2012-07-11T20:38:33Z",
+  "updated_at": "2020-02-06T17:29:39Z",
+  "private_gists": 8,
+  "total_private_repos": 10,
+  "owned_private_repos": 0,
+  "disk_usage": 33697,
+  "collaborators": 0,
+  "two_factor_authentication": true,
+  "plan": {
+    "name": "free",
+    "space": 976562499,
+    "collaborators": 0,
+    "private_repos": 10000
+  }
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/__files/3-r_h_t_fail.json b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/__files/3-r_h_t_fail.json
new file mode 100644
index 000000000..5733e9a2d
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/__files/3-r_h_t_fail.json
@@ -0,0 +1,126 @@
+{
+  "id": 238757196,
+  "node_id": "MDEwOlJlcG9zaXRvcnkyMzg3NTcxOTY=",
+  "name": "temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After",
+  "full_name": "hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After",
+  "private": false,
+  "owner": {
+    "login": "hub4j-test-org",
+    "id": 7544739,
+    "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=",
+    "avatar_url": "https://avatars3.githubusercontent.com/u/7544739?v=4",
+    "gravatar_id": "",
+    "url": "https://api.github.com/users/hub4j-test-org",
+    "html_url": "https://github.com/hub4j-test-org",
+    "followers_url": "https://api.github.com/users/hub4j-test-org/followers",
+    "following_url": "https://api.github.com/users/hub4j-test-org/following{/other_user}",
+    "gists_url": "https://api.github.com/users/hub4j-test-org/gists{/gist_id}",
+    "starred_url": "https://api.github.com/users/hub4j-test-org/starred{/owner}{/repo}",
+    "subscriptions_url": "https://api.github.com/users/hub4j-test-org/subscriptions",
+    "organizations_url": "https://api.github.com/users/hub4j-test-org/orgs",
+    "repos_url": "https://api.github.com/users/hub4j-test-org/repos",
+    "events_url": "https://api.github.com/users/hub4j-test-org/events{/privacy}",
+    "received_events_url": "https://api.github.com/users/hub4j-test-org/received_events",
+    "type": "Organization",
+    "site_admin": false
+  },
+  "html_url": "https://github.com/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After",
+  "description": "A test repository for testing the github-api project: temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After",
+  "fork": false,
+  "url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After",
+  "forks_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/forks",
+  "keys_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/keys{/key_id}",
+  "collaborators_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/collaborators{/collaborator}",
+  "teams_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/teams",
+  "hooks_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/hooks",
+  "issue_events_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/issues/events{/number}",
+  "events_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/events",
+  "assignees_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/assignees{/user}",
+  "branches_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/branches{/branch}",
+  "tags_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/tags",
+  "blobs_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/git/blobs{/sha}",
+  "git_tags_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/git/tags{/sha}",
+  "git_refs_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/git/refs{/sha}",
+  "trees_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/git/trees{/sha}",
+  "statuses_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/statuses/{sha}",
+  "languages_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/languages",
+  "stargazers_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/stargazers",
+  "contributors_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/contributors",
+  "subscribers_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/subscribers",
+  "subscription_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/subscription",
+  "commits_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/commits{/sha}",
+  "git_commits_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/git/commits{/sha}",
+  "comments_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/comments{/number}",
+  "issue_comment_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/issues/comments{/number}",
+  "contents_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/contents/{+path}",
+  "compare_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/compare/{base}...{head}",
+  "merges_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/merges",
+  "archive_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/{archive_format}{/ref}",
+  "downloads_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/downloads",
+  "issues_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/issues{/number}",
+  "pulls_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/pulls{/number}",
+  "milestones_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/milestones{/number}",
+  "notifications_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/notifications{?since,all,participating}",
+  "labels_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/labels{/name}",
+  "releases_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/releases{/id}",
+  "deployments_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/deployments",
+  "created_at": "2020-02-06T18:33:39Z",
+  "updated_at": "2020-02-06T18:33:43Z",
+  "pushed_at": "2020-02-06T18:33:41Z",
+  "git_url": "git://github.com/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After.git",
+  "ssh_url": "git@github.com:hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After.git",
+  "clone_url": "https://github.com/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After.git",
+  "svn_url": "https://github.com/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After",
+  "homepage": "http://github-api.kohsuke.org/",
+  "size": 0,
+  "stargazers_count": 0,
+  "watchers_count": 0,
+  "language": null,
+  "has_issues": true,
+  "has_projects": true,
+  "has_downloads": true,
+  "has_wiki": true,
+  "has_pages": false,
+  "forks_count": 0,
+  "mirror_url": null,
+  "archived": false,
+  "disabled": false,
+  "open_issues_count": 0,
+  "license": null,
+  "forks": 0,
+  "open_issues": 0,
+  "watchers": 0,
+  "default_branch": "main",
+  "permissions": {
+    "admin": true,
+    "push": true,
+    "pull": true
+  },
+  "temp_clone_token": "",
+  "allow_squash_merge": true,
+  "allow_merge_commit": true,
+  "allow_rebase_merge": true,
+  "delete_branch_on_merge": false,
+  "organization": {
+    "login": "hub4j-test-org",
+    "id": 7544739,
+    "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=",
+    "avatar_url": "https://avatars3.githubusercontent.com/u/7544739?v=4",
+    "gravatar_id": "",
+    "url": "https://api.github.com/users/hub4j-test-org",
+    "html_url": "https://github.com/hub4j-test-org",
+    "followers_url": "https://api.github.com/users/hub4j-test-org/followers",
+    "following_url": "https://api.github.com/users/hub4j-test-org/following{/other_user}",
+    "gists_url": "https://api.github.com/users/hub4j-test-org/gists{/gist_id}",
+    "starred_url": "https://api.github.com/users/hub4j-test-org/starred{/owner}{/repo}",
+    "subscriptions_url": "https://api.github.com/users/hub4j-test-org/subscriptions",
+    "organizations_url": "https://api.github.com/users/hub4j-test-org/orgs",
+    "repos_url": "https://api.github.com/users/hub4j-test-org/repos",
+    "events_url": "https://api.github.com/users/hub4j-test-org/events{/privacy}",
+    "received_events_url": "https://api.github.com/users/hub4j-test-org/received_events",
+    "type": "Organization",
+    "site_admin": false
+  },
+  "network_count": 0,
+  "subscribers_count": 6
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/mappings/1-user.json b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/mappings/1-user.json
new file mode 100644
index 000000000..413354685
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/mappings/1-user.json
@@ -0,0 +1,48 @@
+{
+  "id": "a60baf84-5b5c-4f86-af3d-cab0d609c7b2",
+  "name": "user",
+  "request": {
+    "url": "/user",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 200,
+    "bodyFileName": "1-user.json",
+    "headers": {
+      "Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
+      "Content-Type": "application/json; charset=utf-8",
+      "Server": "GitHub.com",
+      "Status": "200 OK",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4930",
+      "X-RateLimit-Reset": "{{now offset='3 seconds' format='unix'}}",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": [
+        "Accept, Authorization, Cookie, X-GitHub-OTP",
+        "Accept-Encoding"
+      ],
+      "ETag": "W/\"1cb30f031c67c499473b3aad01c7f7a5\"",
+      "Last-Modified": "Thu, 06 Feb 2020 17:29:39 GMT",
+      "X-OAuth-Scopes": "admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion",
+      "X-Accepted-OAuth-Scopes": "",
+      "X-GitHub-Media-Type": "unknown, github.v3",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "1; mode=block",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "X-GitHub-Request-Id": "CC37:2605:3F884:4E941:5E3C5BFC"
+    }
+  },
+  "uuid": "a60baf84-5b5c-4f86-af3d-cab0d609c7b2",
+  "persistent": true,
+  "insertionIndex": 1
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/mappings/2-r_h_t_fail.json b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/mappings/2-r_h_t_fail.json
new file mode 100644
index 000000000..41af8b707
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/mappings/2-r_h_t_fail.json
@@ -0,0 +1,52 @@
+{
+  "id": "79fb1092-8bf3-4274-bc8e-ca126c9d9261",
+  "name": "repos_hub4j-test-org_temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After",
+  "request": {
+    "url": "/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 403,
+    "body": "{\"message\":\"You have exceeded a secondary rate limit. Please wait a few minutes before you try again\"}",
+    "headers": {
+      "Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
+      "Content-Type": "application/json; charset=utf-8",
+      "Server": "GitHub.com",
+      "Status": "403 Forbidden",
+      "gh-limited-by": "search-elapsed-time-shared-grouped",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4000",
+      "X-RateLimit-Reset": "{{testStartDate offset='3 seconds' format='unix'}}",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": [
+        "Accept, Authorization, Cookie, X-GitHub-OTP",
+        "Accept-Encoding"
+      ],
+      "ETag": "W/\"7ff3c96399f7ddf6129622d675ca9935\"",
+      "Last-Modified": "Thu, 06 Feb 2020 18:33:37 GMT",
+      "X-OAuth-Scopes": "admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion",
+      "X-Accepted-OAuth-Scopes": "repo",
+      "X-GitHub-Media-Type": "unknown, github.v3",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, gh-limited-by, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "1; mode=block",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "X-GitHub-Request-Id": "CC37:2605:3F982:4E949:5E3C5BFC"
+    }
+  },
+  "uuid": "79fb1092-8bf3-4274-bc8e-ca126c9d9261",
+  "persistent": true,
+  "scenarioName": "scenario-1-repos-hub4j-test-org-temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After",
+  "requiredScenarioState": "Started",
+  "newScenarioState": "scenario-1-repos-hub4j-test-org-temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After-2",
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/mappings/3-r_h_t_fail.json b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/mappings/3-r_h_t_fail.json
new file mode 100644
index 000000000..a29ef6ac2
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After/mappings/3-r_h_t_fail.json
@@ -0,0 +1,49 @@
+{
+  "id": "79fb1092-8bf3-4274-bc8e-ca126c9d9261",
+  "name": "repos_hub4j-test-org_temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After",
+  "request": {
+    "url": "/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 429,
+    "body": "{\"message\":\"You have exceeded a secondary rate limit. Please wait a few minutes before you try again\"}",
+    "headers": {
+      "Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
+      "Content-Type": "application/json; charset=utf-8",
+      "Server": "GitHub.com",
+      "Status": "429 Too Many Requests",
+      "Retry-After": "Mon, 21 Oct 2115 07:28:00 GMT",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": [
+        "Accept, Authorization, Cookie, X-GitHub-OTP",
+        "Accept-Encoding"
+      ],
+      "ETag": "W/\"7ff3c96399f7ddf6129622d675ca9935\"",
+      "Last-Modified": "Thu, 06 Feb 2020 18:33:37 GMT",
+      "X-OAuth-Scopes": "admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion",
+      "X-Accepted-OAuth-Scopes": "repo",
+      "X-GitHub-Media-Type": "unknown, github.v3",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, gh-limited-by, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "1; mode=block",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "X-GitHub-Request-Id": "CC37:2605:3F982:4E949:5E3C5BFC"
+    }
+  },
+  "uuid": "79fb1092-8bf3-4274-bc8e-ca126c9d9261",
+  "persistent": true,
+  "scenarioName": "scenario-4-repos-hub4j-test-org-temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After",
+  "requiredScenarioState": "Started",
+  "newScenarioState": "scenario-4-repos-hub4j-test-org-temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_Date_Retry_After-2",
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After/__files/1-user.json b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After/__files/1-user.json
new file mode 100644
index 000000000..467313f14
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After/__files/1-user.json
@@ -0,0 +1,45 @@
+{
+  "login": "bitwiseman",
+  "id": 1958953,
+  "node_id": "MDQ6VXNlcjE5NTg5NTM=",
+  "avatar_url": "https://avatars3.githubusercontent.com/u/1958953?v=4",
+  "gravatar_id": "",
+  "url": "https://api.github.com/users/bitwiseman",
+  "html_url": "https://github.com/bitwiseman",
+  "followers_url": "https://api.github.com/users/bitwiseman/followers",
+  "following_url": "https://api.github.com/users/bitwiseman/following{/other_user}",
+  "gists_url": "https://api.github.com/users/bitwiseman/gists{/gist_id}",
+  "starred_url": "https://api.github.com/users/bitwiseman/starred{/owner}{/repo}",
+  "subscriptions_url": "https://api.github.com/users/bitwiseman/subscriptions",
+  "organizations_url": "https://api.github.com/users/bitwiseman/orgs",
+  "repos_url": "https://api.github.com/users/bitwiseman/repos",
+  "events_url": "https://api.github.com/users/bitwiseman/events{/privacy}",
+  "received_events_url": "https://api.github.com/users/bitwiseman/received_events",
+  "type": "User",
+  "site_admin": false,
+  "name": "Liam Newman",
+  "company": "Cloudbees, Inc.",
+  "blog": "",
+  "location": "Seattle, WA, USA",
+  "email": "bitwiseman@gmail.com",
+  "hireable": null,
+  "bio": "https://twitter.com/bitwiseman",
+  "public_repos": 181,
+  "public_gists": 7,
+  "followers": 146,
+  "following": 9,
+  "created_at": "2012-07-11T20:38:33Z",
+  "updated_at": "2020-02-06T17:29:39Z",
+  "private_gists": 8,
+  "total_private_repos": 10,
+  "owned_private_repos": 0,
+  "disk_usage": 33697,
+  "collaborators": 0,
+  "two_factor_authentication": true,
+  "plan": {
+    "name": "free",
+    "space": 976562499,
+    "collaborators": 0,
+    "private_repos": 10000
+  }
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After/__files/3-r_h_t_fail.json b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After/__files/3-r_h_t_fail.json
new file mode 100644
index 000000000..4cb1b145a
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After/__files/3-r_h_t_fail.json
@@ -0,0 +1,126 @@
+{
+  "id": 238757196,
+  "node_id": "MDEwOlJlcG9zaXRvcnkyMzg3NTcxOTY=",
+  "name": "temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests",
+  "full_name": "hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests",
+  "private": false,
+  "owner": {
+    "login": "hub4j-test-org",
+    "id": 7544739,
+    "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=",
+    "avatar_url": "https://avatars3.githubusercontent.com/u/7544739?v=4",
+    "gravatar_id": "",
+    "url": "https://api.github.com/users/hub4j-test-org",
+    "html_url": "https://github.com/hub4j-test-org",
+    "followers_url": "https://api.github.com/users/hub4j-test-org/followers",
+    "following_url": "https://api.github.com/users/hub4j-test-org/following{/other_user}",
+    "gists_url": "https://api.github.com/users/hub4j-test-org/gists{/gist_id}",
+    "starred_url": "https://api.github.com/users/hub4j-test-org/starred{/owner}{/repo}",
+    "subscriptions_url": "https://api.github.com/users/hub4j-test-org/subscriptions",
+    "organizations_url": "https://api.github.com/users/hub4j-test-org/orgs",
+    "repos_url": "https://api.github.com/users/hub4j-test-org/repos",
+    "events_url": "https://api.github.com/users/hub4j-test-org/events{/privacy}",
+    "received_events_url": "https://api.github.com/users/hub4j-test-org/received_events",
+    "type": "Organization",
+    "site_admin": false
+  },
+  "html_url": "https://github.com/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests",
+  "description": "A test repository for testing the github-api project: temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests",
+  "fork": false,
+  "url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests",
+  "forks_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/forks",
+  "keys_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/keys{/key_id}",
+  "collaborators_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/collaborators{/collaborator}",
+  "teams_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/teams",
+  "hooks_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/hooks",
+  "issue_events_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/issues/events{/number}",
+  "events_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/events",
+  "assignees_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/assignees{/user}",
+  "branches_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/branches{/branch}",
+  "tags_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/tags",
+  "blobs_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/git/blobs{/sha}",
+  "git_tags_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/git/tags{/sha}",
+  "git_refs_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/git/refs{/sha}",
+  "trees_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/git/trees{/sha}",
+  "statuses_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/statuses/{sha}",
+  "languages_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/languages",
+  "stargazers_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/stargazers",
+  "contributors_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/contributors",
+  "subscribers_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/subscribers",
+  "subscription_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/subscription",
+  "commits_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/commits{/sha}",
+  "git_commits_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/git/commits{/sha}",
+  "comments_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/comments{/number}",
+  "issue_comment_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/issues/comments{/number}",
+  "contents_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/contents/{+path}",
+  "compare_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/compare/{base}...{head}",
+  "merges_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/merges",
+  "archive_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/{archive_format}{/ref}",
+  "downloads_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/downloads",
+  "issues_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/issues{/number}",
+  "pulls_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/pulls{/number}",
+  "milestones_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/milestones{/number}",
+  "notifications_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/notifications{?since,all,participating}",
+  "labels_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/labels{/name}",
+  "releases_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/releases{/id}",
+  "deployments_url": "https://api.github.com/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests/deployments",
+  "created_at": "2020-02-06T18:33:39Z",
+  "updated_at": "2020-02-06T18:33:43Z",
+  "pushed_at": "2020-02-06T18:33:41Z",
+  "git_url": "git://github.com/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests.git",
+  "ssh_url": "git@github.com:hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests.git",
+  "clone_url": "https://github.com/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests.git",
+  "svn_url": "https://github.com/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests",
+  "homepage": "http://github-api.kohsuke.org/",
+  "size": 0,
+  "stargazers_count": 0,
+  "watchers_count": 0,
+  "language": null,
+  "has_issues": true,
+  "has_projects": true,
+  "has_downloads": true,
+  "has_wiki": true,
+  "has_pages": false,
+  "forks_count": 0,
+  "mirror_url": null,
+  "archived": false,
+  "disabled": false,
+  "open_issues_count": 0,
+  "license": null,
+  "forks": 0,
+  "open_issues": 0,
+  "watchers": 0,
+  "default_branch": "main",
+  "permissions": {
+    "admin": true,
+    "push": true,
+    "pull": true
+  },
+  "temp_clone_token": "",
+  "allow_squash_merge": true,
+  "allow_merge_commit": true,
+  "allow_rebase_merge": true,
+  "delete_branch_on_merge": false,
+  "organization": {
+    "login": "hub4j-test-org",
+    "id": 7544739,
+    "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=",
+    "avatar_url": "https://avatars3.githubusercontent.com/u/7544739?v=4",
+    "gravatar_id": "",
+    "url": "https://api.github.com/users/hub4j-test-org",
+    "html_url": "https://github.com/hub4j-test-org",
+    "followers_url": "https://api.github.com/users/hub4j-test-org/followers",
+    "following_url": "https://api.github.com/users/hub4j-test-org/following{/other_user}",
+    "gists_url": "https://api.github.com/users/hub4j-test-org/gists{/gist_id}",
+    "starred_url": "https://api.github.com/users/hub4j-test-org/starred{/owner}{/repo}",
+    "subscriptions_url": "https://api.github.com/users/hub4j-test-org/subscriptions",
+    "organizations_url": "https://api.github.com/users/hub4j-test-org/orgs",
+    "repos_url": "https://api.github.com/users/hub4j-test-org/repos",
+    "events_url": "https://api.github.com/users/hub4j-test-org/events{/privacy}",
+    "received_events_url": "https://api.github.com/users/hub4j-test-org/received_events",
+    "type": "Organization",
+    "site_admin": false
+  },
+  "network_count": 0,
+  "subscribers_count": 6
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After/mappings/1-user.json b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After/mappings/1-user.json
new file mode 100644
index 000000000..413354685
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After/mappings/1-user.json
@@ -0,0 +1,48 @@
+{
+  "id": "a60baf84-5b5c-4f86-af3d-cab0d609c7b2",
+  "name": "user",
+  "request": {
+    "url": "/user",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 200,
+    "bodyFileName": "1-user.json",
+    "headers": {
+      "Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
+      "Content-Type": "application/json; charset=utf-8",
+      "Server": "GitHub.com",
+      "Status": "200 OK",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4930",
+      "X-RateLimit-Reset": "{{now offset='3 seconds' format='unix'}}",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": [
+        "Accept, Authorization, Cookie, X-GitHub-OTP",
+        "Accept-Encoding"
+      ],
+      "ETag": "W/\"1cb30f031c67c499473b3aad01c7f7a5\"",
+      "Last-Modified": "Thu, 06 Feb 2020 17:29:39 GMT",
+      "X-OAuth-Scopes": "admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion",
+      "X-Accepted-OAuth-Scopes": "",
+      "X-GitHub-Media-Type": "unknown, github.v3",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "1; mode=block",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "X-GitHub-Request-Id": "CC37:2605:3F884:4E941:5E3C5BFC"
+    }
+  },
+  "uuid": "a60baf84-5b5c-4f86-af3d-cab0d609c7b2",
+  "persistent": true,
+  "insertionIndex": 1
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After/mappings/3-r_h_t_fail.json b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After/mappings/3-r_h_t_fail.json
new file mode 100644
index 000000000..d6522df8e
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/AbuseLimitHandlerTest/wiremock/testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After/mappings/3-r_h_t_fail.json
@@ -0,0 +1,49 @@
+{
+  "id": "79fb1092-8bf3-4274-bc8e-ca126c9d9261",
+  "name": "repos_hub4j-test-org_temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After",
+  "request": {
+    "url": "/repos/hub4j-test-org/temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 429,
+    "body": "{\"message\":\"You have exceeded a secondary rate limit. Please wait a few minutes before you try again\"}",
+    "headers": {
+      "Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
+      "Content-Type": "application/json; charset=utf-8",
+      "Server": "GitHub.com",
+      "Status": "429 Too Many Requests",
+      "gh-limited-by": "search-elapsed-time-shared-grouped",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": [
+        "Accept, Authorization, Cookie, X-GitHub-OTP",
+        "Accept-Encoding"
+      ],
+      "ETag": "W/\"7ff3c96399f7ddf6129622d675ca9935\"",
+      "Last-Modified": "Thu, 06 Feb 2020 18:33:37 GMT",
+      "X-OAuth-Scopes": "admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion",
+      "X-Accepted-OAuth-Scopes": "repo",
+      "X-GitHub-Media-Type": "unknown, github.v3",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, gh-limited-by, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "1; mode=block",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "X-GitHub-Request-Id": "CC37:2605:3F982:4E949:5E3C5BFC"
+    }
+  },
+  "uuid": "79fb1092-8bf3-4274-bc8e-ca126c9d9261",
+  "persistent": true,
+  "scenarioName": "scenario-4-repos-hub4j-test-org-temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After",
+  "requiredScenarioState": "Started",
+  "newScenarioState": "scenario-4-repos-hub4j-test-org-temp-testHandler_Wait_Secondary_Limits_Too_Many_Requests_No_Retry_After-2",
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/__files/1-user.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/__files/1-user.json
new file mode 100644
index 000000000..eab16ea06
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/__files/1-user.json
@@ -0,0 +1,33 @@
+{
+  "login": "bitwiseman",
+  "id": 1958953,
+  "node_id": "MDQ6VXNlcjE5NTg5NTM=",
+  "avatar_url": "https://avatars3.githubusercontent.com/u/1958953?v=4",
+  "gravatar_id": "",
+  "url": "https://api.github.com/users/bitwiseman",
+  "html_url": "https://github.com/bitwiseman",
+  "followers_url": "https://api.github.com/users/bitwiseman/followers",
+  "following_url": "https://api.github.com/users/bitwiseman/following{/other_user}",
+  "gists_url": "https://api.github.com/users/bitwiseman/gists{/gist_id}",
+  "starred_url": "https://api.github.com/users/bitwiseman/starred{/owner}{/repo}",
+  "subscriptions_url": "https://api.github.com/users/bitwiseman/subscriptions",
+  "organizations_url": "https://api.github.com/users/bitwiseman/orgs",
+  "repos_url": "https://api.github.com/users/bitwiseman/repos",
+  "events_url": "https://api.github.com/users/bitwiseman/events{/privacy}",
+  "received_events_url": "https://api.github.com/users/bitwiseman/received_events",
+  "type": "User",
+  "site_admin": false,
+  "name": "Liam Newman",
+  "company": "Cloudbees, Inc.",
+  "blog": "",
+  "location": "Seattle, WA, USA",
+  "email": "bitwiseman@gmail.com",
+  "hireable": null,
+  "bio": "https://twitter.com/bitwiseman",
+  "public_repos": 166,
+  "public_gists": 4,
+  "followers": 135,
+  "following": 9,
+  "created_at": "2012-07-11T20:38:33Z",
+  "updated_at": "2019-09-24T19:32:29Z"
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/__files/2-orgs_hub4j-test-org.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/__files/2-orgs_hub4j-test-org.json
new file mode 100644
index 000000000..f176fc4ff
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/__files/2-orgs_hub4j-test-org.json
@@ -0,0 +1,42 @@
+{
+  "login": "hub4j-test-org",
+  "id": 7544739,
+  "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=",
+  "url": "https://api.github.com/orgs/hub4j-test-org",
+  "repos_url": "https://api.github.com/orgs/hub4j-test-org/repos",
+  "events_url": "https://api.github.com/orgs/hub4j-test-org/events",
+  "hooks_url": "https://api.github.com/orgs/hub4j-test-org/hooks",
+  "issues_url": "https://api.github.com/orgs/hub4j-test-org/issues",
+  "members_url": "https://api.github.com/orgs/hub4j-test-org/members{/member}",
+  "public_members_url": "https://api.github.com/orgs/hub4j-test-org/public_members{/member}",
+  "avatar_url": "https://avatars3.githubusercontent.com/u/7544739?v=4",
+  "description": null,
+  "is_verified": false,
+  "has_organization_projects": true,
+  "has_repository_projects": true,
+  "public_repos": 9,
+  "public_gists": 0,
+  "followers": 0,
+  "following": 0,
+  "html_url": "https://github.com/hub4j-test-org",
+  "created_at": "2014-05-10T19:39:11Z",
+  "updated_at": "2015-04-20T00:42:30Z",
+  "type": "Organization",
+  "total_private_repos": 0,
+  "owned_private_repos": 0,
+  "private_gists": 0,
+  "disk_usage": 132,
+  "collaborators": 0,
+  "billing_email": "kk@kohsuke.org",
+  "default_repository_permission": "none",
+  "members_can_create_repositories": false,
+  "two_factor_requirement_enabled": false,
+  "members_allowed_repository_creation_type": "none",
+  "plan": {
+    "name": "free",
+    "space": 976562499,
+    "private_repos": 0,
+    "filled_seats": 3,
+    "seats": 0
+  }
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/__files/3-r_h_github-api.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/__files/3-r_h_github-api.json
new file mode 100644
index 000000000..d2a3a7aa9
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/__files/3-r_h_github-api.json
@@ -0,0 +1,330 @@
+{
+  "id": 206888201,
+  "node_id": "MDEwOlJlcG9zaXRvcnkyMDY4ODgyMDE=",
+  "name": "github-api",
+  "full_name": "hub4j-test-org/github-api",
+  "private": false,
+  "owner": {
+    "login": "hub4j-test-org",
+    "id": 7544739,
+    "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=",
+    "avatar_url": "https://avatars3.githubusercontent.com/u/7544739?v=4",
+    "gravatar_id": "",
+    "url": "https://api.github.com/users/hub4j-test-org",
+    "html_url": "https://github.com/hub4j-test-org",
+    "followers_url": "https://api.github.com/users/hub4j-test-org/followers",
+    "following_url": "https://api.github.com/users/hub4j-test-org/following{/other_user}",
+    "gists_url": "https://api.github.com/users/hub4j-test-org/gists{/gist_id}",
+    "starred_url": "https://api.github.com/users/hub4j-test-org/starred{/owner}{/repo}",
+    "subscriptions_url": "https://api.github.com/users/hub4j-test-org/subscriptions",
+    "organizations_url": "https://api.github.com/users/hub4j-test-org/orgs",
+    "repos_url": "https://api.github.com/users/hub4j-test-org/repos",
+    "events_url": "https://api.github.com/users/hub4j-test-org/events{/privacy}",
+    "received_events_url": "https://api.github.com/users/hub4j-test-org/received_events",
+    "type": "Organization",
+    "site_admin": false
+  },
+  "html_url": "https://github.com/hub4j-test-org/github-api",
+  "description": "Tricky",
+  "fork": true,
+  "url": "https://api.github.com/repos/hub4j-test-org/github-api",
+  "forks_url": "https://api.github.com/repos/hub4j-test-org/github-api/forks",
+  "keys_url": "https://api.github.com/repos/hub4j-test-org/github-api/keys{/key_id}",
+  "collaborators_url": "https://api.github.com/repos/hub4j-test-org/github-api/collaborators{/collaborator}",
+  "teams_url": "https://api.github.com/repos/hub4j-test-org/github-api/teams",
+  "hooks_url": "https://api.github.com/repos/hub4j-test-org/github-api/hooks",
+  "issue_events_url": "https://api.github.com/repos/hub4j-test-org/github-api/issues/events{/number}",
+  "events_url": "https://api.github.com/repos/hub4j-test-org/github-api/events",
+  "assignees_url": "https://api.github.com/repos/hub4j-test-org/github-api/assignees{/user}",
+  "branches_url": "https://api.github.com/repos/hub4j-test-org/github-api/branches{/branch}",
+  "tags_url": "https://api.github.com/repos/hub4j-test-org/github-api/tags",
+  "blobs_url": "https://api.github.com/repos/hub4j-test-org/github-api/git/blobs{/sha}",
+  "git_tags_url": "https://api.github.com/repos/hub4j-test-org/github-api/git/tags{/sha}",
+  "git_refs_url": "https://api.github.com/repos/hub4j-test-org/github-api/git/refs{/sha}",
+  "trees_url": "https://api.github.com/repos/hub4j-test-org/github-api/git/trees{/sha}",
+  "statuses_url": "https://api.github.com/repos/hub4j-test-org/github-api/statuses/{sha}",
+  "languages_url": "https://api.github.com/repos/hub4j-test-org/github-api/languages",
+  "stargazers_url": "https://api.github.com/repos/hub4j-test-org/github-api/stargazers",
+  "contributors_url": "https://api.github.com/repos/hub4j-test-org/github-api/contributors",
+  "subscribers_url": "https://api.github.com/repos/hub4j-test-org/github-api/subscribers",
+  "subscription_url": "https://api.github.com/repos/hub4j-test-org/github-api/subscription",
+  "commits_url": "https://api.github.com/repos/hub4j-test-org/github-api/commits{/sha}",
+  "git_commits_url": "https://api.github.com/repos/hub4j-test-org/github-api/git/commits{/sha}",
+  "comments_url": "https://api.github.com/repos/hub4j-test-org/github-api/comments{/number}",
+  "issue_comment_url": "https://api.github.com/repos/hub4j-test-org/github-api/issues/comments{/number}",
+  "contents_url": "https://api.github.com/repos/hub4j-test-org/github-api/contents/{+path}",
+  "compare_url": "https://api.github.com/repos/hub4j-test-org/github-api/compare/{base}...{head}",
+  "merges_url": "https://api.github.com/repos/hub4j-test-org/github-api/merges",
+  "archive_url": "https://api.github.com/repos/hub4j-test-org/github-api/{archive_format}{/ref}",
+  "downloads_url": "https://api.github.com/repos/hub4j-test-org/github-api/downloads",
+  "issues_url": "https://api.github.com/repos/hub4j-test-org/github-api/issues{/number}",
+  "pulls_url": "https://api.github.com/repos/hub4j-test-org/github-api/pulls{/number}",
+  "milestones_url": "https://api.github.com/repos/hub4j-test-org/github-api/milestones{/number}",
+  "notifications_url": "https://api.github.com/repos/hub4j-test-org/github-api/notifications{?since,all,participating}",
+  "labels_url": "https://api.github.com/repos/hub4j-test-org/github-api/labels{/name}",
+  "releases_url": "https://api.github.com/repos/hub4j-test-org/github-api/releases{/id}",
+  "deployments_url": "https://api.github.com/repos/hub4j-test-org/github-api/deployments",
+  "created_at": "2019-09-06T23:26:04Z",
+  "updated_at": "2019-09-25T23:32:35Z",
+  "pushed_at": "2019-09-21T14:29:14Z",
+  "git_url": "git://github.com/hub4j-test-org/github-api.git",
+  "ssh_url": "git@github.com:hub4j-test-org/github-api.git",
+  "clone_url": "https://github.com/hub4j-test-org/github-api.git",
+  "svn_url": "https://github.com/hub4j-test-org/github-api",
+  "homepage": "http://github-api.kohsuke.org/",
+  "size": 11387,
+  "stargazers_count": 0,
+  "watchers_count": 0,
+  "language": "Java",
+  "has_issues": true,
+  "has_projects": true,
+  "has_downloads": true,
+  "has_wiki": true,
+  "has_pages": false,
+  "forks_count": 0,
+  "mirror_url": null,
+  "archived": false,
+  "disabled": false,
+  "open_issues_count": 0,
+  "license": {
+    "key": "mit",
+    "name": "MIT License",
+    "spdx_id": "MIT",
+    "url": "https://api.github.com/licenses/mit",
+    "node_id": "MDc6TGljZW5zZTEz"
+  },
+  "forks": 0,
+  "open_issues": 0,
+  "watchers": 0,
+  "default_branch": "main",
+  "permissions": {
+    "admin": true,
+    "push": true,
+    "pull": true
+  },
+  "allow_squash_merge": true,
+  "allow_merge_commit": true,
+  "allow_rebase_merge": true,
+  "organization": {
+    "login": "hub4j-test-org",
+    "id": 7544739,
+    "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=",
+    "avatar_url": "https://avatars3.githubusercontent.com/u/7544739?v=4",
+    "gravatar_id": "",
+    "url": "https://api.github.com/users/hub4j-test-org",
+    "html_url": "https://github.com/hub4j-test-org",
+    "followers_url": "https://api.github.com/users/hub4j-test-org/followers",
+    "following_url": "https://api.github.com/users/hub4j-test-org/following{/other_user}",
+    "gists_url": "https://api.github.com/users/hub4j-test-org/gists{/gist_id}",
+    "starred_url": "https://api.github.com/users/hub4j-test-org/starred{/owner}{/repo}",
+    "subscriptions_url": "https://api.github.com/users/hub4j-test-org/subscriptions",
+    "organizations_url": "https://api.github.com/users/hub4j-test-org/orgs",
+    "repos_url": "https://api.github.com/users/hub4j-test-org/repos",
+    "events_url": "https://api.github.com/users/hub4j-test-org/events{/privacy}",
+    "received_events_url": "https://api.github.com/users/hub4j-test-org/received_events",
+    "type": "Organization",
+    "site_admin": false
+  },
+  "parent": {
+    "id": 617210,
+    "node_id": "MDEwOlJlcG9zaXRvcnk2MTcyMTA=",
+    "name": "github-api",
+    "full_name": "hub4j/github-api",
+    "private": false,
+    "owner": {
+      "login": "hub4j",
+      "id": 54909825,
+      "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0OTA5ODI1",
+      "avatar_url": "https://avatars3.githubusercontent.com/u/54909825?v=4",
+      "gravatar_id": "",
+      "url": "https://api.github.com/users/hub4j",
+      "html_url": "https://github.com/hub4j",
+      "followers_url": "https://api.github.com/users/hub4j/followers",
+      "following_url": "https://api.github.com/users/hub4j/following{/other_user}",
+      "gists_url": "https://api.github.com/users/hub4j/gists{/gist_id}",
+      "starred_url": "https://api.github.com/users/hub4j/starred{/owner}{/repo}",
+      "subscriptions_url": "https://api.github.com/users/hub4j/subscriptions",
+      "organizations_url": "https://api.github.com/users/hub4j/orgs",
+      "repos_url": "https://api.github.com/users/hub4j/repos",
+      "events_url": "https://api.github.com/users/hub4j/events{/privacy}",
+      "received_events_url": "https://api.github.com/users/hub4j/received_events",
+      "type": "Organization",
+      "site_admin": false
+    },
+    "html_url": "https://github.com/hub4j/github-api",
+    "description": "Java API for GitHub",
+    "fork": true,
+    "url": "https://api.github.com/repos/hub4j/github-api",
+    "forks_url": "https://api.github.com/repos/hub4j/github-api/forks",
+    "keys_url": "https://api.github.com/repos/hub4j/github-api/keys{/key_id}",
+    "collaborators_url": "https://api.github.com/repos/hub4j/github-api/collaborators{/collaborator}",
+    "teams_url": "https://api.github.com/repos/hub4j/github-api/teams",
+    "hooks_url": "https://api.github.com/repos/hub4j/github-api/hooks",
+    "issue_events_url": "https://api.github.com/repos/hub4j/github-api/issues/events{/number}",
+    "events_url": "https://api.github.com/repos/hub4j/github-api/events",
+    "assignees_url": "https://api.github.com/repos/hub4j/github-api/assignees{/user}",
+    "branches_url": "https://api.github.com/repos/hub4j/github-api/branches{/branch}",
+    "tags_url": "https://api.github.com/repos/hub4j/github-api/tags",
+    "blobs_url": "https://api.github.com/repos/hub4j/github-api/git/blobs{/sha}",
+    "git_tags_url": "https://api.github.com/repos/hub4j/github-api/git/tags{/sha}",
+    "git_refs_url": "https://api.github.com/repos/hub4j/github-api/git/refs{/sha}",
+    "trees_url": "https://api.github.com/repos/hub4j/github-api/git/trees{/sha}",
+    "statuses_url": "https://api.github.com/repos/hub4j/github-api/statuses/{sha}",
+    "languages_url": "https://api.github.com/repos/hub4j/github-api/languages",
+    "stargazers_url": "https://api.github.com/repos/hub4j/github-api/stargazers",
+    "contributors_url": "https://api.github.com/repos/hub4j/github-api/contributors",
+    "subscribers_url": "https://api.github.com/repos/hub4j/github-api/subscribers",
+    "subscription_url": "https://api.github.com/repos/hub4j/github-api/subscription",
+    "commits_url": "https://api.github.com/repos/hub4j/github-api/commits{/sha}",
+    "git_commits_url": "https://api.github.com/repos/hub4j/github-api/git/commits{/sha}",
+    "comments_url": "https://api.github.com/repos/hub4j/github-api/comments{/number}",
+    "issue_comment_url": "https://api.github.com/repos/hub4j/github-api/issues/comments{/number}",
+    "contents_url": "https://api.github.com/repos/hub4j/github-api/contents/{+path}",
+    "compare_url": "https://api.github.com/repos/hub4j/github-api/compare/{base}...{head}",
+    "merges_url": "https://api.github.com/repos/hub4j/github-api/merges",
+    "archive_url": "https://api.github.com/repos/hub4j/github-api/{archive_format}{/ref}",
+    "downloads_url": "https://api.github.com/repos/hub4j/github-api/downloads",
+    "issues_url": "https://api.github.com/repos/hub4j/github-api/issues{/number}",
+    "pulls_url": "https://api.github.com/repos/hub4j/github-api/pulls{/number}",
+    "milestones_url": "https://api.github.com/repos/hub4j/github-api/milestones{/number}",
+    "notifications_url": "https://api.github.com/repos/hub4j/github-api/notifications{?since,all,participating}",
+    "labels_url": "https://api.github.com/repos/hub4j/github-api/labels{/name}",
+    "releases_url": "https://api.github.com/repos/hub4j/github-api/releases{/id}",
+    "deployments_url": "https://api.github.com/repos/hub4j/github-api/deployments",
+    "created_at": "2010-04-19T04:13:03Z",
+    "updated_at": "2019-09-25T22:47:32Z",
+    "pushed_at": "2019-09-25T22:56:18Z",
+    "git_url": "git://github.com/hub4j/github-api.git",
+    "ssh_url": "git@github.com:hub4j/github-api.git",
+    "clone_url": "https://github.com/hub4j/github-api.git",
+    "svn_url": "https://github.com/hub4j/github-api",
+    "homepage": "http://github-api.kohsuke.org/",
+    "size": 11678,
+    "stargazers_count": 553,
+    "watchers_count": 553,
+    "language": "Java",
+    "has_issues": true,
+    "has_projects": true,
+    "has_downloads": true,
+    "has_wiki": true,
+    "has_pages": true,
+    "forks_count": 427,
+    "mirror_url": null,
+    "archived": false,
+    "disabled": false,
+    "open_issues_count": 96,
+    "license": {
+      "key": "mit",
+      "name": "MIT License",
+      "spdx_id": "MIT",
+      "url": "https://api.github.com/licenses/mit",
+      "node_id": "MDc6TGljZW5zZTEz"
+    },
+    "forks": 427,
+    "open_issues": 96,
+    "watchers": 553,
+    "default_branch": "main"
+  },
+  "source": {
+    "id": 617210,
+    "node_id": "MDEwOlJlcG9zaXRvcnk2MTcyMTA=",
+    "name": "github-api",
+    "full_name": "hub4j/github-api",
+    "private": false,
+    "owner": {
+      "login": "hub4j",
+      "id": 54909825,
+      "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0OTA5ODI1",
+      "avatar_url": "https://avatars3.githubusercontent.com/u/54909825?v=4",
+      "gravatar_id": "",
+      "url": "https://api.github.com/users/hub4j",
+      "html_url": "https://github.com/hub4j",
+      "followers_url": "https://api.github.com/users/hub4j/followers",
+      "following_url": "https://api.github.com/users/hub4j/following{/other_user}",
+      "gists_url": "https://api.github.com/users/hub4j/gists{/gist_id}",
+      "starred_url": "https://api.github.com/users/hub4j/starred{/owner}{/repo}",
+      "subscriptions_url": "https://api.github.com/users/hub4j/subscriptions",
+      "organizations_url": "https://api.github.com/users/hub4j/orgs",
+      "repos_url": "https://api.github.com/users/hub4j/repos",
+      "events_url": "https://api.github.com/users/hub4j/events{/privacy}",
+      "received_events_url": "https://api.github.com/users/hub4j/received_events",
+      "type": "Organization",
+      "site_admin": false
+    },
+    "html_url": "https://github.com/hub4j/github-api",
+    "description": "Java API for GitHub",
+    "fork": false,
+    "url": "https://api.github.com/repos/hub4j/github-api",
+    "forks_url": "https://api.github.com/repos/hub4j/github-api/forks",
+    "keys_url": "https://api.github.com/repos/hub4j/github-api/keys{/key_id}",
+    "collaborators_url": "https://api.github.com/repos/hub4j/github-api/collaborators{/collaborator}",
+    "teams_url": "https://api.github.com/repos/hub4j/github-api/teams",
+    "hooks_url": "https://api.github.com/repos/hub4j/github-api/hooks",
+    "issue_events_url": "https://api.github.com/repos/hub4j/github-api/issues/events{/number}",
+    "events_url": "https://api.github.com/repos/hub4j/github-api/events",
+    "assignees_url": "https://api.github.com/repos/hub4j/github-api/assignees{/user}",
+    "branches_url": "https://api.github.com/repos/hub4j/github-api/branches{/branch}",
+    "tags_url": "https://api.github.com/repos/hub4j/github-api/tags",
+    "blobs_url": "https://api.github.com/repos/hub4j/github-api/git/blobs{/sha}",
+    "git_tags_url": "https://api.github.com/repos/hub4j/github-api/git/tags{/sha}",
+    "git_refs_url": "https://api.github.com/repos/hub4j/github-api/git/refs{/sha}",
+    "trees_url": "https://api.github.com/repos/hub4j/github-api/git/trees{/sha}",
+    "statuses_url": "https://api.github.com/repos/hub4j/github-api/statuses/{sha}",
+    "languages_url": "https://api.github.com/repos/hub4j/github-api/languages",
+    "stargazers_url": "https://api.github.com/repos/hub4j/github-api/stargazers",
+    "contributors_url": "https://api.github.com/repos/hub4j/github-api/contributors",
+    "subscribers_url": "https://api.github.com/repos/hub4j/github-api/subscribers",
+    "subscription_url": "https://api.github.com/repos/hub4j/github-api/subscription",
+    "commits_url": "https://api.github.com/repos/hub4j/github-api/commits{/sha}",
+    "git_commits_url": "https://api.github.com/repos/hub4j/github-api/git/commits{/sha}",
+    "comments_url": "https://api.github.com/repos/hub4j/github-api/comments{/number}",
+    "issue_comment_url": "https://api.github.com/repos/hub4j/github-api/issues/comments{/number}",
+    "contents_url": "https://api.github.com/repos/hub4j/github-api/contents/{+path}",
+    "compare_url": "https://api.github.com/repos/hub4j/github-api/compare/{base}...{head}",
+    "merges_url": "https://api.github.com/repos/hub4j/github-api/merges",
+    "archive_url": "https://api.github.com/repos/hub4j/github-api/{archive_format}{/ref}",
+    "downloads_url": "https://api.github.com/repos/hub4j/github-api/downloads",
+    "issues_url": "https://api.github.com/repos/hub4j/github-api/issues{/number}",
+    "pulls_url": "https://api.github.com/repos/hub4j/github-api/pulls{/number}",
+    "milestones_url": "https://api.github.com/repos/hub4j/github-api/milestones{/number}",
+    "notifications_url": "https://api.github.com/repos/hub4j/github-api/notifications{?since,all,participating}",
+    "labels_url": "https://api.github.com/repos/hub4j/github-api/labels{/name}",
+    "releases_url": "https://api.github.com/repos/hub4j/github-api/releases{/id}",
+    "deployments_url": "https://api.github.com/repos/hub4j/github-api/deployments",
+    "created_at": "2010-04-19T04:13:03Z",
+    "updated_at": "2019-09-25T22:47:32Z",
+    "pushed_at": "2019-09-25T22:56:18Z",
+    "git_url": "git://github.com/hub4j/github-api.git",
+    "ssh_url": "git@github.com:hub4j/github-api.git",
+    "clone_url": "https://github.com/hub4j/github-api.git",
+    "svn_url": "https://github.com/hub4j/github-api",
+    "homepage": "http://github-api.kohsuke.org/",
+    "size": 11678,
+    "stargazers_count": 553,
+    "watchers_count": 553,
+    "language": "Java",
+    "has_issues": true,
+    "has_projects": true,
+    "has_downloads": true,
+    "has_wiki": true,
+    "has_pages": true,
+    "forks_count": 427,
+    "mirror_url": null,
+    "archived": false,
+    "disabled": false,
+    "open_issues_count": 96,
+    "license": {
+      "key": "mit",
+      "name": "MIT License",
+      "spdx_id": "MIT",
+      "url": "https://api.github.com/licenses/mit",
+      "node_id": "MDc6TGljZW5zZTEz"
+    },
+    "forks": 427,
+    "open_issues": 96,
+    "watchers": 553,
+    "default_branch": "main"
+  },
+  "network_count": 427,
+  "subscribers_count": 0
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/__files/4-r_h_github-api.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/__files/4-r_h_github-api.json
new file mode 100644
index 000000000..59ae8286f
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/__files/4-r_h_github-api.json
@@ -0,0 +1,5 @@
+{
+  "message": "Successfully fetched and fast-forwarded from upstream github-api:main",
+  "merge_type": "fast-forward",
+  "base_branch": "github-api:main"
+}
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/mappings/1-user.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/mappings/1-user.json
new file mode 100644
index 000000000..a7e5c0c21
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/mappings/1-user.json
@@ -0,0 +1,48 @@
+{
+  "id": "7f6e9a01-5bfa-4f72-9947-07df902f56c3",
+  "name": "user",
+  "request": {
+    "url": "/user",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 200,
+    "bodyFileName": "1-user.json",
+    "headers": {
+      "Date": "Wed, 25 Sep 2019 23:35:33 GMT",
+      "Content-Type": "application/json; charset=utf-8",
+      "Server": "GitHub.com",
+      "Status": "200 OK",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4992",
+      "X-RateLimit-Reset": "1569457884",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": [
+        "Accept, Authorization, Cookie, X-GitHub-OTP",
+        "Accept-Encoding"
+      ],
+      "ETag": "W/\"14ffd29009ddc2209c450bb29a5a8330\"",
+      "Last-Modified": "Tue, 24 Sep 2019 19:32:29 GMT",
+      "X-OAuth-Scopes": "gist, notifications, read:org, read:public_key, read:repo_hook, repo",
+      "X-Accepted-OAuth-Scopes": "",
+      "X-GitHub-Media-Type": "unknown, github.v3",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "1; mode=block",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "X-GitHub-Request-Id": "F845:5D1D:FFA88A:12FE539:5D8BF9C5"
+    }
+  },
+  "uuid": "7f6e9a01-5bfa-4f72-9947-07df902f56c3",
+  "persistent": true,
+  "insertionIndex": 1
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/mappings/2-orgs_hub4j-test-org.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/mappings/2-orgs_hub4j-test-org.json
new file mode 100644
index 000000000..64182cc8c
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/mappings/2-orgs_hub4j-test-org.json
@@ -0,0 +1,48 @@
+{
+  "id": "cb173af2-c793-444a-acdf-c3850e7afdbe",
+  "name": "orgs_hub4j-test-org",
+  "request": {
+    "url": "/orgs/hub4j-test-org",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 200,
+    "bodyFileName": "2-orgs_hub4j-test-org.json",
+    "headers": {
+      "Date": "Wed, 25 Sep 2019 23:35:58 GMT",
+      "Content-Type": "application/json; charset=utf-8",
+      "Server": "GitHub.com",
+      "Status": "200 OK",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4989",
+      "X-RateLimit-Reset": "1569457884",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": [
+        "Accept, Authorization, Cookie, X-GitHub-OTP",
+        "Accept-Encoding"
+      ],
+      "ETag": "W/\"b7989d48e6539c9c76038995b902421b\"",
+      "Last-Modified": "Mon, 20 Apr 2015 00:42:30 GMT",
+      "X-OAuth-Scopes": "gist, notifications, read:org, read:public_key, read:repo_hook, repo",
+      "X-Accepted-OAuth-Scopes": "admin:org, read:org, repo, user, write:org",
+      "X-GitHub-Media-Type": "unknown, github.v3",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "1; mode=block",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "X-GitHub-Request-Id": "F855:59E1:1397ED7:171400E:5D8BF9DE"
+    }
+  },
+  "uuid": "cb173af2-c793-444a-acdf-c3850e7afdbe",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/mappings/3-r_h_github-api.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/mappings/3-r_h_github-api.json
new file mode 100644
index 000000000..265e1fd4b
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/mappings/3-r_h_github-api.json
@@ -0,0 +1,51 @@
+{
+  "id": "0a4d7a1a-f99c-47ca-840a-3e920c18bd1f",
+  "name": "repos_hub4j-test-org_github-api",
+  "request": {
+    "url": "/repos/hub4j-test-org/github-api",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 200,
+    "bodyFileName": "3-r_h_github-api.json",
+    "headers": {
+      "Date": "Wed, 25 Sep 2019 23:35:58 GMT",
+      "Content-Type": "application/json; charset=utf-8",
+      "Server": "GitHub.com",
+      "Status": "200 OK",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4988",
+      "X-RateLimit-Reset": "1569457884",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": [
+        "Accept, Authorization, Cookie, X-GitHub-OTP",
+        "Accept-Encoding"
+      ],
+      "ETag": "W/\"0678d1c39ea574f68cc0fb330b067cb7\"",
+      "Last-Modified": "Wed, 25 Sep 2019 23:32:35 GMT",
+      "X-OAuth-Scopes": "gist, notifications, read:org, read:public_key, read:repo_hook, repo",
+      "X-Accepted-OAuth-Scopes": "repo",
+      "X-GitHub-Media-Type": "unknown, github.v3",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "1; mode=block",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "X-GitHub-Request-Id": "F855:59E1:1397EEB:1714029:5D8BF9DE"
+    }
+  },
+  "uuid": "0a4d7a1a-f99c-47ca-840a-3e920c18bd1f",
+  "persistent": true,
+  "scenarioName": "scenario-1-repos-hub4j-test-org-github-api",
+  "requiredScenarioState": "Started",
+  "newScenarioState": "scenario-1-repos-hub4j-test-org-github-api-2",
+  "insertionIndex": 3
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/mappings/4-r_h_github-api.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/mappings/4-r_h_github-api.json
new file mode 100644
index 000000000..d3f36a562
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/sync/mappings/4-r_h_github-api.json
@@ -0,0 +1,54 @@
+{
+  "id": "2c69d5c8-dd81-4204-bad9-ee37f5b0ebfd",
+  "name": "repos_hub4j-test-org_github-api",
+  "request": {
+    "url": "/repos/hub4j-test-org/github-api/merge-upstream",
+    "method": "POST",
+    "bodyPatterns": [
+      {
+        "equalToJson": "{\"branch\":\"main\"}",
+        "ignoreArrayOrder": true,
+        "ignoreExtraElements": false
+      }
+    ],
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 200,
+    "bodyFileName": "4-r_h_github-api.json",
+    "headers": {
+      "Date": "Wed, 25 Sep 2019 23:35:59 GMT",
+      "Content-Type": "application/json; charset=utf-8",
+      "Server": "GitHub.com",
+      "Status": "200 OK",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4987",
+      "X-RateLimit-Reset": "1569457884",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": [
+        "Accept, Authorization, Cookie, X-GitHub-OTP",
+        "Accept-Encoding"
+      ],
+      "ETag": "W/\"e40487cafd3670c0de171f4250dbefb8\"",
+      "X-OAuth-Scopes": "gist, notifications, read:org, read:public_key, read:repo_hook, repo",
+      "X-Accepted-OAuth-Scopes": "",
+      "X-GitHub-Media-Type": "unknown, github.v3",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "1; mode=block",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "X-GitHub-Request-Id": "F855:59E1:1397F0E:1714041:5D8BF9DE"
+    }
+  },
+  "uuid": "2c69d5c8-dd81-4204-bad9-ee37f5b0ebfd",
+  "persistent": true,
+  "insertionIndex": 4
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/__files/1-user.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/__files/1-user.json
new file mode 100644
index 000000000..eab16ea06
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/__files/1-user.json
@@ -0,0 +1,33 @@
+{
+  "login": "bitwiseman",
+  "id": 1958953,
+  "node_id": "MDQ6VXNlcjE5NTg5NTM=",
+  "avatar_url": "https://avatars3.githubusercontent.com/u/1958953?v=4",
+  "gravatar_id": "",
+  "url": "https://api.github.com/users/bitwiseman",
+  "html_url": "https://github.com/bitwiseman",
+  "followers_url": "https://api.github.com/users/bitwiseman/followers",
+  "following_url": "https://api.github.com/users/bitwiseman/following{/other_user}",
+  "gists_url": "https://api.github.com/users/bitwiseman/gists{/gist_id}",
+  "starred_url": "https://api.github.com/users/bitwiseman/starred{/owner}{/repo}",
+  "subscriptions_url": "https://api.github.com/users/bitwiseman/subscriptions",
+  "organizations_url": "https://api.github.com/users/bitwiseman/orgs",
+  "repos_url": "https://api.github.com/users/bitwiseman/repos",
+  "events_url": "https://api.github.com/users/bitwiseman/events{/privacy}",
+  "received_events_url": "https://api.github.com/users/bitwiseman/received_events",
+  "type": "User",
+  "site_admin": false,
+  "name": "Liam Newman",
+  "company": "Cloudbees, Inc.",
+  "blog": "",
+  "location": "Seattle, WA, USA",
+  "email": "bitwiseman@gmail.com",
+  "hireable": null,
+  "bio": "https://twitter.com/bitwiseman",
+  "public_repos": 166,
+  "public_gists": 4,
+  "followers": 135,
+  "following": 9,
+  "created_at": "2012-07-11T20:38:33Z",
+  "updated_at": "2019-09-24T19:32:29Z"
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/__files/2-orgs_hub4j-test-org.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/__files/2-orgs_hub4j-test-org.json
new file mode 100644
index 000000000..f176fc4ff
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/__files/2-orgs_hub4j-test-org.json
@@ -0,0 +1,42 @@
+{
+  "login": "hub4j-test-org",
+  "id": 7544739,
+  "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=",
+  "url": "https://api.github.com/orgs/hub4j-test-org",
+  "repos_url": "https://api.github.com/orgs/hub4j-test-org/repos",
+  "events_url": "https://api.github.com/orgs/hub4j-test-org/events",
+  "hooks_url": "https://api.github.com/orgs/hub4j-test-org/hooks",
+  "issues_url": "https://api.github.com/orgs/hub4j-test-org/issues",
+  "members_url": "https://api.github.com/orgs/hub4j-test-org/members{/member}",
+  "public_members_url": "https://api.github.com/orgs/hub4j-test-org/public_members{/member}",
+  "avatar_url": "https://avatars3.githubusercontent.com/u/7544739?v=4",
+  "description": null,
+  "is_verified": false,
+  "has_organization_projects": true,
+  "has_repository_projects": true,
+  "public_repos": 9,
+  "public_gists": 0,
+  "followers": 0,
+  "following": 0,
+  "html_url": "https://github.com/hub4j-test-org",
+  "created_at": "2014-05-10T19:39:11Z",
+  "updated_at": "2015-04-20T00:42:30Z",
+  "type": "Organization",
+  "total_private_repos": 0,
+  "owned_private_repos": 0,
+  "private_gists": 0,
+  "disk_usage": 132,
+  "collaborators": 0,
+  "billing_email": "kk@kohsuke.org",
+  "default_repository_permission": "none",
+  "members_can_create_repositories": false,
+  "two_factor_requirement_enabled": false,
+  "members_allowed_repository_creation_type": "none",
+  "plan": {
+    "name": "free",
+    "space": 976562499,
+    "private_repos": 0,
+    "filled_seats": 3,
+    "seats": 0
+  }
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/__files/3-r_h_github-api.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/__files/3-r_h_github-api.json
new file mode 100644
index 000000000..2680467bc
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/__files/3-r_h_github-api.json
@@ -0,0 +1,330 @@
+{
+  "id": 206888201,
+  "node_id": "MDEwOlJlcG9zaXRvcnkyMDY4ODgyMDE=",
+  "name": "github-api",
+  "full_name": "hub4j-test-org/github-api",
+  "private": false,
+  "owner": {
+    "login": "hub4j-test-org",
+    "id": 7544739,
+    "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=",
+    "avatar_url": "https://avatars3.githubusercontent.com/u/7544739?v=4",
+    "gravatar_id": "",
+    "url": "https://api.github.com/users/hub4j-test-org",
+    "html_url": "https://github.com/hub4j-test-org",
+    "followers_url": "https://api.github.com/users/hub4j-test-org/followers",
+    "following_url": "https://api.github.com/users/hub4j-test-org/following{/other_user}",
+    "gists_url": "https://api.github.com/users/hub4j-test-org/gists{/gist_id}",
+    "starred_url": "https://api.github.com/users/hub4j-test-org/starred{/owner}{/repo}",
+    "subscriptions_url": "https://api.github.com/users/hub4j-test-org/subscriptions",
+    "organizations_url": "https://api.github.com/users/hub4j-test-org/orgs",
+    "repos_url": "https://api.github.com/users/hub4j-test-org/repos",
+    "events_url": "https://api.github.com/users/hub4j-test-org/events{/privacy}",
+    "received_events_url": "https://api.github.com/users/hub4j-test-org/received_events",
+    "type": "Organization",
+    "site_admin": false
+  },
+  "html_url": "https://github.com/hub4j-test-org/github-api",
+  "description": "Tricky",
+  "fork": false,
+  "url": "https://api.github.com/repos/hub4j-test-org/github-api",
+  "forks_url": "https://api.github.com/repos/hub4j-test-org/github-api/forks",
+  "keys_url": "https://api.github.com/repos/hub4j-test-org/github-api/keys{/key_id}",
+  "collaborators_url": "https://api.github.com/repos/hub4j-test-org/github-api/collaborators{/collaborator}",
+  "teams_url": "https://api.github.com/repos/hub4j-test-org/github-api/teams",
+  "hooks_url": "https://api.github.com/repos/hub4j-test-org/github-api/hooks",
+  "issue_events_url": "https://api.github.com/repos/hub4j-test-org/github-api/issues/events{/number}",
+  "events_url": "https://api.github.com/repos/hub4j-test-org/github-api/events",
+  "assignees_url": "https://api.github.com/repos/hub4j-test-org/github-api/assignees{/user}",
+  "branches_url": "https://api.github.com/repos/hub4j-test-org/github-api/branches{/branch}",
+  "tags_url": "https://api.github.com/repos/hub4j-test-org/github-api/tags",
+  "blobs_url": "https://api.github.com/repos/hub4j-test-org/github-api/git/blobs{/sha}",
+  "git_tags_url": "https://api.github.com/repos/hub4j-test-org/github-api/git/tags{/sha}",
+  "git_refs_url": "https://api.github.com/repos/hub4j-test-org/github-api/git/refs{/sha}",
+  "trees_url": "https://api.github.com/repos/hub4j-test-org/github-api/git/trees{/sha}",
+  "statuses_url": "https://api.github.com/repos/hub4j-test-org/github-api/statuses/{sha}",
+  "languages_url": "https://api.github.com/repos/hub4j-test-org/github-api/languages",
+  "stargazers_url": "https://api.github.com/repos/hub4j-test-org/github-api/stargazers",
+  "contributors_url": "https://api.github.com/repos/hub4j-test-org/github-api/contributors",
+  "subscribers_url": "https://api.github.com/repos/hub4j-test-org/github-api/subscribers",
+  "subscription_url": "https://api.github.com/repos/hub4j-test-org/github-api/subscription",
+  "commits_url": "https://api.github.com/repos/hub4j-test-org/github-api/commits{/sha}",
+  "git_commits_url": "https://api.github.com/repos/hub4j-test-org/github-api/git/commits{/sha}",
+  "comments_url": "https://api.github.com/repos/hub4j-test-org/github-api/comments{/number}",
+  "issue_comment_url": "https://api.github.com/repos/hub4j-test-org/github-api/issues/comments{/number}",
+  "contents_url": "https://api.github.com/repos/hub4j-test-org/github-api/contents/{+path}",
+  "compare_url": "https://api.github.com/repos/hub4j-test-org/github-api/compare/{base}...{head}",
+  "merges_url": "https://api.github.com/repos/hub4j-test-org/github-api/merges",
+  "archive_url": "https://api.github.com/repos/hub4j-test-org/github-api/{archive_format}{/ref}",
+  "downloads_url": "https://api.github.com/repos/hub4j-test-org/github-api/downloads",
+  "issues_url": "https://api.github.com/repos/hub4j-test-org/github-api/issues{/number}",
+  "pulls_url": "https://api.github.com/repos/hub4j-test-org/github-api/pulls{/number}",
+  "milestones_url": "https://api.github.com/repos/hub4j-test-org/github-api/milestones{/number}",
+  "notifications_url": "https://api.github.com/repos/hub4j-test-org/github-api/notifications{?since,all,participating}",
+  "labels_url": "https://api.github.com/repos/hub4j-test-org/github-api/labels{/name}",
+  "releases_url": "https://api.github.com/repos/hub4j-test-org/github-api/releases{/id}",
+  "deployments_url": "https://api.github.com/repos/hub4j-test-org/github-api/deployments",
+  "created_at": "2019-09-06T23:26:04Z",
+  "updated_at": "2019-09-25T23:32:35Z",
+  "pushed_at": "2019-09-21T14:29:14Z",
+  "git_url": "git://github.com/hub4j-test-org/github-api.git",
+  "ssh_url": "git@github.com:hub4j-test-org/github-api.git",
+  "clone_url": "https://github.com/hub4j-test-org/github-api.git",
+  "svn_url": "https://github.com/hub4j-test-org/github-api",
+  "homepage": "http://github-api.kohsuke.org/",
+  "size": 11387,
+  "stargazers_count": 0,
+  "watchers_count": 0,
+  "language": "Java",
+  "has_issues": true,
+  "has_projects": true,
+  "has_downloads": true,
+  "has_wiki": true,
+  "has_pages": false,
+  "forks_count": 0,
+  "mirror_url": null,
+  "archived": false,
+  "disabled": false,
+  "open_issues_count": 0,
+  "license": {
+    "key": "mit",
+    "name": "MIT License",
+    "spdx_id": "MIT",
+    "url": "https://api.github.com/licenses/mit",
+    "node_id": "MDc6TGljZW5zZTEz"
+  },
+  "forks": 0,
+  "open_issues": 0,
+  "watchers": 0,
+  "default_branch": "main",
+  "permissions": {
+    "admin": true,
+    "push": true,
+    "pull": true
+  },
+  "allow_squash_merge": true,
+  "allow_merge_commit": true,
+  "allow_rebase_merge": true,
+  "organization": {
+    "login": "hub4j-test-org",
+    "id": 7544739,
+    "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=",
+    "avatar_url": "https://avatars3.githubusercontent.com/u/7544739?v=4",
+    "gravatar_id": "",
+    "url": "https://api.github.com/users/hub4j-test-org",
+    "html_url": "https://github.com/hub4j-test-org",
+    "followers_url": "https://api.github.com/users/hub4j-test-org/followers",
+    "following_url": "https://api.github.com/users/hub4j-test-org/following{/other_user}",
+    "gists_url": "https://api.github.com/users/hub4j-test-org/gists{/gist_id}",
+    "starred_url": "https://api.github.com/users/hub4j-test-org/starred{/owner}{/repo}",
+    "subscriptions_url": "https://api.github.com/users/hub4j-test-org/subscriptions",
+    "organizations_url": "https://api.github.com/users/hub4j-test-org/orgs",
+    "repos_url": "https://api.github.com/users/hub4j-test-org/repos",
+    "events_url": "https://api.github.com/users/hub4j-test-org/events{/privacy}",
+    "received_events_url": "https://api.github.com/users/hub4j-test-org/received_events",
+    "type": "Organization",
+    "site_admin": false
+  },
+  "parent": {
+    "id": 617210,
+    "node_id": "MDEwOlJlcG9zaXRvcnk2MTcyMTA=",
+    "name": "github-api",
+    "full_name": "hub4j/github-api",
+    "private": false,
+    "owner": {
+      "login": "hub4j",
+      "id": 54909825,
+      "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0OTA5ODI1",
+      "avatar_url": "https://avatars3.githubusercontent.com/u/54909825?v=4",
+      "gravatar_id": "",
+      "url": "https://api.github.com/users/hub4j",
+      "html_url": "https://github.com/hub4j",
+      "followers_url": "https://api.github.com/users/hub4j/followers",
+      "following_url": "https://api.github.com/users/hub4j/following{/other_user}",
+      "gists_url": "https://api.github.com/users/hub4j/gists{/gist_id}",
+      "starred_url": "https://api.github.com/users/hub4j/starred{/owner}{/repo}",
+      "subscriptions_url": "https://api.github.com/users/hub4j/subscriptions",
+      "organizations_url": "https://api.github.com/users/hub4j/orgs",
+      "repos_url": "https://api.github.com/users/hub4j/repos",
+      "events_url": "https://api.github.com/users/hub4j/events{/privacy}",
+      "received_events_url": "https://api.github.com/users/hub4j/received_events",
+      "type": "Organization",
+      "site_admin": false
+    },
+    "html_url": "https://github.com/hub4j/github-api",
+    "description": "Java API for GitHub",
+    "fork": true,
+    "url": "https://api.github.com/repos/hub4j/github-api",
+    "forks_url": "https://api.github.com/repos/hub4j/github-api/forks",
+    "keys_url": "https://api.github.com/repos/hub4j/github-api/keys{/key_id}",
+    "collaborators_url": "https://api.github.com/repos/hub4j/github-api/collaborators{/collaborator}",
+    "teams_url": "https://api.github.com/repos/hub4j/github-api/teams",
+    "hooks_url": "https://api.github.com/repos/hub4j/github-api/hooks",
+    "issue_events_url": "https://api.github.com/repos/hub4j/github-api/issues/events{/number}",
+    "events_url": "https://api.github.com/repos/hub4j/github-api/events",
+    "assignees_url": "https://api.github.com/repos/hub4j/github-api/assignees{/user}",
+    "branches_url": "https://api.github.com/repos/hub4j/github-api/branches{/branch}",
+    "tags_url": "https://api.github.com/repos/hub4j/github-api/tags",
+    "blobs_url": "https://api.github.com/repos/hub4j/github-api/git/blobs{/sha}",
+    "git_tags_url": "https://api.github.com/repos/hub4j/github-api/git/tags{/sha}",
+    "git_refs_url": "https://api.github.com/repos/hub4j/github-api/git/refs{/sha}",
+    "trees_url": "https://api.github.com/repos/hub4j/github-api/git/trees{/sha}",
+    "statuses_url": "https://api.github.com/repos/hub4j/github-api/statuses/{sha}",
+    "languages_url": "https://api.github.com/repos/hub4j/github-api/languages",
+    "stargazers_url": "https://api.github.com/repos/hub4j/github-api/stargazers",
+    "contributors_url": "https://api.github.com/repos/hub4j/github-api/contributors",
+    "subscribers_url": "https://api.github.com/repos/hub4j/github-api/subscribers",
+    "subscription_url": "https://api.github.com/repos/hub4j/github-api/subscription",
+    "commits_url": "https://api.github.com/repos/hub4j/github-api/commits{/sha}",
+    "git_commits_url": "https://api.github.com/repos/hub4j/github-api/git/commits{/sha}",
+    "comments_url": "https://api.github.com/repos/hub4j/github-api/comments{/number}",
+    "issue_comment_url": "https://api.github.com/repos/hub4j/github-api/issues/comments{/number}",
+    "contents_url": "https://api.github.com/repos/hub4j/github-api/contents/{+path}",
+    "compare_url": "https://api.github.com/repos/hub4j/github-api/compare/{base}...{head}",
+    "merges_url": "https://api.github.com/repos/hub4j/github-api/merges",
+    "archive_url": "https://api.github.com/repos/hub4j/github-api/{archive_format}{/ref}",
+    "downloads_url": "https://api.github.com/repos/hub4j/github-api/downloads",
+    "issues_url": "https://api.github.com/repos/hub4j/github-api/issues{/number}",
+    "pulls_url": "https://api.github.com/repos/hub4j/github-api/pulls{/number}",
+    "milestones_url": "https://api.github.com/repos/hub4j/github-api/milestones{/number}",
+    "notifications_url": "https://api.github.com/repos/hub4j/github-api/notifications{?since,all,participating}",
+    "labels_url": "https://api.github.com/repos/hub4j/github-api/labels{/name}",
+    "releases_url": "https://api.github.com/repos/hub4j/github-api/releases{/id}",
+    "deployments_url": "https://api.github.com/repos/hub4j/github-api/deployments",
+    "created_at": "2010-04-19T04:13:03Z",
+    "updated_at": "2019-09-25T22:47:32Z",
+    "pushed_at": "2019-09-25T22:56:18Z",
+    "git_url": "git://github.com/hub4j/github-api.git",
+    "ssh_url": "git@github.com:hub4j/github-api.git",
+    "clone_url": "https://github.com/hub4j/github-api.git",
+    "svn_url": "https://github.com/hub4j/github-api",
+    "homepage": "http://github-api.kohsuke.org/",
+    "size": 11678,
+    "stargazers_count": 553,
+    "watchers_count": 553,
+    "language": "Java",
+    "has_issues": true,
+    "has_projects": true,
+    "has_downloads": true,
+    "has_wiki": true,
+    "has_pages": true,
+    "forks_count": 427,
+    "mirror_url": null,
+    "archived": false,
+    "disabled": false,
+    "open_issues_count": 96,
+    "license": {
+      "key": "mit",
+      "name": "MIT License",
+      "spdx_id": "MIT",
+      "url": "https://api.github.com/licenses/mit",
+      "node_id": "MDc6TGljZW5zZTEz"
+    },
+    "forks": 427,
+    "open_issues": 96,
+    "watchers": 553,
+    "default_branch": "main"
+  },
+  "source": {
+    "id": 617210,
+    "node_id": "MDEwOlJlcG9zaXRvcnk2MTcyMTA=",
+    "name": "github-api",
+    "full_name": "hub4j/github-api",
+    "private": false,
+    "owner": {
+      "login": "hub4j",
+      "id": 54909825,
+      "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0OTA5ODI1",
+      "avatar_url": "https://avatars3.githubusercontent.com/u/54909825?v=4",
+      "gravatar_id": "",
+      "url": "https://api.github.com/users/hub4j",
+      "html_url": "https://github.com/hub4j",
+      "followers_url": "https://api.github.com/users/hub4j/followers",
+      "following_url": "https://api.github.com/users/hub4j/following{/other_user}",
+      "gists_url": "https://api.github.com/users/hub4j/gists{/gist_id}",
+      "starred_url": "https://api.github.com/users/hub4j/starred{/owner}{/repo}",
+      "subscriptions_url": "https://api.github.com/users/hub4j/subscriptions",
+      "organizations_url": "https://api.github.com/users/hub4j/orgs",
+      "repos_url": "https://api.github.com/users/hub4j/repos",
+      "events_url": "https://api.github.com/users/hub4j/events{/privacy}",
+      "received_events_url": "https://api.github.com/users/hub4j/received_events",
+      "type": "Organization",
+      "site_admin": false
+    },
+    "html_url": "https://github.com/hub4j/github-api",
+    "description": "Java API for GitHub",
+    "fork": false,
+    "url": "https://api.github.com/repos/hub4j/github-api",
+    "forks_url": "https://api.github.com/repos/hub4j/github-api/forks",
+    "keys_url": "https://api.github.com/repos/hub4j/github-api/keys{/key_id}",
+    "collaborators_url": "https://api.github.com/repos/hub4j/github-api/collaborators{/collaborator}",
+    "teams_url": "https://api.github.com/repos/hub4j/github-api/teams",
+    "hooks_url": "https://api.github.com/repos/hub4j/github-api/hooks",
+    "issue_events_url": "https://api.github.com/repos/hub4j/github-api/issues/events{/number}",
+    "events_url": "https://api.github.com/repos/hub4j/github-api/events",
+    "assignees_url": "https://api.github.com/repos/hub4j/github-api/assignees{/user}",
+    "branches_url": "https://api.github.com/repos/hub4j/github-api/branches{/branch}",
+    "tags_url": "https://api.github.com/repos/hub4j/github-api/tags",
+    "blobs_url": "https://api.github.com/repos/hub4j/github-api/git/blobs{/sha}",
+    "git_tags_url": "https://api.github.com/repos/hub4j/github-api/git/tags{/sha}",
+    "git_refs_url": "https://api.github.com/repos/hub4j/github-api/git/refs{/sha}",
+    "trees_url": "https://api.github.com/repos/hub4j/github-api/git/trees{/sha}",
+    "statuses_url": "https://api.github.com/repos/hub4j/github-api/statuses/{sha}",
+    "languages_url": "https://api.github.com/repos/hub4j/github-api/languages",
+    "stargazers_url": "https://api.github.com/repos/hub4j/github-api/stargazers",
+    "contributors_url": "https://api.github.com/repos/hub4j/github-api/contributors",
+    "subscribers_url": "https://api.github.com/repos/hub4j/github-api/subscribers",
+    "subscription_url": "https://api.github.com/repos/hub4j/github-api/subscription",
+    "commits_url": "https://api.github.com/repos/hub4j/github-api/commits{/sha}",
+    "git_commits_url": "https://api.github.com/repos/hub4j/github-api/git/commits{/sha}",
+    "comments_url": "https://api.github.com/repos/hub4j/github-api/comments{/number}",
+    "issue_comment_url": "https://api.github.com/repos/hub4j/github-api/issues/comments{/number}",
+    "contents_url": "https://api.github.com/repos/hub4j/github-api/contents/{+path}",
+    "compare_url": "https://api.github.com/repos/hub4j/github-api/compare/{base}...{head}",
+    "merges_url": "https://api.github.com/repos/hub4j/github-api/merges",
+    "archive_url": "https://api.github.com/repos/hub4j/github-api/{archive_format}{/ref}",
+    "downloads_url": "https://api.github.com/repos/hub4j/github-api/downloads",
+    "issues_url": "https://api.github.com/repos/hub4j/github-api/issues{/number}",
+    "pulls_url": "https://api.github.com/repos/hub4j/github-api/pulls{/number}",
+    "milestones_url": "https://api.github.com/repos/hub4j/github-api/milestones{/number}",
+    "notifications_url": "https://api.github.com/repos/hub4j/github-api/notifications{?since,all,participating}",
+    "labels_url": "https://api.github.com/repos/hub4j/github-api/labels{/name}",
+    "releases_url": "https://api.github.com/repos/hub4j/github-api/releases{/id}",
+    "deployments_url": "https://api.github.com/repos/hub4j/github-api/deployments",
+    "created_at": "2010-04-19T04:13:03Z",
+    "updated_at": "2019-09-25T22:47:32Z",
+    "pushed_at": "2019-09-25T22:56:18Z",
+    "git_url": "git://github.com/hub4j/github-api.git",
+    "ssh_url": "git@github.com:hub4j/github-api.git",
+    "clone_url": "https://github.com/hub4j/github-api.git",
+    "svn_url": "https://github.com/hub4j/github-api",
+    "homepage": "http://github-api.kohsuke.org/",
+    "size": 11678,
+    "stargazers_count": 553,
+    "watchers_count": 553,
+    "language": "Java",
+    "has_issues": true,
+    "has_projects": true,
+    "has_downloads": true,
+    "has_wiki": true,
+    "has_pages": true,
+    "forks_count": 427,
+    "mirror_url": null,
+    "archived": false,
+    "disabled": false,
+    "open_issues_count": 96,
+    "license": {
+      "key": "mit",
+      "name": "MIT License",
+      "spdx_id": "MIT",
+      "url": "https://api.github.com/licenses/mit",
+      "node_id": "MDc6TGljZW5zZTEz"
+    },
+    "forks": 427,
+    "open_issues": 96,
+    "watchers": 553,
+    "default_branch": "main"
+  },
+  "network_count": 427,
+  "subscribers_count": 0
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/__files/4-r_h_github-api.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/__files/4-r_h_github-api.json
new file mode 100644
index 000000000..6d0311486
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/__files/4-r_h_github-api.json
@@ -0,0 +1,5 @@
+{
+  "message": "Validation Failed",
+  "documentation_url": "https://docs.github.com/rest/branches/branches#sync-a-fork-branch-with-the-upstream-repository",
+  "status": "422"
+}
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/mappings/1-user.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/mappings/1-user.json
new file mode 100644
index 000000000..a7e5c0c21
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/mappings/1-user.json
@@ -0,0 +1,48 @@
+{
+  "id": "7f6e9a01-5bfa-4f72-9947-07df902f56c3",
+  "name": "user",
+  "request": {
+    "url": "/user",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 200,
+    "bodyFileName": "1-user.json",
+    "headers": {
+      "Date": "Wed, 25 Sep 2019 23:35:33 GMT",
+      "Content-Type": "application/json; charset=utf-8",
+      "Server": "GitHub.com",
+      "Status": "200 OK",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4992",
+      "X-RateLimit-Reset": "1569457884",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": [
+        "Accept, Authorization, Cookie, X-GitHub-OTP",
+        "Accept-Encoding"
+      ],
+      "ETag": "W/\"14ffd29009ddc2209c450bb29a5a8330\"",
+      "Last-Modified": "Tue, 24 Sep 2019 19:32:29 GMT",
+      "X-OAuth-Scopes": "gist, notifications, read:org, read:public_key, read:repo_hook, repo",
+      "X-Accepted-OAuth-Scopes": "",
+      "X-GitHub-Media-Type": "unknown, github.v3",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "1; mode=block",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "X-GitHub-Request-Id": "F845:5D1D:FFA88A:12FE539:5D8BF9C5"
+    }
+  },
+  "uuid": "7f6e9a01-5bfa-4f72-9947-07df902f56c3",
+  "persistent": true,
+  "insertionIndex": 1
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/mappings/2-orgs_hub4j-test-org.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/mappings/2-orgs_hub4j-test-org.json
new file mode 100644
index 000000000..64182cc8c
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/mappings/2-orgs_hub4j-test-org.json
@@ -0,0 +1,48 @@
+{
+  "id": "cb173af2-c793-444a-acdf-c3850e7afdbe",
+  "name": "orgs_hub4j-test-org",
+  "request": {
+    "url": "/orgs/hub4j-test-org",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 200,
+    "bodyFileName": "2-orgs_hub4j-test-org.json",
+    "headers": {
+      "Date": "Wed, 25 Sep 2019 23:35:58 GMT",
+      "Content-Type": "application/json; charset=utf-8",
+      "Server": "GitHub.com",
+      "Status": "200 OK",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4989",
+      "X-RateLimit-Reset": "1569457884",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": [
+        "Accept, Authorization, Cookie, X-GitHub-OTP",
+        "Accept-Encoding"
+      ],
+      "ETag": "W/\"b7989d48e6539c9c76038995b902421b\"",
+      "Last-Modified": "Mon, 20 Apr 2015 00:42:30 GMT",
+      "X-OAuth-Scopes": "gist, notifications, read:org, read:public_key, read:repo_hook, repo",
+      "X-Accepted-OAuth-Scopes": "admin:org, read:org, repo, user, write:org",
+      "X-GitHub-Media-Type": "unknown, github.v3",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "1; mode=block",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "X-GitHub-Request-Id": "F855:59E1:1397ED7:171400E:5D8BF9DE"
+    }
+  },
+  "uuid": "cb173af2-c793-444a-acdf-c3850e7afdbe",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/mappings/3-r_h_github-api.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/mappings/3-r_h_github-api.json
new file mode 100644
index 000000000..265e1fd4b
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/mappings/3-r_h_github-api.json
@@ -0,0 +1,51 @@
+{
+  "id": "0a4d7a1a-f99c-47ca-840a-3e920c18bd1f",
+  "name": "repos_hub4j-test-org_github-api",
+  "request": {
+    "url": "/repos/hub4j-test-org/github-api",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 200,
+    "bodyFileName": "3-r_h_github-api.json",
+    "headers": {
+      "Date": "Wed, 25 Sep 2019 23:35:58 GMT",
+      "Content-Type": "application/json; charset=utf-8",
+      "Server": "GitHub.com",
+      "Status": "200 OK",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4988",
+      "X-RateLimit-Reset": "1569457884",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": [
+        "Accept, Authorization, Cookie, X-GitHub-OTP",
+        "Accept-Encoding"
+      ],
+      "ETag": "W/\"0678d1c39ea574f68cc0fb330b067cb7\"",
+      "Last-Modified": "Wed, 25 Sep 2019 23:32:35 GMT",
+      "X-OAuth-Scopes": "gist, notifications, read:org, read:public_key, read:repo_hook, repo",
+      "X-Accepted-OAuth-Scopes": "repo",
+      "X-GitHub-Media-Type": "unknown, github.v3",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "1; mode=block",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "X-GitHub-Request-Id": "F855:59E1:1397EEB:1714029:5D8BF9DE"
+    }
+  },
+  "uuid": "0a4d7a1a-f99c-47ca-840a-3e920c18bd1f",
+  "persistent": true,
+  "scenarioName": "scenario-1-repos-hub4j-test-org-github-api",
+  "requiredScenarioState": "Started",
+  "newScenarioState": "scenario-1-repos-hub4j-test-org-github-api-2",
+  "insertionIndex": 3
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/mappings/4-r_h_github-api.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/mappings/4-r_h_github-api.json
new file mode 100644
index 000000000..ec44fcf0d
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/syncNoFork/mappings/4-r_h_github-api.json
@@ -0,0 +1,54 @@
+{
+  "id": "2c69d5c8-dd81-4204-bad9-ee37f5b0ebfd",
+  "name": "repos_hub4j-test-org_github-api",
+  "request": {
+    "url": "/repos/hub4j-test-org/github-api/merge-upstream",
+    "method": "POST",
+    "bodyPatterns": [
+      {
+        "equalToJson": "{\"branch\":\"main\"}",
+        "ignoreArrayOrder": true,
+        "ignoreExtraElements": false
+      }
+    ],
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 422,
+    "bodyFileName": "4-r_h_github-api.json",
+    "headers": {
+      "Date": "Wed, 25 Sep 2019 23:35:59 GMT",
+      "Content-Type": "application/json; charset=utf-8",
+      "Server": "GitHub.com",
+      "Status": "422 Unprocessable Entity",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4987",
+      "X-RateLimit-Reset": "1569457884",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": [
+        "Accept, Authorization, Cookie, X-GitHub-OTP",
+        "Accept-Encoding"
+      ],
+      "ETag": "W/\"e40487cafd3670c0de171f4250dbefb8\"",
+      "X-OAuth-Scopes": "gist, notifications, read:org, read:public_key, read:repo_hook, repo",
+      "X-Accepted-OAuth-Scopes": "",
+      "X-GitHub-Media-Type": "unknown, github.v3",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "1; mode=block",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "X-GitHub-Request-Id": "F855:59E1:1397F0E:1714041:5D8BF9DE"
+    }
+  },
+  "uuid": "2c69d5c8-dd81-4204-bad9-ee37f5b0ebfd",
+  "persistent": true,
+  "insertionIndex": 4
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/__files/1-user.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/__files/1-user.json
new file mode 100644
index 000000000..4e07e04a7
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/__files/1-user.json
@@ -0,0 +1,34 @@
+{
+  "login": "ihrigb",
+  "id": 3423161,
+  "node_id": "MDQ6VXNlcjM0MjMxNjE=",
+  "avatar_url": "https://avatars.githubusercontent.com/u/3423161?v=4",
+  "gravatar_id": "",
+  "url": "https://api.github.com/users/ihrigb",
+  "html_url": "https://github.com/ihrigb",
+  "followers_url": "https://api.github.com/users/ihrigb/followers",
+  "following_url": "https://api.github.com/users/ihrigb/following{/other_user}",
+  "gists_url": "https://api.github.com/users/ihrigb/gists{/gist_id}",
+  "starred_url": "https://api.github.com/users/ihrigb/starred{/owner}{/repo}",
+  "subscriptions_url": "https://api.github.com/users/ihrigb/subscriptions",
+  "organizations_url": "https://api.github.com/users/ihrigb/orgs",
+  "repos_url": "https://api.github.com/users/ihrigb/repos",
+  "events_url": "https://api.github.com/users/ihrigb/events{/privacy}",
+  "received_events_url": "https://api.github.com/users/ihrigb/received_events",
+  "type": "User",
+  "site_admin": false,
+  "name": "Benjamin Ihrig",
+  "company": "SAP SE",
+  "blog": "",
+  "location": "Germany",
+  "email": null,
+  "hireable": null,
+  "bio": "Working at @SAP.\r\nDoing software projects for a volunteer fire brigade in free time. Smart home enthusiast. Scuba diving instructor.",
+  "twitter_username": null,
+  "public_repos": 27,
+  "public_gists": 1,
+  "followers": 5,
+  "following": 20,
+  "created_at": "2013-01-30T02:20:16Z",
+  "updated_at": "2024-07-08T08:46:37Z"
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/__files/2-r_i_node-doorbird.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/__files/2-r_i_node-doorbird.json
new file mode 100644
index 000000000..22b2e05ec
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/__files/2-r_i_node-doorbird.json
@@ -0,0 +1,150 @@
+{
+  "id": 404133501,
+  "node_id": "MDEwOlJlcG9zaXRvcnk0MDQxMzM1MDE=",
+  "name": "node-doorbird",
+  "full_name": "ihrigb/node-doorbird",
+  "private": false,
+  "owner": {
+    "login": "ihrigb",
+    "id": 3423161,
+    "node_id": "MDQ6VXNlcjM0MjMxNjE=",
+    "avatar_url": "https://avatars.githubusercontent.com/u/3423161?v=4",
+    "gravatar_id": "",
+    "url": "https://api.github.com/users/ihrigb",
+    "html_url": "https://github.com/ihrigb",
+    "followers_url": "https://api.github.com/users/ihrigb/followers",
+    "following_url": "https://api.github.com/users/ihrigb/following{/other_user}",
+    "gists_url": "https://api.github.com/users/ihrigb/gists{/gist_id}",
+    "starred_url": "https://api.github.com/users/ihrigb/starred{/owner}{/repo}",
+    "subscriptions_url": "https://api.github.com/users/ihrigb/subscriptions",
+    "organizations_url": "https://api.github.com/users/ihrigb/orgs",
+    "repos_url": "https://api.github.com/users/ihrigb/repos",
+    "events_url": "https://api.github.com/users/ihrigb/events{/privacy}",
+    "received_events_url": "https://api.github.com/users/ihrigb/received_events",
+    "type": "User",
+    "site_admin": false
+  },
+  "html_url": "https://github.com/ihrigb/node-doorbird",
+  "description": "Node client library for Doorbird's HTTP API.",
+  "fork": false,
+  "url": "https://api.github.com/repos/ihrigb/node-doorbird",
+  "forks_url": "https://api.github.com/repos/ihrigb/node-doorbird/forks",
+  "keys_url": "https://api.github.com/repos/ihrigb/node-doorbird/keys{/key_id}",
+  "collaborators_url": "https://api.github.com/repos/ihrigb/node-doorbird/collaborators{/collaborator}",
+  "teams_url": "https://api.github.com/repos/ihrigb/node-doorbird/teams",
+  "hooks_url": "https://api.github.com/repos/ihrigb/node-doorbird/hooks",
+  "issue_events_url": "https://api.github.com/repos/ihrigb/node-doorbird/issues/events{/number}",
+  "events_url": "https://api.github.com/repos/ihrigb/node-doorbird/events",
+  "assignees_url": "https://api.github.com/repos/ihrigb/node-doorbird/assignees{/user}",
+  "branches_url": "https://api.github.com/repos/ihrigb/node-doorbird/branches{/branch}",
+  "tags_url": "https://api.github.com/repos/ihrigb/node-doorbird/tags",
+  "blobs_url": "https://api.github.com/repos/ihrigb/node-doorbird/git/blobs{/sha}",
+  "git_tags_url": "https://api.github.com/repos/ihrigb/node-doorbird/git/tags{/sha}",
+  "git_refs_url": "https://api.github.com/repos/ihrigb/node-doorbird/git/refs{/sha}",
+  "trees_url": "https://api.github.com/repos/ihrigb/node-doorbird/git/trees{/sha}",
+  "statuses_url": "https://api.github.com/repos/ihrigb/node-doorbird/statuses/{sha}",
+  "languages_url": "https://api.github.com/repos/ihrigb/node-doorbird/languages",
+  "stargazers_url": "https://api.github.com/repos/ihrigb/node-doorbird/stargazers",
+  "contributors_url": "https://api.github.com/repos/ihrigb/node-doorbird/contributors",
+  "subscribers_url": "https://api.github.com/repos/ihrigb/node-doorbird/subscribers",
+  "subscription_url": "https://api.github.com/repos/ihrigb/node-doorbird/subscription",
+  "commits_url": "https://api.github.com/repos/ihrigb/node-doorbird/commits{/sha}",
+  "git_commits_url": "https://api.github.com/repos/ihrigb/node-doorbird/git/commits{/sha}",
+  "comments_url": "https://api.github.com/repos/ihrigb/node-doorbird/comments{/number}",
+  "issue_comment_url": "https://api.github.com/repos/ihrigb/node-doorbird/issues/comments{/number}",
+  "contents_url": "https://api.github.com/repos/ihrigb/node-doorbird/contents/{+path}",
+  "compare_url": "https://api.github.com/repos/ihrigb/node-doorbird/compare/{base}...{head}",
+  "merges_url": "https://api.github.com/repos/ihrigb/node-doorbird/merges",
+  "archive_url": "https://api.github.com/repos/ihrigb/node-doorbird/{archive_format}{/ref}",
+  "downloads_url": "https://api.github.com/repos/ihrigb/node-doorbird/downloads",
+  "issues_url": "https://api.github.com/repos/ihrigb/node-doorbird/issues{/number}",
+  "pulls_url": "https://api.github.com/repos/ihrigb/node-doorbird/pulls{/number}",
+  "milestones_url": "https://api.github.com/repos/ihrigb/node-doorbird/milestones{/number}",
+  "notifications_url": "https://api.github.com/repos/ihrigb/node-doorbird/notifications{?since,all,participating}",
+  "labels_url": "https://api.github.com/repos/ihrigb/node-doorbird/labels{/name}",
+  "releases_url": "https://api.github.com/repos/ihrigb/node-doorbird/releases{/id}",
+  "deployments_url": "https://api.github.com/repos/ihrigb/node-doorbird/deployments",
+  "created_at": "2021-09-07T21:58:15Z",
+  "updated_at": "2024-07-01T18:54:00Z",
+  "pushed_at": "2024-07-10T21:44:07Z",
+  "git_url": "git://github.com/ihrigb/node-doorbird.git",
+  "ssh_url": "git@github.com:ihrigb/node-doorbird.git",
+  "clone_url": "https://github.com/ihrigb/node-doorbird.git",
+  "svn_url": "https://github.com/ihrigb/node-doorbird",
+  "homepage": "",
+  "size": 1055,
+  "stargazers_count": 4,
+  "watchers_count": 4,
+  "language": "TypeScript",
+  "has_issues": true,
+  "has_projects": false,
+  "has_downloads": true,
+  "has_wiki": false,
+  "has_pages": false,
+  "has_discussions": false,
+  "forks_count": 2,
+  "mirror_url": null,
+  "archived": false,
+  "disabled": false,
+  "open_issues_count": 5,
+  "license": {
+    "key": "apache-2.0",
+    "name": "Apache License 2.0",
+    "spdx_id": "Apache-2.0",
+    "url": "https://api.github.com/licenses/apache-2.0",
+    "node_id": "MDc6TGljZW5zZTI="
+  },
+  "allow_forking": true,
+  "is_template": false,
+  "web_commit_signoff_required": false,
+  "topics": [
+    "client-library",
+    "doorbell",
+    "doorbird",
+    "library",
+    "smarthome"
+  ],
+  "visibility": "public",
+  "forks": 2,
+  "open_issues": 5,
+  "watchers": 4,
+  "default_branch": "main",
+  "permissions": {
+    "admin": true,
+    "maintain": true,
+    "push": true,
+    "triage": true,
+    "pull": true
+  },
+  "temp_clone_token": "",
+  "allow_squash_merge": true,
+  "allow_merge_commit": true,
+  "allow_rebase_merge": true,
+  "allow_auto_merge": false,
+  "delete_branch_on_merge": false,
+  "allow_update_branch": false,
+  "use_squash_pr_title_as_default": false,
+  "squash_merge_commit_message": "COMMIT_MESSAGES",
+  "squash_merge_commit_title": "COMMIT_OR_PR_TITLE",
+  "merge_commit_message": "PR_TITLE",
+  "merge_commit_title": "MERGE_MESSAGE",
+  "security_and_analysis": {
+    "secret_scanning": {
+      "status": "disabled"
+    },
+    "secret_scanning_push_protection": {
+      "status": "disabled"
+    },
+    "dependabot_security_updates": {
+      "status": "disabled"
+    },
+    "secret_scanning_non_provider_patterns": {
+      "status": "disabled"
+    },
+    "secret_scanning_validity_checks": {
+      "status": "disabled"
+    }
+  },
+  "network_count": 2,
+  "subscribers_count": 6
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/__files/3-r_i_n_rules_branches_main.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/__files/3-r_i_n_rules_branches_main.json
new file mode 100644
index 000000000..82223a475
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/__files/3-r_i_n_rules_branches_main.json
@@ -0,0 +1,27 @@
+[
+  {
+    "type": "deletion",
+    "ruleset_source_type": "Repository",
+    "ruleset_source": "ihrigb/node-doorbird",
+    "ruleset_id": 1170520
+  },
+  {
+    "type": "non_fast_forward",
+    "ruleset_source_type": "Repository",
+    "ruleset_source": "ihrigb/node-doorbird",
+    "ruleset_id": 1170520
+  },
+  {
+    "type": "pull_request",
+    "parameters": {
+      "required_approving_review_count": 1,
+      "dismiss_stale_reviews_on_push": true,
+      "require_code_owner_review": false,
+      "require_last_push_approval": false,
+      "required_review_thread_resolution": false
+    },
+    "ruleset_source_type": "Repository",
+    "ruleset_source": "ihrigb/node-doorbird",
+    "ruleset_id": 1170520
+  }
+]
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/mappings/1-user.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/mappings/1-user.json
new file mode 100644
index 000000000..4bc414dbf
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/mappings/1-user.json
@@ -0,0 +1,48 @@
+{
+  "id": "3db4f955-4396-42bc-9025-19cf605fc06c",
+  "name": "user",
+  "request": {
+    "url": "/user",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 200,
+    "bodyFileName": "1-user.json",
+    "headers": {
+      "Date": "Mon, 15 Jul 2024 08:30:49 GMT",
+      "Content-Type": "application/json; charset=utf-8",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": "Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With",
+      "ETag": "W/\"ddc9069d08e23a7137c1afd3a7582b40343a9531d163859e421e699865eed231\"",
+      "Last-Modified": "Mon, 08 Jul 2024 08:46:37 GMT",
+      "X-OAuth-Scopes": "admin:org, repo",
+      "X-Accepted-OAuth-Scopes": "",
+      "github-authentication-token-expiration": "2024-08-14 08:24:53 UTC",
+      "X-GitHub-Media-Type": "github.v3; format=json",
+      "x-github-api-version-selected": "2022-11-28",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4986",
+      "X-RateLimit-Reset": "1721035644",
+      "X-RateLimit-Used": "14",
+      "X-RateLimit-Resource": "core",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "0",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "Server": "github.com",
+      "X-GitHub-Request-Id": "2F9F:1AB9D3:A03037B:A25F83C:6694DE39"
+    }
+  },
+  "uuid": "3db4f955-4396-42bc-9025-19cf605fc06c",
+  "persistent": true,
+  "insertionIndex": 1
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/mappings/2-r_i_node-doorbird.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/mappings/2-r_i_node-doorbird.json
new file mode 100644
index 000000000..8345afaed
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/mappings/2-r_i_node-doorbird.json
@@ -0,0 +1,48 @@
+{
+  "id": "348f8bdb-afc0-42cf-8160-bf3bf5596ed7",
+  "name": "repos_ihrigb_node-doorbird",
+  "request": {
+    "url": "/repos/ihrigb/node-doorbird",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 200,
+    "bodyFileName": "2-r_i_node-doorbird.json",
+    "headers": {
+      "Date": "Mon, 15 Jul 2024 08:30:49 GMT",
+      "Content-Type": "application/json; charset=utf-8",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": "Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With",
+      "ETag": "W/\"185e10d64c2a19173cb1150148d87a1c0da1f66d8b553c79689f0a5e73143d30\"",
+      "Last-Modified": "Mon, 01 Jul 2024 18:54:00 GMT",
+      "X-OAuth-Scopes": "admin:org, repo",
+      "X-Accepted-OAuth-Scopes": "repo",
+      "github-authentication-token-expiration": "2024-08-14 08:24:53 UTC",
+      "X-GitHub-Media-Type": "github.v3; format=json",
+      "x-github-api-version-selected": "2022-11-28",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4984",
+      "X-RateLimit-Reset": "1721035644",
+      "X-RateLimit-Used": "16",
+      "X-RateLimit-Resource": "core",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "0",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "Server": "github.com",
+      "X-GitHub-Request-Id": "442E:34EF67:55A9DC3:56E9441:6694DE39"
+    }
+  },
+  "uuid": "348f8bdb-afc0-42cf-8160-bf3bf5596ed7",
+  "persistent": true,
+  "insertionIndex": 2
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/mappings/3-r_i_n_rules_branches_main.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/mappings/3-r_i_n_rules_branches_main.json
new file mode 100644
index 000000000..8f7a60dd1
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/testGetRulesForBranch/mappings/3-r_i_n_rules_branches_main.json
@@ -0,0 +1,47 @@
+{
+  "id": "5d5471fe-6842-47d0-876e-0083b8d7708f",
+  "name": "repos_ihrigb_node-doorbird_rules_branches_main",
+  "request": {
+    "url": "/repos/ihrigb/node-doorbird/rules/branches/main",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 200,
+    "bodyFileName": "3-r_i_n_rules_branches_main.json",
+    "headers": {
+      "Date": "Mon, 15 Jul 2024 08:30:50 GMT",
+      "Content-Type": "application/json; charset=utf-8",
+      "Cache-Control": "private, max-age=60, s-maxage=60",
+      "Vary": "Accept, Authorization, Cookie, X-GitHub-OTP,Accept-Encoding, Accept, X-Requested-With",
+      "ETag": "W/\"bfdf4f7b088f8bb098a04db8694a3e420c4e6953de47a7a0fb0f1c8f756a1854\"",
+      "X-OAuth-Scopes": "admin:org, repo",
+      "X-Accepted-OAuth-Scopes": "",
+      "github-authentication-token-expiration": "2024-08-14 08:24:53 UTC",
+      "X-GitHub-Media-Type": "github.v3; format=json",
+      "x-github-api-version-selected": "2022-11-28",
+      "X-RateLimit-Limit": "5000",
+      "X-RateLimit-Remaining": "4983",
+      "X-RateLimit-Reset": "1721035644",
+      "X-RateLimit-Used": "17",
+      "X-RateLimit-Resource": "core",
+      "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset",
+      "Access-Control-Allow-Origin": "*",
+      "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload",
+      "X-Frame-Options": "deny",
+      "X-Content-Type-Options": "nosniff",
+      "X-XSS-Protection": "0",
+      "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "Content-Security-Policy": "default-src 'none'",
+      "Server": "github.com",
+      "X-GitHub-Request-Id": "E229:31B5A3:74633C:759FE7:6694DE39"
+    }
+  },
+  "uuid": "5d5471fe-6842-47d0-876e-0083b8d7708f",
+  "persistent": true,
+  "insertionIndex": 3
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHUserTest/wiremock/verifySuspendedAt/__files/1-users_normal.json b/src/test/resources/org/kohsuke/github/GHUserTest/wiremock/verifySuspendedAt/__files/1-users_normal.json
new file mode 100644
index 000000000..11ffa2db9
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHUserTest/wiremock/verifySuspendedAt/__files/1-users_normal.json
@@ -0,0 +1,35 @@
+{
+  "login": "kartikpatodi",
+  "id": 23272937,
+  "node_id": "MDQ6VXNlcjIzMjcyOTM3",
+  "avatar_url": "https://avatars.githubusercontent.com/u/23272937?v=4",
+  "gravatar_id": "",
+  "url": "https://api.github.com/users/kartikpatodi",
+  "html_url": "https://github.com/kartikpatodi",
+  "followers_url": "https://api.github.com/users/kartikpatodi/followers",
+  "following_url": "https://api.github.com/users/kartikpatodi/following{/other_user}",
+  "gists_url": "https://api.github.com/users/kartikpatodi/gists{/gist_id}",
+  "starred_url": "https://api.github.com/users/kartikpatodi/starred{/owner}{/repo}",
+  "subscriptions_url": "https://api.github.com/users/kartikpatodi/subscriptions",
+  "organizations_url": "https://api.github.com/users/kartikpatodi/orgs",
+  "repos_url": "https://api.github.com/users/kartikpatodi/repos",
+  "events_url": "https://api.github.com/users/kartikpatodi/events{/privacy}",
+  "received_events_url": "https://api.github.com/users/kartikpatodi/received_events",
+  "type": "User",
+  "ldap_dn": "CN=kartikpatodi,OU=Users,DC=github,DC=com",
+  "site_admin": false,
+  "name": "Kartik Patodi",
+  "company": null,
+  "blog": "",
+  "location": "Nimbahera, Rajasthan, India",
+  "email": null,
+  "hireable": null,
+  "bio": null,
+  "twitter_username": "kartikpatodi",
+  "public_repos": 12,
+  "public_gists": 0,
+  "followers": 2,
+  "following": 7,
+  "created_at": "2016-11-05T05:01:41Z",
+  "updated_at": "2022-02-24T13:54:34Z"
+}
\ No newline at end of file
diff --git a/src/test/resources/org/kohsuke/github/GHUserTest/wiremock/verifySuspendedAt/__files/1-users_suspended.json b/src/test/resources/org/kohsuke/github/GHUserTest/wiremock/verifySuspendedAt/__files/1-users_suspended.json
new file mode 100644
index 000000000..74546e01f
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHUserTest/wiremock/verifySuspendedAt/__files/1-users_suspended.json
@@ -0,0 +1,36 @@
+{
+  "login": "kartikpatodi",
+  "id": 23272937,
+  "node_id": "MDQ6VXNlcjIzMjcyOTM3",
+  "avatar_url": "https://avatars.githubusercontent.com/u/23272937?v=4",
+  "gravatar_id": "",
+  "url": "https://api.github.com/users/kartikpatodi",
+  "html_url": "https://github.com/kartikpatodi",
+  "followers_url": "https://api.github.com/users/kartikpatodi/followers",
+  "following_url": "https://api.github.com/users/kartikpatodi/following{/other_user}",
+  "gists_url": "https://api.github.com/users/kartikpatodi/gists{/gist_id}",
+  "starred_url": "https://api.github.com/users/kartikpatodi/starred{/owner}{/repo}",
+  "subscriptions_url": "https://api.github.com/users/kartikpatodi/subscriptions",
+  "organizations_url": "https://api.github.com/users/kartikpatodi/orgs",
+  "repos_url": "https://api.github.com/users/kartikpatodi/repos",
+  "events_url": "https://api.github.com/users/kartikpatodi/events{/privacy}",
+  "received_events_url": "https://api.github.com/users/kartikpatodi/received_events",
+  "type": "User",
+  "ldap_dn": "CN=kartikpatodi,OU=Users,DC=github,DC=com",
+  "site_admin": false,
+  "name": "Kartik Patodi",
+  "company": null,
+  "blog": "",
+  "location": "Nimbahera, Rajasthan, India",
+  "email": null,
+  "hireable": null,
+  "bio": null,
+  "twitter_username": "kartikpatodi",
+  "public_repos": 12,
+  "public_gists": 0,
+  "followers": 2,
+  "following": 7,
+  "created_at": "2016-11-05T05:01:41Z",
+  "updated_at": "2022-02-24T13:54:34Z",
+  "suspended_at": "2024-08-08T00:00:00Z"
+}
diff --git a/src/test/resources/org/kohsuke/github/GHUserTest/wiremock/verifySuspendedAt/mappings/1-users_normal.json b/src/test/resources/org/kohsuke/github/GHUserTest/wiremock/verifySuspendedAt/mappings/1-users_normal.json
new file mode 100644
index 000000000..c9cdc7013
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHUserTest/wiremock/verifySuspendedAt/mappings/1-users_normal.json
@@ -0,0 +1,41 @@
+{
+  "name": "users_normal",
+  "request": {
+    "url": "/users/normal",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 200,
+    "bodyFileName": "1-users_normal.json",
+    "headers": {
+      "server": "GitHub.com",
+      "date": "Mon, 04 Apr 2022 19:10:00 GMT",
+      "content-type": "application/json; charset=utf-8",
+      "status": "200 OK",
+      "cache-control": "public, max-age=60, s-maxage=60",
+      "vary": "Accept, Accept-Encoding, Accept, X-Requested-With",
+      "etag": "W/\"960f568b7a2dd1591a136e36748cc44e\"",
+      "last-modified": "Thu, 24 Feb 2022 13:54:34 GMT",
+      "x-github-media-type": "unknown, github.v3",
+      "strict-transport-security": "max-age=31536000; includeSubdomains; preload",
+      "x-frame-options": "deny",
+      "x-content-type-options": "nosniff",
+      "x-xss-protection": "1; mode=block",
+      "referrer-policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "content-security-policy": "default-src 'none'",
+      "X-Ratelimit-Limit": "60",
+      "X-Ratelimit-Remaining": "47",
+      "X-Ratelimit-Reset": "1649100347",
+      "Accept-Ranges": "bytes",
+      "X-GitHub-Request-Id": "45F4:0D15:1B4EE4:373E4C:624B4288"
+    }
+  },
+  "uuid": "39860a04-002b-45da-aae7-70c97031c79e",
+  "persistent": true,
+  "insertionIndex": 1
+}
diff --git a/src/test/resources/org/kohsuke/github/GHUserTest/wiremock/verifySuspendedAt/mappings/1-users_suspended.json b/src/test/resources/org/kohsuke/github/GHUserTest/wiremock/verifySuspendedAt/mappings/1-users_suspended.json
new file mode 100644
index 000000000..15654a081
--- /dev/null
+++ b/src/test/resources/org/kohsuke/github/GHUserTest/wiremock/verifySuspendedAt/mappings/1-users_suspended.json
@@ -0,0 +1,41 @@
+{
+  "name": "users_suspended",
+  "request": {
+    "url": "/users/suspended",
+    "method": "GET",
+    "headers": {
+      "Accept": {
+        "equalTo": "application/vnd.github+json"
+      }
+    }
+  },
+  "response": {
+    "status": 200,
+    "bodyFileName": "1-users_suspended.json",
+    "headers": {
+      "server": "GitHub.com",
+      "date": "Mon, 04 Apr 2022 19:10:00 GMT",
+      "content-type": "application/json; charset=utf-8",
+      "status": "200 OK",
+      "cache-control": "public, max-age=60, s-maxage=60",
+      "vary": "Accept, Accept-Encoding, Accept, X-Requested-With",
+      "etag": "W/\"960f568b7a2dd1591a136e36748cc44e\"",
+      "last-modified": "Thu, 24 Feb 2022 13:54:34 GMT",
+      "x-github-media-type": "unknown, github.v3",
+      "strict-transport-security": "max-age=31536000; includeSubdomains; preload",
+      "x-frame-options": "deny",
+      "x-content-type-options": "nosniff",
+      "x-xss-protection": "1; mode=block",
+      "referrer-policy": "origin-when-cross-origin, strict-origin-when-cross-origin",
+      "content-security-policy": "default-src 'none'",
+      "X-Ratelimit-Limit": "60",
+      "X-Ratelimit-Remaining": "47",
+      "X-Ratelimit-Reset": "1649100347",
+      "Accept-Ranges": "bytes",
+      "X-GitHub-Request-Id": "45F4:0D15:1B4EE4:373E4C:624B4288"
+    }
+  },
+  "uuid": "39860a04-002b-45da-aae7-70c97031c79e",
+  "persistent": true,
+  "insertionIndex": 1
+}