From 83749b56a893fbfab062a47bf4608e0c8dd66524 Mon Sep 17 00:00:00 2001 From: Kevin Brown Date: Sun, 21 Dec 2025 20:03:36 +0300 Subject: [PATCH 1/2] Refactor input process for GITHUB_TOKEN in action scripts --- .../src/main.py | 47 ++++++++++++++----- .../src/main.py | 21 ++++++++- .../src/main.py | 21 ++++++++- .../download-build-artifact/src/main.py | 21 ++++++++- .../mark-deployment-in-progress/src/main.py | 23 +++++++-- .../update-deployment-status/src/main.py | 29 +++++++++--- .github/workflows/cron.yml | 29 +++++++++++- test/__mocks__/astro:transitions/client.ts | 2 - 8 files changed, 163 insertions(+), 30 deletions(-) diff --git a/.github/actions/check-prerequisites-and-locate-build-artifact/src/main.py b/.github/actions/check-prerequisites-and-locate-build-artifact/src/main.py index 0efc8f0fa..8a94c3c86 100644 --- a/.github/actions/check-prerequisites-and-locate-build-artifact/src/main.py +++ b/.github/actions/check-prerequisites-and-locate-build-artifact/src/main.py @@ -16,6 +16,31 @@ class WorkflowDescriptor: label: str +def get_input_compat(name: str, *, required: bool = False) -> str: + """Reads action inputs while tolerating runner normalization. + + Unit tests for these actions frequently monkeypatch `core.get_input`. + We prefer `core.get_input` first, then fall back to direct env lookups + that accept both hyphen and underscore variants. + """ + + value = core.get_input(name, required=False) + if value: + return value.strip() + + normalized = name.replace(" ", "_").upper() + candidates = {normalized, normalized.replace("-", "_"), normalized.replace("_", "-")} + for candidate in candidates: + env_value = os.getenv(f"INPUT_{candidate}", "") + if env_value: + return env_value.strip() + + if required: + # Preserve the same error message format as actions_toolkit. + return core.get_input(name, required=True) + return "" + + def get_github_api_base_url() -> str: raw = (os.environ.get("GITHUB_API_URL") or "https://api.github.com").strip() parsed = urlparse(raw) @@ -114,17 +139,17 @@ def find_artifact_download_url( def run() -> None: try: - token = core.get_input("github-token", required=True) - sha = core.get_input("sha", required=True).strip() - trigger_event = core.get_input("trigger-event") - head_branch = core.get_input("head-branch") - is_fork = (core.get_input("is-fork") or "false").strip().lower() == "true" - skip_hotfix = (core.get_input("skip-hotfix") or "false").strip().lower() == "true" - skip_forks = (core.get_input("skip-forks") or "false").strip().lower() == "true" - require_trigger_event = (core.get_input("require-trigger-event") or "").strip() - build_workflow_file = core.get_input("build-workflow-file", required=True).strip() - artifact_name = core.get_input("artifact-name", required=True).strip() - required_workflows = parse_required_workflows(core.get_input("required-workflows-json", required=True)) + token = get_input_compat("github-token", required=True) + sha = get_input_compat("sha", required=True).strip() + trigger_event = get_input_compat("trigger-event") + head_branch = get_input_compat("head-branch") + is_fork = (get_input_compat("is-fork") or "false").strip().lower() == "true" + skip_hotfix = (get_input_compat("skip-hotfix") or "false").strip().lower() == "true" + skip_forks = (get_input_compat("skip-forks") or "false").strip().lower() == "true" + require_trigger_event = (get_input_compat("require-trigger-event") or "").strip() + build_workflow_file = get_input_compat("build-workflow-file", required=True).strip() + artifact_name = get_input_compat("artifact-name", required=True).strip() + required_workflows = parse_required_workflows(get_input_compat("required-workflows-json", required=True)) if require_trigger_event and trigger_event and trigger_event != require_trigger_event: core.notice( diff --git a/.github/actions/create-github-deployment-preview/src/main.py b/.github/actions/create-github-deployment-preview/src/main.py index 785d64d39..52bb25eef 100644 --- a/.github/actions/create-github-deployment-preview/src/main.py +++ b/.github/actions/create-github-deployment-preview/src/main.py @@ -7,6 +7,23 @@ from actions_toolkit import core +def get_input_compat(name: str, *, required: bool = False) -> str: + value = core.get_input(name, required=False) + if value: + return value.strip() + + normalized = name.replace(" ", "_").upper() + candidates = {normalized, normalized.replace("-", "_"), normalized.replace("_", "-")} + for candidate in candidates: + env_value = os.getenv(f"INPUT_{candidate}", "") + if env_value: + return env_value.strip() + + if required: + return core.get_input(name, required=True) + return "" + + def get_github_api_base_url() -> str: raw = (os.environ.get("GITHUB_API_URL") or "https://api.github.com").strip() parsed = urlparse(raw) @@ -17,8 +34,8 @@ def get_github_api_base_url() -> str: def run() -> None: try: - token = core.get_input("github-token", required=True) - sha = core.get_input("sha", required=True).strip() + token = get_input_compat("github-token", required=True) + sha = get_input_compat("sha", required=True).strip() repo_full = (os.environ.get("GITHUB_REPOSITORY") or "").strip() if "/" not in repo_full: diff --git a/.github/actions/create-github-deployment-production/src/main.py b/.github/actions/create-github-deployment-production/src/main.py index 453bf4216..d316455aa 100644 --- a/.github/actions/create-github-deployment-production/src/main.py +++ b/.github/actions/create-github-deployment-production/src/main.py @@ -7,6 +7,23 @@ from actions_toolkit import core +def get_input_compat(name: str, *, required: bool = False) -> str: + value = core.get_input(name, required=False) + if value: + return value.strip() + + normalized = name.replace(" ", "_").upper() + candidates = {normalized, normalized.replace("-", "_"), normalized.replace("_", "-")} + for candidate in candidates: + env_value = os.getenv(f"INPUT_{candidate}", "") + if env_value: + return env_value.strip() + + if required: + return core.get_input(name, required=True) + return "" + + def get_github_api_base_url() -> str: raw = (os.environ.get("GITHUB_API_URL") or "https://api.github.com").strip() parsed = urlparse(raw) @@ -17,8 +34,8 @@ def get_github_api_base_url() -> str: def run() -> None: try: - token = core.get_input("github-token", required=True) - sha = core.get_input("sha", required=True).strip() + token = get_input_compat("github-token", required=True) + sha = get_input_compat("sha", required=True).strip() repo_full = (os.environ.get("GITHUB_REPOSITORY") or "").strip() if "/" not in repo_full: diff --git a/.github/actions/download-build-artifact/src/main.py b/.github/actions/download-build-artifact/src/main.py index 328de076e..49e9e7be6 100644 --- a/.github/actions/download-build-artifact/src/main.py +++ b/.github/actions/download-build-artifact/src/main.py @@ -12,6 +12,23 @@ from actions_toolkit import core +def get_input_compat(name: str, *, required: bool = False) -> str: + value = core.get_input(name, required=False) + if value: + return value.strip() + + normalized = name.replace(" ", "_").upper() + candidates = {normalized, normalized.replace("-", "_"), normalized.replace("_", "-")} + for candidate in candidates: + env_value = os.getenv(f"INPUT_{candidate}", "") + if env_value: + return env_value.strip() + + if required: + return core.get_input(name, required=True) + return "" + + def get_github_api_base_url() -> str: raw = (os.environ.get("GITHUB_API_URL") or "https://api.github.com").strip() parsed = urlparse(raw) @@ -27,8 +44,8 @@ def is_allowed_fetch_url(url: str, allowed_hosts: set[str]) -> bool: def run() -> None: try: - token = core.get_input("github-token", required=True) - download_url = core.get_input("artifact-download-url", required=True).strip() + token = get_input_compat("github-token", required=True) + download_url = get_input_compat("artifact-download-url", required=True).strip() allowed_hosts = {urlparse(get_github_api_base_url()).hostname} if not is_allowed_fetch_url(download_url, allowed_hosts): diff --git a/.github/actions/mark-deployment-in-progress/src/main.py b/.github/actions/mark-deployment-in-progress/src/main.py index 8674f1545..afca73d99 100644 --- a/.github/actions/mark-deployment-in-progress/src/main.py +++ b/.github/actions/mark-deployment-in-progress/src/main.py @@ -7,6 +7,23 @@ from actions_toolkit import core +def get_input_compat(name: str, *, required: bool = False) -> str: + value = core.get_input(name, required=False) + if value: + return value.strip() + + normalized = name.replace(" ", "_").upper() + candidates = {normalized, normalized.replace("-", "_"), normalized.replace("_", "-")} + for candidate in candidates: + env_value = os.getenv(f"INPUT_{candidate}", "") + if env_value: + return env_value.strip() + + if required: + return core.get_input(name, required=True) + return "" + + def get_github_api_base_url() -> str: raw = (os.environ.get("GITHUB_API_URL") or "https://api.github.com").strip() parsed = urlparse(raw) @@ -17,9 +34,9 @@ def get_github_api_base_url() -> str: def run() -> None: try: - token = core.get_input("github-token", required=True) - deployment_id = core.get_input("deployment-id", required=True).strip() - description = core.get_input("description", required=True).strip() + token = get_input_compat("github-token", required=True) + deployment_id = get_input_compat("deployment-id", required=True).strip() + description = get_input_compat("description", required=True).strip() repo_full = (os.environ.get("GITHUB_REPOSITORY") or "").strip() if "/" not in repo_full: diff --git a/.github/actions/update-deployment-status/src/main.py b/.github/actions/update-deployment-status/src/main.py index 77a79787f..3d99571ed 100644 --- a/.github/actions/update-deployment-status/src/main.py +++ b/.github/actions/update-deployment-status/src/main.py @@ -7,6 +7,23 @@ from actions_toolkit import core +def get_input_compat(name: str, *, required: bool = False) -> str: + value = core.get_input(name, required=False) + if value: + return value.strip() + + normalized = name.replace(" ", "_").upper() + candidates = {normalized, normalized.replace("-", "_"), normalized.replace("_", "-")} + for candidate in candidates: + env_value = os.getenv(f"INPUT_{candidate}", "") + if env_value: + return env_value.strip() + + if required: + return core.get_input(name, required=True) + return "" + + def get_github_api_base_url() -> str: raw = (os.environ.get("GITHUB_API_URL") or "https://api.github.com").strip() parsed = urlparse(raw) @@ -17,12 +34,12 @@ def get_github_api_base_url() -> str: def run() -> None: try: - token = core.get_input("github-token", required=True) - deployment_id = core.get_input("deployment-id", required=True).strip() - exit_code = int(core.get_input("exit-code", required=True).strip() or "1") - environment_url = (core.get_input("environment-url") or "").strip() - success_description = core.get_input("success-description", required=True).strip() - failure_description = core.get_input("failure-description", required=True).strip() + token = get_input_compat("github-token", required=True) + deployment_id = get_input_compat("deployment-id", required=True).strip() + exit_code = int(get_input_compat("exit-code", required=True).strip() or "1") + environment_url = (get_input_compat("environment-url") or "").strip() + success_description = get_input_compat("success-description", required=True).strip() + failure_description = get_input_compat("failure-description", required=True).strip() repo_full = (os.environ.get("GITHUB_REPOSITORY") or "").strip() if "/" not in repo_full: diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index 608d476ef..d4e54da3c 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -13,9 +13,10 @@ concurrency: cancel-in-progress: true jobs: - ping: + ping-production: name: Ping Turso Production DB runs-on: ubuntu-latest + environment: production steps: - name: Checkout repository @@ -33,5 +34,29 @@ jobs: - name: Execute keep-alive query uses: './.github/actions/keep-alive' with: - astro-db-remote-url: ${{ secrets.ASTRO_DB_REMOTE_URL }} + astro-db-remote-url: ${{ vars.ASTRO_DB_REMOTE_URL }} + astro-db-app-token: ${{ secrets.ASTRO_DB_APP_TOKEN }} + + ping-preview: + name: Ping Turso Preview DB + runs-on: ubuntu-latest + environment: preview + + steps: + - name: Checkout repository + uses: actions/checkout@v6.0.1 + + - name: Setup Python + uses: actions/setup-python@v6.1.0 + with: + python-version: '3.13' + cache: 'pip' + + - name: Install Python dependencies + run: python3 -m pip install -r requirements.txt + + - name: Execute keep-alive query + uses: './.github/actions/keep-alive' + with: + astro-db-remote-url: ${{ vars.ASTRO_DB_REMOTE_URL }} astro-db-app-token: ${{ secrets.ASTRO_DB_APP_TOKEN }} diff --git a/test/__mocks__/astro:transitions/client.ts b/test/__mocks__/astro:transitions/client.ts index d438fa9c8..e7531707f 100644 --- a/test/__mocks__/astro:transitions/client.ts +++ b/test/__mocks__/astro:transitions/client.ts @@ -8,5 +8,3 @@ export const navigate = vi.fn().mockImplementation((_url: string | URL) => { // Mock navigation - just resolve immediately return Promise.resolve() }) - -export const isTransitionBeforeSwapEvent = vi.fn().mockReturnValue(false) \ No newline at end of file From cf860104a89fd9c9f64bd1ef8fa4fdbc26a24565 Mon Sep 17 00:00:00 2001 From: Kevin Brown Date: Sun, 21 Dec 2025 20:08:01 +0300 Subject: [PATCH 2/2] Fix auto-reformatting of generated .cache/pages.json file on commits --- .cache/pages.json | 12 +++++++++--- .prettierignore | 2 ++ package.json | 7 +++---- 3 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 .prettierignore diff --git a/.cache/pages.json b/.cache/pages.json index cb8585a13..ba53f9859 100644 --- a/.cache/pages.json +++ b/.cache/pages.json @@ -22,10 +22,16 @@ "contact", "offline", { - "privacy": ["my-data"] + "privacy": [ + "my-data" + ] }, { - "services": ["consulting", "overview", "web-development"] + "services": [ + "consulting", + "overview", + "web-development" + ] }, { "tags": [ @@ -40,4 +46,4 @@ "typescript" ] } -] +] \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..472c37ca3 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,2 @@ +# Generated file +.cache/pages.json \ No newline at end of file diff --git a/package.json b/package.json index 4a2ee7773..f949711f4 100644 --- a/package.json +++ b/package.json @@ -36,17 +36,16 @@ "containers:logs": "FORCE_COLOR=1 docker compose --env-file test/containers/.env -f test/containers/docker-compose.e2e.yml logs -f", "dev": "npm run sync && cross-env NODE_ENV=development FORCE_COLOR=1 npx astro dev", "dev:env": "FORCE_COLOR=1 dotenv -e .env.development -- npm run dev", - "format": "npm run format:json && npm run format:code && npm run format:style", + "format": "npm run format:code && npm run format:style", "format:code": "FORCE_COLOR=1 npx prettier --write \"@types/**/*.{js,ts}\" \"src/**/*.{js,ts,tsx,astro}\" --plugin=prettier-plugin-astro", - "format:json": "FORCE_COLOR=1 npx prettier --write '**/*.json' --cache --ignore-path .gitignore", "format:style": "FORCE_COLOR=1 npx stylelint --fix \"src/**/*.{css,astro}\"", "lint": "npm run lint:base && npm run check", - "lint:actions": "FORCE_COLOR=1 npx node-actionlint && FORCE_COLOR=1 python3 -m pylint $(find .github/actions -type f -path '*/src/*.py')", "lint:base": "npm run lint:json && npm run lint:style && npm run lint:tsc:check && npm run lint:code && npm run lint:actions && npm run lint:inclusive-language", + "lint:actions": "FORCE_COLOR=1 npx node-actionlint && FORCE_COLOR=1 python3 -m pylint $(find .github/actions -type f -path '*/src/*.py')", "lint:code": "npx eslint \"@types/**/*.{js,ts}\" \"src/**/*.{js,ts,tsx,astro}\" \"test/**/*.{js,ts,tsx,astro}\"", "lint:inclusive-language": "npx alex src/content", + "lint:json": "FORCE_COLOR=1 npx prettier '**/*.json' --cache --ignore-path .gitignore", "lint:md": "FORCE_COLOR=1 npx markdownlint-cli2 \"**/*.{md,mdx}\" \"!**/node_modules/**\" \"!**/dist/**\" \"!**/.astro/**\" \"!**/dev-dist/**\" \"!**/__blobstorage__/**\"", - "lint:json": "FORCE_COLOR=1 npx prettier --write '**/*.json' --cache --ignore-path .gitignore", "lint:style": "FORCE_COLOR=1 npx stylelint \"src/**/*.{css,astro}\"", "lint:tsc:check": "npm run sync && tsc --noEmit -p tsconfig.json --pretty false", "sync": "FORCE_COLOR=1 npx astro sync",