From 1ef34a7beeefa0634a1c9852e688bb8b70bfb579 Mon Sep 17 00:00:00 2001 From: Nedas Date: Sun, 11 Oct 2026 12:22:44 +0200 Subject: [PATCH 1/9] Added temp pipeline --- .github/workflows/deploy-staging.yml | 76 ++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 .github/workflows/deploy-staging.yml diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml new file mode 100644 index 000000000..df278a08c --- /dev/null +++ b/.github/workflows/deploy-staging.yml @@ -0,0 +1,76 @@ +name: Deploy to Staging (manual) + +# One-off / on-demand deploy of the full site to the staging Static Web App (tedocstestswa). +# Build steps mirror deploy.yml exactly. Manual trigger only for now - in the pipeline +# hardening stage this becomes the automatic deploy target for merges to main. +# +# Requires the AZURE_SWA_TOKEN_TEST repository secret (the staging SWA's deployment token). + +on: + workflow_dispatch: + +jobs: + build_job: + runs-on: windows-latest + name: Build Documentation + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Set up .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0.x' + - name: Cache DocFX + uses: actions/cache@v4 + with: + path: ~/.dotnet/tools + key: docfx-${{ runner.os }} + - name: Install DocFX + run: dotnet tool install -g docfx --ignore-failed-sources + - name: Generate configs + run: | + python build_scripts/gen_redirects.py + python build_scripts/gen_languages.py + - name: Generate API metadata + run: docfx metadata localizedContent/en/docfx.json + - name: Verify API files generated + run: | + if (!(Test-Path "content/api/toc.yml")) { + Write-Error "API metadata generation failed - toc.yml not found" + exit 1 + } + Write-Host "API files generated: $((Get-ChildItem content/api/*.yml).Count) YAML files" + shell: pwsh + - name: Build all documentation + run: python build-docs.py --all --skip-gen + - name: Upload build artifact + uses: actions/upload-artifact@v4 + with: + name: site + path: _site + retention-days: 7 + + deploy_job: + needs: build_job + runs-on: ubuntu-latest + name: Deploy to Staging + steps: + - name: Download build artifact + uses: actions/download-artifact@v4 + with: + name: site + path: _site + - name: Deploy to Azure Static Web Apps (staging) + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_SWA_TOKEN_TEST }} + action: "upload" + app_location: "_site" + api_location: "" + output_location: "" + skip_app_build: true From 0ba87a5752bbe903aaefe28f7d562a7721621aaf Mon Sep 17 00:00:00 2001 From: Nedas Date: Sun, 11 Oct 2026 12:28:08 +0200 Subject: [PATCH 2/9] Temp solution --- .github/workflows/deploy-staging.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index df278a08c..8c2bcaf7f 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -8,6 +8,12 @@ name: Deploy to Staging (manual) on: workflow_dispatch: + # TEMP: lets this run from the feature branch before it exists on main + # (workflow_dispatch only registers once the file is on the default branch). + # Remove this push trigger when merging to main. + push: + branches: + - feature/docs-migration jobs: build_job: From b814614ce9e545f4ad6191b3f97450084374d7c3 Mon Sep 17 00:00:00 2001 From: Nedas Date: Sun, 11 Oct 2026 12:32:49 +0200 Subject: [PATCH 3/9] Temp fix --- content/features/mcp-server.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/features/mcp-server.md b/content/features/mcp-server.md index b2a5652f1..e4bd2dbff 100644 --- a/content/features/mcp-server.md +++ b/content/features/mcp-server.md @@ -216,7 +216,7 @@ The [AI Assistant](xref:ai-assistant) chat runs scripts the same way, with the s These are blocked regardless of your grants: - `ExecuteCommand`, which runs raw TMSL or XMLA, always fails in an agent-run script. -- An agent script that accesses the file system, makes a web request or references an external assembly doesn't run. The check is the same analysis of the compiled script that the `BlockUnsafeScripts` policy uses; see [What BlockUnsafeScripts blocks](xref:csharp-scripts#what-blockunsafescripts-blocks) for the full list. What happens to the script depends on your grants and policies: +- An agent script that accesses the file system, makes a web request or references an external assembly doesn't run. The check is the same analysis of the compiled script that the `BlockUnsafeScripts` policy uses; see [What counts as staying within the model](xref:csharp-scripts#what-counts-as-staying-within-the-model) for the full list. What happens to the script depends on your grants and policies: - With **Documents > Write**, the script opens as an **Agent script (review)** document, and the tool result tells the agent to have you review and run it. - Without **Documents > Write**, the script doesn't run and no document opens. - With the `BlockUnsafeScripts` [policy](xref:policies) set, the script doesn't run and no document opens. From 8a33d482265c4eaf6a17bca700f0831a100a615c Mon Sep 17 00:00:00 2001 From: Nedas Date: Sun, 11 Oct 2026 12:40:29 +0200 Subject: [PATCH 4/9] Also deploy to prod --- .github/workflows/deploy-staging.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index 8c2bcaf7f..46c45ae45 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -74,7 +74,7 @@ jobs: - name: Deploy to Azure Static Web Apps (staging) uses: Azure/static-web-apps-deploy@v1 with: - azure_static_web_apps_api_token: ${{ secrets.AZURE_SWA_TOKEN_TEST }} + azure_static_web_apps_api_token: ${{ secrets.AZURE_SWA_TOKEN_PROD }} action: "upload" app_location: "_site" api_location: "" From d4551e41fd4efae056ff56f04dc441f452c4dd3e Mon Sep 17 00:00:00 2001 From: Nedas Date: Mon, 12 Oct 2026 13:40:22 +0200 Subject: [PATCH 5/9] Saving changes --- .github/workflows/deploy.yml | 120 +++++++++++++++++++++++++++++++---- 1 file changed, 107 insertions(+), 13 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 81844d417..79d646a1d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,4 +1,29 @@ -name: Azure Static Web Apps CI/CD +name: Docs CI/CD + +# Stage-2 pipeline for the docs site (new governance setup). +# +# Flow: +# PR -> build -> preview environment on the test SWA (URL commented on the PR) +# main push -> build once -> staging (test SWA, automatic) +# -> production (prod SWA) AFTER required-reviewer approval +# +# BEFORE this lands on main (order matters): +# 1. Create the GitHub environment "production": add Required Reviewers (the docs release +# group), restrict deployments to the main branch, and add AZURE_SWA_TOKEN_PROD as an +# ENVIRONMENT secret. If the environment does not exist when this workflow first runs, +# GitHub auto-creates it WITHOUT protection rules and the approval gate is a no-op. +# 2. AZURE_SWA_TOKEN_TEST stays a repository secret (previews + staging need it on PR events). +# 3. The DNS flip to the new prod SWA must already be done - this PR deletes the old +# deploy.yml, so after the merge nothing deploys to the old SWA anymore. (Between the +# flip and this merge, main merges reach no live site - keep that window short.) +# +# Cleanup that rides along or follows: deploy-staging.yml is deleted before this PR is merged +# (it only exists to seed the staging SWA from the feature branch), and the old +# AZURE_STATIC_WEB_APPS_API_TOKEN_DELIGHTFUL_MUD_081AFFE03 secret is deleted once the old SWA +# is decommissioned. +# +# Fork PRs: repository secrets are not exposed to pull_request runs from forks, so fork PRs +# build but do not get preview deployments - same limitation as the old setup. on: push: @@ -11,6 +36,8 @@ on: jobs: build_job: + # Same localization-branch carve-out as the old deploy.yml: the bulk 'localization' PR only + # builds when a review is requested, to avoid rebuilding on every bot sync. if: (github.head_ref != 'localization' && github.event_name == 'push') || (github.head_ref != 'localization' && github.event_name == 'pull_request' && github.event.action != 'closed') || (github.head_ref == 'localization' && github.event.action == 'review_requested') runs-on: windows-latest name: Build Documentation @@ -53,25 +80,28 @@ jobs: uses: actions/upload-artifact@v4 with: name: site + # 30 days so a pending prod approval (GitHub expires them after 30 days) can always + # still deploy its artifact, and recent runs stay re-runnable as a rollback path. + retention-days: 30 path: _site - retention-days: 7 - deploy_job: - if: (github.head_ref != 'localization' && github.event_name == 'push') || (github.head_ref != 'localization' && github.event_name == 'pull_request' && github.event.action != 'closed') || (github.head_ref == 'localization' && github.event.action == 'review_requested') + # PR -> preview environment on the TEST Static Web App. The SWA action creates/updates a + # preview environment automatically for pull_request events and comments the URL on the PR. + deploy_preview: + if: github.event_name == 'pull_request' && github.event.action != 'closed' needs: build_job runs-on: ubuntu-latest - name: Deploy to Azure + name: Deploy PR Preview (staging SWA) steps: - name: Download build artifact uses: actions/download-artifact@v4 with: name: site path: _site - - name: Deploy to Azure Static Web Apps - id: builddeploy + - name: Deploy preview environment uses: Azure/static-web-apps-deploy@v1 with: - azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_DELIGHTFUL_MUD_081AFFE03 }} + azure_static_web_apps_api_token: ${{ secrets.AZURE_SWA_TOKEN_TEST }} repo_token: ${{ secrets.GITHUB_TOKEN }} action: "upload" app_location: "_site" @@ -79,14 +109,78 @@ jobs: output_location: "" skip_app_build: true - close_pull_request_job: + close_preview: if: github.event_name == 'pull_request' && github.event.action == 'closed' runs-on: ubuntu-latest - name: Close Pull Request Job + name: Close PR Preview steps: - - name: Close Pull Request - id: closepullrequest + - name: Close preview environment uses: Azure/static-web-apps-deploy@v1 with: - azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_DELIGHTFUL_MUD_081AFFE03 }} + azure_static_web_apps_api_token: ${{ secrets.AZURE_SWA_TOKEN_TEST }} action: "close" + + # main -> staging, automatically (production slot of the test SWA). + deploy_staging: + if: github.event_name == 'push' + needs: build_job + runs-on: ubuntu-latest + name: Deploy to Staging + environment: + name: staging + url: https://docs-staging.tabulareditor.com + steps: + - name: Download build artifact + uses: actions/download-artifact@v4 + with: + name: site + path: _site + # OPTIONAL (stakeholder decision): keep crawlers off staging without touching the + # artifact that prod will reuse - patches only the staging COPY of the SWA config. + # Canonical tags already point at prod, so this is belt-and-braces, not required. + # - name: Add noindex header to staging copy + # run: | + # jq '.globalHeaders["X-Robots-Tag"] = "noindex"' _site/staticwebapp.config.json > tmp.json + # mv tmp.json _site/staticwebapp.config.json + - name: Deploy to staging SWA + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_SWA_TOKEN_TEST }} + action: "upload" + app_location: "_site" + api_location: "" + output_location: "" + skip_app_build: true + + # main -> production, gated. The job pauses here until someone in the 'production' + # environment's Required Reviewers approves it in the Actions UI. It then ships the SAME + # artifact staging verified - never a rebuild. + deploy_production: + if: github.event_name == 'push' + needs: [build_job, deploy_staging] + runs-on: ubuntu-latest + name: Deploy to Production + environment: + name: production + url: https://docs.tabulareditor.com + # If several merges stack up unapproved, older pending deployments are cancelled so only + # the newest merge can be approved - stale content can never be promoted by accident. + concurrency: + group: docs-prod-deploy + cancel-in-progress: true + steps: + - name: Download build artifact + uses: actions/download-artifact@v4 + with: + name: site + path: _site + - name: Deploy to production SWA + uses: Azure/static-web-apps-deploy@v1 + with: + # Environment secret under 'production' - unreadable before the approval gate. + azure_static_web_apps_api_token: ${{ secrets.AZURE_SWA_TOKEN_PROD }} + action: "upload" + app_location: "_site" + api_location: "" + output_location: "" + skip_app_build: true From b7255dcf4612c54b7f0dd5906f49b7b2831246fe Mon Sep 17 00:00:00 2001 From: Nedas Date: Wed, 21 Oct 2026 14:36:12 +0200 Subject: [PATCH 6/9] Removed the one off pipeline and removed unnecessary comments --- .github/workflows/deploy-staging.yml | 82 ---------------------------- .github/workflows/deploy.yml | 37 +------------ 2 files changed, 2 insertions(+), 117 deletions(-) delete mode 100644 .github/workflows/deploy-staging.yml diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml deleted file mode 100644 index 46c45ae45..000000000 --- a/.github/workflows/deploy-staging.yml +++ /dev/null @@ -1,82 +0,0 @@ -name: Deploy to Staging (manual) - -# One-off / on-demand deploy of the full site to the staging Static Web App (tedocstestswa). -# Build steps mirror deploy.yml exactly. Manual trigger only for now - in the pipeline -# hardening stage this becomes the automatic deploy target for merges to main. -# -# Requires the AZURE_SWA_TOKEN_TEST repository secret (the staging SWA's deployment token). - -on: - workflow_dispatch: - # TEMP: lets this run from the feature branch before it exists on main - # (workflow_dispatch only registers once the file is on the default branch). - # Remove this push trigger when merging to main. - push: - branches: - - feature/docs-migration - -jobs: - build_job: - runs-on: windows-latest - name: Build Documentation - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - name: Set up .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: '8.0.x' - - name: Cache DocFX - uses: actions/cache@v4 - with: - path: ~/.dotnet/tools - key: docfx-${{ runner.os }} - - name: Install DocFX - run: dotnet tool install -g docfx --ignore-failed-sources - - name: Generate configs - run: | - python build_scripts/gen_redirects.py - python build_scripts/gen_languages.py - - name: Generate API metadata - run: docfx metadata localizedContent/en/docfx.json - - name: Verify API files generated - run: | - if (!(Test-Path "content/api/toc.yml")) { - Write-Error "API metadata generation failed - toc.yml not found" - exit 1 - } - Write-Host "API files generated: $((Get-ChildItem content/api/*.yml).Count) YAML files" - shell: pwsh - - name: Build all documentation - run: python build-docs.py --all --skip-gen - - name: Upload build artifact - uses: actions/upload-artifact@v4 - with: - name: site - path: _site - retention-days: 7 - - deploy_job: - needs: build_job - runs-on: ubuntu-latest - name: Deploy to Staging - steps: - - name: Download build artifact - uses: actions/download-artifact@v4 - with: - name: site - path: _site - - name: Deploy to Azure Static Web Apps (staging) - uses: Azure/static-web-apps-deploy@v1 - with: - azure_static_web_apps_api_token: ${{ secrets.AZURE_SWA_TOKEN_PROD }} - action: "upload" - app_location: "_site" - api_location: "" - output_location: "" - skip_app_build: true diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 11d86c381..2e1774d79 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,29 +1,9 @@ name: Docs CI/CD -# Stage-2 pipeline for the docs site (new governance setup). -# # Flow: # PR -> build -> preview environment on the test SWA (URL commented on the PR) # main push -> build once -> staging (test SWA, automatic) # -> production (prod SWA) AFTER required-reviewer approval -# -# BEFORE this lands on main (order matters): -# 1. Create the GitHub environment "production": add Required Reviewers (the docs release -# group), restrict deployments to the main branch, and add AZURE_SWA_TOKEN_PROD as an -# ENVIRONMENT secret. If the environment does not exist when this workflow first runs, -# GitHub auto-creates it WITHOUT protection rules and the approval gate is a no-op. -# 2. AZURE_SWA_TOKEN_TEST stays a repository secret (previews + staging need it on PR events). -# 3. The DNS flip to the new prod SWA must already be done - this PR deletes the old -# deploy.yml, so after the merge nothing deploys to the old SWA anymore. (Between the -# flip and this merge, main merges reach no live site - keep that window short.) -# -# Cleanup that rides along or follows: deploy-staging.yml is deleted before this PR is merged -# (it only exists to seed the staging SWA from the feature branch), and the old -# AZURE_STATIC_WEB_APPS_API_TOKEN_DELIGHTFUL_MUD_081AFFE03 secret is deleted once the old SWA -# is decommissioned. -# -# Fork PRs: repository secrets are not exposed to pull_request runs from forks, so fork PRs -# build but do not get preview deployments - same limitation as the old setup. on: push: @@ -109,8 +89,6 @@ jobs: run: echo "::notice title=Doctests not executed::Set the TE_CLI_DOWNLOAD_URL repository secret to a te-linux-x64.tar.gz download URL to compile and run the annotated C# blocks in CI. Only annotation validation ran." build_job: - # Same localization-branch carve-out as the old deploy.yml: the bulk 'localization' PR only - # builds when a review is requested, to avoid rebuilding on every bot sync. if: (github.head_ref != 'localization' && github.event_name == 'push') || (github.head_ref != 'localization' && github.event_name == 'pull_request' && github.event.action != 'closed') || (github.head_ref == 'localization' && github.event.action == 'review_requested') runs-on: windows-latest name: Build Documentation @@ -167,8 +145,6 @@ jobs: uses: actions/upload-artifact@v4 with: name: site - # 30 days so a pending prod approval (GitHub expires them after 30 days) can always - # still deploy its artifact, and recent runs stay re-runnable as a rollback path. retention-days: 30 path: _site link_check_job: @@ -246,7 +222,7 @@ jobs: azure_static_web_apps_api_token: ${{ secrets.AZURE_SWA_TOKEN_TEST }} action: "close" - # main -> staging, automatically (production slot of the test SWA). + # main -> staging, automatically deploy_staging: if: github.event_name == 'push' needs: build_job @@ -261,13 +237,6 @@ jobs: with: name: site path: _site - # OPTIONAL (stakeholder decision): keep crawlers off staging without touching the - # artifact that prod will reuse - patches only the staging COPY of the SWA config. - # Canonical tags already point at prod, so this is belt-and-braces, not required. - # - name: Add noindex header to staging copy - # run: | - # jq '.globalHeaders["X-Robots-Tag"] = "noindex"' _site/staticwebapp.config.json > tmp.json - # mv tmp.json _site/staticwebapp.config.json - name: Deploy to staging SWA uses: Azure/static-web-apps-deploy@v1 with: @@ -278,9 +247,7 @@ jobs: output_location: "" skip_app_build: true - # main -> production, gated. The job pauses here until someone in the 'production' - # environment's Required Reviewers approves it in the Actions UI. It then ships the SAME - # artifact staging verified - never a rebuild. + # main -> production, gated. deploy_production: if: github.event_name == 'push' needs: [build_job, deploy_staging] From 186259217a8a417a284ee1c622a82ec718e41796 Mon Sep 17 00:00:00 2001 From: Nedas Surkus Date: Wed, 21 Oct 2026 16:13:44 +0200 Subject: [PATCH 7/9] Update .github/workflows/deploy.yml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Morten Lønskov --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 2e1774d79..31e3f51e1 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -225,7 +225,7 @@ jobs: # main -> staging, automatically deploy_staging: if: github.event_name == 'push' - needs: build_job + needs: [build_job, lint_job, doctest_job, link_check_job] runs-on: ubuntu-latest name: Deploy to Staging environment: From af2ebc993779af412e6f2974e23b0bdc8d27b54f Mon Sep 17 00:00:00 2001 From: Nedas Surkus Date: Wed, 21 Oct 2026 16:14:09 +0200 Subject: [PATCH 8/9] Update .github/workflows/deploy.yml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Morten Lønskov --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 31e3f51e1..75c64ae61 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -145,7 +145,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: site - retention-days: 30 + retention-days: ${{ github.event_name == 'push' && 30 || 7 }} path: _site link_check_job: needs: build_job From 5a4c5070e586edb649c740bc02e49a6f725efaf2 Mon Sep 17 00:00:00 2001 From: Nedas Date: Wed, 21 Oct 2026 16:33:44 +0200 Subject: [PATCH 9/9] Fixed comment --- .github/workflows/deploy.yml | 39 +++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 75c64ae61..aaa28b1c8 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,10 +1,5 @@ name: Docs CI/CD -# Flow: -# PR -> build -> preview environment on the test SWA (URL commented on the PR) -# main push -> build once -> staging (test SWA, automatic) -# -> production (prod SWA) AFTER required-reviewer approval - on: push: branches: @@ -14,17 +9,33 @@ on: branches: - main -# Every job except close_pull_request_job carries the same `if`: run on pushes -# to main and on open PRs, but only build the translation `localization` branch -# (Translated review PRs) once a review is requested. GitHub Actions has no way to share a job -# condition, so the expression is repeated verbatim; keep the copies in sync. +# Flow: +# PR -> checks + build -> preview environment on the test SWA +# (URL commented on the PR; removed on close) +# main push -> checks + build once -> staging (test SWA, automatic) +# -> production (prod SWA) AFTER required-reviewer +# approval on the `production` environment # # Job layout: -# lint_job, doctest_job independent checks on the repo sources -# build_job full multi-language site build -# link_check_job needs the built site from build_job -# deploy_job waits for all of the above, so a failing check -# blocks the deploy (production and PR previews) +# lint_job, doctest_job independent checks on the repo sources +# build_job full multi-language site build; uploads the `site` +# artifact that every deploy job downloads +# link_check_job needs the built site from build_job +# deploy_job PR preview on the test SWA; waits for all of the +# above, so a failing check blocks the preview +# close_preview PR closed -> removes its preview environment +# deploy_staging main push -> test SWA; waits for all checks, so a +# failing check blocks staging +# deploy_production main push -> prod SWA; needs deploy_staging and is +# gated by the `production` environment's reviewers +# +# lint_job, doctest_job, build_job and deploy_job carry the same `if`: run on +# pushes to main and on open PRs, but only build the translation `localization` +# branch (Translated review PRs) once a review is requested. GitHub Actions has +# no way to share a job condition, so the expression is repeated verbatim; keep +# the copies in sync. link_check_job inherits it through `needs: build_job`; +# close_preview, deploy_staging and deploy_production have their own event +# conditions. jobs: lint_job: if: (github.head_ref != 'localization' && github.event_name == 'push') || (github.head_ref != 'localization' && github.event_name == 'pull_request' && github.event.action != 'closed') || (github.head_ref == 'localization' && github.event.action == 'review_requested')