diff --git a/.github/actions/get-changed-files/get-changed-files.sh b/.github/actions/get-changed-files/get-changed-files.sh index c9e25549f1de..a2f49f8b0d93 100755 --- a/.github/actions/get-changed-files/get-changed-files.sh +++ b/.github/actions/get-changed-files/get-changed-files.sh @@ -18,8 +18,9 @@ git fetch --depth=1 origin main git fetch --depth=1 origin ${INPUT_HEAD:-HEAD} # Get diff with status information +# Find the merge-base (common ancestor) instead of using origin/main directly echo "__ running git diff with status __" -DIFF_OUTPUT=$(git diff --name-status origin/main origin/${INPUT_HEAD:-HEAD}) +DIFF_OUTPUT=$(git diff --name-status origin/main...origin/${INPUT_HEAD:-HEAD}) # Function to extract files by pattern from diff output extract_files() { diff --git a/.github/workflows/article-api-docs.yml b/.github/workflows/article-api-docs.yml index be55be40cb46..4f87a815b93b 100644 --- a/.github/workflows/article-api-docs.yml +++ b/.github/workflows/article-api-docs.yml @@ -18,7 +18,7 @@ permissions: jobs: check-content-linter-rules-docs: - runs-on: ${{ fromJSON('["ubuntu-latest", "ubuntu-20.04-xl"]')[github.repository == 'github/docs-internal'] }} + runs-on: ubuntu-latest if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' steps: - name: Checkout diff --git a/.github/workflows/content-lint-markdown.yml b/.github/workflows/content-lint-markdown.yml index ac80a26e1fbf..f097e34e364b 100644 --- a/.github/workflows/content-lint-markdown.yml +++ b/.github/workflows/content-lint-markdown.yml @@ -20,7 +20,7 @@ permissions: jobs: lint-content: if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - runs-on: ${{ fromJSON('["ubuntu-latest", "ubuntu-20.04-xl"]')[github.repository == 'github/docs-internal'] }} + runs-on: ubuntu-latest steps: - name: Check out repo uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 diff --git a/.github/workflows/content-linter-rules-docs.yml b/.github/workflows/content-linter-rules-docs.yml index ebdcb64ca5a6..fe1dc03ca736 100644 --- a/.github/workflows/content-linter-rules-docs.yml +++ b/.github/workflows/content-linter-rules-docs.yml @@ -21,7 +21,7 @@ permissions: jobs: check-content-linter-rules-docs: - runs-on: ${{ fromJSON('["ubuntu-latest", "ubuntu-20.04-xl"]')[github.repository == 'github/docs-internal'] }} + runs-on: ubuntu-latest if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' steps: - name: Checkout diff --git a/.github/workflows/count-translation-corruptions.yml b/.github/workflows/count-translation-corruptions.yml index 87c96c225b0a..9b6b134a666b 100644 --- a/.github/workflows/count-translation-corruptions.yml +++ b/.github/workflows/count-translation-corruptions.yml @@ -21,7 +21,7 @@ permissions: jobs: count-translation-corruptions: if: github.repository == 'github/docs-internal' - runs-on: ubuntu-20.04-xl + runs-on: ubuntu-latest steps: - name: Checkout English repo uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 diff --git a/.github/workflows/generate-code-scanning-query-lists.yml b/.github/workflows/generate-code-scanning-query-lists.yml index 1c62e4e779b1..200b5b3527db 100644 --- a/.github/workflows/generate-code-scanning-query-lists.yml +++ b/.github/workflows/generate-code-scanning-query-lists.yml @@ -29,7 +29,7 @@ permissions: jobs: generate-query-lists: if: github.repository == 'github/docs-internal' - runs-on: ubuntu-20.04-xl + runs-on: ubuntu-latest steps: - name: Checkout repository code uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 diff --git a/.github/workflows/headless-tests.yml b/.github/workflows/headless-tests.yml index 5c1ced60b3ff..6b1f78b76a41 100644 --- a/.github/workflows/headless-tests.yml +++ b/.github/workflows/headless-tests.yml @@ -25,7 +25,7 @@ env: jobs: playwright-tests: if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - runs-on: ${{ fromJSON('["ubuntu-latest", "ubuntu-20.04-xl"]')[github.repository == 'github/docs-internal'] }} + runs-on: ubuntu-latest strategy: # When we're comfortable a11y tests aren't generating false positives and helping, # let's remove the matrix and just run playwright in a single job. diff --git a/.github/workflows/index-autocomplete-search.yml b/.github/workflows/index-autocomplete-search.yml index fb9fdfe8924a..79582d796aca 100644 --- a/.github/workflows/index-autocomplete-search.yml +++ b/.github/workflows/index-autocomplete-search.yml @@ -20,7 +20,7 @@ permissions: jobs: index-autocomplete-elasticsearch: if: ${{ github.repository == 'github/docs-internal' }} - runs-on: ubuntu-20.04-xl + runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 diff --git a/.github/workflows/index-general-search-pr.yml b/.github/workflows/index-general-search-pr.yml index 70e565cf25ee..96127559d3c9 100644 --- a/.github/workflows/index-general-search-pr.yml +++ b/.github/workflows/index-general-search-pr.yml @@ -33,7 +33,7 @@ env: jobs: dryRunElasticsearchIndexes: - runs-on: ubuntu-20.04-xl + runs-on: ubuntu-latest if: github.repository == 'github/docs-internal' steps: - name: Check out repo diff --git a/.github/workflows/index-general-search.yml b/.github/workflows/index-general-search.yml index 90e086b3cf7a..ce4abbbef3c0 100644 --- a/.github/workflows/index-general-search.yml +++ b/.github/workflows/index-general-search.yml @@ -98,7 +98,7 @@ jobs: needs: figureOutMatrix name: Update indexes if: ${{ github.repository == 'github/docs-internal' && needs.figureOutMatrix.outputs.matrix != '[]' }} - runs-on: ubuntu-20.04-xl + runs-on: ubuntu-latest strategy: fail-fast: false # When it's only English (i.e. a simple array of ['en']), this value diff --git a/.github/workflows/keep-caches-warm.yml b/.github/workflows/keep-caches-warm.yml index 35163e1fd608..04daa6d9c045 100644 --- a/.github/workflows/keep-caches-warm.yml +++ b/.github/workflows/keep-caches-warm.yml @@ -26,7 +26,7 @@ permissions: jobs: keep-caches-warm: if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - runs-on: ${{ fromJSON('["ubuntu-latest", "ubuntu-20.04-xl"]')[github.repository == 'github/docs-internal'] }} + runs-on: ubuntu-latest steps: - name: Check out repo uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 diff --git a/.github/workflows/link-check-daily.yml b/.github/workflows/link-check-daily.yml index 9c4ffa005529..1f0876acbd22 100644 --- a/.github/workflows/link-check-daily.yml +++ b/.github/workflows/link-check-daily.yml @@ -17,7 +17,7 @@ jobs: check_all_english_links: name: Check all links if: github.repository == 'github/docs-internal' - runs-on: ubuntu-20.04-xl + runs-on: ubuntu-latest steps: - name: Check that gh CLI is installed run: gh --version diff --git a/.github/workflows/link-check-on-pr.yml b/.github/workflows/link-check-on-pr.yml index df5d39e47d77..c91fe77e9324 100644 --- a/.github/workflows/link-check-on-pr.yml +++ b/.github/workflows/link-check-on-pr.yml @@ -22,7 +22,7 @@ concurrency: jobs: check-links: - runs-on: ${{ fromJSON('["ubuntu-latest", "ubuntu-20.04-xl"]')[github.repository == 'github/docs-internal'] }} + runs-on: ubuntu-latest if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' steps: - name: Checkout diff --git a/.github/workflows/lint-code.yml b/.github/workflows/lint-code.yml index 0ee0a8758b3a..7506716f6d66 100644 --- a/.github/workflows/lint-code.yml +++ b/.github/workflows/lint-code.yml @@ -20,7 +20,7 @@ concurrency: jobs: lint-code: if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - runs-on: ${{ fromJSON('["ubuntu-latest", "ubuntu-20.04-xl"]')[github.repository == 'github/docs-internal'] }} + runs-on: ubuntu-latest steps: - name: Check out repo uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 diff --git a/.github/workflows/lint-entire-content-data-markdown.yml b/.github/workflows/lint-entire-content-data-markdown.yml index b2d57e2e3699..42699314f95d 100644 --- a/.github/workflows/lint-entire-content-data-markdown.yml +++ b/.github/workflows/lint-entire-content-data-markdown.yml @@ -17,7 +17,7 @@ jobs: lint-entire-content-data: name: Lint entire content and data directories if: github.repository == 'github/docs-internal' - runs-on: ubuntu-20.04-xl + runs-on: ubuntu-latest steps: - name: Check that gh CLI is installed run: gh --version diff --git a/.github/workflows/local-dev.yml b/.github/workflows/local-dev.yml index 55acf15eafb5..1b6d0d4b3603 100644 --- a/.github/workflows/local-dev.yml +++ b/.github/workflows/local-dev.yml @@ -16,7 +16,7 @@ permissions: jobs: local-dev: if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - runs-on: ${{ fromJSON('["ubuntu-latest", "ubuntu-20.04-xl"]')[github.repository == 'github/docs-internal'] }} + runs-on: ubuntu-latest steps: - name: Check out repo uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 @@ -51,7 +51,7 @@ jobs: PLAYWRIGHT_RETRIES: 0 TEST_EARLY_ACCESS: ${{ github.repository == 'github/docs-internal' }} # workaround for https://github.com/nodejs/node/issues/59364 as of 22.18.0 - NODE_OPTIONS: '--no-experimental-strip-types' + NODE_OPTIONS: '--no-experimental-strip-types --max-old-space-size=8192' run: npm run playwright-test -- playwright-local-dev - name: Start server in the background diff --git a/.github/workflows/readability.yml b/.github/workflows/readability.yml index bc338c130714..32ffec056a33 100644 --- a/.github/workflows/readability.yml +++ b/.github/workflows/readability.yml @@ -25,7 +25,7 @@ permissions: jobs: readability-analysis: if: github.repository == 'github/docs-internal' - runs-on: ${{ fromJSON('["ubuntu-latest", "ubuntu-20.04-xl"]')[github.repository == 'github/docs-internal'] }} + runs-on: ubuntu-latest steps: - name: Check out repo with full history uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 diff --git a/.github/workflows/sync-openapi.yml b/.github/workflows/sync-openapi.yml index 4344dd0ff801..f43b9ccc6666 100644 --- a/.github/workflows/sync-openapi.yml +++ b/.github/workflows/sync-openapi.yml @@ -27,7 +27,7 @@ concurrency: jobs: generate-decorated-files: if: github.repository == 'github/docs-internal' - runs-on: ubuntu-20.04-xl + runs-on: ubuntu-latest steps: - name: Checkout repository code uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 diff --git a/.github/workflows/test-changed-content.yml b/.github/workflows/test-changed-content.yml index fa7f56180243..2e2548c7b77a 100644 --- a/.github/workflows/test-changed-content.yml +++ b/.github/workflows/test-changed-content.yml @@ -21,7 +21,7 @@ permissions: jobs: test-changed-content: - runs-on: ${{ fromJSON('["ubuntu-latest", "ubuntu-20.04-xl"]')[github.repository == 'github/docs-internal'] }} + runs-on: ubuntu-latest if: ${{ github.repository == 'github/docs-internal' || github.repository == 'github/docs' }} steps: # Each of these ifs needs to be repeated at each step to make sure the required check still runs diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index be7019e9b837..e9892fffcea0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,10 +27,7 @@ jobs: test: name: ${{ matrix.name }} if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - - # Run on ubuntu-20.04-xl if the private repo or ubuntu-latest if the public repo - # See pull # 17442 in the private repo for context - runs-on: ${{ fromJSON('["ubuntu-latest", "ubuntu-20.04-xl"]')[github.repository == 'github/docs-internal'] }} + runs-on: ubuntu-latest timeout-minutes: 60 strategy: fail-fast: false diff --git a/.github/workflows/validate-github-github-docs-urls.yml b/.github/workflows/validate-github-github-docs-urls.yml index 4f5609b0f490..d53df2636b5e 100644 --- a/.github/workflows/validate-github-github-docs-urls.yml +++ b/.github/workflows/validate-github-github-docs-urls.yml @@ -31,7 +31,7 @@ jobs: validate_github_github_docs_urls: name: Validate github/github docs URLs if: github.repository == 'github/docs-internal' - runs-on: ubuntu-20.04-xl + runs-on: ubuntu-latest steps: - name: Check out repo's default branch uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 diff --git a/assets/images/banner-images/hero-1.png b/assets/images/banner-images/hero-1.png new file mode 100644 index 000000000000..60df8ea86ed2 Binary files /dev/null and b/assets/images/banner-images/hero-1.png differ diff --git a/assets/images/banner-images/hero-2.png b/assets/images/banner-images/hero-2.png new file mode 100644 index 000000000000..0d02dfd6c078 Binary files /dev/null and b/assets/images/banner-images/hero-2.png differ diff --git a/assets/images/banner-images/hero-3.png b/assets/images/banner-images/hero-3.png new file mode 100644 index 000000000000..7de28041c963 Binary files /dev/null and b/assets/images/banner-images/hero-3.png differ diff --git a/assets/images/banner-images/hero-4.png b/assets/images/banner-images/hero-4.png new file mode 100644 index 000000000000..8d2bcb1ebaf6 Binary files /dev/null and b/assets/images/banner-images/hero-4.png differ diff --git a/assets/images/banner-images/hero-5.png b/assets/images/banner-images/hero-5.png new file mode 100644 index 000000000000..ef06249436e7 Binary files /dev/null and b/assets/images/banner-images/hero-5.png differ diff --git a/assets/images/banner-images/hero-6.png b/assets/images/banner-images/hero-6.png new file mode 100644 index 000000000000..3f68a2ebdf33 Binary files /dev/null and b/assets/images/banner-images/hero-6.png differ diff --git a/content/account-and-profile/concepts/changing-your-github-username.md b/content/account-and-profile/concepts/changing-your-github-username.md deleted file mode 100644 index fee5f1777ccc..000000000000 --- a/content/account-and-profile/concepts/changing-your-github-username.md +++ /dev/null @@ -1,115 +0,0 @@ ---- -title: Changing your GitHub username -intro: 'You can change the username for your account on {% data variables.product.prodname_dotcom %}{% ifversion ghes %} if your instance uses built-in authentication{% endif %}.' -redirect_from: - - /articles/how-to-change-your-username - - /articles/changing-your-github-user-name - - /articles/renaming-a-user - - /articles/what-happens-when-i-change-my-username - - /articles/changing-your-github-username - - /github/setting-up-and-managing-your-github-user-account/changing-your-github-username - - /github/setting-up-and-managing-your-github-user-account/managing-user-account-settings/changing-your-github-username - - /account-and-profile/setting-up-and-managing-your-github-user-account/managing-user-account-settings/changing-your-github-username - - /account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-personal-account-settings/changing-your-github-username - - /account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-user-account-settings/changing-your-github-username -versions: - fpt: '*' - ghes: '*' - ghec: '*' -topics: - - Accounts -shortTitle: Change your username ---- - -{% ifversion ghec or ghes %} - -{% ifversion ghec %} - -> [!NOTE] -> Members of an {% data variables.enterprise.prodname_emu_enterprise %} cannot change usernames. Your enterprise's IdP administrator controls your {% data variables.product.github %} username. For more information, see [AUTOTITLE](/admin/identity-and-access-management/using-enterprise-managed-users-for-iam/about-enterprise-managed-users). - -{% elsif ghes %} - -> [!NOTE] -> If you sign into {% data variables.location.product_location %} with LDAP credentials or single sign-on (SSO), only your local administrator can change your username. For more information about authentication methods for {% data variables.product.prodname_ghe_server %}, see [AUTOTITLE](/admin/identity-and-access-management/managing-iam-for-your-enterprise). - -{% endif %} - -{% endif %} - -## About username changes - -You can change your username to another username that is not currently in use.{% ifversion fpt or ghec %} If the username you want is not available, consider other names or unique variations. Using a number, hyphen, or an alternative spelling might help you find a similar username that's still available. - -If you hold a trademark for the username, you can find more information about making a trademark complaint on our [Trademark Policy](/free-pro-team@latest/site-policy/content-removal-policies/github-trademark-policy) page. - -If you do not hold a trademark for the name, you can choose another username or keep your current username. {% data variables.contact.github_support %} cannot release the unavailable username for you. For more information, see [Changing your username](#changing-your-username).{% endif %} - -After changing your username, your old username becomes available for anyone else to claim. Most references to your repositories under the old username automatically change to the new username. However, some links to your profile won't automatically redirect. - -{% data variables.product.github %} cannot set up redirects for: -* [@mentions](/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#mentioning-people-and-teams) using your old username -* Links to [gists](/get-started/writing-on-github/editing-and-sharing-content-with-gists/creating-gists) that include your old username - -{% ifversion fpt or ghec %} - -If you're a member of an {% data variables.enterprise.prodname_emu_enterprise %}, you cannot make changes to your username. {% data reusables.enterprise-accounts.emu-more-info-account %} - -{% endif %} - -{% ifversion fpt or ghec %} - -{% data reusables.accounts.rename-account-repo-namespace-retirement %} If you try to create a repository using a retired owner name and repository name combination, you will see the error: "The repository `` has been retired and cannot be reused." - -{% endif %} - -{% data reusables.package_registry.rename-account-namespace-retirement %} - -## Repository references - -After you change your username, {% data variables.product.github %} will automatically redirect references to your repositories. -* Web links to your existing repositories will continue to work. This can take a few minutes to complete after you make the change. -* Command line pushes from your local repository clones to the old remote tracking URLs will continue to work. - -If the new owner of your old username creates a repository with the same name as your repository, that will override the redirect entry and your redirect will stop working. Because of this possibility, we recommend you update all existing remote repository URLs after changing your username. For more information, see [AUTOTITLE](/get-started/git-basics/managing-remote-repositories). - -## Links to your previous profile page - -After changing your username, links to your previous profile page, such as `https://{% data variables.product.product_url %}/previoususername`, will return a 404 error. We recommend updating any links to your profile from elsewhere{% ifversion fpt or ghec %}, such as your LinkedIn or Twitter profile{% endif %}. - -## Accounts logged in on GitHub Mobile - -Accounts logged in on the {% data variables.product.prodname_mobile %} app may continue to display your original username until you log out. To ensure your updated username is displayed, we recommend you sign out and back in to your account on each mobile device. - -## Your Git commits - -If your Git commits are associated with another email address you've added to your {% data variables.product.prodname_dotcom %} account, they'll continue to be attributed to you and appear in your contributions graph after you've changed your username. For more information on setting your email address, see [AUTOTITLE](/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/setting-your-commit-email-address) and [AUTOTITLE](/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/adding-an-email-address-to-your-github-account). - -{% ifversion fpt or ghec %}If you've been using a {% data variables.product.prodname_dotcom %}-provided private commit email address, whether or not your commit history will be retained after an account rename depends on the format of the email address. Git commits that are associated with your {% data variables.product.github %}-provided `noreply` email address won't be attributed to your new username and won't appear in your contributions graph, unless your `noreply` email address is in the form of `ID+USERNAME@users.noreply.github.com`. Older versions of the `noreply` email address that do not contain a numeric ID will not be associated with your {% data variables.product.prodname_dotcom %} account after changing your username.{% endif %} - -> [!WARNING] -> * After a username change, verified commits signed using the previous {% data variables.product.github %}-provided `noreply` email address will lose their "Verified" status. -> * When verifying a signature, {% data variables.product.github %} checks that the email address of the committer or tagger exactly matches one of the email addresses associated with the GPG key's identities. Additionally, {% data variables.product.github %} confirms that the email address is verified and linked to the user's account. This ensures that the key belongs to you and that you created the commit or tag. Because the username of the `noreply` email address changes, these commits can no longer be verified. - -## Your gists - -After changing your username, the URLs to any public or secret gists will also change and previous links to these will return a 404 error. We recommend updating the links to these gists anywhere you may have shared them. - -## CODEOWNERS files - -After changing your username, CODEOWNERS files that include your old username will need to be manually updated. When you view the CODEOWNERS files on {% data variables.product.prodname_dotcom %}, an error message is displayed if the file contains any unknown users, or users without write access. We recommend updating all relevant CODEOWNERS files with your new username. For more information, see [AUTOTITLE](/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners). - -## Changing your username - -{% data reusables.user-settings.access_settings %} -{% data reusables.user-settings.account_settings %} -1. In the "Change username" section, click **Change username**.{% ifversion fpt or ghec %} -1. Read the warnings about changing your username. If you still want to change your username, click **I understand, let's change my username**. -1. Type a new username. -1. If the username you've chosen is available, click **Change my username**. If the username you've chosen is unavailable, you can try a different username or one of the suggestions you see. -{% endif %} - -## Further reading - -* [AUTOTITLE](/pull-requests/committing-changes-to-your-project/troubleshooting-commits/why-are-my-commits-linked-to-the-wrong-user){% ifversion fpt or ghec %} -* [AUTOTITLE](/free-pro-team@latest/site-policy/other-site-policies/github-username-policy){% endif %} diff --git a/content/account-and-profile/concepts/index.md b/content/account-and-profile/concepts/index.md index 19d91b395d2e..5ceb7ce08513 100644 --- a/content/account-and-profile/concepts/index.md +++ b/content/account-and-profile/concepts/index.md @@ -15,8 +15,9 @@ children: - /contributions-visible-on-your-profile - /about-your-organizations-profile - /about-organization-membership - - /changing-your-github-username + - /username-changes - /email-addresses - /scheduled-reminders - /personal-repository-access-and-collaboration --- + diff --git a/content/account-and-profile/concepts/username-changes.md b/content/account-and-profile/concepts/username-changes.md new file mode 100644 index 000000000000..2b2d3daa8618 --- /dev/null +++ b/content/account-and-profile/concepts/username-changes.md @@ -0,0 +1,67 @@ +--- +title: Username changes +intro: You can change the username for your {% data variables.product.github %} account {% ifversion ghes %} if your instance uses built-in authentication{% endif %}. +redirect_from: + - /articles/how-to-change-your-username + - /articles/changing-your-github-user-name + - /articles/renaming-a-user + - /articles/what-happens-when-i-change-my-username + - /articles/changing-your-github-username + - /github/setting-up-and-managing-your-github-user-account/changing-your-github-username + - /github/setting-up-and-managing-your-github-user-account/managing-user-account-settings/changing-your-github-username + - /account-and-profile/setting-up-and-managing-your-github-user-account/managing-user-account-settings/changing-your-github-username + - /account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-personal-account-settings/changing-your-github-username + - /account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-user-account-settings/changing-your-github-username + - /account-and-profile/concepts/changing-your-github-username +versions: + fpt: '*' + ghes: '*' + ghec: '*' +topics: + - Accounts + - Usernames +shortTitle: Username changes +contentType: concepts +--- + +## About username changes + +You can change your username to another username that is not currently in use.{% ifversion fpt or ghec %} If the username you want is not available, consider other names or unique variations. Using a number, hyphen, or an alternative spelling might help you find a similar username that's still available. + +After changing your username, your old username becomes available for anyone else to claim. Most references to your repositories under the old username automatically change to the new username. However, some links to your profile won't automatically redirect. + +## Username trademarks + +If you hold a trademark for the username, you can find more information about making a trademark complaint on our [Trademark Policy](/free-pro-team@latest/site-policy/content-removal-policies/github-trademark-policy) page. + +If you do not hold a trademark for the name, you can choose another username or keep your current username. {% data variables.contact.github_support %} cannot release the unavailable username for you.{% endif %} + +## Repository references + +After you change your username, {% data variables.product.github %} will automatically redirect references to your repositories. + +If the new owner of your old username creates a repository with the same name as your repository, that will override the redirect entry and your redirect will stop working. Because of this possibility, we recommend you update all existing remote repository URLs after changing your username. For more information, see [AUTOTITLE](/get-started/git-basics/managing-remote-repositories). + +## Links to your previous profile page + +After changing your username, links to your previous profile page, such as `https://{% data variables.product.product_url %}/previoususername`, will return a 404 error. We recommend updating any links to your profile from elsewhere{% ifversion fpt or ghec %}, such as your LinkedIn or Twitter profile{% endif %}. + +## Accounts logged in on {% data variables.product.prodname_mobile %} + +Accounts logged in on the {% data variables.product.prodname_mobile %} app may continue to display your original username until you log out. To ensure your updated username is displayed, we recommend you sign out and back in to your account on each mobile device. + +## Your Git commits + +If your Git commits are associated with another email address you've added to your {% data variables.product.github %} account, they'll continue to be attributed to you and appear in your contributions graph after you've changed your username. However, some commits using {% data variables.product.github %}-provided email addresses may be affected. For details, see [AUTOTITLE](/account-and-profile/reference/username-reference#git-commits-after-a-username-change). + +## Your gists + +After changing your username, the URLs to any public or secret gists will also change and previous links to these will return a 404 error. We recommend updating the links to these gists anywhere you may have shared them. + +## CODEOWNERS files + +After changing your username, CODEOWNERS files that include your old username will need to be manually updated. When you view the CODEOWNERS files on {% data variables.product.github %}, an error message is displayed if the file contains any unknown users, or users without write access. We recommend updating all relevant CODEOWNERS files with your new username. + +## Next steps + +To change your username, see [AUTOTITLE](/account-and-profile/how-tos/setting-up-and-managing-your-personal-account-on-github/managing-your-personal-account/changing-your-username). diff --git a/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/index.md b/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/index.md index 7c90ee9a5c65..aa03da2a625d 100644 --- a/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/index.md +++ b/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/index.md @@ -15,10 +15,10 @@ topics: children: - /showing-an-overview-of-your-activity-on-your-profile - /viewing-contributions-on-your-profile - - /showing-your-private-contributions-and-achievements-on-your-profile + - /manage-visibility-settings-for-private-contributions-and-achievements - /sharing-contributions-from-github-enterprise-server - /troubleshooting-missing-contributions - - /troubleshooting-commits-on-your-timeline + - /viewing-commit-details-from-your-timeline shortTitle: Manage contribution settings --- diff --git a/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/showing-your-private-contributions-and-achievements-on-your-profile.md b/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/manage-visibility-settings-for-private-contributions-and-achievements.md similarity index 50% rename from content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/showing-your-private-contributions-and-achievements-on-your-profile.md rename to content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/manage-visibility-settings-for-private-contributions-and-achievements.md index c28e94b8e61b..5218710c5de2 100644 --- a/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/showing-your-private-contributions-and-achievements-on-your-profile.md +++ b/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/manage-visibility-settings-for-private-contributions-and-achievements.md @@ -1,38 +1,26 @@ --- -title: 'Showing your private contributions {% ifversion hide-individual-achievements %}and achievements {% endif %}on your profile' -intro: Your profile shows a graph of your repository contributions over the past year. You can choose to show anonymized activity from private and internal repositories in addition to the activity from public repositories. +title: Manage visibility settings for private contributions {% ifversion hide-individual-achievements %}and achievements {% endif %} +intro: Show anonymized activity from private and internal repositories. redirect_from: - /articles/publicizing-or-hiding-your-private-contributions-on-your-profile - /github/setting-up-and-managing-your-github-profile/publicizing-or-hiding-your-private-contributions-on-your-profile - /github/setting-up-and-managing-your-github-profile/managing-contribution-graphs-on-your-profile/publicizing-or-hiding-your-private-contributions-on-your-profile - /account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-graphs-on-your-profile/publicizing-or-hiding-your-private-contributions-on-your-profile - /account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/showing-your-private-contributions-and-achievements-on-your-profile + - /account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/showing-your-private-contributions-and-achievements-on-your-profile versions: fpt: '*' ghes: '*' ghec: '*' topics: - Profiles -shortTitle: 'Private contributions {% ifversion hide-individual-achievements %}and achievements{% endif %}' +shortTitle: Private contributions {% ifversion hide-individual-achievements %}and achievements{% endif %} allowTitleToDifferFromFilename: true +contentType: how-tos --- -{% ifversion ghec %} - ->[!NOTE] Achievements are not available on subdomains of {% data variables.enterprise.data_residency_site %}, such as `octocorp.ghe.com`. - -{% endif %} - -If you publicize your private contributions, people without access to the private repositories you work in won't be able to see the details of your private contributions. Instead, they'll see the number of private contributions you made on any given day. Your public contributions will include detailed information. For more information, see [AUTOTITLE](/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/viewing-contributions-on-your-profile). - ->[!NOTE] On {% ifversion fpt or ghec %}{% data variables.product.prodname_dotcom_the_website %}{% elsif ghes %}{% data variables.product.prodname_ghe_server %}{% endif %}, public contributions on your profile are visible {% ifversion fpt or ghec %}to anyone in the world who can access {% data variables.product.prodname_dotcom_the_website %}{% elsif ghes %}only to other users of {% data variables.location.product_location %}{% endif %}. - ## Changing the visibility of your private contributions -You can choose to publicize your private contributions, which allows visitors to your profile to see private contribution counts, without further details. - -If you choose to hide your private contributions, visitors will only see your public contributions. - {% data reusables.profile.access_profile %} 1. Above the contribution calendar, click **Contribution settings**. @@ -63,7 +51,6 @@ You can hide an individual achievement on your profile. When hidden, badges are {% endif %} -## Further reading +## Next steps -* [AUTOTITLE](/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/viewing-contributions-on-your-profile) -* [AUTOTITLE](/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/why-are-my-contributions-not-showing-up-on-my-profile) +For more information about contribution visibility, see [AUTOTITLE](/account-and-profile/reference/profile-contributions-reference#who-can-see-your-contributions-and-achievements). diff --git a/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/sharing-contributions-from-github-enterprise-server.md b/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/sharing-contributions-from-github-enterprise-server.md index 13c28d672c3b..c369c5f195cc 100644 --- a/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/sharing-contributions-from-github-enterprise-server.md +++ b/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/sharing-contributions-from-github-enterprise-server.md @@ -19,15 +19,7 @@ topics: shortTitle: Send enterprise contributions --- -## About enterprise contributions - -When you share contributions, your {% data variables.product.prodname_dotcom_the_website %} or {% data variables.enterprise.data_residency_site %} profile shows {% data variables.product.prodname_ghe_server %} contribution counts from the past 90 days. {% data reusables.github-connect.sync-frequency %} Contribution counts from {% data variables.product.prodname_ghe_server %} are considered private contributions. The commit details will only show the contribution counts and that these contributions were made on {% data variables.product.prodname_ghe_server %}. - -You can decide whether to show counts for private contributions on your profile. For more information, see [AUTOTITLE](/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/showing-your-private-contributions-and-achievements-on-your-profile). - -For more information about how contributions are calculated, see [AUTOTITLE](/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile). - -> [!NOTE] +> [!IMPORTANT] > The connection between your accounts is governed by [GitHub's Privacy Statement](/free-pro-team@latest/site-policy/privacy-policies/github-privacy-statement) and users enabling the connection must agree to the [GitHub Terms of Service](/free-pro-team@latest/site-policy/github-terms/github-terms-of-service). ## Sending your enterprise contributions to your profile @@ -36,7 +28,7 @@ Before you can connect your {% data variables.product.prodname_ghe_server %} pro {% ifversion fpt or ghec %} -To share contributions from {% data variables.product.prodname_ghe_server %}, view this article in the [{% data variables.product.prodname_ghe_server %} version of the site](/enterprise-server@latest/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/sending-enterprise-contributions-to-your-githubcom-profile)." +To share contributions from {% data variables.product.prodname_ghe_server %}, switch to the [{% data variables.product.prodname_ghe_server %} version of this article](/enterprise-server@latest/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/sending-enterprise-contributions-to-your-githubcom-profile). {% elsif ghes %} diff --git a/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/showing-an-overview-of-your-activity-on-your-profile.md b/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/showing-an-overview-of-your-activity-on-your-profile.md index 95c9ca2e7db0..22199f9c4ca1 100644 --- a/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/showing-an-overview-of-your-activity-on-your-profile.md +++ b/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/showing-an-overview-of-your-activity-on-your-profile.md @@ -16,15 +16,13 @@ topics: shortTitle: Show an overview --- -## About the activity overview - -{% data reusables.profile.activity-overview-summary %} For more information, see [AUTOTITLE](/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/viewing-contributions-on-your-profile). - -![Screenshot of the activity overview section of a user profile.](/assets/images/help/profile/activity-overview-section.png) - ## Managing the visibility of the activity overview on your profile {% data reusables.profile.access_profile %} 1. Above your contributions graph, select the **Contribution settings** dropdown menu, then click **Activity overview**. ![Screenshot of the contributions graph on a user profile. A dropdown menu, labeled "Contribution settings", is highlighted with an orange outline.](/assets/images/help/profile/activity-overview.png) + +## Next steps + +For more information about what is visible on your profile, see [AUTOTITLE](/account-and-profile/reference/profile-contributions-reference). diff --git a/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/troubleshooting-commits-on-your-timeline.md b/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/troubleshooting-commits-on-your-timeline.md deleted file mode 100644 index 983698442b63..000000000000 --- a/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/troubleshooting-commits-on-your-timeline.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: Troubleshooting commits on your timeline -intro: 'You can view details for commits from your profile''s timeline. If you don''t see commits you expect on your profile or can''t find commit details from your profile page, the commit date and the commit author date may be different.' -redirect_from: - - /articles/troubleshooting-commits-on-your-timeline - - /github/setting-up-and-managing-your-github-profile/troubleshooting-commits-on-your-timeline - - /github/setting-up-and-managing-your-github-profile/managing-contribution-graphs-on-your-profile/troubleshooting-commits-on-your-timeline - - /account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-graphs-on-your-profile/troubleshooting-commits-on-your-timeline - - /account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/troubleshooting-commits-on-your-timeline -versions: - fpt: '*' - ghes: '*' - ghec: '*' -topics: - - Profiles -shortTitle: Troubleshoot commits ---- - -## Expected behavior to view commit details - -In the "Contribution activity" section of your profile page, you can click the number of commits next to a specific repository to see more details about your commits from that time period, including a diff of specific changes made in a repository. - -![Screenshot of the "Contribution activity" section of a user profile. A link, labeled "29 commits" is highlighted with an orange outline.](/assets/images/help/profile/commit-link-on-profile-timeline.png) - -## Missing commit details from commits in your timeline - -If you click a commit link from your profile page and don't see all of the expected commits on the repository's commits page, then it's possible the commit history in Git was rewritten and the commit author date and the commit date are different. - -## How GitHub uses the Git author date and commit date - -In Git, the author date is when someone first creates a commit with `git commit`. The commit date is identical to the author date unless someone changes the commit date by using `git commit --amend`, a force push, a rebase, or other Git commands. - -On your profile page, the author date is used to calculate when a commit was made. Whereas, in a repository, the commit date is used to calculate when a commit was made in the repository. - -Most often, the author date and commit date are the same but you may notice that your commit sequence is out of order if the commit history is changed. For more information, see [AUTOTITLE](/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/why-are-my-contributions-not-showing-up-on-my-profile) - -## Viewing missing commit details from commits in your timeline - -You can use the `git show` command with the `--pretty=fuller` flag to check if the commit author date and commit date are different. - -```shell -$ git show YOUR_COMMIT_SHA_NUMBER --pretty=fuller -commit YOUR_COMMIT_SHA_NUMBER -Author: octocat USER_EMAIL -AuthorDate: Tue Apr 03 02:02:30 2018 +0900 -Commit: Sally Johnson USER_EMAIL -CommitDate: Tue Apr 10 06:25:08 2018 +0900 -``` - -If the author and commit date are different, you can manually change the commit date in the URL to see the commit details. - -For example: -* This URL uses the author date of `2018-04-03`: - - `https://github.com/your-organization-or-personal-account/your-repository/commits?author=octocat&since=2018-04-03T00:00:00Z&until=2018-04-03T23:59:59Z` -* This URL uses the commit date of `2018-04-10`: - - `https://github.com/your-organization-or-personal-account/your-repository/commits?author=octocat&since=2018-04-10T00:00:00Z&until=2018-04-10T23:59:59Z` - -When you open the URL with the modified commit date, you can see the commit details. - -## Expected commits missing in your timeline - -If you're not seeing expected commits on your timeline, it's possible the commit history in Git was rewritten and the commit author date and the commit date are different. For other possibilities, see [AUTOTITLE](/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/why-are-my-contributions-not-showing-up-on-my-profile) diff --git a/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/viewing-commit-details-from-your-timeline.md b/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/viewing-commit-details-from-your-timeline.md new file mode 100644 index 000000000000..9ddea890efab --- /dev/null +++ b/content/account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/viewing-commit-details-from-your-timeline.md @@ -0,0 +1,58 @@ +--- +title: Viewing commit details from your timeline +intro: You can view details for commits from your profile's timeline. If you don't see commits you expect on your profile or can't find commit details from your profile page, the commit date and the commit author date may be different. +redirect_from: + - /articles/troubleshooting-commits-on-your-timeline + - /github/setting-up-and-managing-your-github-profile/troubleshooting-commits-on-your-timeline + - /github/setting-up-and-managing-your-github-profile/managing-contribution-graphs-on-your-profile/troubleshooting-commits-on-your-timeline + - /account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-graphs-on-your-profile/troubleshooting-commits-on-your-timeline + - /account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/troubleshooting-commits-on-your-timeline + - /account-and-profile/how-tos/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/troubleshooting-commits-on-your-timeline +versions: + fpt: '*' + ghes: '*' + ghec: '*' +topics: + - Profiles +shortTitle: Viewing commit details +contentType: how-tos +--- + +## View commit details + +1. In the "Contribution activity" section of your profile, click the number of commits next to a specific repository. + +![Screenshot of the "Contribution activity" section of a user profile. A link, labeled "29 commits" is highlighted with an orange outline.](/assets/images/help/profile/commit-link-on-profile-timeline.png) + +## Finding missing commits in your timeline + +If you can't find expected commits on your profile, the commit history may have been rewritten, creating different author and commit dates. Follow these steps to locate missing commits: + +1. To check if the author date differs from the commit date, use the `git show` command: + + ```shell + $ git show YOUR_COMMIT_SHA_NUMBER --pretty=fuller + commit YOUR_COMMIT_SHA_NUMBER + Author: octocat USER_EMAIL + AuthorDate: Tue Apr 03 02:02:30 2018 +0900 + Commit: Sally Johnson USER_EMAIL + CommitDate: Tue Apr 10 06:25:08 2018 +0900 + ``` + +1. If the dates differ, modify the GitHub URL to search by the specific date: + + * To search by author date (`2018-04-03`): + + `https://github.com/your-organization-or-personal-account/your-repository/commits?author=octocat&since=2018-04-03T00:00:00Z&until=2018-04-03T23:59:59Z` + + * To search by commit date (`2018-04-10`): + + `https://github.com/your-organization-or-personal-account/your-repository/commits?author=octocat&since=2018-04-10T00:00:00Z&until=2018-04-10T23:59:59Z` + +1. Open the modified URL in your browser to view the commit details. + +## Next steps + +If you're not seeing expected commits on your timeline, it's possible the commit history in Git was rewritten and the commit author date and the commit date are different. For other possibilities, see [AUTOTITLE](/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/why-are-my-contributions-not-showing-up-on-my-profile). + +For other reference information, see [AUTOTITLE](/account-and-profile/reference/profile-contributions-reference#how-github-uses-the-git-author-date-and-commit-date). diff --git a/content/account-and-profile/how-tos/setting-up-and-managing-your-personal-account-on-github/managing-your-personal-account/changing-your-username.md b/content/account-and-profile/how-tos/setting-up-and-managing-your-personal-account-on-github/managing-your-personal-account/changing-your-username.md new file mode 100644 index 000000000000..265ed588028f --- /dev/null +++ b/content/account-and-profile/how-tos/setting-up-and-managing-your-personal-account-on-github/managing-your-personal-account/changing-your-username.md @@ -0,0 +1,31 @@ +--- +title: Changing your username +intro: 'Change your {% data variables.product.github %} username.' +versions: + fpt: '*' + ghes: '*' + ghec: '*' +topics: + - Accounts + - Usernames +shortTitle: Change username +permissions: '{% ifversion ghec %}Users with personal accounts can change their username. Members of an {% data variables.enterprise.prodname_emu_enterprise %} cannot change their username.{% elsif ghes %}If your instance uses built-in authentication, you can change your username. If you sign in to {% data variables.location.product_location %} with LDAP credentials or single sign-on (SSO), only your local administrator can change your username.{% else %}Users with personal accounts can change their username.{% endif %}' +--- + +## Prerequisites + +Before changing your username, you should be aware of potential impacts on your account and activity. For more information, see [AUTOTITLE](/account-and-profile/concepts/username-changes). + +## Changing your username + +{% data reusables.user-settings.access_settings %} +{% data reusables.user-settings.account_settings %} +1. In the "Change username" section, click **Change username**.{% ifversion fpt or ghec %} +1. Read the warnings about changing your username. If you still want to change your username, click **I understand, let's change my username**. +1. Type a new username. +1. If the username you've chosen is available, click **Change my username**. If the username you've chosen is unavailable, you can try a different username or one of the suggestions you see. +{% endif %} + +## Next steps + +For reference information and limitations, see [AUTOTITLE](/account-and-profile/reference/username-reference#changing-your-username). diff --git a/content/account-and-profile/how-tos/setting-up-and-managing-your-personal-account-on-github/managing-your-personal-account/index.md b/content/account-and-profile/how-tos/setting-up-and-managing-your-personal-account-on-github/managing-your-personal-account/index.md index 614051638335..170004ba71d4 100644 --- a/content/account-and-profile/how-tos/setting-up-and-managing-your-personal-account-on-github/managing-your-personal-account/index.md +++ b/content/account-and-profile/how-tos/setting-up-and-managing-your-personal-account-on-github/managing-your-personal-account/index.md @@ -11,6 +11,7 @@ topics: children: - /managing-multiple-accounts - /merging-multiple-personal-accounts + - /changing-your-username - /converting-a-user-into-an-organization - /unlinking-your-email-address-from-a-locked-account - /deleting-your-personal-account diff --git a/content/account-and-profile/index.md b/content/account-and-profile/index.md index 401c4212027b..e39f45825567 100644 --- a/content/account-and-profile/index.md +++ b/content/account-and-profile/index.md @@ -7,7 +7,7 @@ introLinks: - /get-started/onboarding/getting-started-with-your-github-account featuredLinks: startHere: - - /account-and-profile/concepts/changing-your-github-username + - /account-and-profile/concepts/username-changes - /account-and-profile/how-tos/setting-up-and-managing-your-github-profile/customizing-your-profile/managing-your-profile-readme popular: - /account-and-profile/how-tos/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/setting-your-commit-email-address diff --git a/content/account-and-profile/reference/index.md b/content/account-and-profile/reference/index.md index d1afedeb42ba..381235fcb8a7 100644 --- a/content/account-and-profile/reference/index.md +++ b/content/account-and-profile/reference/index.md @@ -14,5 +14,6 @@ children: - /types-of-emails-github-sends - /email-addresses-reference - /personal-account-reference + - /username-reference --- diff --git a/content/account-and-profile/reference/profile-contributions-reference.md b/content/account-and-profile/reference/profile-contributions-reference.md index aaa2c0f3cd36..86ffc4dc5dcc 100644 --- a/content/account-and-profile/reference/profile-contributions-reference.md +++ b/content/account-and-profile/reference/profile-contributions-reference.md @@ -48,6 +48,20 @@ In addition, **at least one** of the following must be true: * You have forked the repository. * You have opened a pull request or issue in the repository. +## Who can see your contributions and achievements + +On {% ifversion fpt or ghec %}{% data variables.product.prodname_dotcom_the_website %}{% elsif ghes %}{% data variables.product.prodname_ghe_server %}{% endif %}, **public** contributions on your profile are visible {% ifversion fpt or ghec %}to anyone in the world who can access {% data variables.product.prodname_dotcom_the_website %}{% elsif ghes %}only to other users of {% data variables.location.product_location %}{% endif %}. + +When you publicize private contributions, people without access to those private repositories will see the number of contributions you made each day. They will not see specific details. + +{% ifversion ghec %} + +### {% data variables.enterprise.data_residency %} + +Achievements are not available on subdomains of {% data variables.enterprise.data_residency_site %}, such as `octocorp.ghe.com`. + +{% endif %} + ## Who receives contribution credit {% ifversion ghes %} @@ -69,3 +83,15 @@ If you merged multiple personal accounts, issues, pull requests, and discussions Timestamps are calculated differently for commits and pull requests: * **Commits** use the time zone information in the commit timestamp. For more information, see [AUTOTITLE](/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/troubleshooting-commits-on-your-timeline). * **Pull requests** and **issues** opened on {% data variables.product.github %} use your browser's time zone. Those opened via the API use the timestamp or time zone [specified in the API call](https://developer.github.com/changes/2014-03-04-timezone-handling-changes). + +## How GitHub uses the Git author date and commit date + +In Git, the author date is when someone first creates a commit with `git commit`. The commit date is identical to the author date unless someone changes the commit date by using `git commit --amend`, a force push, a rebase, or other Git commands. + +On your profile page, the author date is used to calculate when a commit was made. Whereas, in a repository, the commit date is used to calculate when a commit was made in the repository. + +Most often, the author date and commit date are the same but you may notice that your commit sequence is out of order if the commit history is changed. For more information, see [AUTOTITLE](/account-and-profile/setting-up-and-managing-your-github-profile/managing-contribution-settings-on-your-profile/why-are-my-contributions-not-showing-up-on-my-profile). + +## Sharing contributions from {% data variables.product.prodname_ghe_server %} + +When you share contributions, your {% data variables.product.prodname_dotcom_the_website %} or {% data variables.enterprise.data_residency_site %} profile shows {% data variables.product.prodname_ghe_server %} contribution counts from the past 90 days. {% data reusables.github-connect.sync-frequency %} Contribution counts from {% data variables.product.prodname_ghe_server %} are considered private contributions. The commit details will only show the contribution counts and that these contributions were made on {% data variables.product.prodname_ghe_server %}. diff --git a/content/account-and-profile/reference/username-reference.md b/content/account-and-profile/reference/username-reference.md new file mode 100644 index 000000000000..b2dca7dd21b7 --- /dev/null +++ b/content/account-and-profile/reference/username-reference.md @@ -0,0 +1,60 @@ +--- +title: Username reference +shortTitle: Username reference +intro: 'Find information about changing your {% data variables.product.github %} username.' +topics: + - Accounts + - Usernames +versions: + fpt: '*' + ghes: '*' + ghec: '*' +--- + +## Changing your username + +The following list contains limitations and considerations when changing your {% data variables.product.github %} username.{% ifversion fpt or ghec %} For the {% data variables.product.github %} username policy, see [AUTOTITLE](/free-pro-team@latest/site-policy/other-site-policies/github-username-policy){% endif %}. + +### Limitations of username changes + +{% ifversion ghec or ghes %} + +{% ifversion ghec %} + +Members of an {% data variables.enterprise.prodname_emu_enterprise %} cannot change usernames. Your enterprise's IdP administrator controls your {% data variables.product.github %} username. For more information, see [AUTOTITLE](/admin/identity-and-access-management/using-enterprise-managed-users-for-iam/about-enterprise-managed-users). + +{% elsif ghes %} + +If you sign into {% data variables.location.product_location %} with LDAP credentials or single sign-on (SSO), only your local administrator can change your username. For more information about authentication methods for {% data variables.product.prodname_ghe_server %}, see [AUTOTITLE](/admin/identity-and-access-management/managing-iam-for-your-enterprise). + +{% endif %} + +{% endif %} + +{% ifversion fpt or ghec %} + +{% data reusables.accounts.rename-account-repo-namespace-retirement %} If you try to create a repository using a retired owner name and repository name combination, you will see the error: "The repository `` has been retired and cannot be reused." + +{% endif %} + +{% data reusables.package_registry.rename-account-namespace-retirement %} + +### Repository redirects after username change + +After you change your username, web links to your existing repositories will continue to work. This can take a few minutes to complete after you make the change. + +Command line pushes from your local repository clones to the old remote tracking URLs will continue to work. + +### Redirects for changed usernames + +{% data variables.product.github %} cannot set up redirects for: +* [@mentions](/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#mentioning-people-and-teams) using your old username +* Links to [gists](/get-started/writing-on-github/editing-and-sharing-content-with-gists/creating-gists) that include your old username + +### Git commits after a username change + +After a username change, verified commits signed using the previous {% data variables.product.github %}-provided `noreply` email address will lose their "Verified" status. + +When verifying a signature, {% data variables.product.github %} checks that the email address of the committer or tagger exactly matches one of the email addresses associated with the GPG key's identities. Additionally, {% data variables.product.github %} confirms that the email address is verified and linked to the user's account. This ensures that the key belongs to you and that you created the commit or tag. Because the username of the `noreply` email address changes, these commits can no longer be verified. + +{% ifversion fpt or ghec %}If you've been using a {% data variables.product.github %}-provided private commit email address, whether or not your commit history will be retained after an account rename depends on the format of the email address. Git commits that are associated with your {% data variables.product.github %}-provided `noreply` email address won't be attributed to your new username and won't appear in your contributions graph, unless your `noreply` email address is in the form of `ID+USERNAME@users.noreply.github.com`. Older versions of the `noreply` email address that do not contain a numeric ID will not be associated with your {% data variables.product.github %} account after changing your username.{% endif %} diff --git a/content/authentication/securing-your-account-with-two-factor-authentication-2fa/accessing-github-using-two-factor-authentication.md b/content/authentication/securing-your-account-with-two-factor-authentication-2fa/accessing-github-using-two-factor-authentication.md index f38c4b860fd1..8a4b49f63842 100644 --- a/content/authentication/securing-your-account-with-two-factor-authentication-2fa/accessing-github-using-two-factor-authentication.md +++ b/content/authentication/securing-your-account-with-two-factor-authentication-2fa/accessing-github-using-two-factor-authentication.md @@ -25,7 +25,7 @@ If you access {% data variables.product.github %} using other methods, such as t {% else %} -With two-factor authentication enabled, you'll need to provide an authentication code{% ifversion fpt or ghec %}, tap a notification in GitHub Mobile,{% endif %} or use a security key when accessing {% data variables.product.github %} through your browser. If you access {% data variables.product.github %} using other methods, such as the API or the command line, you'll need to use an alternative form of authentication. For more information, see [AUTOTITLE](/authentication/keeping-your-account-and-data-secure/about-authentication-to-github). +With two-factor authentication enabled, you'll need to provide an authentication code{% ifversion fpt or ghec %}, tap a notification in GitHub Mobile,{% endif %} or use a passkey or security key when accessing {% data variables.product.github %} through your browser. If you access {% data variables.product.github %} using other methods, such as the API or the command line, you'll need to use an alternative form of authentication. For more information, see [AUTOTITLE](/authentication/keeping-your-account-and-data-secure/about-authentication-to-github). {% endif %} @@ -101,20 +101,12 @@ Enabling 2FA doesn't change how you authenticate to {% data variables.product.gi ## Troubleshooting -If you lose access to your two-factor authentication credentials, you can use your recovery codes or another recovery method (if you've set one up) to regain access to your account. For more information, see [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/recovering-your-account-if-you-lose-your-2fa-credentials). - -{% ifversion fpt or ghec %} - -> [!NOTE] -> {% data reusables.two_fa.unlink-email-address %} - -{% endif %} - -If your authentication fails several times, you may wish to synchronize your phone's clock with your mobile provider. Often, this involves checking the "Set automatically" option on your phone's clock, rather than providing your own time zone. +If you are receiving a "Two-factor authentication failed" error when authenticating with 2FA, the authentication code you are entering is incorrect. You can try troubleshooting your configured authentication methods before attempting account recovery. See [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/troubleshooting-two-factor-authentication-issues). ## Further reading * [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/about-two-factor-authentication) * [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication) * [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication-recovery-methods) +* [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/troubleshooting-two-factor-authentication-issues) * [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/recovering-your-account-if-you-lose-your-2fa-credentials) diff --git a/content/authentication/securing-your-account-with-two-factor-authentication-2fa/changing-your-two-factor-authentication-method.md b/content/authentication/securing-your-account-with-two-factor-authentication-2fa/changing-your-two-factor-authentication-method.md index dd3332073611..7743e6d47385 100644 --- a/content/authentication/securing-your-account-with-two-factor-authentication-2fa/changing-your-two-factor-authentication-method.md +++ b/content/authentication/securing-your-account-with-two-factor-authentication-2fa/changing-your-two-factor-authentication-method.md @@ -1,6 +1,6 @@ --- title: Changing your two-factor authentication method -intro: You can change two-factor authentication (2FA) method without disabling 2FA entirely. +intro: You can change your two-factor authentication (2FA) method without disabling 2FA entirely. redirect_from: - /articles/changing-two-factor-authentication-delivery-methods - /articles/changing-two-factor-authentication-delivery-methods-for-your-mobile-device diff --git a/content/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication.md b/content/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication.md index b3125ea10b00..9b91170d27f7 100644 --- a/content/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication.md +++ b/content/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication.md @@ -52,7 +52,7 @@ If you're a member of an {% data variables.enterprise.prodname_emu_enterprise %} {% endif %} > [!NOTE] -> You can reconfigure your 2FA settings without disabling 2FA entirely, allowing you to keep both your recovery codes and your membership in organizations that require 2FA. +> You can reconfigure your 2FA settings without disabling 2FA entirely, allowing you to keep both your recovery codes and your membership in organizations that require 2FA. See [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/changing-your-two-factor-authentication-method). ## Configuring two-factor authentication using a TOTP app @@ -141,5 +141,6 @@ After signing in and turning on push notifications, you can now use your device * [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/about-two-factor-authentication) * [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication-recovery-methods) * [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/accessing-github-using-two-factor-authentication) +* [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/troubleshooting-two-factor-authentication-issues) * [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/recovering-your-account-if-you-lose-your-2fa-credentials) * [AUTOTITLE](/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) diff --git a/content/authentication/securing-your-account-with-two-factor-authentication-2fa/index.md b/content/authentication/securing-your-account-with-two-factor-authentication-2fa/index.md index 6fc5ecbf6599..c83bfe1ed75c 100644 --- a/content/authentication/securing-your-account-with-two-factor-authentication-2fa/index.md +++ b/content/authentication/securing-your-account-with-two-factor-authentication-2fa/index.md @@ -14,13 +14,14 @@ topics: - 2FA children: - /about-two-factor-authentication + - /about-mandatory-two-factor-authentication - /configuring-two-factor-authentication - /configuring-two-factor-authentication-recovery-methods - /accessing-github-using-two-factor-authentication - - /recovering-your-account-if-you-lose-your-2fa-credentials - - /changing-your-two-factor-authentication-method - - /about-mandatory-two-factor-authentication - /countries-where-sms-authentication-is-supported + - /changing-your-two-factor-authentication-method + - /troubleshooting-two-factor-authentication-issues + - /recovering-your-account-if-you-lose-your-2fa-credentials - /disabling-two-factor-authentication-for-your-personal-account shortTitle: Secure your account with 2FA --- diff --git a/content/authentication/securing-your-account-with-two-factor-authentication-2fa/recovering-your-account-if-you-lose-your-2fa-credentials.md b/content/authentication/securing-your-account-with-two-factor-authentication-2fa/recovering-your-account-if-you-lose-your-2fa-credentials.md index 6231cc200b80..0a5dbd86fe0a 100644 --- a/content/authentication/securing-your-account-with-two-factor-authentication-2fa/recovering-your-account-if-you-lose-your-2fa-credentials.md +++ b/content/authentication/securing-your-account-with-two-factor-authentication-2fa/recovering-your-account-if-you-lose-your-2fa-credentials.md @@ -35,6 +35,9 @@ Use one of your recovery codes to automatically regain entry into your account. {% data reusables.accounts.prompt-for-2fa-recovery-code %} 1. Type one of your recovery codes, then click **Verify**. +> [!NOTE] +> If you are receiving a "Recovery code authentication failed" error when using a recovery code, the code you are entering is invalid. You can try troubleshooting your recovery codes. See [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/troubleshooting-two-factor-authentication-issues). + ## Authenticating with a passkey If you have added a passkey to your account, you can use your passkey to automatically regain access to your account. Passkeys satisfy both password and 2FA requirements, so you don't need to know your password in order to recover your account. See [AUTOTITLE](/authentication/authenticating-with-a-passkey/about-passkeys). @@ -101,4 +104,5 @@ If you have exhausted your recovery options, you can unlink your email address f ## Further reading +* [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/troubleshooting-two-factor-authentication-issues) * [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication-recovery-methods) diff --git a/content/authentication/securing-your-account-with-two-factor-authentication-2fa/troubleshooting-two-factor-authentication-issues.md b/content/authentication/securing-your-account-with-two-factor-authentication-2fa/troubleshooting-two-factor-authentication-issues.md new file mode 100644 index 000000000000..93243d752ed1 --- /dev/null +++ b/content/authentication/securing-your-account-with-two-factor-authentication-2fa/troubleshooting-two-factor-authentication-issues.md @@ -0,0 +1,100 @@ +--- +title: Troubleshooting two-factor authentication issues +intro: 'If you are having trouble authenticating with 2FA, you can try troubleshooting your configured authentication methods.' +versions: + fpt: '*' + ghec: '*' + ghes: '*' +topics: + - 2FA + - Authentication +shortTitle: Troubleshooting 2FA +--- + +If you are receiving a "Two-factor authentication failed" error when authenticating with two-factor authentication (2FA), the authentication code you are entering is incorrect. You can try troubleshooting your configured authentication methods before attempting account recovery. + +## Troubleshooting authentication using a TOTP app + +### Use the right app + +When authenticating with a TOTP app, {% data variables.product.github %} does not send you anything; you need to provide {% data variables.product.github %} with a valid code, based on the secret key that you saved to your TOTP app when 2FA was set up. Find the app or program that you originally used to setup 2FA and retrieve the authentication code from there. + +### Check your device’s date and time + +TOTP codes are time‑based. If the clock on your phone or computer is out of sync with {% data variables.product.github %}'s server, the code will be invalid. Ensure that your device’s date, time and time zone are set automatically by your network provider. On most mobile devices, this means turning on the **Set automatically** option. + +### Wait for a new code and enter it promptly + +Codes change every 30 seconds. Open your TOTP app, wait for the next code to appear and enter it immediately. Avoid typing spaces or extra characters as these will make the code invalid. + +### Verify you’re using the correct account entry + +Most TOTP apps support multiple accounts for a single website. Make sure you’re reading the code from the correct entry in the app. Codes generated for a different account will not work. + +### Restore from a TOTP backup + +Many TOTP apps support cloud backup or key export. If you lose or reset your device, you may be able restore your 2FA data from the app’s backup to a new device. Consult your app’s documentation for instructions. + +{% ifversion fpt or ghec %} + +## Troubleshooting authentication using text messages + +### Confirm that you can receive text messages + +Make sure your device and cellular plan is capable of receiving Short Message Service (SMS) messages. Some "data-only" phone plans and tablet devices connected to a cellular network may not support receiving text messages. Check with your provider and device manufacturer. + +Carrier rates may apply for received SMS messages. Ensure your cellular plan covers potential charges. + +Disable "Do Not Disturb" mode or spam‑filtering apps that might block receipt of authentication codes. + +### Check that you have cellular coverage + +Receiving text messages generally requires a strong network signal. Ensure you have adequate coverage before requesting an authentication code. + +### Power cycle your phone + +Turning your phone off and on will re-register the device with the network, which may resolve some deliverability issues. Enabling and disabling an "Airplane Mode" may also be sufficient, but power cycling your phone is more reliable. + +### Consult with your cellular provider + +Check with your cellular provider or carrier to see if there are any local outages or delivery issues in your area. They may also be able to investigate delivery issues for your connection. Provide them with the SMS number configured on your {% data variables.product.github %} account and the time that you requested an authentication code from {% data variables.product.github %}. + +> [!NOTE] +> {% data variables.product.github %}, along with our SMS delivery partners, proactively monitors our SMS deliverability success rates. Periods of low-deliverability that would indicate a widespread issue are promptly investigated. You can check active and historical incidents affecting SMS delivery in your region on [{% data variables.product.github %}'s status page](https://githubstatus.com). + +{% endif %} + +## Recovering your account if troubleshooting doesn't help + +If you have tried troubleshooting and you are still having trouble, you can try authenticating with another method, such as a passkey, {% ifversion fpt or ghec %}{% data variables.product.prodname_mobile %},{% endif %} or a security key, if pre-configured on the account. For more information, see [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/accessing-github-using-two-factor-authentication). + +{% ifversion fpt or ghec %} + +> [!WARNING] +> For security reasons, {% data variables.contact.github_support %} cannot assist with troubleshooting your 2FA methods, including SMS delivery. + +{% endif %} + +If you don't have another authentication method, you will need to try account recovery. For more information about account recovery, see [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/recovering-your-account-if-you-lose-your-2fa-credentials). + +## Troubleshooting using recovery codes + +If you are receiving a "Recovery code authentication failed" error when using a recovery code, the code you are entering is invalid. You can try troubleshooting your recovery codes. + +### Use one code at a time + +A set of recovery codes contains more than one code. A single code is 10 alphanumeric characters with a hyphen in the middle: `xxxxx-yyyyy`. + +### Try using a different code + +Each code is single-use only: once it has been used to authenticate, it cannot be used again. Try using a different code from the set. + +### Check you're using the right set of codes + +When 2FA is disabled and re-enabled, a new set of codes are created which invalidates the previous set. Recovery codes are also invalidated whenever a new set of codes is generated. Even if you think you might not have another set of codes, you could try searching for them in your devices, backups, and password managers. They will have the default filename `github-recovery-codes.txt`. + +## Further reading + +* [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/about-two-factor-authentication) +* [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/accessing-github-using-two-factor-authentication) +* [AUTOTITLE](/authentication/securing-your-account-with-two-factor-authentication-2fa/recovering-your-account-if-you-lose-your-2fa-credentials) diff --git a/data/reusables/accounts/prompt-for-2fa-recovery-code.md b/data/reusables/accounts/prompt-for-2fa-recovery-code.md index 8591c32d5d3e..87bafd91013b 100644 --- a/data/reusables/accounts/prompt-for-2fa-recovery-code.md +++ b/data/reusables/accounts/prompt-for-2fa-recovery-code.md @@ -1,5 +1,9 @@ -1. Navigate to [https://github.com/login](https://github.com/login). +1. Navigate to {% data variables.product.login_url %}. 1. To prompt two-factor authentication, type your username and password, then click **Sign in**. +{% ifversion fpt or ghec %} + > [!NOTE] - > If you have linked a Google account to your {% data variables.product.prodname_dotcom %} account, you can sign-in with your social login instead of using your password. + > If you have linked a social account to your {% data variables.product.github %} account, you can sign-in with your social login instead of using your password. + +{% endif %} 1. Under "More options", click **2FA recovery code**. diff --git a/data/reusables/two_fa/support-may-not-help.md b/data/reusables/two_fa/support-may-not-help.md index d984c705ea41..a0106095d576 100644 --- a/data/reusables/two_fa/support-may-not-help.md +++ b/data/reusables/two_fa/support-may-not-help.md @@ -1 +1 @@ -For security reasons, {% data variables.product.company_short %} Support [will not be able to restore access to accounts](/free-pro-team@latest/site-policy/other-site-policies/github-account-recovery-policy) with two-factor authentication enabled if you lose your two-factor authentication credentials or lose access to your account recovery methods. +For security reasons, {% data variables.contact.github_support %} [will not be able to restore access to accounts](/free-pro-team@latest/site-policy/other-site-policies/github-account-recovery-policy) with two-factor authentication enabled if you lose your two-factor authentication credentials or lose access to your account recovery methods. diff --git a/data/variables/product.yml b/data/variables/product.yml index e4f9ead6a7fd..bf0c3c3bc360 100644 --- a/data/variables/product.yml +++ b/data/variables/product.yml @@ -237,7 +237,7 @@ prodname_learning_link: 'https://skills.github.com/' prodname_roadmap: 'GitHub public roadmap' prodname_roadmap_link: 'https://github.com/github/roadmap#github-public-roadmap' -# GitHub support +# GitHub Support plans standard_support_plan: 'Standard plan' premium_support_plan: 'Premium plan' premium_plus_support_plan: 'Premium Plus plan / GitHub Engineering Direct' @@ -334,6 +334,12 @@ pricing_url: 'https://github.com/pricing' pricing_link: '[GitHub Pricing](https://github.com/pricing)' raw_github_com: >- {% ifversion fpt or ghec %}raw.githubusercontent.com{% else %}HOSTNAME/user/repo/raw{% endif %} +login_url: >- + {%- ifversion fpt or ghec %} + [`https://github.com/login`](https://github.com/login) + {%- elsif ghes %} + `http(s)://HOSTNAME/login` + {%- endif %} # GitHub Enterprise Server past versions current-340-version: '11.10.354' diff --git a/package.json b/package.json index b5c18f05d11c..6de1c29682be 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "cmp-files": "tsx src/workflows/cmp-files.ts", "content-changes-table-comment": "tsx src/workflows/content-changes-table-comment.ts", "copy-fixture-data": "tsx src/tests/scripts/copy-fixture-data.ts", - "count-translation-corruptions": "tsx src/languages/scripts/count-translation-corruptions.ts", + "count-translation-corruptions": "cross-env NODE_OPTIONS=--max-old-space-size=8192 tsx src/languages/scripts/count-translation-corruptions.ts", "create-enterprise-issue": "tsx src/ghes-releases/scripts/create-enterprise-issue.ts", "debug": "cross-env NODE_ENV=development ENABLED_LANGUAGES=en nodemon --inspect src/frame/server.ts", "delete-orphan-translation-files": "tsx src/workflows/delete-orphan-translation-files.ts", diff --git a/src/frame/lib/frontmatter.js b/src/frame/lib/frontmatter.js index ca99e44ffce9..9de39a7ac389 100644 --- a/src/frame/lib/frontmatter.js +++ b/src/frame/lib/frontmatter.js @@ -202,6 +202,10 @@ export const schema = { product_video_transcript: { type: 'string', }, + // Hero image for landing pages + heroImage: { + type: 'string', + }, interactive: { type: 'boolean', }, diff --git a/src/landings/components/ProductLandingContext.tsx b/src/landings/components/ProductLandingContext.tsx index deecd64572e7..f732228e93da 100644 --- a/src/landings/components/ProductLandingContext.tsx +++ b/src/landings/components/ProductLandingContext.tsx @@ -39,6 +39,7 @@ export type ProductLandingContextT = { introLinks: Record | null productVideo: string productVideoTranscript: string + heroImage?: string featuredLinks: Record> productUserExamples: Array<{ username: string; description: string }> productCommunityExamples: Array<{ repo: string; description: string }> @@ -113,6 +114,7 @@ export const getProductLandingContextFromRequest = async ( ...pick(page, ['introPlainText', 'beta_product', 'intro']), productVideo, productVideoTranscript: page.product_video_transcript || null, + heroImage: page.heroImage || null, hasGuidesPage, product: { href: productTree.href, diff --git a/src/landings/components/bespoke/BespokeLanding.tsx b/src/landings/components/bespoke/BespokeLanding.tsx index 29746737c2dc..0e61f7bf561f 100644 --- a/src/landings/components/bespoke/BespokeLanding.tsx +++ b/src/landings/components/bespoke/BespokeLanding.tsx @@ -1,14 +1,14 @@ import { useMemo } from 'react' import { DefaultLayout } from '@/frame/components/DefaultLayout' -import { useBespokeContext } from '@/landings/context/BespokeContext' +import { useLandingContext } from '@/landings/context/LandingContext' import { LandingHero } from '@/landings/components/shared/LandingHero' import { ArticleGrid } from '@/landings/components/shared/LandingArticleGridWithFilter' import type { ArticleCardItems } from '@/landings/types' export const BespokeLanding = () => { - const { title, intro, tocItems } = useBespokeContext() + const { title, intro, heroImage, introLinks, tocItems } = useLandingContext() const flatArticles: ArticleCardItems = useMemo( () => tocItems.flatMap((item) => item.childTocItems || []), @@ -18,7 +18,7 @@ export const BespokeLanding = () => { return (
- +
diff --git a/src/landings/components/discovery/DiscoveryLanding.tsx b/src/landings/components/discovery/DiscoveryLanding.tsx index 4bd247378cf5..61c87ba0b883 100644 --- a/src/landings/components/discovery/DiscoveryLanding.tsx +++ b/src/landings/components/discovery/DiscoveryLanding.tsx @@ -1,7 +1,7 @@ import { useMemo } from 'react' import { DefaultLayout } from '@/frame/components/DefaultLayout' -import { useDiscoveryContext } from '@/landings/context/DiscoveryContext' +import { useLandingContext } from '@/landings/context/LandingContext' import { LandingHero } from '@/landings/components/shared/LandingHero' import { ArticleGrid } from '@/landings/components/shared/LandingArticleGridWithFilter' import { LandingCarousel } from '@/landings/components/shared/LandingCarousel' @@ -9,7 +9,7 @@ import { LandingCarousel } from '@/landings/components/shared/LandingCarousel' import type { ArticleCardItems } from '@/landings/types' export const DiscoveryLanding = () => { - const { title, intro, tocItems, recommended } = useDiscoveryContext() + const { title, intro, heroImage, introLinks, tocItems, recommended } = useLandingContext() const flatArticles: ArticleCardItems = useMemo( () => tocItems.flatMap((item) => item.childTocItems || []), @@ -19,7 +19,7 @@ export const DiscoveryLanding = () => { return (
- +
diff --git a/src/landings/components/journey/JourneyLanding.tsx b/src/landings/components/journey/JourneyLanding.tsx index 9ce831ef7610..7eb489fe0e7f 100644 --- a/src/landings/components/journey/JourneyLanding.tsx +++ b/src/landings/components/journey/JourneyLanding.tsx @@ -1,14 +1,14 @@ import { DefaultLayout } from '@/frame/components/DefaultLayout' -import { useJourneyContext } from '@/landings/context/JourneyContext' +import { useLandingContext } from '@/landings/context/LandingContext' import { LandingHero } from '@/landings/components/shared/LandingHero' export const JourneyLanding = () => { - const { title, intro } = useJourneyContext() + const { title, intro, heroImage, introLinks } = useLandingContext() return (
- +
TODO
diff --git a/src/landings/components/shared/LandingHero.module.scss b/src/landings/components/shared/LandingHero.module.scss new file mode 100644 index 000000000000..9068b7d93e4c --- /dev/null +++ b/src/landings/components/shared/LandingHero.module.scss @@ -0,0 +1,191 @@ +.landingHero { + position: relative; + display: flex; + align-items: center; + padding: 4rem 0; + background-color: var(--bgColor-muted, var(--color-canvas-subtle, #f6f8fa)); + background-size: cover; + background-position: center center; + background-repeat: no-repeat; + overflow: hidden; + height: 28rem; + width: 100%; +} + +.heroContent { + position: relative; + width: 50rem; + max-width: 50rem; + padding: 0 7rem; + display: flex; + align-items: center; +} + +.heroText { + text-align: left; + width: 100%; +} + +.heroHeading { + font-size: 4rem; + font-weight: 600; + line-height: 1.2; + margin: 0 0 1rem 0; + color: var(--fgColor-default, var(--color-fg-default, #1f2328)); + max-width: 48rem; +} + +.heroDescription { + font-size: 1.25rem; + line-height: 1.5; + color: var(--fgColor-muted, var(--color-fg-muted, #656d76)); + margin: 0 0 2rem 0; + max-width: 36rem; +} + +.heroActions { + display: flex; + gap: 1rem; + flex-wrap: wrap; +} + +.heroAction { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.75rem 1.5rem; + border-radius: 6px; + font-weight: 500; + text-decoration: none; + transition: all 0.2s ease; + min-height: 2.75rem; + border: 1px solid transparent; +} + +.heroPrimaryAction { + background-color: var( + --bgColor-success-emphasis, + var(--color-btn-primary-bg, #1f883d) + ); + color: var(--fgColor-onEmphasis, var(--color-btn-primary-text, #ffffff)); + border-color: var( + --borderColor-success-emphasis, + var(--color-btn-primary-border, #1f883d) + ); + + &:hover { + background-color: var( + --bgColor-success-emphasis, + var(--color-btn-primary-hover-bg, #1a7f37) + ); + border-color: var( + --borderColor-success-emphasis, + var(--color-btn-primary-hover-border, #1a7f37) + ); + text-decoration: none; + } + + &:focus { + outline: 2px solid + var( + --borderColor-success-emphasis, + var(--color-btn-primary-focus, #1f883d) + ); + outline-offset: 2px; + } +} + +.heroSecondaryAction { + background-color: transparent; + color: var(--fgColor-default, var(--color-fg-default, #1f2328)); + border-color: var( + --borderColor-default, + var(--color-border-default, #d1d9e0) + ); + + &:hover { + background-color: var(--bgColor-muted, var(--color-canvas-subtle, #f3f4f6)); + border-color: var( + --borderColor-default, + var(--color-border-default, #d1d9e0) + ); + text-decoration: none; + } + + &:focus { + outline: 2px solid + var(--borderColor-accent-emphasis, var(--color-accent-emphasis, #0969da)); + outline-offset: 2px; + } +} + +@media (max-width: 865px) { + .landingHero { + height: 24rem; + background-image: none !important; + flex-direction: column; + text-align: center; + justify-content: center; + background-color: var(--bgColor-muted, var(--color-canvas-subtle, #f6f8fa)); + } + + .heroContent { + width: 100%; + order: 2; + padding: 0 1rem; + } + + .heroHeading { + font-size: 3rem; + } + + .heroDescription { + font-size: 1.1rem; + } + + .heroActions { + justify-content: center; + } + + .heroAction { + width: auto; + min-width: 12rem; + } + + .heroText { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + } +} + +@media (max-width: 480px) { + .landingHero { + height: 32rem; + background-image: none !important; + background-color: var(--bgColor-muted, var(--color-canvas-subtle, #f6f8fa)); + flex-direction: column; + text-align: center; + padding: 2rem 0 1rem; + justify-content: center; + } + + .heroContent { + width: 100%; + order: 2; + padding: 1rem; + } + + .heroText { + display: flex; + flex-direction: column; + text-align: center; + align-items: center; + } + + .heroActions { + justify-content: center; + align-items: center; + } +} diff --git a/src/landings/components/shared/LandingHero.tsx b/src/landings/components/shared/LandingHero.tsx index fc717b2799a7..83649ecb4d76 100644 --- a/src/landings/components/shared/LandingHero.tsx +++ b/src/landings/components/shared/LandingHero.tsx @@ -1,18 +1,61 @@ -import { Lead } from '@/frame/components/ui/Lead/Lead' +import styles from './LandingHero.module.scss' +import { useTranslation } from '@/languages/components/useTranslation' type LandingHeroProps = { title: string intro?: string + heroImage?: string + introLinks?: Record | null } -export const LandingHero = ({ title, intro }: LandingHeroProps) => { +export const LandingHero = ({ title, intro, heroImage, introLinks }: LandingHeroProps) => { + const { t } = useTranslation(['product_landing']) + + const linkEntries = introLinks ? Object.entries(introLinks) : [] + const primaryAction = linkEntries[0] + const secondaryAction = linkEntries[1] + return ( -
-
-

TODO: Landing hero placeholder

-

{title}

- {intro && {intro}} +
+
+
+

{title}

+ {intro && ( +
+
+
+ )} + {(primaryAction || secondaryAction) && ( +
+ {primaryAction && ( + + {t(primaryAction[0])} + + )} + {secondaryAction && ( + + {t(secondaryAction[0])} + + )} +
+ )} +
-
+
) } diff --git a/src/landings/context/BespokeContext.tsx b/src/landings/context/BespokeContext.tsx deleted file mode 100644 index f7bd5b9ca940..000000000000 --- a/src/landings/context/BespokeContext.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { createContext, useContext } from 'react' -import { FeaturedLink, getFeaturedLinksFromReq } from '@/landings/components/ProductLandingContext' -import { mapRawTocItemToTocItem } from '@/landings/types' -import type { TocItem } from '@/landings/types' -import type { LearningTrack } from '@/types' - -export type BespokeContextT = { - title: string - intro: string - productCallout: string - permissions: string - tocItems: Array - variant?: 'compact' | 'expanded' - featuredLinks: Record> - renderedPage: string - currentLearningTrack?: LearningTrack - currentLayout: string -} - -export const BespokeContext = createContext(null) - -export const useBespokeContext = (): BespokeContextT => { - const context = useContext(BespokeContext) - - if (!context) { - throw new Error('"useBespokeContext" may only be used inside "BespokeContext.Provider"') - } - - return context -} - -export const getBespokeContextFromRequest = async (req: any): Promise => { - const page = req.context.page - - return { - title: page.title, - productCallout: page.product || '', - permissions: page.permissions || '', - intro: page.intro, - tocItems: (req.context.genericTocFlat || req.context.genericTocNested || []).map( - mapRawTocItemToTocItem, - ), - variant: req.context.genericTocFlat ? 'expanded' : 'compact', - featuredLinks: getFeaturedLinksFromReq(req), - renderedPage: req.context.renderedPage, - currentLearningTrack: req.context.currentLearningTrack, - currentLayout: req.context.currentLayoutName, - } -} diff --git a/src/landings/context/DiscoveryContext.tsx b/src/landings/context/DiscoveryContext.tsx deleted file mode 100644 index c4b13f2702d6..000000000000 --- a/src/landings/context/DiscoveryContext.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { createContext, useContext } from 'react' -import { FeaturedLink, getFeaturedLinksFromReq } from '@/landings/components/ProductLandingContext' -import { mapRawTocItemToTocItem } from '@/landings/types' -import type { TocItem } from '@/landings/types' -import type { LearningTrack } from '@/types' - -export type DiscoveryContextT = { - title: string - intro: string - productCallout: string - permissions: string - tocItems: Array - variant?: 'compact' | 'expanded' - featuredLinks: Record> - renderedPage: string - currentLearningTrack?: LearningTrack - currentLayout: string - recommended?: string[] // Array of article paths -} - -export const DiscoveryContext = createContext(null) - -export const useDiscoveryContext = (): DiscoveryContextT => { - const context = useContext(DiscoveryContext) - - if (!context) { - throw new Error('"useDiscoveryContext" may only be used inside "DiscoveryContext.Provider"') - } - - return context -} - -export const getDiscoveryContextFromRequest = async (req: any): Promise => { - const page = req.context.page - - // Support legacy `spotlight` property as `recommended` for pages like Copilot Cookbook - // However, `spotlight` will have lower priority than the `recommended` property - let recommended: string[] = [] - if (page.recommended && page.recommended.length > 0) { - recommended = page.recommended - } else if (page.spotlight && page.spotlight.length > 0) { - // Remove the `image` property from spotlight items, since we don't use those for the carousel - recommended = page.spotlight.map((item: any) => item.article) - } - - return { - title: page.title, - productCallout: page.product || '', - permissions: page.permissions || '', - intro: page.intro, - tocItems: (req.context.genericTocFlat || req.context.genericTocNested || []).map( - mapRawTocItemToTocItem, - ), - variant: req.context.genericTocFlat ? 'expanded' : 'compact', - featuredLinks: getFeaturedLinksFromReq(req), - renderedPage: req.context.renderedPage, - currentLearningTrack: req.context.currentLearningTrack, - currentLayout: req.context.currentLayoutName, - recommended, - } -} diff --git a/src/landings/context/JourneyContext.tsx b/src/landings/context/JourneyContext.tsx deleted file mode 100644 index 47c0c8340172..000000000000 --- a/src/landings/context/JourneyContext.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { createContext, useContext } from 'react' -import { FeaturedLink, getFeaturedLinksFromReq } from '@/landings/components/ProductLandingContext' -import { mapRawTocItemToTocItem } from '@/landings/types' -import type { TocItem } from '@/landings/types' -import type { LearningTrack } from '@/types' - -export type JourneyContextT = { - title: string - intro: string - productCallout: string - permissions: string - tocItems: Array - variant?: 'compact' | 'expanded' - featuredLinks: Record> - renderedPage: string - currentLearningTrack?: LearningTrack - currentLayout: string -} - -export const JourneyContext = createContext(null) - -export const useJourneyContext = (): JourneyContextT => { - const context = useContext(JourneyContext) - - if (!context) { - throw new Error('"useJourneyContext" may only be used inside "JourneyContext.Provider"') - } - - return context -} - -export const getJourneyContextFromRequest = async (req: any): Promise => { - const page = req.context.page - - return { - title: page.title, - productCallout: page.product || '', - permissions: page.permissions || '', - intro: page.intro, - tocItems: (req.context.genericTocFlat || req.context.genericTocNested || []).map( - mapRawTocItemToTocItem, - ), - variant: req.context.genericTocFlat ? 'expanded' : 'compact', - featuredLinks: getFeaturedLinksFromReq(req), - renderedPage: req.context.renderedPage, - currentLearningTrack: req.context.currentLearningTrack, - currentLayout: req.context.currentLayoutName, - } -} diff --git a/src/landings/context/LandingContext.tsx b/src/landings/context/LandingContext.tsx new file mode 100644 index 000000000000..0739c142295e --- /dev/null +++ b/src/landings/context/LandingContext.tsx @@ -0,0 +1,76 @@ +import { createContext, useContext } from 'react' +import { FeaturedLink, getFeaturedLinksFromReq } from '@/landings/components/ProductLandingContext' +import { mapRawTocItemToTocItem } from '@/landings/types' +import type { TocItem } from '@/landings/types' +import type { LearningTrack } from '@/types' + +export type LandingType = 'bespoke' | 'discovery' | 'journey' + +export type LandingContextT = { + landingType: LandingType + title: string + intro: string + productCallout: string + permissions: string + tocItems: Array + variant?: 'compact' | 'expanded' + featuredLinks: Record> + renderedPage: string + currentLearningTrack?: LearningTrack + currentLayout: string + heroImage?: string + // For discovery landing pages + recommended?: string[] // Array of article paths + // For discovery landing pages + introLinks?: Record +} + +export const LandingContext = createContext(null) + +export const useLandingContext = (): LandingContextT => { + const context = useContext(LandingContext) + + if (!context) { + throw new Error('"useLandingContext" may only be used inside "LandingContext.Provider"') + } + + return context +} + +export const getLandingContextFromRequest = async ( + req: any, + landingType: LandingType, +): Promise => { + const page = req.context.page + + let recommended: string[] = [] + if (landingType === 'discovery') { + // Support legacy `spotlight` property as `recommended` for pages like Copilot Cookbook + // However, `spotlight` will have lower priority than the `recommended` property + if (page.recommended && page.recommended.length > 0) { + recommended = page.recommended + } else if (page.spotlight && page.spotlight.length > 0) { + // Remove the `image` property from spotlight items, since we don't use those for the carousel + recommended = page.spotlight.map((item: any) => item.article) + } + } + + return { + landingType, + title: page.title, + productCallout: page.product || '', + permissions: page.permissions || '', + intro: page.intro, + tocItems: (req.context.genericTocFlat || req.context.genericTocNested || []).map( + mapRawTocItemToTocItem, + ), + variant: req.context.genericTocFlat ? 'expanded' : 'compact', + featuredLinks: getFeaturedLinksFromReq(req), + renderedPage: req.context.renderedPage, + currentLearningTrack: req.context.currentLearningTrack, + currentLayout: req.context.currentLayoutName, + heroImage: page.heroImage || '/assets/images/banner-images/hero-1.png', + introLinks: page.introLinks || null, + recommended, + } +} diff --git a/src/landings/pages/product.tsx b/src/landings/pages/product.tsx index eeed5a9c96d6..c5414d908267 100644 --- a/src/landings/pages/product.tsx +++ b/src/landings/pages/product.tsx @@ -49,22 +49,12 @@ import { } from '@/frame/components/context/CategoryLandingContext' import { BespokeLanding } from '@/landings/components/bespoke/BespokeLanding' import { - BespokeContext, - getBespokeContextFromRequest, - BespokeContextT, -} from '@/landings/context/BespokeContext' + LandingContext, + getLandingContextFromRequest, + LandingContextT, +} from '@/landings/context/LandingContext' import { DiscoveryLanding } from '@/landings/components/discovery/DiscoveryLanding' -import { - DiscoveryContext, - DiscoveryContextT, - getDiscoveryContextFromRequest, -} from '@/landings/context/DiscoveryContext' import { JourneyLanding } from '@/landings/components/journey/JourneyLanding' -import { - getJourneyContextFromRequest, - JourneyContext, - JourneyContextT, -} from '@/landings/context/JourneyContext' function initiateArticleScripts() { copyCode() @@ -79,9 +69,9 @@ type Props = { tocLandingContext?: TocLandingContextT articleContext?: ArticleContextT categoryLandingContext?: CategoryLandingContextT - bespokeContext?: BespokeContextT - discoveryContext?: DiscoveryContextT - journeyContext?: JourneyContextT + bespokeContext?: LandingContextT + discoveryContext?: LandingContextT + journeyContext?: LandingContextT } const GlobalPage = ({ mainContext, @@ -108,21 +98,21 @@ const GlobalPage = ({ let content if (bespokeContext) { content = ( - + - + ) } else if (discoveryContext) { content = ( - + - + ) } else if (journeyContext) { content = ( - + - + ) } else if (productLandingContext) { content = ( @@ -184,23 +174,23 @@ export const getServerSideProps: GetServerSideProps = async (context) => // This looks a little funky, but it's so we only send one context's data to the client // TODO: TEMP: This is a temporary solution to turn off/on new landing pages while we develop them if (currentLayoutName === 'bespoke-landing' || req.query?.feature === 'bespoke-landing') { - props.bespokeContext = await getBespokeContextFromRequest(req) - additionalUINamespaces.push('bespoke_landing') + props.bespokeContext = await getLandingContextFromRequest(req, 'bespoke') + additionalUINamespaces.push('bespoke_landing', 'product_landing') } else if (currentLayoutName === 'journey-landing' || req.query?.feature === 'journey-landing') { - props.journeyContext = await getJourneyContextFromRequest(req) - additionalUINamespaces.push('journey_landing') + props.journeyContext = await getLandingContextFromRequest(req, 'journey') + additionalUINamespaces.push('journey_landing', 'product_landing') } else if ( currentLayoutName === 'discovery-landing' || req?.query?.feature === 'discovery-landing' ) { - props.discoveryContext = await getDiscoveryContextFromRequest(req) - additionalUINamespaces.push('discovery_landing') + props.discoveryContext = await getLandingContextFromRequest(req, 'discovery') + additionalUINamespaces.push('discovery_landing', 'product_landing') } else if (currentLayoutName === 'product-landing') { props.productLandingContext = await getProductLandingContextFromRequest(req) additionalUINamespaces.push('product_landing') } else if (currentLayoutName === 'product-guides') { props.productGuidesContext = getProductGuidesContextFromRequest(req) - additionalUINamespaces.push('product_guides') + additionalUINamespaces.push('product_guides', 'product_landing') } else if (relativePath?.endsWith('index.md')) { if (currentLayoutName === 'category-landing') { props.categoryLandingContext = getCategoryLandingContextFromRequest(req) diff --git a/src/links/scripts/rendered-content-link-checker.ts b/src/links/scripts/rendered-content-link-checker.ts index f2a847070d4e..dacfe7009718 100755 --- a/src/links/scripts/rendered-content-link-checker.ts +++ b/src/links/scripts/rendered-content-link-checker.ts @@ -1073,6 +1073,20 @@ async function checkExternalURLCached( const now = new Date().getTime() const url = href.split('#')[0] + // Skip domains that are currently rate limited (with 1 hour TTL) + const { hostname } = new URL(url) + const rateLimitTime = _rateLimitedDomains.get(hostname) + if (rateLimitTime) { + const oneHourAgo = Date.now() - 60 * 60 * 1000 // 1 hour in ms + if (rateLimitTime > oneHourAgo) { + if (verbose) core.info(`Skipping ${url} - domain ${hostname} is rate limited`) + return { ok: false, statusCode: 429, skipReason: 'Domain rate limited' } + } else { + // Rate limit has expired, remove it + _rateLimitedDomains.delete(hostname) + } + } + if (cacheMaxAge) { const tooOld = now - Math.floor(jitter(cacheMaxAge, 10)) if (db && db.data.urls[url]) { @@ -1122,105 +1136,70 @@ async function checkExternalURL( return _fetchCache.get(cleanURL) } -const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)) - -// Global for recording which domains we get rate-limited on. -// For example, if you got rate limited on `something.github.com/foo` -// and now we're asked to fetch for `something.github.com/bar` -// it's good to know to now bother yet. -const _rateLimitedDomains = new Map() +// Track domains that have returned 429 to skip future requests +// Maps hostname to timestamp when rate limit was detected +const _rateLimitedDomains = new Map() async function innerFetch( core: CoreInject, url: string, - config: { verbose?: boolean; useGET?: boolean; patient?: boolean; retries?: number } = {}, + config: { verbose?: boolean; patient?: boolean; retries?: number } = {}, ) { - const { verbose, useGET, patient } = config - - const { hostname } = new URL(url) - if (_rateLimitedDomains.has(hostname)) { - await sleep(_rateLimitedDomains.get(hostname)) - } - // The way `got` does retries: - // - // sleep = 1000 * Math.pow(2, retry - 1) + Math.random() * 100 - // - // So, it means: - // - // 1. ~1000ms - // 2. ~2000ms - // 3. ~4000ms - // - // ...if the limit we set is 3. - // Our own timeout, in @/frame/middleware/timeout.js defaults to 10 seconds. - // So there's no point in trying more attempts than 3 because it would - // just timeout on the 10s. (i.e. 1000 + 2000 + 4000 + 8000 > 10,000) - const retry = { - limit: patient ? 6 : 2, - } - const timeout = { request: patient ? 10000 : 2000 } + const { verbose, patient } = config const headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36', } - const retries = config.retries || 0 - const method = useGET ? 'GET' : 'HEAD' + const retries = patient ? 3 : 2 + const timeout = patient ? 10000 : 5000 + + if (verbose) core.info(`External URL HEAD: ${url}`) - if (verbose) core.info(`External URL ${method}: ${url} (retries: ${retries})`) try { - const r = await fetchWithRetry( + // Try HEAD first + let r = await fetchWithRetry( url, { - method, + method: 'HEAD', headers, }, { - retries: retry.limit, - timeout: timeout.request, + retries, + timeout, throwHttpErrors: false, }, ) + + // If HEAD doesn't work, try GET + if (r.status === 405 || r.status === 404 || r.status === 403) { + if (verbose) core.info(`External URL GET: ${url} (HEAD failed with ${r.status})`) + r = await fetchWithRetry( + url, + { + method: 'GET', + headers, + }, + { + retries, + timeout, + throwHttpErrors: false, + }, + ) + } + if (verbose) { - core.info(`External URL ${method} ${url}: ${r.status} (retries: ${retries})`) + core.info(`External URL ${url}: ${r.status}`) } - // If we get rate limited, remember that this hostname is now all - // rate limited. And sleep for the number of seconds that the - // `retry-after` header indicated. + // Track rate limited domains with timestamp + const { hostname } = new URL(url) if (r.status === 429) { - let sleepTime = Math.min( - 60_000, - Math.max( - 10_000, - r.headers.get('retry-after') ? getRetryAfterSleep(r.headers.get('retry-after')) : 1_000, - ), - ) - // Sprinkle a little jitter so it doesn't all start again all - // at the same time - sleepTime += Math.random() * 10 * 1000 - // Give it a bit extra when we can be really patient - if (patient) sleepTime += 30 * 1000 - - _rateLimitedDomains.set(hostname, sleepTime + Math.random() * 10 * 1000) - if (verbose) - core.info( - chalk.yellow( - `Rate limited on ${hostname} (${url}). Sleeping for ${(sleepTime / 1000).toFixed(1)}s`, - ), - ) - await sleep(sleepTime) - return innerFetch(core, url, Object.assign({}, config, { retries: retries + 1 })) - } else { - _rateLimitedDomains.delete(hostname) + _rateLimitedDomains.set(hostname, Date.now()) + if (verbose) core.info(`Domain ${hostname} is now rate limited for 1 hour`) } - // Perhaps the server doesn't support HEAD requests. - // If so, try again with a regular GET. - if ((r.status === 405 || r.status === 404 || r.status === 403) && !useGET) { - return innerFetch(core, url, Object.assign({}, config, { useGET: true })) - } if (verbose) { core.info((r.ok ? chalk.green : chalk.red)(`${r.status} on ${url}`)) } @@ -1236,17 +1215,6 @@ async function innerFetch( } } -// Return number of milliseconds from a `Retry-After` header value -function getRetryAfterSleep(headerValue: string | null) { - if (!headerValue) return 0 - let ms = Math.round(parseFloat(headerValue) * 1000) - if (isNaN(ms)) { - const nextDate = new Date(headerValue) - ms = Math.max(0, nextDate.getTime() - new Date().getTime()) - } - return ms -} - function checkImageSrc(src: string) { if (!src.startsWith('/') && !src.startsWith('http')) { return { CRITICAL: 'Image path is not absolute. Should start with a /' }