diff --git a/.github/actions/deploy-to-github-pages/action.yml b/.github/actions/deploy-to-github-pages/action.yml index d11464ed94..b0ee7c6eb7 100644 --- a/.github/actions/deploy-to-github-pages/action.yml +++ b/.github/actions/deploy-to-github-pages/action.yml @@ -20,6 +20,10 @@ inputs: cloudflare-zone: description: The Cloudflare zone to purge. required: false + external-https: + description: Whether HTTPS is set up externally, e.g. on Cloudflare instead of GitHub. + default: false + required: false outputs: url: description: The URL to which the site was deployed @@ -41,6 +45,15 @@ runs: id: pages uses: actions/configure-pages@v5 + - name: set base URL + shell: bash + run: | + base_url="${{ steps.pages.outputs.base_url }}" + if [ "${{ inputs.external-https }}" = true ] ; then + base_url="$(echo "$base_url" | sed 's/^http:/https:/')" + fi + echo "base_url=$base_url" >>"$GITHUB_ENV" + - name: configure Hugo and Pagefind version shell: bash run: | @@ -59,7 +72,7 @@ runs: env: HUGO_RELATIVEURLS: false shell: bash - run: hugo config && hugo --baseURL "${{ steps.pages.outputs.base_url }}/" + run: hugo config && hugo --baseURL "${{ env.base_url }}/" - name: run Pagefind ${{ env.PAGEFIND_VERSION }} to build the search index shell: bash @@ -110,7 +123,6 @@ runs: id: remap shell: bash run: | - base_url='${{ steps.pages.outputs.base_url }}' echo "result=$(echo "$base_url" | sed 's|^\(.*\)\(/git-scm\.com\)$|(\1)?\2(.*)|') file://$PWD/public\$2" \ >>$GITHUB_OUTPUT @@ -120,6 +132,17 @@ runs: sed -n 's|^\(https\?:\/\/.*\)\(/git-scm\.com\)$|--remap '\''(\1.*) file://../$1'\''|p')" \ >>$GITHUB_OUTPUT + - name: check for downgrades to unencrypted HTTP + if: startsWith(env.base_url, 'https://') + shell: bash + # The `--require-https` option of lychee could come in handy, + # but it also complains about `http://` links to other sites, + # and (more importantly) doesn't work in offline mode. + # A simple `grep` should work without any false positives, + # unless git-scm.com mentions the base URL of one of its forks, + # which is unlikely. + run: '! grep -FInr "http:${base_url#https:}" public' + - name: check for broken links id: lychee uses: lycheeverse/lychee-action@v2 @@ -127,7 +150,7 @@ runs: args: >- --offline --fallback-extensions html - --base '${{ steps.pages.outputs.base_url }}' + --base '${{ env.base_url }}' --remap '${{ steps.remap.outputs.result }}' ${{ steps.remap.outputs.remap-dotdot }} --exclude file:///path/to/repo.git/ @@ -192,23 +215,21 @@ runs: - name: Install @playwright/test shell: bash run: npm install @playwright/test - - name: Edit /etc/hosts to map git-scm.com to GitHub + - name: Edit /etc/hosts to map the deployed domain to GitHub shell: bash - # This side-steps the Cloudflare caches - run: sudo sh -c 'echo "185.199.108.153 git-scm.com" >>/etc/hosts' + # This side-steps any caches that might be configured on the domain, + # and works even when the real server is not reachable from GitHub. + run: | + host="$(echo "$base_url" | sed -E 's|^https?://([^:/]+).*|\1|')" + sudo sh -c "echo '185.199.108.153 $host' >>/etc/hosts" - name: Run Playwright tests shell: bash id: playwright env: - PLAYWRIGHT_TEST_URL: ${{ steps.pages.outputs.base_url }} - run: | + PLAYWRIGHT_TEST_URL: ${{ env.base_url }} # avoid test failures when HTTPS is enforced half-way through - case "$PLAYWRIGHT_TEST_URL" in - https://*|http://git-scm.com) ;; # okay, leave as-is - http://*) PLAYWRIGHT_TEST_URL="https://${PLAYWRIGHT_TEST_URL#http://}";; - esac && - echo "result=$PLAYWRIGHT_TEST_URL" >>$GITHUB_OUTPUT && - npx playwright test --project=chrome + PLAYWRIGHT_EXTERNAL_HTTPS: ${{ inputs.external-https }} + run: npx playwright test --project=chrome - uses: actions/upload-artifact@v4 if: always() && steps.playwright.outputs.result != '' with: diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 02bdb826af..de8b94d79b 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -27,3 +27,4 @@ jobs: with: cloudflare-token: ${{ secrets.CLOUDFLARE_TOKEN }} cloudflare-zone: ${{ secrets.CLOUDFLARE_ZONE }} + external-https: ${{ vars.EXTERNAL_HTTPS }} diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 884896b320..45ecd6b99d 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -34,6 +34,16 @@ With this change, the site can be tested in the fork by pushing to the `gh-pages` branch (which will trigger the `deploy.yml` workflow) and then navigating to https://git-scm..github.io/. +If the site will be deployed to a custom domain that supports HTTPS, +but the "[Enforce HTTPS]" option cannot be enabled in the GitHub Pages settings +(this can happen if the domain points to a third-party gateway), +the [GitHub Actions variable] `EXTERNAL_HTTPS` should be set to `true`, +so that the site can be built with a proper HTTPS base URL. +The official `git-scm.com` domain is an example of such a setup. + +[Enforce HTTPS]: https://docs.github.com/en/pages/getting-started-with-github-pages/securing-your-github-pages-site-with-https#enforcing-https-for-your-github-pages-site +[GitHub Actions variable]: https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#defining-configuration-variables-for-multiple-workflows + ## Non-static parts While the site consists mostly of static content, there are a couple of diff --git a/assets/js/application.js b/assets/js/application.js index 0610b18cb5..0b7f0f54e9 100644 --- a/assets/js/application.js +++ b/assets/js/application.js @@ -56,27 +56,27 @@ var DownloadBox = { var os = window.session.browser.os; // Mac, Win, Linux if(os == "Mac") { $(".monitor").addClass("mac"); - $("#download-link").text("Download for Mac").attr("href", `${baseURLPrefix}download/mac`); + $("#download-link").text("Download for Mac").attr("href", `${baseURLPrefix}downloads/mac`); $("#gui-link").removeClass('mac').addClass('gui'); - $("#gui-link").text("Mac GUIs").attr("href", `${baseURLPrefix}download/gui/mac`); + $("#gui-link").text("Mac GUIs").attr("href", `${baseURLPrefix}downloads/guis?os=mac`); $("#gui-os-filter").attr('data-os', 'mac'); $("#gui-os-filter").text("Only show GUIs for my OS (Mac)") } else if (os == "Windows") { $(".monitor").addClass("windows"); - $("#download-link").text("Download for Windows").attr("href", `${baseURLPrefix}download/win`); + $("#download-link").text("Download for Windows").attr("href", `${baseURLPrefix}downloads/win`); $("#gui-link").removeClass('mac').addClass('gui'); - $("#gui-link").text("Windows GUIs").attr("href", `${baseURLPrefix}download/gui/windows`); + $("#gui-link").text("Windows GUIs").attr("href", `${baseURLPrefix}downloads/guis?os=windows`); $("#alt-link").removeClass("windows").addClass("mac"); - $("#alt-link").text("Mac Build").attr("href", `${baseURLPrefix}download/mac`); + $("#alt-link").text("Mac Build").attr("href", `${baseURLPrefix}downloads/mac`); $("#gui-os-filter").attr('data-os', 'windows'); $("#gui-os-filter").text("Only show GUIs for my OS (Windows)") } else if (os == "Linux") { $(".monitor").addClass("linux"); - $("#download-link").text("Download for Linux").attr("href", `${baseURLPrefix}download/linux`); + $("#download-link").text("Download for Linux").attr("href", `${baseURLPrefix}downloads/linux`); $("#gui-link").removeClass('mac').addClass('gui'); - $("#gui-link").text("Linux GUIs").attr("href", `${baseURLPrefix}download/gui/linux`); + $("#gui-link").text("Linux GUIs").attr("href", `${baseURLPrefix}downloads/guis?os=linux`); $("#alt-link").removeClass("windows").addClass("mac"); - $("#alt-link").text("Mac Build").attr("href", `${baseURLPrefix}download/mac`); + $("#alt-link").text("Mac Build").attr("href", `${baseURLPrefix}downloads/mac`); $("#gui-os-filter").attr('data-os', 'linux'); $("#gui-os-filter").text("Only show GUIs for my OS (Linux)") } else { diff --git a/content/downloads/_index.html b/content/downloads/_index.html index ff097fba5c..f683cb51db 100644 --- a/content/downloads/_index.html +++ b/content/downloads/_index.html @@ -14,15 +14,15 @@

Downloads

- }}" class="icon mac">macOS + }}" class="icon mac">macOS - }}" class="icon windows">Windows + }}" class="icon windows">Windows
- }}" class="icon linux">Linux/Unix + }}" class="icon linux">Linux/Unix
diff --git a/layouts/partials/site-root.html b/layouts/partials/site-root.html index 70f5ded911..01ce7be7bf 100644 --- a/layouts/partials/site-root.html +++ b/layouts/partials/site-root.html @@ -50,7 +50,7 @@

Community

Tarballs - Windows Build + Windows Build Source Code diff --git a/playwright.config.js b/playwright.config.js index 3f67b94ac0..a5da5c5f7f 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -34,6 +34,10 @@ module.exports = defineConfig({ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry', + + /* Ignore ERR_CERT_COMMON_NAME_INVALID when tesing against GitHub's server, + if the real certificate is hosted by a third party (e.g. Cloudflare). */ + ignoreHTTPSErrors: process.env.PLAYWRIGHT_EXTERNAL_HTTPS === 'true', }, /* Configure projects for major browsers */ diff --git a/tests/git-scm.spec.js b/tests/git-scm.spec.js index f47f98792b..234bb4bcb1 100644 --- a/tests/git-scm.spec.js +++ b/tests/git-scm.spec.js @@ -59,7 +59,7 @@ test.describe('Windows', () => { await expect(page.getByRole('link', { name: 'Graphical UIs' })).toBeHidden() const windowsGUIs = page.getByRole('link', { name: 'Windows GUIs' }) await expect(windowsGUIs).toBeVisible() - await expect(windowsGUIs).toHaveAttribute('href', /\/download\/gui\/windows$/) + await expect(windowsGUIs).toHaveAttribute('href', /\/downloads\/guis\?os=windows$/) // navigate to Windows GUIs await windowsGUIs.click()