From aa4371889b8576ffb566b6b58978488723d5a3f1 Mon Sep 17 00:00:00 2001 From: Jim Zhang Date: Wed, 25 Feb 2026 07:32:29 +0800 Subject: [PATCH 1/3] Fix GitHub Pages build by upgrading Simiki deps --- .github/workflows/jekyll-gh-pages.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/jekyll-gh-pages.yml b/.github/workflows/jekyll-gh-pages.yml index 7b7b769..e3ea943 100644 --- a/.github/workflows/jekyll-gh-pages.yml +++ b/.github/workflows/jekyll-gh-pages.yml @@ -28,6 +28,10 @@ jobs: run: | python -m pip install --upgrade pip pip install simiki + # Simiki pins legacy dependencies that are incompatible with Python 3.11+ + # (e.g. pytz==2015.7, Pygments==1.6). Override them with modern versions + # so `simiki g` can run on GitHub-hosted runners. + pip install --upgrade pytz tzlocal watchdog pygments - name: Build site run: | simiki g From 4d9200f71b34076b753f9eb700df28ebb09afff4 Mon Sep 17 00:00:00 2001 From: Jim Zhang Date: Fri, 10 Jul 2026 19:47:34 +0800 Subject: [PATCH 2/3] Fix Simiki Pages build and modernize CI --- .github/workflows/codeql-analysis.yml | 76 ++++++++------------------- .github/workflows/jekyll-gh-pages.yml | 49 ++++++++++------- Dockerfile | 18 ++++--- requirements-build.txt | 13 +++++ 4 files changed, 78 insertions(+), 78 deletions(-) create mode 100644 requirements-build.txt diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index f353cd9..eea13af 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,67 +1,35 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" +name: CodeQL on: push: - branches: [ master ] + branches: ["master"] pull_request: - # The branches below must be a subset of the branches above - branches: [ master ] + branches: ["master"] schedule: - - cron: '32 12 * * 0' + - cron: "32 12 * * 0" + +permissions: + contents: read + security-events: write + +concurrency: + group: "codeql-${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true jobs: analyze: - name: Analyze + name: Analyze Python runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - language: [ 'python' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + timeout-minutes: 20 steps: - - name: Checkout repository - uses: actions/checkout@v2 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language + - name: Checkout repository + uses: actions/checkout@v7 - #- run: | - # make bootstrap - # make release + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: python - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + - name: Perform CodeQL analysis + uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/jekyll-gh-pages.yml b/.github/workflows/jekyll-gh-pages.yml index e3ea943..78e39fb 100644 --- a/.github/workflows/jekyll-gh-pages.yml +++ b/.github/workflows/jekyll-gh-pages.yml @@ -3,45 +3,58 @@ name: Deploy Simiki to GitHub Pages on: push: branches: ["master"] + pull_request: + branches: ["master"] workflow_dispatch: permissions: contents: read - pages: write - id-token: write - -concurrency: - group: "pages" - cancel-in-progress: false jobs: build: + timeout-minutes: 15 runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.11" - - name: Install Simiki + cache: pip + cache-dependency-path: requirements-build.txt + - name: Install pinned build dependencies run: | - python -m pip install --upgrade pip - pip install simiki - # Simiki pins legacy dependencies that are incompatible with Python 3.11+ - # (e.g. pytz==2015.7, Pygments==1.6). Override them with modern versions - # so `simiki g` can run on GitHub-hosted runners. - pip install --upgrade pytz tzlocal watchdog pygments + python -m pip install --upgrade "pip==26.1.2" "setuptools==80.9.0" "wheel==0.45.1" + python -m pip install --no-deps --no-build-isolation "simiki==1.6.2.3" + python -m pip install --no-deps -r requirements-build.txt - name: Build site + shell: bash run: | - simiki g + set -euo pipefail + build_log="$(mktemp)" + simiki g 2>&1 | tee "$build_log" + if grep -Eq "pages failed|failed to generate" "$build_log"; then + echo "Simiki reported page-generation failures." + exit 1 + fi + test -s output/index.html touch output/.nojekyll - name: Upload artifact - uses: actions/upload-pages-artifact@v3 + if: github.event_name != 'pull_request' + uses: actions/upload-pages-artifact@v5 with: path: output deploy: + if: github.event_name != 'pull_request' + timeout-minutes: 10 + permissions: + pages: write + id-token: write + concurrency: + group: "pages" + cancel-in-progress: false environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} @@ -50,4 +63,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@v5 diff --git a/Dockerfile b/Dockerfile index 656a6f4..5cd20a3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,21 @@ -FROM python:3.7-alpine +FROM python:3.11-alpine + ENV LANG=C.UTF-8 ENV PYTHONIOENCODING=utf-8 -RUN pip install simiki -i https://pypi.tuna.tsinghua.edu.cn/simple -RUN apk add --no-cache gcc musl-dev python3-dev -RUN pip install --upgrade pytz tzlocal watchdog WORKDIR /src + +COPY requirements-build.txt /tmp/requirements-build.txt +RUN python -m pip install --no-cache-dir --upgrade "pip==26.1.2" "setuptools==80.9.0" "wheel==0.45.1" \ + && python -m pip install --no-cache-dir --no-deps --no-build-isolation "simiki==1.6.2.3" \ + && python -m pip install --no-cache-dir --no-deps -r /tmp/requirements-build.txt + COPY . /src -RUN simiki -V -RUN simiki g +RUN simiki -V \ + && simiki g \ + && test -s output/index.html \ + && touch output/.nojekyll CMD ["simiki", "p", "-w", "--host", "0.0.0.0", "--port", "8000"] diff --git a/requirements-build.txt b/requirements-build.txt new file mode 100644 index 0000000..aba25d0 --- /dev/null +++ b/requirements-build.txt @@ -0,0 +1,13 @@ +# Simiki 1.6.2.3 pins dependencies from 2013-2019 that do not run reliably on +# current Python. The workflow installs Simiki itself with --no-deps, then uses +# this tested, reproducible compatibility set on Python 3.11+. +Markdown==3.8.2 +Pygments==2.19.2 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +docopt==0.6.2 +watchdog==6.0.0 +pytz==2025.2 +tzlocal==5.3.1 +tzdata==2026.2 From 13497e852fcd321c02460d4b743b4d6e702cae82 Mon Sep 17 00:00:00 2001 From: Jim Zhang Date: Fri, 10 Jul 2026 19:56:00 +0800 Subject: [PATCH 3/3] Harden deployment helpers and add regression tests --- .github/workflows/jekyll-gh-pages.yml | 17 +++++- .travis.yml | 27 --------- fabfile.py | 6 +- tests/test_fabfile.py | 85 +++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 31 deletions(-) delete mode 100644 .travis.yml create mode 100644 tests/test_fabfile.py diff --git a/.github/workflows/jekyll-gh-pages.yml b/.github/workflows/jekyll-gh-pages.yml index 78e39fb..1d27cd0 100644 --- a/.github/workflows/jekyll-gh-pages.yml +++ b/.github/workflows/jekyll-gh-pages.yml @@ -46,6 +46,21 @@ jobs: with: path: output + test: + timeout-minutes: 10 + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v7 + - name: Setup Python + uses: actions/setup-python@v6 + with: + python-version: "3.11" + - name: Run deployment helper tests + run: | + python -m pip install --upgrade "pip==26.1.2" "pytest==8.4.2" + python -m pytest -q + deploy: if: github.event_name != 'pull_request' timeout-minutes: 10 @@ -59,7 +74,7 @@ jobs: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest - needs: build + needs: [build, test] steps: - name: Deploy to GitHub Pages id: deployment diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index dd89648..0000000 --- a/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: python -python: - - "3.8" - -env: - global: - # Keep the existing GH_REF, it might be used by ghp-import or for reference - - GH_REF: github.com/zhang787jun/Wiki.git - # The existing secure token for gh_token needs to be preserved EXACTLY. - - secure: "... entrypted data ..." # Preserved from original - -install: - - pip install simiki ghp-import - - pip install --upgrade pytz tzlocal watchdog - -script: - # Generate the site using Simiki - - simiki g - # Create .nojekyll file for GitHub Pages - - touch output/.nojekyll - # Deploy the 'output' directory to the 'gh-pages' branch - # The GITHUB_TOKEN (from the secure env) should allow ghp-import to push - # to the same repository (origin) by default. - - ghp-import -n -p -f -m "Update documentation from Travis CI" -r https://${gh_token}@${GH_REF} -b gh-pages output - -notifications: - email: false # Optional: disable email notifications diff --git a/fabfile.py b/fabfile.py index 3bcfc17..f2d5a24 100644 --- a/fabfile.py +++ b/fabfile.py @@ -108,8 +108,8 @@ def deploy_ftp(deploy_configs): rel_root = os.path.relpath(root, output_dir) for fn in files: store_fn = os.path.join(ftp_dir, rel_root, fn) - ftp.storbinary('STOR %s' % store_fn, - open(os.path.join(root, fn), 'rb')) + with open(os.path.join(root, fn), 'rb') as upload_file: + ftp.storbinary('STOR %s' % store_fn, upload_file) ftp.close() @@ -142,7 +142,7 @@ def deploy(type=None): func_name = 'deploy_{0}'.format(deploy_type) func = globals().get(func_name) if not func: - do_exit('Warning: not supprt {0} deploy method' + do_exit('Warning: not support {0} deploy method' .format(deploy_type)) func(deploy_item) done = True diff --git a/tests/test_fabfile.py b/tests/test_fabfile.py new file mode 100644 index 0000000..de0bde4 --- /dev/null +++ b/tests/test_fabfile.py @@ -0,0 +1,85 @@ +import contextlib +import pathlib +import sys +import types + +ROOT = pathlib.Path(__file__).resolve().parents[1] +sys.path.insert(0, str(ROOT)) + +fabric_module = types.ModuleType("fabric") +fabric_api = types.ModuleType("fabric.api") +fabric_colors = types.ModuleType("fabric.colors") +fabric_contrib = types.ModuleType("fabric.contrib") +fabric_contrib_project = types.ModuleType("fabric.contrib.project") +simiki_module = types.ModuleType("simiki") +simiki_config = types.ModuleType("simiki.config") +simiki_compat = types.ModuleType("simiki.compat") + + +@contextlib.contextmanager +def _settings(*args, **kwargs): + yield + + +def _task(func=None, *args, **kwargs): + if func is None: + return lambda inner: inner + return func + + +def _local(*args, **kwargs): + return None + + +fabric_api.env = types.SimpleNamespace() +fabric_api.local = _local +fabric_api.task = _task +fabric_api.settings = _settings +fabric_colors.blue = lambda message: message +fabric_colors.red = lambda message: message +fabric_contrib_project.rsync_project = lambda *args, **kwargs: None +simiki_config.parse_config = lambda *args, **kwargs: {} +simiki_compat.raw_input = lambda *args, **kwargs: "" + +sys.modules["fabric"] = fabric_module +sys.modules["fabric.api"] = fabric_api +sys.modules["fabric.colors"] = fabric_colors +sys.modules["fabric.contrib"] = fabric_contrib +sys.modules["fabric.contrib.project"] = fabric_contrib_project +sys.modules["simiki"] = simiki_module +sys.modules["simiki.config"] = simiki_config +sys.modules["simiki.compat"] = simiki_compat + +import fabfile + + +def test_get_rsync_configs_returns_rsync_entry(monkeypatch): + sample_configs = { + "deploy": [ + {"type": "ftp", "host": "ftp.example.com"}, + {"type": "rsync", "host": "rsync.example.com"}, + {"type": "git", "remote": "origin"}, + ] + } + + monkeypatch.setattr(fabfile, "configs", sample_configs) + + assert fabfile.get_rsync_configs() == { + "type": "rsync", + "host": "rsync.example.com", + } + + +def test_deploy_does_not_mutate_config(monkeypatch): + sample_configs = {"deploy": [{"type": "git", "remote": "origin"}]} + received_config = {} + + monkeypatch.setattr(fabfile, "configs", sample_configs) + monkeypatch.setattr( + fabfile, "deploy_git", lambda deploy_config: received_config.update(deploy_config) + ) + + fabfile.deploy() + + assert sample_configs["deploy"][0]["type"] == "git" + assert received_config == {"type": "git", "remote": "origin"}