├── .github └── workflows │ ├── compress.yml │ ├── release.yml │ └── sync.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── action.yml ├── app ├── action.py ├── const.py └── log.py ├── images ├── 404.png ├── action.png ├── add_secrets.png ├── add_ssh_key_gitee.png ├── add_ssh_key_github.png ├── antv.png ├── doocs.png ├── gen_ssh_key.png ├── logo.png ├── logo.svg ├── qrcode-for-doocs.jpg ├── qrcode-for-yanglbme.jpg ├── qwerty-learner-logo.svg └── wechat_notification.jpg ├── main.py ├── requirements.txt └── test.py /.github/workflows/compress.yml: -------------------------------------------------------------------------------- 1 | name: Compress 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * 3" 6 | workflow_dispatch: 7 | 8 | jobs: 9 | compress: 10 | runs-on: ubuntu-latest 11 | if: github.repository == 'yanglbme/gitee-pages-action' 12 | steps: 13 | - name: Checkout Branch 14 | uses: actions/checkout@v2 15 | 16 | - name: Compress Images 17 | id: calibre 18 | uses: calibreapp/image-actions@main 19 | with: 20 | githubToken: ${{ secrets.ACTION_TOKEN }} 21 | compressOnly: true 22 | 23 | - name: Commit Files 24 | if: | 25 | steps.calibre.outputs.markdown != '' 26 | run: | 27 | git config --local user.email "szuyanglb@outlook.com" 28 | git config --local user.name "yanglbme" 29 | git commit -m "chore: auto compress images" -a 30 | 31 | - name: Push Changes 32 | if: | 33 | steps.calibre.outputs.markdown != '' 34 | uses: ad-m/github-push-action@master 35 | with: 36 | github_token: ${{ secrets.ACTION_TOKEN }} 37 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Create Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*" 7 | 8 | jobs: 9 | build: 10 | name: Create Release 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v2 15 | - name: Create Release 16 | id: create_release 17 | uses: actions/create-release@v1 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | with: 21 | tag_name: ${{ github.ref }} 22 | release_name: ${{ github.ref }} 23 | body: | 24 | Gitee Pages Action ${{ github.ref }} released! 25 | draft: false 26 | prerelease: false 27 | -------------------------------------------------------------------------------- /.github/workflows/sync.yml: -------------------------------------------------------------------------------- 1 | name: Sync 2 | 3 | on: 4 | push: 5 | branches: [master, main] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | if: github.repository == 'yanglbme/gitee-pages-action' 11 | steps: 12 | - name: Sync to Gitee 13 | uses: wearerequired/git-mirror-action@master 14 | env: 15 | SSH_PRIVATE_KEY: ${{ secrets.GITEE_RSA_PRIVATE_KEY }} 16 | with: 17 | source-repo: git@github.com:yanglbme/gitee-pages-action.git 18 | destination-repo: git@gitee.com:yanglbme/gitee-pages-action.git -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | *.iml 132 | .idea/ 133 | *.ipr 134 | *.iws 135 | .DS_Store 136 | .vscode -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3-slim AS builder 2 | 3 | ENV VIRTUAL_ENV=/opt/venv 4 | RUN python3 -m venv $VIRTUAL_ENV 5 | ENV PATH="$VIRTUAL_ENV/bin:$PATH" 6 | 7 | COPY . /app 8 | WORKDIR /app 9 | 10 | COPY requirements.txt . 11 | RUN python3 -m pip install --upgrade pip 12 | RUN pip install --target=/app -r requirements.txt 13 | 14 | FROM gcr.io/distroless/python3 15 | COPY --from=builder /app /app 16 | WORKDIR /app 17 | ENV PYTHONPATH /app 18 | CMD ["/app/main.py"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2020 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | gitee-pages-action 4 | 5 |

6 | 7 |

8 | license 9 | release 10 | users 11 | users 12 | github 13 | gitee
14 | stars 15 | forks 16 |

17 | 18 |

Gitee Pages Action

19 | 20 | 由于 Gitee Pages 的访问速度很快,很多朋友会选择 Gitee Pages 部署项目(如:个人博客、开源项目国内镜像站点)。但是它不像 GitHub Pages 那样,一提交代码就能自动更新 Pages,因为 Gitee 的自动部署属于 Gitee Pages Pro 的服务。 21 | 22 | 为了实现 Gitee Pages 的自动部署,我开发了 [Gitee Pages Action](https://github.com/marketplace/actions/gitee-pages-action) ,只需要在 GitHub 项目的 Settings 页面下配置 keys,然后在 `.github/workflows/` 下创建一个工作流,引入一些配置参数即可。欢迎 Star ⭐ 关注本项目。 23 | 24 | 欢迎体验,若有使用上的问题,也欢迎随时提交 [Issues](https://github.com/yanglbme/gitee-pages-action/issues) 反馈。 25 | 26 | 注: 27 | 28 | 1. 首次需要**手动**登录 Gitee ,点击“启动”进行 Gitee Pages 服务的部署。 29 | 1. 由于 Gitee 改版,使用 Gitee Pages 前需要先完成实名认证。 30 | 31 | ## 入参 32 | 33 | | 参数 | 描述 | 是否必传 | 默认值 | 示例 | 34 | | ---------------- | ---------------------------- | -------- | -------- | ------------------------------- | 35 | | `gitee-username` | Gitee 用户名 | 是 | - | `yanglbme` | 36 | | `gitee-password` | Gitee 密码 | 是 | - | `${{ secrets.GITEE_PASSWORD }}` | 37 | | `gitee-repo` | Gitee 仓库(严格区分大小写) | 是 | - | `doocs/leetcode` | 38 | | `branch` | 要部署的分支(分支必须存在) | 否 | `master` | `main` | 39 | | `directory` | 要部署的分支上的目录 | 否 | | `src` | 40 | | `https` | 是否强制使用 HTTPS | 否 | `true` | `false` | 41 | 42 | ## 完整示例 43 | 44 | ### 1. 创建 workflow 45 | 46 | 在你的 GitHub 项目 `.github/workflows/` 文件夹下创建一个 `.yml` 文件,如 `sync.yml`,内容如下: 47 | 48 | ```yml 49 | name: Sync 50 | 51 | on: 52 | push: 53 | branches: [main] 54 | workflow_dispatch: 55 | 56 | jobs: 57 | build: 58 | runs-on: ubuntu-latest 59 | steps: 60 | - name: Sync to Gitee 61 | uses: wearerequired/git-mirror-action@master 62 | env: 63 | # 注意在 Settings->Secrets 配置 GITEE_RSA_PRIVATE_KEY 64 | SSH_PRIVATE_KEY: ${{ secrets.GITEE_RSA_PRIVATE_KEY }} 65 | with: 66 | # 注意替换为你的 GitHub 源仓库地址 67 | source-repo: git@github.com:doocs/leetcode.git 68 | # 注意替换为你的 Gitee 目标仓库地址 69 | destination-repo: git@gitee.com:Doocs/leetcode.git 70 | 71 | - name: Build Gitee Pages 72 | uses: yanglbme/gitee-pages-action@main 73 | with: 74 | # 注意替换为你的 Gitee 用户名 75 | gitee-username: yanglbme 76 | # 注意在 Settings->Secrets 配置 GITEE_PASSWORD 77 | gitee-password: ${{ secrets.GITEE_PASSWORD }} 78 | # 注意替换为你的 Gitee 仓库,仓库名严格区分大小写,请准确填写,否则会出错 79 | gitee-repo: doocs/leetcode 80 | # 要部署的分支,默认是 master,若是其他分支,则需要指定(指定的分支必须存在) 81 | branch: main 82 | ``` 83 | 84 | 注: 85 | 86 | 1. 这里我先使用 [wearerequired/git-mirror-action](https://github.com/wearerequired/git-mirror-action) 将 GitHub 仓库同步到 Gitee 仓库,再使用 [yanglbme/gitee-pages-action](https://github.com/yanglbme/gitee-pages-action) 实现 Gitee Pages 的自动部署。如果你已经通过其它的方式,将代码 push 至 Gitee 了,那么可以不使用 [wearerequired/git-mirror-action](https://github.com/wearerequired/git-mirror-action),也不需要配置 `GITEE_RSA_PRIVATE_KEY`。 87 | 1. `branch` 参数默认是 `master`,如果你是部署在 `gh-pages`(或者 `main`) 分支等等,务必指定 `branch: gh-pages`(或者 `branch: main`)。 88 | 1. `branch` 对应的分支,必须在仓库中实际存在,请不要随意(不)指定分支,否则可能导致 Gitee Pages 站点出现 404 无法访问的情况。 89 | 1. 对于 `gitee-repo` 参数,如果你的项目在 Gitee 的地址为 https://gitee.com/用户名/xxx ,那么 `gitee-repo` 就填写为 `用户名/xxx`。[#54](https://github.com/yanglbme/gitee-pages-action/issues/54) 90 | 1. 对于 workflow 的触发事件,你可以根据项目实际情况,指定为其它的触发事件。比如: 91 | ```bash 92 | on: 93 | push: 94 | branches: [main, master] 95 | ``` 96 | 更多触发事件,请参考 [Events that trigger workflows](https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows) 97 | 98 | ### 2. 配置密钥 99 | 100 | 密钥的配置步骤如下(可展开看示例图): 101 | 102 |
103 | a. 在命令行终端或 Git Bash 使用命令 ssh-keygen -t rsa -C "youremail@example.com" 生成 SSH Key,注意替换为自己的邮箱。生成的 id_rsa 是私钥,id_rsa.pub 是公钥。(⚠️注意此处不要设置密码,生成的公私钥用于下面 GitHub / Gitee 的配置,以保证公私钥成对,否则从 GitHub -> Gitee 的同步将会失败。) 104 | gen_ssh_key 105 |
106 |
107 | b. 在 GitHub 项目的「Settings -> Secrets」路径下配置好命名为 GITEE_RSA_PRIVATE_KEYGITEE_PASSWORD 的两个密钥。其中:GITEE_RSA_PRIVATE_KEY 存放 id_rsa 私钥;GITEE_PASSWORD 存放 Gitee 帐号的密码。 108 | add_secrets 109 |
110 |
111 | c. 在 GitHub 的个人设置页面「Settings -> SSH and GPG keys」配置 SSH 公钥(即:id_rsa.pub),命名随意。 112 | add_ssh_key_github 113 |
114 |
115 | d. 在 Gitee 的个人设置页面「安全设置 -> SSH 公钥」配置 SSH 公钥(即:id_rsa.pub),命名随意。 116 | add_ssh_key_gitee 117 |
118 | 119 | ### 3. 关注 Gitee 公众号 120 | 121 | 关注 Gitee 官方公众号,并绑定个人 Gitee 帐号,用于接收帐号登录通知、以及绕过短信验证码校验,见[错误及解决方案](#错误及解决方案) 第 3 点。 122 | 123 | ### 4. 运行结果 124 | 125 | 如果一切配置正常,并成功触发 [Gitee Pages Action](https://github.com/marketplace/actions/gitee-pages-action) ,Gitee Pages Action 会打印出成功的结果。并且,我们会在 Gitee 公众号收到一条登录通知。这是 Gitee Pages Action 程序帮我们登录到 Gitee 官网,并为我们点击了项目的部署按钮。 126 | 127 | ```bash 128 | Run yanglbme/gitee-pages-action@main 129 | with: 130 | gitee-username: yanglbme 131 | gitee-password: *** 132 | gitee-repo: doocs/leetcode 133 | branch: main 134 | https: true 135 | /usr/bin/docker run --name e28490f27de0ee43bb49109a40cea0e43202d2_d4911a --label e28490 --workdir /github/workspace --rm -e INPUT_GITEE-USERNAME -e INPUT_GITEE*** INPUT_GITEE-REPO -e INPUT_BRANCH -e INPUT_DIRECTORY -e INPUT_HTTPS -e HOME -e GITHUB_JOB -e GITHUB_REF -e GITHUB_SHA -e GITHUB_REPOSITORY -e GITHUB_REPOSITORY_OWNER -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RETENTION_DAYS -e GITHUB_RUN_ATTEMPT -e GITHUB_ACTOR -e GITHUB_WORKFLOW -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GITHUB_EVENT_NAME -e GITHUB_SERVER_URL -e GITHUB_API_URL -e GITHUB_GRAPHQL_URL -e GITHUB_REF_NAME -e GITHUB_REF_PROTECTED -e GITHUB_REF_TYPE -e GITHUB_WORKSPACE -e GITHUB_ACTION -e GITHUB_EVENT_PATH -e GITHUB_ACTION_REPOSITORY -e GITHUB_ACTION_REF -e GITHUB_PATH -e GITHUB_ENV -e RUNNER_OS -e RUNNER_ARCH -e RUNNER_NAME -e RUNNER_TOOL_CACHE -e RUNNER_TEMP -e RUNNER_WORKSPACE -e ACTIONS_RUNTIME_URL -e ACTIONS_RUNTIME_TOKEN -e ACTIONS_CACHE_URL -e GITHUB_ACTIONS=true -e CI=true -v "/var/run/docker.sock":"/var/run/docker.sock" -v "/home/runner/work/_temp/_github_home":"/github/home" -v "/home/runner/work/_temp/_github_workflow":"/github/workflow" -v "/home/runner/work/_temp/_runner_file_commands":"/github/file_commands" -v "/home/runner/work/leetcode/leetcode":"/github/workspace" e28490:f27de0ee43bb49109a40cea0e43202d2 136 | [2021-11-27 20:16:30] Welcome to use Gitee Pages Action ❤ 137 | 138 | 📕 Getting Started Guide: https://github.com/marketplace/actions/gitee-pages-action 139 | 📣 Maintained by Yang Libin: https://github.com/yanglbme 140 | 141 | [2021-11-27 20:16:34] Login successfully 142 | [2021-11-27 20:16:35] Rebuild Gitee Pages successfully 143 | [2021-11-27 20:16:35] Success, thanks for using @yanglbme/gitee-pages-action! 144 | ``` 145 | 146 | action_result 147 | 148 | add_ssh_key_gitee 149 | 150 | ## 错误及解决方案 151 | 152 | | # | 错误 | 解决方案 | 153 | | --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 154 | | 1 | Error: Wrong username or password, login failed . | 帐号或密码错误,请检查参数 `gitee-username`、`gitee-password`是否准确配置。 | 155 | | 2 | Error: Need captcha validation, please visit https://gitee.com/login, login to validate your account. | 需要图片验证码校验。可以手动登录 Gitee 官方,校验验证码。 | 156 | | 3 | Error: Need phone captcha validation, please follow wechat official account "Gitee" to bind account to turn off authentication. | 需要短信验证码校验。可以关注 Gitee 微信公众号,并绑定 Gitee 帐号,接收登录提示。[#6](https://github.com/yanglbme/gitee-pages-action/issues/6) | 157 | | 4 | Error: Do not deploy frequently, try again one minute later. | 短期内频繁部署 Gitee Pages 导致,可以稍后再触发自动部署。 | 158 | | 5 | Error: Deploy error occurred, please re-run job or check your input `gitee-repo`. | `gitee-repo` 参数格式如:`doocs/leetcode`,并且严格区分大小写,请准确填写。[#10](https://github.com/yanglbme/gitee-pages-action/issues/10) | 159 | | 6 | Error: Unknown error occurred in login method, resp: ... | 登录出现未知错误,请在 [issues](https://github.com/yanglbme/gitee-pages-action/issues) 区反馈。 | 160 | | 7 | Error: Rebuild page error, status code: xxx | 更新 Pages 时状态码异常,请尝试再次触发 Action 执行。也可能为 gitee pages 未初始化,第一次需要手动部署 gitee pages。 | 161 | | 8 | Error: HTTPSConnectionPool(host='gitee.com', port=443): Read timed out. (read timeout=6)

Error: HTTPSConnectionPool(host='gitee.com', port=443): Max retries exceeded with url: /login (Caused by ConnectTimeoutError(, 'Connection to gitee.com timed out. (connect timeout=6)')) | 网络请求出错,请尝试 Re-run jobs 。[#27](https://github.com/yanglbme/gitee-pages-action/issues/27) | 162 | | 9 | Error: The repository owner is not authenticated and is not allowed to deploy pages services. | 仓库持有者未实名认证,不允许部署 pages 服务。 | 163 | | 10 | git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.
Please make sure you have the correct access rights and the repository exists.. | 先尝试 Re-run job。[#56](https://github.com/yanglbme/gitee-pages-action/issues/56)
若仍旧失败,可能是 SSH 公私钥配置有问题,或是使用了带密码的私钥,请参照上文提及的密钥配置步骤进行相应配置。[#29](https://github.com/yanglbme/gitee-pages-action/issues/29) | 164 | | 11 | Hexo Gitee Pages 自动部署站点问题。 | [@No5972](https://github.com/No5972) 详细给出了一种解决方案。[#34](https://github.com/yanglbme/gitee-pages-action/issues/34) | 165 | | 12 | "/root/.ssh/id_rsa": invalid format. | 操作系统环境不同,生成 ssh key 的方式可能有所差别,尝试添加 `-m PEM` 参数试试。[#49](https://github.com/yanglbme/gitee-pages-action/issues/49) | 166 | | ... | ... | ... | 167 | 168 | ## 谁在使用 169 | 170 | 171 | 172 | 178 | 184 | 190 | 191 | 192 | 203 | 212 | 218 | 219 |
173 | 174 | 蚂蚁金服
175 | 蚂蚁金服 - 数据可视化 176 |
177 |
179 | 180 | Doocs
181 | Doocs 技术社区 182 |
183 |
185 | 186 | Qwerty Learner
187 | Qwerty Learner 188 |
189 |
193 | 202 | 204 | 211 | 213 | 217 |
220 | 221 | 查看更多用户,请访问 https://cs.github.com/?scopeName=All+repos&scope=&q=yanglbme%2Fgitee-pages-action 222 | 223 | ## 联系我 224 | 225 | 对于 Gitee Pages Action 有任何的疑问,还可以通过以下方式找到我。 226 | 227 | 228 | 229 | 232 | 235 | 236 |
230 |
231 |
233 |
234 |
237 | 238 | ## 许可证 239 | 240 | MIT 241 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: "Gitee Pages Action" 2 | description: "GitHub Action for Gitee Pages" 3 | author: "yanglbme" 4 | branding: 5 | icon: "git-branch" 6 | color: "gray-dark" 7 | inputs: 8 | gitee-username: 9 | description: "The Gitee username, like yanglbme" 10 | required: true 11 | gitee-password: 12 | description: "The Gitee password" 13 | required: true 14 | gitee-repo: 15 | description: "The Gitee repository, like doocs/leetcode" 16 | required: true 17 | branch: 18 | description: "Which branch to build" 19 | required: false 20 | default: "master" 21 | directory: 22 | description: "Which directory to build" 23 | required: false 24 | default: "" 25 | https: 26 | description: "Use force https or not" 27 | required: false 28 | default: "true" 29 | runs: 30 | using: "docker" 31 | image: "Dockerfile" 32 | -------------------------------------------------------------------------------- /app/action.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import re 3 | 4 | import requests 5 | import rsa 6 | import urllib3 7 | from retry import retry 8 | 9 | from app import log 10 | from app.const import domain, ua, timeout, pubkey 11 | 12 | urllib3.disable_warnings() 13 | 14 | 15 | class Action: 16 | def __init__(self, username: str, password: str, 17 | repo: str, branch: str = 'master', 18 | directory: str = '', https: str = 'true'): 19 | self.session = requests.session() 20 | self.session.keep_alive = False 21 | self.username = username 22 | self.password = password 23 | self.repo = repo.replace(domain, '').strip('/') 24 | self.branch = branch 25 | self.directory = directory 26 | self.https = https 27 | 28 | @staticmethod 29 | def get_csrf_token(html: str) -> str: 30 | res1 = re.search( 31 | '(.*?)' 32 | '', html, re.S) 33 | res2 = re.search( 34 | '(.*?)' 35 | '', html, re.S) 36 | res = res1 or res2 37 | if res is None: 38 | raise Exception('Deploy error occurred, please re-run job or check your input `gitee-repo`.') 39 | return res.group(2) 40 | 41 | @retry((requests.exceptions.ReadTimeout, 42 | requests.exceptions.ConnectTimeout, 43 | requests.exceptions.ConnectionError, 44 | requests.Timeout, 45 | requests.RequestException), 46 | tries=4, delay=2, backoff=3) 47 | def login(self): 48 | login_index_url = f'{domain}/login' 49 | check_login_url = f'{domain}/check_user_login' 50 | form_data = {'user_login': self.username} 51 | 52 | index_headers = { 53 | 'Accept': 'text/html,application/xhtml+xml,application/xml;' 54 | 'q=0.9,image/webp,image/apng,*/*;' 55 | 'q=0.8,application/signed-exchange;v=b3;q=0.9', 56 | 'Host': 'gitee.com', 57 | 'User-Agent': ua 58 | } 59 | 60 | resp = self.session.get(url=login_index_url, 61 | headers=index_headers, 62 | timeout=timeout, 63 | verify=False) 64 | csrf_token = Action.get_csrf_token(resp.text) 65 | headers = { 66 | 'Referer': login_index_url, 67 | 'X-Requested-With': 'XMLHttpRequest', 68 | 'X-CSRF-Token': csrf_token, 69 | 'User-Agent': ua 70 | } 71 | self.session.post(url=check_login_url, 72 | headers=headers, 73 | data=form_data, 74 | timeout=timeout, 75 | verify=False) 76 | 77 | # https://assets.gitee.com/assets/encrypt.js 78 | separator = '$gitee$' 79 | data = f'{csrf_token[-8:]}{separator}{self.password}' 80 | pk = rsa.PublicKey.load_pkcs1_openssl_pem(pubkey.encode()) 81 | encrypt_data = rsa.encrypt(data.encode(), pk) 82 | encrypt_data = base64.b64encode(encrypt_data).decode() 83 | 84 | form_data = { 85 | 'encrypt_key': 'password', 86 | 'utf8': '✓', 87 | 'authenticity_token': csrf_token, 88 | 'redirect_to_url': '', 89 | 'user[login]': self.username, 90 | 'encrypt_data[user[password]]': encrypt_data, 91 | 'user[remember_me]': 1 92 | } 93 | res = self.session.post(url=login_index_url, 94 | headers=index_headers, 95 | data=form_data, 96 | timeout=timeout, 97 | verify=False).text 98 | 99 | case1 = ['"message": "帐号或者密码错误"', '"message": "Invalid email or password."', 100 | '"message": "not_found_in_database"', '"message": "not_found_and_show_captcha"'] 101 | case2 = ['"message": "captcha_expired"', '"message": "captcha_fail"'] 102 | case3 = ['"message": "phone_captcha_fail"', '当前帐号存在异常登录行为,为确认你的有效身份', 103 | '一条包含验证码的信息已发送至你的', 'A message containing a verification code has been sent to you'] 104 | case4 = ['个人主页', '我的工作台', '我的工作臺', 'Dashboard - Gitee'] 105 | 106 | if any(e in res for e in case1): 107 | raise Exception('Wrong username or password, login failed.') 108 | if any(e in res for e in case2): 109 | raise Exception('Need captcha validation, please visit ' 110 | 'https://gitee.com/login, login to validate your account.') 111 | if any(e in res for e in case3): 112 | raise Exception('Need phone captcha validation, please follow wechat ' 113 | 'official account "Gitee" to bind account to turn off authentication.') 114 | if not any(e in res for e in case4): 115 | raise Exception(f'Unknown error occurred in login method, resp: {res}') 116 | 117 | @retry((requests.exceptions.ReadTimeout, 118 | requests.exceptions.ConnectTimeout, 119 | requests.exceptions.ConnectionError, 120 | requests.Timeout, 121 | requests.RequestException), 122 | tries=4, delay=2, backoff=3) 123 | def rebuild_pages(self): 124 | if '/' not in self.repo: 125 | self.repo = f'{self.username}/{self.repo}' 126 | 127 | pages_url = f'{domain}/{self.repo}/pages' 128 | rebuild_url = f'{pages_url}/rebuild' 129 | 130 | pages = self.session.get(pages_url) 131 | csrf_token = Action.get_csrf_token(pages.text) 132 | headers = { 133 | 'Content-Type': 'application/x-www-form-urlencoded; ' 134 | 'charset=UTF-8', 135 | 'Referer': pages_url, 136 | 'X-Requested-With': 'XMLHttpRequest', 137 | 'X-CSRF-Token': csrf_token, 138 | 'User-Agent': ua 139 | } 140 | form_data = { 141 | 'branch': self.branch, 142 | 'build_directory': self.directory, 143 | 'force_https': self.https 144 | } 145 | resp = self.session.post(url=rebuild_url, 146 | headers=headers, 147 | data=form_data, 148 | timeout=timeout, 149 | verify=False) 150 | if resp.status_code != 200: 151 | raise Exception(f'Rebuild page error, status code: {resp.status_code}, resp: {resp.text}') 152 | html = resp.text 153 | if '正在部署,请耐心等待' in html: 154 | return 155 | if '部署失败' in html and '错误信息' in html: 156 | res = re.search('

错误信息:(.*?)<\\\/p>', html, re.S) 157 | if res: 158 | raise Exception(res.group(1).strip()) 159 | if '请勿频繁更新部署,稍等1分钟再试试看' in html: 160 | raise Exception('Do not deploy frequently, try again one minute later.') 161 | if '仓库持有者未实名认证,不允许部署 pages 服务' in html: 162 | raise Exception('The repository owner is not authenticated and is not allowed to deploy pages services.') 163 | log.warning(f'Unknown html: {html}') 164 | 165 | def run(self): 166 | self.login() 167 | self.rebuild_pages() 168 | -------------------------------------------------------------------------------- /app/const.py: -------------------------------------------------------------------------------- 1 | timeout = 6 2 | domain = 'https://gitee.com' 3 | 4 | ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ' \ 5 | '(KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36' 6 | 7 | pubkey = """-----BEGIN PUBLIC KEY----- 8 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIrn+WB2Yi4ABAL5Tq6E09tumY 9 | qVTFdpU01kCDUmClczJOCGZriLNMrshmN9NJxazpqizPthwS1OIK3HwRLEP9D3GL 10 | 7gCnvN6lpIpoVwppWd65f/rK2ewv6dstN0fCmtVj4WsLUchWlgNuVTfWljiBK/Dc 11 | YkfslRZzCq5Fl3ooowIDAQAB 12 | -----END PUBLIC KEY-----""" 13 | -------------------------------------------------------------------------------- /app/log.py: -------------------------------------------------------------------------------- 1 | from datetime import timedelta, timezone, datetime 2 | 3 | from actions_toolkit import core 4 | 5 | 6 | def now(): 7 | tz = timezone(timedelta(hours=+8)) 8 | return datetime.now(tz).strftime('%Y-%m-%d %H:%M:%S') 9 | 10 | 11 | def info(s: str = ''): 12 | core.info(f'[{now()}] {s}') 13 | 14 | 15 | def warning(s: str = ''): 16 | core.warning(f'[{now()}] {s}') 17 | 18 | 19 | def error(s: str = ''): 20 | core.info(f'[{now()}] {s}') 21 | 22 | 23 | def set_failed(s: str = ''): 24 | core.set_failed(f'[{now()}] {s}') 25 | -------------------------------------------------------------------------------- /images/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanglbme/gitee-pages-action/182366ca48f1838d47fab7a0f3f51c83088a1259/images/404.png -------------------------------------------------------------------------------- /images/action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanglbme/gitee-pages-action/182366ca48f1838d47fab7a0f3f51c83088a1259/images/action.png -------------------------------------------------------------------------------- /images/add_secrets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanglbme/gitee-pages-action/182366ca48f1838d47fab7a0f3f51c83088a1259/images/add_secrets.png -------------------------------------------------------------------------------- /images/add_ssh_key_gitee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanglbme/gitee-pages-action/182366ca48f1838d47fab7a0f3f51c83088a1259/images/add_ssh_key_gitee.png -------------------------------------------------------------------------------- /images/add_ssh_key_github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanglbme/gitee-pages-action/182366ca48f1838d47fab7a0f3f51c83088a1259/images/add_ssh_key_github.png -------------------------------------------------------------------------------- /images/antv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanglbme/gitee-pages-action/182366ca48f1838d47fab7a0f3f51c83088a1259/images/antv.png -------------------------------------------------------------------------------- /images/doocs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanglbme/gitee-pages-action/182366ca48f1838d47fab7a0f3f51c83088a1259/images/doocs.png -------------------------------------------------------------------------------- /images/gen_ssh_key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanglbme/gitee-pages-action/182366ca48f1838d47fab7a0f3f51c83088a1259/images/gen_ssh_key.png -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanglbme/gitee-pages-action/182366ca48f1838d47fab7a0f3f51c83088a1259/images/logo.png -------------------------------------------------------------------------------- /images/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/qrcode-for-doocs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanglbme/gitee-pages-action/182366ca48f1838d47fab7a0f3f51c83088a1259/images/qrcode-for-doocs.jpg -------------------------------------------------------------------------------- /images/qrcode-for-yanglbme.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanglbme/gitee-pages-action/182366ca48f1838d47fab7a0f3f51c83088a1259/images/qrcode-for-yanglbme.jpg -------------------------------------------------------------------------------- /images/qwerty-learner-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /images/wechat_notification.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yanglbme/gitee-pages-action/182366ca48f1838d47fab7a0f3f51c83088a1259/images/wechat_notification.jpg -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from actions_toolkit import core 2 | 3 | from app import log 4 | from app.action import Action 5 | 6 | author = { 7 | 'name': 'Yang Libin', 8 | 'link': 'https://github.com/yanglbme' 9 | } 10 | marketplace = 'https://github.com/marketplace/actions/gitee-pages-action' 11 | 12 | log.info(f'Welcome to use Gitee Pages Action ❤\n\n' 13 | f'📕 Getting Started Guide: {marketplace}\n' 14 | f'📣 Maintained by {author["name"]}: {author["link"]}\n') 15 | 16 | try: 17 | username = core.get_input('gitee-username', required=True) 18 | password = core.get_input('gitee-password', required=True) 19 | repo = core.get_input('gitee-repo', required=True) 20 | 21 | branch = core.get_input('branch') 22 | directory = core.get_input('directory') 23 | https = core.get_input('https') 24 | 25 | action = Action(username, password, repo, branch, directory, https) 26 | 27 | action.login() 28 | log.info('Login successfully') 29 | 30 | action.rebuild_pages() 31 | log.info('Rebuild Gitee Pages successfully') 32 | 33 | log.info('Success, thanks for using @yanglbme/gitee-pages-action!') 34 | except Exception as e: 35 | log.set_failed(str(e)) 36 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | actions-toolkit 2 | requests 3 | retry 4 | rsa 5 | urllib3 -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from actions_toolkit import core 4 | 5 | from app import log 6 | from app.action import Action 7 | 8 | os.environ['INPUT_GITEE-USERNAME'] = 'yanglbme' 9 | os.environ['INPUT_GITEE-PASSWORD'] = '***' 10 | os.environ['INPUT_GITEE-REPO'] = 'yanglbme/reading' 11 | os.environ['INPUT_BRANCH'] = 'main' 12 | 13 | try: 14 | username = core.get_input('gitee-username', required=True) 15 | password = core.get_input('gitee-password', required=True) 16 | repo = core.get_input('gitee-repo', required=True) 17 | branch = core.get_input('branch') 18 | 19 | action = Action(username, password, repo, branch) 20 | action.run() 21 | except Exception as e: 22 | log.set_failed(str(e)) 23 | --------------------------------------------------------------------------------