forked from Gitlink/gitlink_help_center
Compare commits
9 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
211f20eef4 | |
|
|
a074a9c25c | |
|
|
a094f464ec | |
|
|
3422b32669 | |
|
|
b74b92f66e | |
|
|
96231da6fe | |
|
|
8b39d43460 | |
|
|
75ce405ca7 | |
|
|
4f085a23e2 |
|
|
@ -6,24 +6,19 @@ global:
|
|||
trigger:
|
||||
webhook: gitlink@1.0.0
|
||||
event:
|
||||
- ref: pr
|
||||
- ref: push
|
||||
ruleset-operator: AND
|
||||
workflow:
|
||||
- ref: start
|
||||
name: 开始
|
||||
task: start
|
||||
- ref: end
|
||||
name: 结束
|
||||
task: end
|
||||
needs:
|
||||
- ssh_cmd_0
|
||||
- ref: git_clone_0
|
||||
name: git clone
|
||||
task: git_clone@1.2.9
|
||||
input:
|
||||
username: ((wen.gitlink_username))
|
||||
password: ((wen.gitlink_passwd))
|
||||
remote_url: '"https://gitlink.org.cn/wenjiankun/gitlink_help_center.git"'
|
||||
username: ((ganshihao21.ganshihao21_user))
|
||||
password: ((ganshihao21.ganshihao21))
|
||||
remote_url: '"https://gitlink.org.cn/ganshihao21/reposync.git"'
|
||||
ref: '"refs/heads/master"'
|
||||
commit_id: '""'
|
||||
depth: 1
|
||||
|
|
@ -33,11 +28,11 @@ workflow:
|
|||
name: docker镜像构建
|
||||
task: docker_image_build@1.6.0
|
||||
input:
|
||||
docker_username: ((wen.aliyun_name))
|
||||
docker_password: ((wen.aliyun_passwd))
|
||||
image_name: '"crpi-b9yruhd9zitzsf2p.cn-hangzhou.personal.cr.aliyuncs.com/wenjiankun/group_02"'
|
||||
docker_username: ((nudt_devops.nudt_devops))
|
||||
docker_password: ((nudt_devops.nudt_devops))
|
||||
image_name: '"registry.cn-guangzhou.aliyuncs.com/nudt_devops/reposync_group5"'
|
||||
image_tag: '"latest"'
|
||||
registry_address: '"crpi-b9yruhd9zitzsf2p.cn-hangzhou.personal.cr.aliyuncs.com"'
|
||||
registry_address: '"registry.cn-guangzhou.aliyuncs.com"'
|
||||
docker_file: '"Dockerfile"'
|
||||
docker_build_path: '"."'
|
||||
workspace: git_clone_0.git_path
|
||||
|
|
@ -49,15 +44,19 @@ workflow:
|
|||
name: ssh执行命令
|
||||
task: ssh_cmd@1.1.1
|
||||
input:
|
||||
ssh_pass: ((wen.ssh_passwd))
|
||||
ssh_ip: '"120.27.244.74"'
|
||||
ssh_pass: ((ssh_key.ssh_key))
|
||||
ssh_ip: '"47.96.164.145"'
|
||||
ssh_port: '"22"'
|
||||
ssh_user: '"root"'
|
||||
ssh_cmd: '"docker stop group_02 || true && docker rm group_02 || true && docker
|
||||
pull
|
||||
crpi-b9yruhd9zitzsf2p.cn-hangzhou.personal.cr.aliyuncs.com/wenjiankun/group_02:latest;
|
||||
docker run -d -p 3000:3000 --name group_02
|
||||
crpi-b9yruhd9zitzsf2p.cn-hangzhou.personal.cr.aliyuncs.com/wenjiankun/group_02:latest"'
|
||||
ssh_cmd: '"docker stop abc_group5 && docker rm abc_group5 && docker pull
|
||||
registry.cn-guangzhou.aliyuncs.com/nudt_devops/reposync_group5:latest &&
|
||||
docker run -d -p 3000:3000 --name abc_group5
|
||||
registry.cn-guangzhou.aliyuncs.com/nudt_devops/reposync_group5:latest"'
|
||||
needs:
|
||||
- docker_image_build_0
|
||||
- ref: end
|
||||
name: 结束
|
||||
task: end
|
||||
needs:
|
||||
- ssh_cmd_0
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,3 @@ deploy.sh
|
|||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
gitee私人令牌.txt
|
||||
wen
|
||||
jiankun
|
||||
|
|
@ -5,12 +5,6 @@ WORKDIR /gitlink_help_center
|
|||
|
||||
COPY ./ /gitlink_help_center/
|
||||
|
||||
# 注释掉不存在的图片引用
|
||||
RUN sed -i 's/!\[vis_workflow_serial\](\/img\/engine\/vis_workflow_serial.png)/<!--  -->/g' docs/DevOps引擎/图形流水线.md && \
|
||||
sed -i 's/!\[vis_workflow_parallel\](\/img\/engine\/vis_workflow_parallel.png)/<!--  -->/g' docs/DevOps引擎/图形流水线.md && \
|
||||
sed -i 's/!\[vis_workflow_mixed\](\/img\/engine\/vis_workflow_mixed.png)/<!--  -->/g' docs/DevOps引擎/图形流水线.md
|
||||
|
||||
RUN yarn install
|
||||
RUN npm run build -- --locale zh-cn
|
||||
CMD ["npm", "run", "serve"]
|
||||
# 这是在GitLink上添加的测试注释"
|
||||
194
LICENSE
194
LICENSE
|
|
@ -1,194 +0,0 @@
|
|||
木兰宽松许可证,第2版
|
||||
|
||||
木兰宽松许可证,第2版
|
||||
|
||||
2020年1月 http://license.coscl.org.cn/MulanPSL2
|
||||
|
||||
您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束:
|
||||
|
||||
0. 定义
|
||||
|
||||
“软件” 是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。
|
||||
|
||||
“贡献” 是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。
|
||||
|
||||
“贡献者” 是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。
|
||||
|
||||
“法人实体” 是指提交贡献的机构及其“关联实体”。
|
||||
|
||||
“关联实体” 是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是
|
||||
指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。
|
||||
|
||||
1. 授予版权许可
|
||||
|
||||
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可
|
||||
以复制、使用、修改、分发其“贡献”,不论修改与否。
|
||||
|
||||
2. 授予专利许可
|
||||
|
||||
每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定
|
||||
撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡
|
||||
献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软
|
||||
件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“
|
||||
关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或
|
||||
其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权
|
||||
行动之日终止。
|
||||
|
||||
3. 无商标许可
|
||||
|
||||
“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定
|
||||
的声明义务而必须使用除外。
|
||||
|
||||
4. 分发限制
|
||||
|
||||
您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“
|
||||
本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。
|
||||
|
||||
5. 免责声明与责任限制
|
||||
|
||||
“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对
|
||||
任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于
|
||||
何种法律理论,即使其曾被建议有此种损失的可能性。
|
||||
|
||||
6. 语言
|
||||
|
||||
“本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文
|
||||
版为准。
|
||||
|
||||
条款结束
|
||||
|
||||
如何将木兰宽松许可证,第2版,应用到您的软件
|
||||
|
||||
如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步:
|
||||
|
||||
1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字;
|
||||
|
||||
2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中;
|
||||
|
||||
3, 请将如下声明文本放入每个源文件的头部注释中。
|
||||
|
||||
Copyright (c) [Year] [name of copyright holder]
|
||||
[Software Name] is licensed under Mulan PSL v2.
|
||||
You can use this software according to the terms and conditions of the Mulan
|
||||
PSL v2.
|
||||
You may obtain a copy of Mulan PSL v2 at:
|
||||
http://license.coscl.org.cn/MulanPSL2
|
||||
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
See the Mulan PSL v2 for more details.
|
||||
|
||||
Mulan Permissive Software License,Version 2
|
||||
|
||||
Mulan Permissive Software License,Version 2 (Mulan PSL v2)
|
||||
|
||||
January 2020 http://license.coscl.org.cn/MulanPSL2
|
||||
|
||||
Your reproduction, use, modification and distribution of the Software shall
|
||||
be subject to Mulan PSL v2 (this License) with the following terms and
|
||||
conditions:
|
||||
|
||||
0. Definition
|
||||
|
||||
Software means the program and related documents which are licensed under
|
||||
this License and comprise all Contribution(s).
|
||||
|
||||
Contribution means the copyrightable work licensed by a particular
|
||||
Contributor under this License.
|
||||
|
||||
Contributor means the Individual or Legal Entity who licenses its
|
||||
copyrightable work under this License.
|
||||
|
||||
Legal Entity means the entity making a Contribution and all its
|
||||
Affiliates.
|
||||
|
||||
Affiliates means entities that control, are controlled by, or are under
|
||||
common control with the acting entity under this License, ‘control’ means
|
||||
direct or indirect ownership of at least fifty percent (50%) of the voting
|
||||
power, capital or other securities of controlled or commonly controlled
|
||||
entity.
|
||||
|
||||
1. Grant of Copyright License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to you a perpetual, worldwide, royalty-free, non-exclusive,
|
||||
irrevocable copyright license to reproduce, use, modify, or distribute its
|
||||
Contribution, with modification or not.
|
||||
|
||||
2. Grant of Patent License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to you a perpetual, worldwide, royalty-free, non-exclusive,
|
||||
irrevocable (except for revocation under this Section) patent license to
|
||||
make, have made, use, offer for sale, sell, import or otherwise transfer its
|
||||
Contribution, where such patent license is only limited to the patent claims
|
||||
owned or controlled by such Contributor now or in future which will be
|
||||
necessarily infringed by its Contribution alone, or by combination of the
|
||||
Contribution with the Software to which the Contribution was contributed.
|
||||
The patent license shall not apply to any modification of the Contribution,
|
||||
and any other combination which includes the Contribution. If you or your
|
||||
Affiliates directly or indirectly institute patent litigation (including a
|
||||
cross claim or counterclaim in a litigation) or other patent enforcement
|
||||
activities against any individual or entity by alleging that the Software or
|
||||
any Contribution in it infringes patents, then any patent license granted to
|
||||
you under this License for the Software shall terminate as of the date such
|
||||
litigation or activity is filed or taken.
|
||||
|
||||
3. No Trademark License
|
||||
|
||||
No trademark license is granted to use the trade names, trademarks, service
|
||||
marks, or product names of Contributor, except as required to fulfill notice
|
||||
requirements in section 4.
|
||||
|
||||
4. Distribution Restriction
|
||||
|
||||
You may distribute the Software in any medium with or without modification,
|
||||
whether in source or executable forms, provided that you provide recipients
|
||||
with a copy of this License and retain copyright, patent, trademark and
|
||||
disclaimer statements in the Software.
|
||||
|
||||
5. Disclaimer of Warranty and Limitation of Liability
|
||||
|
||||
THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR
|
||||
COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT
|
||||
LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO
|
||||
MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF
|
||||
THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
6. Language
|
||||
|
||||
THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION
|
||||
AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF
|
||||
DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION
|
||||
SHALL PREVAIL.
|
||||
|
||||
END OF THE TERMS AND CONDITIONS
|
||||
|
||||
How to Apply the Mulan Permissive Software License,Version 2
|
||||
(Mulan PSL v2) to Your Software
|
||||
|
||||
To apply the Mulan PSL v2 to your work, for easy identification by
|
||||
recipients, you are suggested to complete following three steps:
|
||||
|
||||
i. Fill in the blanks in following statement, including insert your software
|
||||
name, the year of the first publication of your software, and your name
|
||||
identified as the copyright owner;
|
||||
|
||||
ii. Create a file named "LICENSE" which contains the whole context of this
|
||||
License in the first directory of your software package;
|
||||
|
||||
iii. Attach the statement to the appropriate annotated syntax at the
|
||||
beginning of each source file.
|
||||
|
||||
Copyright (c) [Year] [name of copyright holder]
|
||||
[Software Name] is licensed under Mulan PSL v2.
|
||||
You can use this software according to the terms and conditions of the Mulan
|
||||
PSL v2.
|
||||
You may obtain a copy of Mulan PSL v2 at:
|
||||
http://license.coscl.org.cn/MulanPSL2
|
||||
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
See the Mulan PSL v2 for more details.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# 确实开源帮助中心lc
|
||||
# 确实开源帮助中心
|
||||
|
||||
## 贡献文档方式
|
||||
#### 1.复刻主仓库
|
||||
|
|
@ -84,7 +84,8 @@
|
|||

|
||||
|
||||
```
|
||||
|
||||
初始化项目
|
||||
node v20.x npm install --force
|
||||
## 前端build成中文 (i18n中可编辑对应中文内容)
|
||||
```
|
||||
npm run build -- --locale zh-CN
|
||||
|
|
@ -101,7 +102,7 @@
|
|||
npm run dev
|
||||
```
|
||||
|
||||
这是在Gitee上添加的测试内容
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,323 +5,8 @@ sidebar_position: 5
|
|||
# 代码流水线
|
||||
可以通过代码的形式(YAML格式)来配置流水线,首先选择代码流水线和对应的分支:
|
||||
|
||||

|
||||

|
||||
|
||||
编辑流水线代码,其流水线名称描述、触发器、全局参数、执行串行/并发和流水线编排等概念同图形流水线,具体描述如下:
|
||||
|
||||

|
||||
|
||||
## YAML格式详解
|
||||
|
||||
代码流水线使用YAML格式配置,基本结构包括以下几个主要部分:
|
||||
|
||||
### 1. 基本信息
|
||||
|
||||
```yaml
|
||||
name: "Java应用构建部署流水线" # 流水线名称
|
||||
description: "用于构建和部署Java应用的CI/CD流水线" # 流水线描述
|
||||
```
|
||||
|
||||
### 2. 触发器配置
|
||||
|
||||
```yaml
|
||||
trigger:
|
||||
# 代码事件触发器
|
||||
type: GitLink_Webhook
|
||||
events:
|
||||
- push # 推送代码时触发
|
||||
- pull_request # 创建合并请求时触发
|
||||
- tag # 创建标签时触发
|
||||
branches:
|
||||
- master # 仅在master分支上触发
|
||||
- release/* # 支持通配符匹配release开头的分支
|
||||
|
||||
# 或者使用定时触发器
|
||||
# type: cron
|
||||
# expression: "0 0 * * *" # 每天零点触发,使用标准cron表达式
|
||||
```
|
||||
|
||||
### 3. 全局参数
|
||||
|
||||
```yaml
|
||||
parameters:
|
||||
- name: VERSION # 参数名
|
||||
type: string # 参数类型:string, number, boolean
|
||||
value: "1.0.0" # 默认值
|
||||
description: "应用版本号" # 参数描述
|
||||
|
||||
- name: DEBUG_MODE
|
||||
type: boolean
|
||||
value: false
|
||||
description: "是否开启调试模式"
|
||||
|
||||
- name: MAX_MEMORY
|
||||
type: number
|
||||
value: 1024
|
||||
description: "最大内存配置(MB)"
|
||||
```
|
||||
|
||||
### 4. 并发执行设置
|
||||
|
||||
```yaml
|
||||
concurrent:
|
||||
enabled: true # 是否允许并发执行
|
||||
max: 3 # 最大并发数
|
||||
```
|
||||
|
||||
### 5. 作业和步骤定义
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build: # 作业ID
|
||||
name: "构建应用" # 作业名称
|
||||
steps: # 步骤列表
|
||||
- name: "检出代码" # 步骤名称
|
||||
uses: checkout@v1 # 使用的动作
|
||||
|
||||
- name: "编译构建"
|
||||
uses: shell@v1
|
||||
with: # 步骤参数
|
||||
script: |
|
||||
echo "开始构建项目"
|
||||
mvn clean package -DskipTests
|
||||
|
||||
- name: "运行测试"
|
||||
uses: shell@v1
|
||||
with:
|
||||
script: "mvn test"
|
||||
|
||||
deploy: # 另一个作业
|
||||
name: "部署应用"
|
||||
needs: build # 依赖前一个作业完成
|
||||
steps:
|
||||
- name: "部署到服务器"
|
||||
uses: deploy@v1
|
||||
with:
|
||||
target: production
|
||||
artifacts: target/*.jar
|
||||
```
|
||||
|
||||
## 完整示例
|
||||
|
||||
下面是一个完整的Java应用CI/CD流水线示例:
|
||||
|
||||
```yaml
|
||||
name: "Java应用CI/CD流水线"
|
||||
description: "构建、测试和部署Java应用"
|
||||
|
||||
trigger:
|
||||
type: GitLink_Webhook
|
||||
events:
|
||||
- push
|
||||
- pull_request
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
|
||||
parameters:
|
||||
- name: JAVA_VERSION
|
||||
type: string
|
||||
value: "11"
|
||||
- name: SKIP_TESTS
|
||||
type: boolean
|
||||
value: false
|
||||
- name: DEPLOY_ENV
|
||||
type: string
|
||||
value: "test"
|
||||
description: "部署环境(test/staging/production)"
|
||||
|
||||
concurrent:
|
||||
enabled: true
|
||||
max: 2
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: "构建和测试"
|
||||
steps:
|
||||
- name: "检出代码"
|
||||
uses: checkout@v1
|
||||
|
||||
- name: "设置Java环境"
|
||||
uses: setup-java@v1
|
||||
with:
|
||||
java-version: ${JAVA_VERSION}
|
||||
|
||||
- name: "缓存Maven依赖"
|
||||
uses: cache@v1
|
||||
with:
|
||||
path: ~/.m2
|
||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||
|
||||
- name: "编译构建"
|
||||
uses: shell@v1
|
||||
with:
|
||||
script: |
|
||||
echo "开始构建项目"
|
||||
if [ "${SKIP_TESTS}" = "true" ]; then
|
||||
mvn clean package -DskipTests
|
||||
else
|
||||
mvn clean package
|
||||
fi
|
||||
|
||||
- name: "代码质量检查"
|
||||
uses: sonarqube@v1
|
||||
with:
|
||||
host: ${secrets.SONAR_HOST}
|
||||
token: ${secrets.SONAR_TOKEN}
|
||||
|
||||
- name: "构建Docker镜像"
|
||||
uses: shell@v1
|
||||
with:
|
||||
script: |
|
||||
docker build -t myapp:${GITLINK_COMMIT_SHA} .
|
||||
docker tag myapp:${GITLINK_COMMIT_SHA} myregistry/myapp:latest
|
||||
|
||||
- name: "推送Docker镜像"
|
||||
uses: shell@v1
|
||||
with:
|
||||
script: |
|
||||
echo ${secrets.DOCKER_PASSWORD} | docker login -u ${secrets.DOCKER_USERNAME} --password-stdin
|
||||
docker push myregistry/myapp:latest
|
||||
|
||||
deploy:
|
||||
name: "部署应用"
|
||||
needs: build
|
||||
steps:
|
||||
- name: "部署到环境"
|
||||
uses: deploy@v1
|
||||
with:
|
||||
environment: ${DEPLOY_ENV}
|
||||
credentials: ${secrets.SSH_KEY}
|
||||
script: |
|
||||
ssh ${secrets.SERVER_HOST} "cd /app && docker-compose pull && docker-compose up -d"
|
||||
|
||||
- name: "健康检查"
|
||||
uses: shell@v1
|
||||
with:
|
||||
script: |
|
||||
for i in {1..30}; do
|
||||
if curl -s http://${secrets.SERVER_HOST}:8080/health | grep -q "UP"; then
|
||||
echo "服务已成功启动"
|
||||
exit 0
|
||||
fi
|
||||
echo "等待服务启动... $i/30"
|
||||
sleep 10
|
||||
done
|
||||
echo "服务启动超时"
|
||||
exit 1
|
||||
|
||||
- name: "发送通知"
|
||||
uses: notification@v1
|
||||
with:
|
||||
type: email
|
||||
recipients: team@example.com
|
||||
subject: "部署完成通知"
|
||||
message: "应用已成功部署到${DEPLOY_ENV}环境"
|
||||
```
|
||||
|
||||
## 常用节点类型及配置
|
||||
|
||||
### 检出代码
|
||||
|
||||
```yaml
|
||||
- name: "检出代码"
|
||||
uses: checkout@v1
|
||||
with:
|
||||
repository: owner/repo # 可选,默认为当前仓库
|
||||
ref: master # 可选,分支、标签或提交ID
|
||||
depth: 1 # 可选,git历史深度
|
||||
```
|
||||
|
||||
### 执行Shell命令
|
||||
|
||||
```yaml
|
||||
- name: "执行Shell命令"
|
||||
uses: shell@v1
|
||||
with:
|
||||
script: |
|
||||
echo "执行多行Shell命令"
|
||||
ls -la
|
||||
mkdir -p build
|
||||
working-directory: ./src # 可选,指定工作目录
|
||||
timeout: 300 # 可选,超时时间(秒)
|
||||
```
|
||||
|
||||
### 构建应用
|
||||
|
||||
```yaml
|
||||
- name: "构建Java应用"
|
||||
uses: build@v1
|
||||
with:
|
||||
type: maven # 构建类型:maven, gradle, npm等
|
||||
command: "clean package" # 构建命令
|
||||
jdk-version: "11" # JDK版本
|
||||
```
|
||||
|
||||
### 部署应用
|
||||
|
||||
```yaml
|
||||
- name: "部署到服务器"
|
||||
uses: deploy@v1
|
||||
with:
|
||||
type: ssh # 部署类型:ssh, kubernetes, docker等
|
||||
host: ${secrets.SERVER_HOST}
|
||||
credentials: ${secrets.SSH_KEY}
|
||||
source: target/*.jar
|
||||
destination: /app/
|
||||
post-deploy: "systemctl restart myapp"
|
||||
```
|
||||
|
||||
### 条件执行
|
||||
|
||||
```yaml
|
||||
- name: "仅在生产环境执行"
|
||||
if: ${DEPLOY_ENV} == 'production'
|
||||
uses: shell@v1
|
||||
with:
|
||||
script: "echo '执行生产环境特定操作'"
|
||||
```
|
||||
|
||||
## 变量引用
|
||||
|
||||
在YAML配置中,可以通过以下方式引用变量:
|
||||
|
||||
1. **参数变量**:使用`${参数名}`格式引用
|
||||
```yaml
|
||||
script: "mvn -Dversion=${VERSION} package"
|
||||
```
|
||||
|
||||
2. **环境变量**:使用`${env.变量名}`格式引用
|
||||
```yaml
|
||||
script: "echo ${env.PATH}"
|
||||
```
|
||||
|
||||
3. **密钥变量**:使用`${secrets.密钥名}`格式引用
|
||||
```yaml
|
||||
credentials: ${secrets.API_TOKEN}
|
||||
```
|
||||
|
||||
4. **内置变量**:GitLink提供的内置变量
|
||||
```yaml
|
||||
# 提交相关
|
||||
${GITLINK_COMMIT_SHA} # 当前提交的SHA
|
||||
${GITLINK_BRANCH_NAME} # 当前分支名称
|
||||
|
||||
# 仓库相关
|
||||
${GITLINK_REPO_NAME} # 仓库名称
|
||||
${GITLINK_REPO_OWNER} # 仓库所有者
|
||||
|
||||
# 流水线相关
|
||||
${GITLINK_WORKFLOW_ID} # 流水线ID
|
||||
${GITLINK_RUN_ID} # 执行ID
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **版本控制**:将流水线配置文件提交到代码仓库,与应用代码一起版本控制
|
||||
2. **模块化**:将复杂流水线拆分为多个作业,便于维护和复用
|
||||
3. **参数化**:使用参数使流水线更灵活,适应不同场景
|
||||
4. **密钥管理**:敏感信息使用密钥管理,避免硬编码
|
||||
5. **注释**:添加适当注释,提高可读性
|
||||
6. **错误处理**:添加适当的错误处理和重试机制
|
||||
7. **通知机制**:配置通知,及时了解流水线执行状态
|
||||

|
||||
|
|
@ -3,179 +3,13 @@ sidebar_label: '参数配置'
|
|||
sidebar_position: 2
|
||||
---
|
||||
|
||||
# 参数配置
|
||||
# 参数配置
|
||||
|
||||
可在流水线中使用,实现动态参数配置;有字符串、数字、布尔三种类型。
|
||||
可在流水线中使用,实现动态参数配置;有字符串、数字、布尔三种类型。
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
在流水线的配置中通过如下方式获取参数:
|
||||
|
||||

|
||||
|
||||
## 参数类型详解
|
||||
|
||||
GitLink DevOps引擎支持三种类型的参数,可以根据不同需求选择合适的类型:
|
||||
|
||||
### 1. 字符串参数 (String)
|
||||
|
||||
字符串参数用于存储文本值,如版本号、环境名称、分支名等。
|
||||
|
||||
**特点**:
|
||||
- 可以包含任意文本内容
|
||||
- 支持空字符串
|
||||
- 最大长度为2000个字符
|
||||
|
||||
**使用场景**:
|
||||
- 指定版本号:`1.0.0`
|
||||
- 环境名称:`production`
|
||||
- 配置文件路径:`/config/app.properties`
|
||||
|
||||
**示例**:
|
||||
```yaml
|
||||
parameters:
|
||||
- name: VERSION
|
||||
type: string
|
||||
value: "1.0.0"
|
||||
description: "应用版本号"
|
||||
```
|
||||
|
||||
### 2. 数字参数 (Number)
|
||||
|
||||
数字参数用于存储整数或浮点数值,如端口号、超时时间、内存大小等。
|
||||
|
||||
**特点**:
|
||||
- 支持整数和浮点数
|
||||
- 可以进行数学运算
|
||||
- 范围限制:-2^53 到 2^53
|
||||
|
||||
**使用场景**:
|
||||
- 端口号:`8080`
|
||||
- 超时时间:`300`(秒)
|
||||
- 内存限制:`1024`(MB)
|
||||
|
||||
**示例**:
|
||||
```yaml
|
||||
parameters:
|
||||
- name: PORT
|
||||
type: number
|
||||
value: 8080
|
||||
description: "应用端口号"
|
||||
```
|
||||
|
||||
### 3. 布尔参数 (Boolean)
|
||||
|
||||
布尔参数用于表示是/否选项,如开关功能、跳过步骤等。
|
||||
|
||||
**特点**:
|
||||
- 只有两个可能值:`true` 或 `false`
|
||||
- 用于条件判断
|
||||
|
||||
**使用场景**:
|
||||
- 是否跳过测试:`true`/`false`
|
||||
- 是否启用调试模式:`true`/`false`
|
||||
- 是否发送通知:`true`/`false`
|
||||
|
||||
**示例**:
|
||||
```yaml
|
||||
parameters:
|
||||
- name: SKIP_TESTS
|
||||
type: boolean
|
||||
value: false
|
||||
description: "是否跳过测试"
|
||||
```
|
||||
|
||||
## 参数使用方法
|
||||
|
||||
### 在图形流水线中使用参数
|
||||
|
||||
在图形流水线的节点配置中,可以通过以下方式引用参数:
|
||||
|
||||
1. **Shell节点**:在脚本中使用`${参数名}`格式引用
|
||||
```bash
|
||||
echo "当前版本: ${VERSION}"
|
||||
if [ "${SKIP_TESTS}" = "true" ]; then
|
||||
echo "跳过测试"
|
||||
else
|
||||
echo "运行测试"
|
||||
fi
|
||||
```
|
||||
|
||||
2. **构建节点**:在构建参数中引用
|
||||
```
|
||||
-Dversion=${VERSION} -DskipTests=${SKIP_TESTS}
|
||||
```
|
||||
|
||||
3. **部署节点**:在部署配置中引用
|
||||
```
|
||||
目标环境: ${ENVIRONMENT}
|
||||
部署端口: ${PORT}
|
||||
```
|
||||
|
||||
### 在代码流水线中使用参数
|
||||
|
||||
在YAML配置的代码流水线中,可以在任何需要的地方引用参数:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
steps:
|
||||
- name: "编译构建"
|
||||
uses: shell@v1
|
||||
with:
|
||||
script: |
|
||||
echo "构建版本: ${VERSION}"
|
||||
mvn clean package -Dversion=${VERSION} -DskipTests=${SKIP_TESTS}
|
||||
|
||||
- name: "条件步骤"
|
||||
if: ${DEBUG_MODE} == true
|
||||
uses: shell@v1
|
||||
with:
|
||||
script: "echo '调试模式已启用'"
|
||||
```
|
||||
|
||||
## 参数作用域
|
||||
|
||||
参数的作用域决定了它们在哪些地方可以被访问和使用:
|
||||
|
||||
1. **全局参数**:在参数配置页面定义的参数,可在整个流水线中使用
|
||||
2. **作业参数**:在特定作业中定义的参数,仅在该作业及其步骤中可用
|
||||
3. **步骤参数**:在特定步骤中定义的参数,仅在该步骤中可用
|
||||
|
||||
## 参数优先级
|
||||
|
||||
当存在同名参数时,遵循以下优先级规则(从高到低):
|
||||
|
||||
1. 步骤参数
|
||||
2. 作业参数
|
||||
3. 全局参数
|
||||
4. 默认值
|
||||
|
||||
## 参数最佳实践
|
||||
|
||||
### 命名规范
|
||||
|
||||
- 使用大写字母和下划线:`VERSION`、`API_TOKEN`、`MAX_RETRY_COUNT`
|
||||
- 名称应清晰表达参数用途
|
||||
- 避免使用特殊字符和空格
|
||||
|
||||
### 提供默认值
|
||||
|
||||
- 始终为参数提供合理的默认值
|
||||
- 默认值应确保流水线在不指定参数时也能正常运行
|
||||
|
||||
### 添加描述
|
||||
|
||||
- 为每个参数添加清晰的描述
|
||||
- 说明参数的用途、可选值和影响
|
||||
|
||||
### 参数分组
|
||||
|
||||
- 相关参数应使用一致的前缀,如`DB_HOST`、`DB_PORT`、`DB_USER`
|
||||
- 便于理解和管理
|
||||
|
||||
### 敏感信息处理
|
||||
|
||||
- 不要在参数中存储敏感信息(如密码、令牌)
|
||||
- 敏感信息应使用密钥管理功能
|
||||

|
||||
|
|
@ -9,126 +9,42 @@ sidebar_position: 4
|
|||
|
||||
同一仓库下的流水线名称不能重复
|
||||
|
||||

|
||||

|
||||
|
||||
## 触发器
|
||||
注:流水线编排时,触发器要放在开始节点之前;目前一条流水线仅添加支持一个触发器
|
||||
|
||||
* 定时触发器cron:可通过填写cron表达式设置触发的具体时间
|
||||

|
||||

|
||||
|
||||
* 事件触发器GitLink_Webhook:给出了常见的代码变更事件触发,包括推送代码、合并请求、创建标签
|
||||

|
||||

|
||||
|
||||
## 全局参数
|
||||
|
||||
添加后可在当前流水线中使用
|
||||
|
||||

|
||||

|
||||
|
||||
使用实例
|
||||
|
||||

|
||||

|
||||
|
||||
## 并发执行
|
||||
|
||||

|
||||

|
||||
|
||||
开启后,同一流水线可同时并发执行n个流水线实例(每触发一次我们得到一个流水线实例);
|
||||
|
||||

|
||||

|
||||
|
||||
若未开启,则当前流水线实例执行中,后面的实例处于排队状态(最多可排队5个实例)。当前实例执行完成,下一个实例开始执行。
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
## 流水线编排
|
||||
|
||||
每条流水线必须要有一个开始节点、结束节点,至少一个任务节点。支持串行编排和并行编排。
|
||||
|
||||
### 串行编排
|
||||
|
||||
串行编排是指流水线中的任务按顺序一个接一个执行,当前任务完成后,下一个任务才会开始。这是最基本的流水线执行方式,适合有明确依赖关系的任务。
|
||||
|
||||
<!--  -->
|
||||
|
||||
**如何创建串行流水线**:
|
||||
1. 在流水线编辑界面,点击左侧工具栏中的"开始"节点,拖拽到画布上
|
||||
2. 添加任务节点(如Shell、构建、部署等)
|
||||
3. 使用连接线将节点按顺序连接起来
|
||||
4. 最后添加"结束"节点并连接
|
||||
|
||||
**串行编排的优点**:
|
||||
- 执行逻辑清晰,易于理解
|
||||
- 每个步骤都依赖于前一步骤的成功完成
|
||||
- 便于调试和故障排除
|
||||
|
||||
**串行编排的缺点**:
|
||||
- 执行效率较低,总执行时间为所有任务执行时间之和
|
||||
- 一个节点失败会导致整个流水线停止
|
||||
|
||||
### 并行编排
|
||||
|
||||
并行编排允许多个任务同时执行,适用于相互独立的任务,可以显著提高流水线的执行效率。
|
||||
|
||||
<!--  -->
|
||||
|
||||
**如何创建并行流水线**:
|
||||
1. 在流水线编辑界面创建开始节点
|
||||
2. 从开始节点连接到多个任务节点,形成分支
|
||||
3. 使用"汇合"节点将多个并行分支合并
|
||||
4. 连接到结束节点完成流水线
|
||||
|
||||
**并行编排的优点**:
|
||||
- 提高执行效率,减少总执行时间
|
||||
- 充分利用系统资源
|
||||
- 适合执行相互独立的任务
|
||||
|
||||
**并行编排的缺点**:
|
||||
- 增加流水线复杂度
|
||||
- 可能导致资源竞争
|
||||
- 需要注意并行任务间的数据共享问题
|
||||
|
||||
### 混合编排
|
||||
|
||||
在实际应用中,通常会结合使用串行和并行编排,根据任务的依赖关系灵活设计流水线结构。
|
||||
|
||||
<!--  -->
|
||||
|
||||
**混合编排示例**:
|
||||
1. 代码检出(串行)
|
||||
2. 并行执行单元测试和代码质量检查
|
||||
3. 构建应用(串行,依赖前两步完成)
|
||||
4. 并行部署到多个环境
|
||||
|
||||
### 常用节点类型
|
||||
|
||||
GitLink DevOps引擎提供多种预定义节点类型,满足不同场景需求:
|
||||
|
||||
#### 基础节点
|
||||
- **开始节点**:流水线的起点
|
||||
- **结束节点**:流水线的终点
|
||||
- **汇合节点**:合并多个并行分支
|
||||
|
||||
#### 任务节点
|
||||
- **Shell节点**:执行Shell命令或脚本
|
||||
- **构建节点**:编译和构建项目
|
||||
- **部署节点**:将应用部署到目标环境
|
||||
- **测试节点**:执行自动化测试
|
||||
- **通知节点**:发送邮件或其他通知
|
||||
|
||||
#### 控制节点
|
||||
- **条件节点**:根据条件决定执行路径
|
||||
- **循环节点**:重复执行特定任务
|
||||
- **等待节点**:暂停流水线直到满足条件
|
||||
|
||||
### 节点配置最佳实践
|
||||
|
||||
1. **命名规范**:使用描述性名称,如"编译Java项目"而非简单的"编译"
|
||||
2. **超时设置**:为长时间运行的节点设置合理的超时时间
|
||||
3. **错误处理**:配置节点失败时的处理策略(继续/中止)
|
||||
4. **资源限制**:根据任务需求合理设置CPU和内存限制
|
||||
5. **日志管理**:配置重要日志的保存策略
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,200 +3,14 @@ sidebar_label: '密钥设置'
|
|||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# 密钥设置
|
||||
# 密钥设置
|
||||
|
||||
将账号密码、密钥、证书等存放到密钥管理里,配置后可直接在流水线中使用,避免因直接填写引起的泄露风险。
|
||||
|
||||

|
||||

|
||||
|
||||
使用示例
|
||||
|
||||
注:节点输入参数中,下拉选项为密钥类型,需要提前配置好密钥在流水线中选择使用
|
||||
|
||||

|
||||
|
||||
## 密钥类型
|
||||
|
||||
GitLink DevOps引擎支持多种类型的密钥,以满足不同的安全需求:
|
||||
|
||||
### 1. 用户名密码
|
||||
|
||||
用于存储需要用户名和密码的凭证,如数据库连接、应用登录等。
|
||||
|
||||
**配置字段**:
|
||||
- 密钥名称:唯一标识符
|
||||
- 用户名:登录账号
|
||||
- 密码:登录密码
|
||||
- 描述:可选的说明文字
|
||||
|
||||
**使用场景**:
|
||||
- 数据库连接
|
||||
- 应用系统登录
|
||||
- API认证
|
||||
|
||||
**流水线中引用方式**:
|
||||
```yaml
|
||||
# 在代码流水线中引用
|
||||
with:
|
||||
username: ${secrets.DB_CREDENTIAL.username}
|
||||
password: ${secrets.DB_CREDENTIAL.password}
|
||||
|
||||
# 在Shell脚本中引用
|
||||
echo "连接数据库..."
|
||||
mysql -u${secrets.DB_CREDENTIAL.username} -p${secrets.DB_CREDENTIAL.password} -h localhost
|
||||
```
|
||||
|
||||
### 2. SSH密钥
|
||||
|
||||
用于SSH连接远程服务器,支持公钥/私钥认证方式。
|
||||
|
||||
**配置字段**:
|
||||
- 密钥名称:唯一标识符
|
||||
- 私钥:SSH私钥内容
|
||||
- 密码短语:私钥的密码(如有)
|
||||
- 描述:可选的说明文字
|
||||
|
||||
**使用场景**:
|
||||
- 远程服务器部署
|
||||
- Git仓库访问
|
||||
- 自动化运维操作
|
||||
|
||||
**流水线中引用方式**:
|
||||
```yaml
|
||||
# 在代码流水线中引用
|
||||
with:
|
||||
type: ssh
|
||||
credentials: ${secrets.SERVER_SSH_KEY}
|
||||
host: example.com
|
||||
|
||||
# 使用SSH密钥部署
|
||||
- name: "部署到服务器"
|
||||
uses: deploy@v1
|
||||
with:
|
||||
type: ssh
|
||||
credentials: ${secrets.SERVER_SSH_KEY}
|
||||
host: ${SERVER_HOST}
|
||||
script: |
|
||||
cd /app
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
### 3. 访问令牌
|
||||
|
||||
用于API访问的令牌,如GitHub Token、OAuth令牌等。
|
||||
|
||||
**配置字段**:
|
||||
- 密钥名称:唯一标识符
|
||||
- 令牌值:访问令牌字符串
|
||||
- 描述:可选的说明文字
|
||||
|
||||
**使用场景**:
|
||||
- API认证
|
||||
- 第三方服务集成
|
||||
- 容器仓库访问
|
||||
|
||||
**流水线中引用方式**:
|
||||
```yaml
|
||||
# 在代码流水线中引用
|
||||
with:
|
||||
token: ${secrets.API_TOKEN}
|
||||
|
||||
# 在Shell脚本中使用
|
||||
curl -H "Authorization: Bearer ${secrets.API_TOKEN}" https://api.example.com/data
|
||||
```
|
||||
|
||||
### 4. 证书
|
||||
|
||||
用于存储SSL证书、签名证书等。
|
||||
|
||||
**配置字段**:
|
||||
- 密钥名称:唯一标识符
|
||||
- 证书内容:PEM格式的证书
|
||||
- 私钥:对应的私钥
|
||||
- 描述:可选的说明文字
|
||||
|
||||
**使用场景**:
|
||||
- HTTPS配置
|
||||
- 应用签名
|
||||
- 身份认证
|
||||
|
||||
**流水线中引用方式**:
|
||||
```yaml
|
||||
# 在代码流水线中引用
|
||||
with:
|
||||
certificate: ${secrets.SSL_CERT.certificate}
|
||||
private_key: ${secrets.SSL_CERT.private_key}
|
||||
```
|
||||
|
||||
## 密钥权限管理
|
||||
|
||||
GitLink DevOps引擎提供细粒度的密钥权限管理,确保敏感信息的安全:
|
||||
|
||||
### 密钥作用域
|
||||
|
||||
1. **仓库级别**:仅在特定代码仓库的流水线中可用
|
||||
2. **组织级别**:在组织内的所有代码仓库流水线中可用
|
||||
3. **用户级别**:仅对特定用户可见和使用
|
||||
|
||||
### 访问控制
|
||||
|
||||
1. **创建者**:默认情况下,只有密钥创建者可以查看和编辑密钥
|
||||
2. **共享**:可以与特定用户或组织共享密钥,并设置只读或读写权限
|
||||
3. **审计**:所有密钥的使用都会被记录,便于安全审计
|
||||
|
||||
## 密钥使用最佳实践
|
||||
|
||||
### 安全性建议
|
||||
|
||||
1. **定期轮换**:定期更新密钥内容,尤其是高敏感度的密钥
|
||||
2. **最小权限**:为密钥配置最小必要的权限
|
||||
3. **避免硬编码**:永远不要在脚本或配置文件中硬编码密钥
|
||||
4. **加密传输**:确保密钥在传输过程中使用TLS/SSL加密
|
||||
|
||||
### 命名规范
|
||||
|
||||
1. **描述性名称**:使用清晰描述性的名称,如`PROD_DB_CREDENTIAL`而非简单的`DB_CRED`
|
||||
2. **环境前缀**:使用环境前缀区分不同环境的密钥,如`DEV_`、`TEST_`、`PROD_`
|
||||
3. **一致性**:保持命名风格一致,推荐使用大写字母和下划线
|
||||
|
||||
### 密钥组织
|
||||
|
||||
1. **按环境分组**:为不同环境(开发、测试、生产)创建不同的密钥
|
||||
2. **按用途分组**:按照用途(数据库、API、部署等)组织密钥
|
||||
3. **文档记录**:维护密钥清单文档,记录用途、权限和有效期
|
||||
|
||||
## 密钥轮换流程
|
||||
|
||||
为确保系统安全,应定期轮换密钥:
|
||||
|
||||
1. **创建新密钥**:创建新版本的密钥,但不立即启用
|
||||
2. **更新系统**:更新使用该密钥的外部系统
|
||||
3. **更新流水线**:更新流水线配置,使用新密钥
|
||||
4. **验证**:验证所有系统和流水线正常工作
|
||||
5. **废弃旧密钥**:确认无问题后,删除或禁用旧密钥
|
||||
|
||||
## 常见问题排查
|
||||
|
||||
### 密钥访问被拒绝
|
||||
|
||||
**可能原因**:
|
||||
- 权限不足
|
||||
- 密钥已过期
|
||||
- 密钥名称错误
|
||||
|
||||
**解决方法**:
|
||||
- 检查密钥权限设置
|
||||
- 验证密钥是否有效
|
||||
- 确认密钥名称拼写正确
|
||||
|
||||
### 密钥内容不正确
|
||||
|
||||
**可能原因**:
|
||||
- 格式错误(如多余的换行符、空格)
|
||||
- 编码问题
|
||||
- 复制粘贴错误
|
||||
|
||||
**解决方法**:
|
||||
- 重新生成并配置密钥
|
||||
- 确保使用正确的格式和编码
|
||||
- 使用密钥测试功能验证
|
||||

|
||||
|
|
@ -1,192 +0,0 @@
|
|||
---
|
||||
sidebar_label: '常见问题排查'
|
||||
sidebar_position: 8
|
||||
---
|
||||
|
||||
# 常见问题排查
|
||||
|
||||
本文档汇总了使用GitLink DevOps引擎时可能遇到的常见问题及解决方案。
|
||||
|
||||
## 流水线触发问题
|
||||
|
||||
### 问题:流水线没有自动触发
|
||||
**可能原因**:
|
||||
1. Webhook配置不正确
|
||||
2. 触发条件不匹配
|
||||
3. 分支名称不匹配
|
||||
|
||||
**解决方法**:
|
||||
1. 检查项目设置中的Webhook配置是否正确
|
||||
2. 确认触发事件(如push、pull request等)是否与配置一致
|
||||
3. 检查触发器配置中的分支规则是否匹配
|
||||
|
||||
### 问题:流水线重复触发
|
||||
**可能原因**:
|
||||
1. 多个触发器配置重叠
|
||||
2. Webhook重复注册
|
||||
|
||||
**解决方法**:
|
||||
1. 检查并简化触发器配置,避免重叠
|
||||
2. 在项目设置中检查并删除重复的Webhook
|
||||
|
||||
## 执行失败问题
|
||||
|
||||
### 问题:节点执行超时
|
||||
**可能原因**:
|
||||
1. 任务执行时间超过默认超时时间
|
||||
2. 资源不足导致执行缓慢
|
||||
3. 死循环或无限等待
|
||||
|
||||
**解决方法**:
|
||||
1. 在节点配置中增加超时时间
|
||||
2. 优化任务脚本,减少执行时间
|
||||
3. 检查脚本中是否存在死循环或无限等待情况
|
||||
|
||||
### 问题:权限不足导致失败
|
||||
**可能原因**:
|
||||
1. 执行环境权限不足
|
||||
2. 密钥配置不正确
|
||||
3. 外部系统访问受限
|
||||
|
||||
**解决方法**:
|
||||
1. 检查并调整执行环境的权限设置
|
||||
2. 验证密钥配置是否正确
|
||||
3. 确认外部系统的访问权限和网络连通性
|
||||
|
||||
### 问题:构建失败但没有明确错误信息
|
||||
**可能原因**:
|
||||
1. 日志输出不完整
|
||||
2. 错误发生在脚本内部
|
||||
|
||||
**解决方法**:
|
||||
1. 增加脚本的日志输出
|
||||
2. 添加错误捕获和输出
|
||||
3. 在关键步骤添加调试信息
|
||||
|
||||
```bash
|
||||
# 增加错误处理和日志输出的示例
|
||||
set -e # 任何命令失败立即退出
|
||||
trap 'echo "发生错误,行号: $LINENO, 命令: $BASH_COMMAND"' ERR
|
||||
|
||||
# 增加详细日志
|
||||
set -x # 打印执行的每条命令
|
||||
```
|
||||
|
||||
## 参数和密钥问题
|
||||
|
||||
### 问题:参数值未正确传递
|
||||
**可能原因**:
|
||||
1. 参数引用语法不正确
|
||||
2. 参数名称拼写错误
|
||||
3. 参数作用域问题
|
||||
|
||||
**解决方法**:
|
||||
1. 检查参数引用语法是否正确,如`${parameter_name}`
|
||||
2. 确认参数名称拼写正确
|
||||
3. 确认参数在正确的作用域中定义
|
||||
|
||||
### 问题:密钥无法正常使用
|
||||
**可能原因**:
|
||||
1. 密钥配置不正确
|
||||
2. 密钥权限不足
|
||||
3. 密钥引用方式错误
|
||||
|
||||
**解决方法**:
|
||||
1. 在密钥管理页面验证密钥配置
|
||||
2. 确认密钥具有足够的权限
|
||||
3. 检查密钥的引用方式,如`${secrets.SECRET_NAME}`
|
||||
|
||||
## 性能问题
|
||||
|
||||
### 问题:流水线执行缓慢
|
||||
**可能原因**:
|
||||
1. 资源配置不足
|
||||
2. 存在性能瓶颈
|
||||
3. 不必要的串行执行
|
||||
|
||||
**解决方法**:
|
||||
1. 增加节点资源配置
|
||||
2. 识别并优化性能瓶颈
|
||||
3. 将独立任务改为并行执行
|
||||
|
||||
### 问题:资源使用率过高
|
||||
**可能原因**:
|
||||
1. 资源配置不合理
|
||||
2. 并发任务过多
|
||||
3. 存在资源泄漏
|
||||
|
||||
**解决方法**:
|
||||
1. 调整资源配置,避免过度分配
|
||||
2. 限制并发任务数量
|
||||
3. 检查并修复资源泄漏问题
|
||||
|
||||
## 代码流水线语法问题
|
||||
|
||||
### 问题:YAML语法错误
|
||||
**可能原因**:
|
||||
1. 缩进不正确
|
||||
2. 引号使用不当
|
||||
3. 特殊字符处理不当
|
||||
|
||||
**解决方法**:
|
||||
1. 使用YAML验证工具检查语法
|
||||
2. 确保缩进一致(通常是2个空格)
|
||||
3. 对包含特殊字符的字符串使用引号
|
||||
|
||||
**常见YAML语法错误示例**:
|
||||
|
||||
```yaml
|
||||
# 错误:缩进不一致
|
||||
jobs:
|
||||
build:
|
||||
steps: # 缩进不足
|
||||
- name: 检出代码
|
||||
uses: checkout@v1
|
||||
|
||||
# 正确:缩进一致
|
||||
jobs:
|
||||
build:
|
||||
steps: # 缩进正确
|
||||
- name: 检出代码
|
||||
uses: checkout@v1
|
||||
```
|
||||
|
||||
```yaml
|
||||
# 错误:特殊字符未使用引号
|
||||
script: echo Hello World! > output.txt # > 是特殊字符
|
||||
|
||||
# 正确:使用引号包裹特殊字符
|
||||
script: "echo Hello World! > output.txt"
|
||||
```
|
||||
|
||||
## 其他常见问题
|
||||
|
||||
### 问题:流水线配置无法保存
|
||||
**可能原因**:
|
||||
1. 表单验证失败
|
||||
2. 网络连接问题
|
||||
3. 服务器错误
|
||||
|
||||
**解决方法**:
|
||||
1. 检查表单输入是否符合要求
|
||||
2. 确认网络连接正常
|
||||
3. 查看浏览器控制台是否有错误信息
|
||||
|
||||
### 问题:流水线执行结果通知未收到
|
||||
**可能原因**:
|
||||
1. 通知配置不正确
|
||||
2. 通知服务异常
|
||||
3. 接收方过滤规则
|
||||
|
||||
**解决方法**:
|
||||
1. 检查通知配置是否正确
|
||||
2. 确认通知服务正常运行
|
||||
3. 检查接收方的过滤规则
|
||||
|
||||
## 联系支持
|
||||
|
||||
如果您遇到的问题无法通过上述方法解决,请通过以下方式联系GitLink支持团队:
|
||||
|
||||
1. 在GitLink平台提交疑修(Issue)
|
||||
2. 发送邮件至support@gitlink.org.cn
|
||||
3. 通过GitLink官方社区寻求帮助
|
||||
|
|
@ -8,6 +8,6 @@ sidebar_position: 1
|
|||
引擎(Engine)是GitLink提供的一款DevOps工具,通过简单的节点编排来构建开发、测试、部署流水线,从而创建自动化的软件交付流程。
|
||||
它可以实现持续的代码集成,让开发者能尽早发现质量问题,快速定位修复,提升软件开发效率和质量;自动化的代码扫描、编译打包、单元测试,把研发团队从重复的工作中解放出来,聚焦到更有价值的事情上。
|
||||
|
||||

|
||||

|
||||
|
||||
在引擎页面中,用户可以创建和编辑图形流水线或代码流水线、设置外部参数、管理密钥等操作。
|
||||
|
|
@ -3,159 +3,8 @@ sidebar_label: '执行记录查询'
|
|||
sidebar_position: 6
|
||||
---
|
||||
|
||||
# 执行记录查询
|
||||
# 执行记录查询
|
||||
|
||||
用户可以查看流水线的运行状态
|
||||
用户可以查看流水线的运行状态
|
||||
|
||||

|
||||
|
||||
## 执行记录概述
|
||||
|
||||
执行记录查询功能允许用户查看、分析和管理流水线的执行情况,帮助用户了解流水线的运行状态、执行历史和性能表现。通过执行记录,用户可以:
|
||||
|
||||
- 监控当前正在运行的流水线实例
|
||||
- 查看历史执行记录和结果
|
||||
- 分析流水线执行时间和资源消耗
|
||||
- 排查流水线执行中的问题
|
||||
- 重新运行或取消流水线实例
|
||||
|
||||
## 执行记录列表
|
||||
|
||||
执行记录列表页面显示了流水线的所有执行实例,包括以下关键信息:
|
||||
|
||||
1. **执行ID**:每次执行的唯一标识符
|
||||
2. **流水线名称**:关联的流水线名称
|
||||
3. **触发方式**:如何触发的流水线(手动、代码推送、定时等)
|
||||
4. **触发用户**:谁触发了这次执行
|
||||
5. **开始时间**:执行开始的时间
|
||||
6. **结束时间**:执行结束的时间
|
||||
7. **执行时长**:从开始到结束的总时长
|
||||
8. **状态**:当前执行状态(等待中、运行中、成功、失败、取消)
|
||||
|
||||
用户可以通过以下条件筛选执行记录:
|
||||
- 流水线名称
|
||||
- 执行状态
|
||||
- 触发方式
|
||||
- 时间范围
|
||||
- 触发用户
|
||||
|
||||
## 执行详情
|
||||
|
||||
点击执行记录列表中的任一记录,可以进入执行详情页面,查看该次执行的详细信息:
|
||||
|
||||
### 基本信息
|
||||
|
||||
- 执行ID和流水线名称
|
||||
- 触发信息(触发方式、触发用户、触发时间)
|
||||
- 执行状态和时间信息
|
||||
- 关联的代码信息(分支、提交ID等)
|
||||
|
||||
### 执行图
|
||||
|
||||
执行图以可视化方式展示流水线的执行过程,包括:
|
||||
|
||||
- 节点执行状态(等待中、运行中、成功、失败、跳过)
|
||||
- 节点执行顺序和依赖关系
|
||||
- 当前执行位置
|
||||
- 节点执行时间
|
||||
|
||||
### 节点详情
|
||||
|
||||
点击执行图中的节点,可以查看该节点的详细信息:
|
||||
|
||||
- 节点名称和类型
|
||||
- 执行状态和时间
|
||||
- 输入参数和环境变量
|
||||
- 执行日志
|
||||
- 输出结果和制品
|
||||
|
||||
### 执行日志
|
||||
|
||||
执行日志页面显示流水线执行过程中产生的所有日志,帮助用户了解执行过程和排查问题:
|
||||
|
||||
- 实时日志流
|
||||
- 按节点筛选日志
|
||||
- 日志搜索功能
|
||||
- 日志下载选项
|
||||
|
||||
## 操作功能
|
||||
|
||||
在执行记录页面,用户可以对流水线执行实例进行以下操作:
|
||||
|
||||
### 重新运行
|
||||
|
||||
对于已完成(成功或失败)的执行实例,用户可以选择重新运行:
|
||||
|
||||
- **完全重新运行**:从头开始重新执行整个流水线
|
||||
- **从失败处重新运行**:从上次失败的节点开始重新执行
|
||||
- **使用相同参数**:使用原执行实例的参数重新运行
|
||||
- **修改参数后运行**:修改参数后重新运行
|
||||
|
||||
### 取消执行
|
||||
|
||||
对于正在运行中的执行实例,用户可以选择取消执行:
|
||||
|
||||
- **立即取消**:立即停止所有正在运行的节点
|
||||
- **优雅取消**:等待当前正在运行的节点完成后取消后续节点
|
||||
|
||||
### 比较执行
|
||||
|
||||
用户可以选择两个执行实例进行比较,了解它们之间的差异:
|
||||
|
||||
- 执行时间和性能差异
|
||||
- 参数和环境差异
|
||||
- 执行结果差异
|
||||
- 节点执行状态差异
|
||||
|
||||
## 执行统计与分析
|
||||
|
||||
执行记录查询功能还提供了统计和分析工具,帮助用户了解流水线的整体表现:
|
||||
|
||||
### 执行趋势
|
||||
|
||||
- 执行成功率趋势
|
||||
- 执行时间趋势
|
||||
- 执行频率趋势
|
||||
|
||||
### 性能分析
|
||||
|
||||
- 节点执行时间分布
|
||||
- 资源使用情况
|
||||
- 瓶颈节点识别
|
||||
|
||||
### 故障分析
|
||||
|
||||
- 常见失败原因统计
|
||||
- 失败节点分布
|
||||
- 失败率最高的节点
|
||||
|
||||
## 通知与集成
|
||||
|
||||
执行记录查询功能支持与通知系统和其他工具集成:
|
||||
|
||||
- **邮件通知**:执行完成后发送结果通知
|
||||
- **消息推送**:通过企业即时通讯工具推送执行状态
|
||||
- **状态回调**:向外部系统提供执行状态回调
|
||||
|
||||
## 权限控制
|
||||
|
||||
执行记录的查看和操作受权限控制:
|
||||
|
||||
- **查看权限**:谁可以查看执行记录
|
||||
- **操作权限**:谁可以重新运行或取消执行
|
||||
- **管理权限**:谁可以删除或归档执行记录
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 执行记录管理
|
||||
|
||||
- 定期归档或清理旧的执行记录
|
||||
- 为重要的执行记录添加标签或说明
|
||||
- 下载并保存关键执行的日志和结果
|
||||
|
||||
### 问题排查
|
||||
|
||||
- 从执行日志中查找错误信息
|
||||
- 比较成功和失败的执行记录
|
||||
- 检查环境和参数差异
|
||||
- 分析节点执行时间异常的原因
|
||||

|
||||
|
|
@ -1,123 +0,0 @@
|
|||
---
|
||||
sidebar_label: '流水线最佳实践'
|
||||
sidebar_position: 7
|
||||
---
|
||||
|
||||
# 流水线最佳实践
|
||||
|
||||
## 设计流水线的基本原则
|
||||
|
||||
### 1. 保持简单明了
|
||||
- 每个节点专注于单一任务
|
||||
- 使用有意义的节点名称
|
||||
- 添加适当的注释说明节点用途
|
||||
|
||||
### 2. 模块化设计
|
||||
- 将常用功能封装成独立节点
|
||||
- 合理划分阶段,便于维护和复用
|
||||
- 使用参数化设计,提高流水线灵活性
|
||||
|
||||
### 3. 错误处理
|
||||
- 添加适当的错误处理机制
|
||||
- 设置关键节点的超时时间
|
||||
- 配置失败通知,及时发现问题
|
||||
|
||||
## 常见场景的最佳实践
|
||||
|
||||
### 持续集成(CI)最佳实践
|
||||
1. **代码检出**:始终使用特定版本的检出工具
|
||||
2. **依赖缓存**:缓存依赖包加速构建
|
||||
3. **并行测试**:将测试分组并行执行
|
||||
4. **代码质量检查**:集成SonarQube等工具
|
||||
5. **构建制品归档**:保存构建结果便于追溯
|
||||
|
||||
示例流水线:
|
||||
```yaml
|
||||
name: CI最佳实践
|
||||
jobs:
|
||||
build:
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: checkout@v1
|
||||
|
||||
- name: 缓存依赖
|
||||
uses: cache@v1
|
||||
with:
|
||||
path: ~/.m2
|
||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||
|
||||
- name: 编译构建
|
||||
uses: shell@v1
|
||||
with:
|
||||
script: mvn -B package --file pom.xml
|
||||
|
||||
- name: 代码质量检查
|
||||
uses: sonarqube@v1
|
||||
with:
|
||||
host: ${secrets.SONAR_HOST}
|
||||
token: ${secrets.SONAR_TOKEN}
|
||||
|
||||
- name: 归档制品
|
||||
uses: archive@v1
|
||||
with:
|
||||
path: target/*.jar
|
||||
```
|
||||
|
||||
### 持续部署(CD)最佳实践
|
||||
1. **环境隔离**:严格区分开发、测试、生产环境
|
||||
2. **蓝绿部署**:减少部署风险
|
||||
3. **自动化测试**:部署后进行自动化验证
|
||||
4. **回滚机制**:配置快速回滚方案
|
||||
5. **部署审批**:关键环境部署前增加人工审批
|
||||
|
||||
示例流水线:
|
||||
```yaml
|
||||
name: CD最佳实践
|
||||
jobs:
|
||||
deploy:
|
||||
steps:
|
||||
- name: 部署到测试环境
|
||||
uses: deploy@v1
|
||||
with:
|
||||
target: test
|
||||
artifacts: app.jar
|
||||
|
||||
- name: 自动化测试
|
||||
uses: shell@v1
|
||||
with:
|
||||
script: ./run-tests.sh
|
||||
|
||||
- name: 人工审批
|
||||
uses: approval@v1
|
||||
with:
|
||||
approvers: tech-leads
|
||||
timeout: 24h
|
||||
|
||||
- name: 部署到生产环境
|
||||
uses: deploy@v1
|
||||
with:
|
||||
target: production
|
||||
strategy: blue-green
|
||||
artifacts: app.jar
|
||||
|
||||
- name: 健康检查
|
||||
uses: shell@v1
|
||||
with:
|
||||
script: ./health-check.sh
|
||||
```
|
||||
|
||||
## 性能优化技巧
|
||||
|
||||
1. **并行执行**:将独立任务设置为并行执行
|
||||
2. **资源限制**:合理设置节点资源限制,避免资源浪费
|
||||
3. **减少依赖**:减少节点间的不必要依赖
|
||||
4. **缓存利用**:合理使用缓存加速构建
|
||||
5. **定期清理**:清理旧的构建记录和无用缓存
|
||||
|
||||
## 安全最佳实践
|
||||
|
||||
1. **密钥管理**:敏感信息使用密钥管理,避免硬编码
|
||||
2. **最小权限**:为流水线配置最小必要权限
|
||||
3. **依赖扫描**:集成依赖安全扫描工具
|
||||
4. **镜像扫描**:部署前扫描容器镜像漏洞
|
||||
5. **审计日志**:保留完整的流水线执行日志
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
const lightCodeTheme = require('prism-react-renderer/themes/github');
|
||||
const darkCodeTheme = require('prism-react-renderer/themes/dracula');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
//Docusaurus v3写法
|
||||
// const { themes } = require('prism-react-renderer');
|
||||
// import { themes } from 'prism-react-renderer';
|
||||
import("@easyops-cn/docusaurus-search-local").PluginOptions;
|
||||
|
||||
/** @type {import('@docusaurus/types').DocusaurusConfig} */
|
||||
|
|
@ -10,48 +11,13 @@ module.exports = {
|
|||
tagline:'gitlink帮助中心',
|
||||
url: 'https://help.gitlink.org.cn/',
|
||||
baseUrl: '/',
|
||||
onBrokenLinks: 'ignore',
|
||||
onBrokenMarkdownLinks: 'ignore',
|
||||
onBrokenLinks: 'warn',
|
||||
onBrokenMarkdownLinks: 'warn',
|
||||
favicon: 'img/icon.ico',
|
||||
organizationName: 'luffyZh', // Usually your GitHub org/user name.
|
||||
projectName: 'docusaurus-luffyzh-website', // Usually your repo name.
|
||||
scripts: [],
|
||||
// stylesheets: ['styles/dark-mode.css'],
|
||||
plugins: [
|
||||
// 添加API路由
|
||||
function apiRoutes(context, options) {
|
||||
return {
|
||||
name: 'api-routes-plugin',
|
||||
configureWebpack(config, isServer, utils) {
|
||||
return {
|
||||
resolve: {
|
||||
alias: {
|
||||
// 添加API路径别名
|
||||
'@api': path.resolve(__dirname, 'api'),
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
// 添加API路由处理
|
||||
async postBuild({ routesPaths = [], outDir }) {
|
||||
// 创建API目录
|
||||
const apiOutDir = path.join(outDir, 'api');
|
||||
if (!fs.existsSync(apiOutDir)) {
|
||||
fs.mkdirSync(apiOutDir);
|
||||
}
|
||||
|
||||
// 复制反馈数据文件到构建目录
|
||||
const dataFilePath = path.join(process.cwd(), 'feedback-data.json');
|
||||
if (fs.existsSync(dataFilePath)) {
|
||||
fs.copyFileSync(dataFilePath, path.join(outDir, 'feedback-data.json'));
|
||||
} else {
|
||||
fs.writeFileSync(path.join(outDir, 'feedback-data.json'), '[]', 'utf8');
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
],
|
||||
themeConfig: {
|
||||
docs:{
|
||||
sidebar:{
|
||||
|
|
@ -65,7 +31,7 @@ module.exports = {
|
|||
{property:"og:image:alt",content:"GitLink(确实开源)是中国计算机学会CCF官方指定的开源创新服务平台 - Gitlink/forgeplus:GitLink(确实开源)是中国计算机学会CCF官方指定的开源创新服务平台 for gitlink Gitlink/forgeplus for git"}
|
||||
],
|
||||
prism: {
|
||||
theme: lightCodeTheme,
|
||||
theme:lightCodeTheme,
|
||||
darkTheme: darkCodeTheme,
|
||||
},
|
||||
zoom: {
|
||||
|
|
@ -106,11 +72,26 @@ module.exports = {
|
|||
position: 'left',
|
||||
dropdownActiveClassDisabled: true
|
||||
},
|
||||
{
|
||||
to: '/feedback-management',
|
||||
label: '反馈管理',
|
||||
position: 'right',
|
||||
},
|
||||
// {
|
||||
// type: 'localeDropdown',
|
||||
// position: 'right',
|
||||
// },
|
||||
// {
|
||||
// position: 'right',
|
||||
// component:'./src/components/LanguageSwitcher',
|
||||
// label:"language",
|
||||
// to:"#"
|
||||
// items: [
|
||||
// {
|
||||
// label: 'English',
|
||||
// onClick: () => handleLocaleChange('en')
|
||||
// },
|
||||
// {
|
||||
// label: '简体中文',
|
||||
// onClick: () => handleLocaleChange('zh-Hans')
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// {
|
||||
// href: 'https://github.com/boxyhq',
|
||||
// position: 'right',
|
||||
|
|
@ -223,6 +204,16 @@ module.exports = {
|
|||
],
|
||||
i18n: {
|
||||
defaultLocale: 'zh-cn',
|
||||
locales: ['zh-cn'],
|
||||
locales: ['zh-cn','en'],
|
||||
localeConfigs: {
|
||||
en: {
|
||||
label: 'English',
|
||||
htmlLang: 'en',
|
||||
},
|
||||
'zh-cn': {
|
||||
label: '简体中文',
|
||||
htmlLang: 'zh-CN',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
23e041136cc43bcfa244f806799f5640
|
||||
|
|
@ -1 +0,0 @@
|
|||
测试同步详细日志增强功能
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
@echo off
|
||||
echo 正在下载Node.js安装程序...
|
||||
powershell -Command "Invoke-WebRequest -Uri https://nodejs.org/dist/v20.11.1/node-v20.11.1-x64.msi -OutFile node-installer.msi"
|
||||
echo 下载完成,正在安装Node.js...
|
||||
start /wait msiexec /i node-installer.msi /quiet /norestart
|
||||
echo 安装完成,请重新打开命令提示符或PowerShell以使用Node.js和npm。
|
||||
pause
|
||||
Binary file not shown.
|
|
@ -1,4 +0,0 @@
|
|||
@echo off
|
||||
set PATH=%PATH%;C:\nodejs
|
||||
cd /d %~dp0
|
||||
npm install
|
||||
BIN
nvm-setup.exe
BIN
nvm-setup.exe
Binary file not shown.
|
|
@ -0,0 +1,47 @@
|
|||
为了构建更好的平台生态环境,我们推出了基于OAuth2的API版本。
|
||||
API 接口使用方式以及Url都参照GitHub,为了各位开发者更好的兼容已经存在的第三方应用。
|
||||
|
||||
# API 使用条款
|
||||
|
||||
未经用户允许,不准爬取或存储用户的资源。
|
||||
禁止滥用 API,请求频率过快将导致请求终止。
|
||||
OAuth2 认证基本流程
|
||||

|
||||
|
||||
# OAuth2 获取 AccessToken 认证步骤
|
||||
|
||||
### 1. 授权码模式
|
||||
* 应用通过 浏览器 或 Webview 将用户引导到平台三方认证页面上( GET请求 )
|
||||
|
||||
`https://gitlink.org.cn/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code`
|
||||
|
||||
* 用户对应用进行授权
|
||||
注意: 如果之前已经授权过的需要跳过授权页面,需要在上面第一步的 URL 加上 scope 参数,且 scope 的值需要和用户上次授权的勾选的一致。如用户在上次授权了user_info。则步骤A 中 GET 请求应为:
|
||||
|
||||
`https://gitlink.org.cn/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&scope=user_info`
|
||||
|
||||
* 平台认证服务器通过回调地址`{redirect_uri}`将 用户授权码 传递给 应用服务器 或者直接在 Webview 中跳转到携带 用户授权码的回调地址上,Webview 直接获取code即可(`{redirect_uri}?code=abc&state=xyz`)
|
||||
* 应用服务器 或 Webview 使用 access_token API 向平台认证服务器发送post请求传入 用户授权码 以及 回调地址( POST请求 )
|
||||
注:请求过程建议将 client_secret 放在 Body 中传值,以保证数据安全。
|
||||
|
||||
`https://gitlink.org.cn/oauth/token?grant_type=authorization_code&code={code}&client_id={client_id}&redirect_uri={redirect_uri}&client_secret={client_secret}`
|
||||
|
||||
* 平台认证服务器返回 access_token
|
||||
|
||||
应用通过 access_token 访问 Open API 使用用户数据。
|
||||
当 access_token 过期后(有效期为一天),你可以通过以下 refresh_token 方式重新获取 access_token( POST请求 )
|
||||
|
||||
`https://gitlink.org.cn/oauth/token?grant_type=refresh_token&refresh_token={refresh_token}`
|
||||
|
||||
> 注意:如果获取 access_token 返回 403,可能是没有设置User-Agent的原因。
|
||||
详见:获取Token时服务端响应状态403是什么情况
|
||||
|
||||
### 2. 密码模式
|
||||
* 用户向客户端提供邮箱地址和密码。客户端将邮箱地址和密码发给平台认证服务器,并向平台认证服务器请求令牌。( POST请求。Content-Type: application/x-www-form-urlencoded )
|
||||
|
||||
`curl -X POST --data-urlencode "grant_type=password" --data-urlencode "username={email}" --data-urlencode "password={password}" --data-urlencode "client_id={client_id}" --data-urlencode "client_secret={client_secret}" --data-urlencode "scope=user_info" https://gitlink.org.cn/oauth/token`
|
||||
|
||||
scope表示权限范围,有以下选项,请求时使用空格隔开
|
||||
`user_info` `projects` `pull_requests` `issues` `notes` `keys` `hook groups` `gists` `enterprises`
|
||||
* 认证服务器返回 access_token
|
||||
应用通过 access_token 访问 Open API 使用用户数据。
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 135 KiB |
File diff suppressed because it is too large
Load Diff
91
package.json
91
package.json
|
|
@ -1,42 +1,49 @@
|
|||
{
|
||||
"name": "docusaurus",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
"start": "docusaurus start",
|
||||
"build": "docusaurus build",
|
||||
"swizzle": "docusaurus swizzle",
|
||||
"deploy": "docusaurus deploy",
|
||||
"clear": "docusaurus clear",
|
||||
"serve": "docusaurus serve",
|
||||
"write-translations": "docusaurus write-translations",
|
||||
"write-heading-ids": "docusaurus write-heading-ids",
|
||||
"dev": "docusaurus start --port 3000"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.4.1",
|
||||
"@docusaurus/preset-classic": "2.4.1",
|
||||
"@easyops-cn/docusaurus-search-local": "^0.35.0",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"body-parser": "^1.20.2",
|
||||
"clsx": "^1.2.1",
|
||||
"docusaurus-plugin-image-zoom": "^1.0.1",
|
||||
"express": "^4.18.2",
|
||||
"prism-react-renderer": "^1.3.5",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.5%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
{
|
||||
"name": "docusaurus",
|
||||
"version": "3.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
"dev": "docusaurus start --port 3000",
|
||||
"build": "docusaurus build",
|
||||
"swizzle": "docusaurus swizzle",
|
||||
"deploy": "docusaurus deploy",
|
||||
"clear": "docusaurus clear",
|
||||
"serve": "docusaurus serve",
|
||||
"write-translations": "docusaurus write-translations",
|
||||
"write-heading-ids": "docusaurus write-heading-ids"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cmfcmf/docusaurus-search-local": "1.1.0",
|
||||
"@docusaurus/core": "3.9.2",
|
||||
"@docusaurus/plugin-client-redirects": "3.9.2",
|
||||
"@docusaurus/preset-classic": "3.9.2",
|
||||
"@easyops-cn/docusaurus-search-local": "^0.35.0",
|
||||
"@mdx-js/react": "^3.1.1",
|
||||
"@node-rs/jieba": "^1.7.0",
|
||||
"clsx": "1.2.1",
|
||||
"docusaurus-gtm-plugin": "0.0.2",
|
||||
"docusaurus-plugin-image-zoom": "1.0.1",
|
||||
"or": "^0.2.0",
|
||||
"prism-react-renderer": "^1.3.5",
|
||||
"prismjs": "^1.30.0",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-modal": "3.16.1"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.5%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.x"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
{
|
||||
"name": "docusaurus",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
"start": "docusaurus start",
|
||||
"build": "docusaurus build",
|
||||
"swizzle": "docusaurus swizzle",
|
||||
"deploy": "docusaurus deploy",
|
||||
"clear": "docusaurus clear",
|
||||
"serve": "docusaurus serve",
|
||||
"write-translations": "docusaurus write-translations",
|
||||
"write-heading-ids": "docusaurus write-heading-ids",
|
||||
"dev": "docusaurus start --port 3000",
|
||||
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.4.1",
|
||||
"@docusaurus/preset-classic": "2.4.1",
|
||||
"@easyops-cn/docusaurus-search-local": "^0.35.0",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"body-parser": "^1.20.2",
|
||||
"clsx": "^1.2.1",
|
||||
"docusaurus-plugin-image-zoom": "^1.0.1",
|
||||
"express": "^4.18.2",
|
||||
"prism-react-renderer": "^1.3.5",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.5%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
@echo off
|
||||
set PATH=%PATH%;C:\nodejs
|
||||
cd /d %~dp0
|
||||
npm run dev
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
@echo off
|
||||
echo 正在设置Node.js环境变量...
|
||||
setx PATH "%PATH%;C:\nodejs" /M
|
||||
echo 环境变量设置完成!请重新打开命令提示符或PowerShell以使更改生效。
|
||||
pause
|
||||
|
|
@ -1,178 +0,0 @@
|
|||
import React, { useState } from 'react';
|
||||
import styles from './styles.module.css';
|
||||
|
||||
export default function DocFeedback() {
|
||||
const [voted, setVoted] = useState(false);
|
||||
const [feedback, setFeedback] = useState('');
|
||||
const [showForm, setShowForm] = useState(false);
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
// 获取当前页面URL作为文档标识
|
||||
const documentUrl = typeof window !== 'undefined' ? window.location.pathname : '';
|
||||
|
||||
const handleVote = (isHelpful) => {
|
||||
setVoted(true);
|
||||
setShowForm(!isHelpful);
|
||||
|
||||
// 发送投票结果到服务器
|
||||
if (typeof window !== 'undefined') {
|
||||
try {
|
||||
const feedbackData = {
|
||||
documentUrl: documentUrl,
|
||||
isHelpful: isHelpful,
|
||||
timestamp: new Date().toISOString(),
|
||||
feedbackType: 'vote'
|
||||
};
|
||||
|
||||
// 将反馈保存到localStorage以便在客户端保留记录
|
||||
const storedFeedbacks = JSON.parse(localStorage.getItem('docFeedbacks') || '[]');
|
||||
storedFeedbacks.push(feedbackData);
|
||||
localStorage.setItem('docFeedbacks', JSON.stringify(storedFeedbacks));
|
||||
|
||||
console.log(isHelpful ? '用户认为有帮助' : '用户认为没有帮助', feedbackData);
|
||||
|
||||
// 这里应该添加发送到服务器的代码
|
||||
// fetch('/api/feedback', {
|
||||
// method: 'POST',
|
||||
// headers: { 'Content-Type': 'application/json' },
|
||||
// body: JSON.stringify(feedbackData)
|
||||
// });
|
||||
} catch (error) {
|
||||
console.error('提交反馈时出错:', error);
|
||||
}
|
||||
}
|
||||
|
||||
if (isHelpful) {
|
||||
setTimeout(() => setVoted(false), 3000);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
setIsSubmitting(true);
|
||||
|
||||
// 发送详细反馈到服务器
|
||||
if (typeof window !== 'undefined') {
|
||||
try {
|
||||
const feedbackData = {
|
||||
documentUrl: documentUrl,
|
||||
feedback: feedback,
|
||||
timestamp: new Date().toISOString(),
|
||||
feedbackType: 'detailed'
|
||||
};
|
||||
|
||||
// 将反馈保存到localStorage以便在客户端保留记录
|
||||
const storedFeedbacks = JSON.parse(localStorage.getItem('docFeedbacks') || '[]');
|
||||
storedFeedbacks.push(feedbackData);
|
||||
localStorage.setItem('docFeedbacks', JSON.stringify(storedFeedbacks));
|
||||
|
||||
console.log('用户反馈:', feedbackData);
|
||||
|
||||
// 这里应该添加发送到服务器的代码
|
||||
// fetch('/api/feedback', {
|
||||
// method: 'POST',
|
||||
// headers: { 'Content-Type': 'application/json' },
|
||||
// body: JSON.stringify(feedbackData)
|
||||
// })
|
||||
// .then(response => response.json())
|
||||
// .then(data => {
|
||||
// setSubmitted(true);
|
||||
// setShowForm(false);
|
||||
// setIsSubmitting(false);
|
||||
// })
|
||||
// .catch(error => {
|
||||
// console.error('提交反馈时出错:', error);
|
||||
// setIsSubmitting(false);
|
||||
// });
|
||||
|
||||
// 模拟提交成功
|
||||
setTimeout(() => {
|
||||
setSubmitted(true);
|
||||
setShowForm(false);
|
||||
setIsSubmitting(false);
|
||||
|
||||
setTimeout(() => {
|
||||
setVoted(false);
|
||||
setFeedback('');
|
||||
setSubmitted(false);
|
||||
}, 3000);
|
||||
}, 500);
|
||||
} catch (error) {
|
||||
console.error('提交反馈时出错:', error);
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.feedbackContainer}>
|
||||
{!voted && !submitted && (
|
||||
<div className={styles.feedbackQuestion}>
|
||||
<p>这篇文档对您有帮助吗?</p>
|
||||
<div className={styles.feedbackButtons}>
|
||||
<button
|
||||
onClick={() => handleVote(true)}
|
||||
className={styles.feedbackButton}
|
||||
>
|
||||
👍 有帮助
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleVote(false)}
|
||||
className={styles.feedbackButton}
|
||||
>
|
||||
👎 没有帮助
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{voted && !showForm && !submitted && (
|
||||
<div className={styles.feedbackThanks}>
|
||||
感谢您的反馈!
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showForm && (
|
||||
<form onSubmit={handleSubmit} className={styles.feedbackForm}>
|
||||
<p>您希望如何改进这篇文档?</p>
|
||||
<textarea
|
||||
value={feedback}
|
||||
onChange={(e) => setFeedback(e.target.value)}
|
||||
placeholder="请告诉我们如何改进这篇文档..."
|
||||
rows={4}
|
||||
className={styles.feedbackTextarea}
|
||||
required
|
||||
/>
|
||||
<div className={styles.feedbackFormButtons}>
|
||||
<button
|
||||
type="submit"
|
||||
className={styles.submitButton}
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
{isSubmitting ? '提交中...' : '提交反馈'}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setShowForm(false);
|
||||
setVoted(false);
|
||||
}}
|
||||
className={styles.cancelButton}
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
取消
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
|
||||
{submitted && (
|
||||
<div className={styles.feedbackThanks}>
|
||||
感谢您的宝贵反馈!我们会认真考虑您的建议。
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
.feedbackContainer {
|
||||
margin-top: 3rem;
|
||||
padding: 1.5rem;
|
||||
border-top: 1px solid var(--ifm-color-emphasis-200);
|
||||
}
|
||||
|
||||
.feedbackQuestion {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.feedbackButtons {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.feedbackButton {
|
||||
padding: 0.5rem 1rem;
|
||||
border: 1px solid var(--ifm-color-emphasis-300);
|
||||
border-radius: 4px;
|
||||
background: var(--ifm-color-emphasis-100);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.feedbackButton:hover {
|
||||
background: var(--ifm-color-emphasis-200);
|
||||
}
|
||||
|
||||
.feedbackThanks {
|
||||
text-align: center;
|
||||
padding: 1rem;
|
||||
color: var(--ifm-color-success-dark);
|
||||
}
|
||||
|
||||
.feedbackForm {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.feedbackTextarea {
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
border: 1px solid var(--ifm-color-emphasis-300);
|
||||
border-radius: 4px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.feedbackFormButtons {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.submitButton {
|
||||
padding: 0.5rem 1rem;
|
||||
background: var(--ifm-color-primary);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.submitButton:hover {
|
||||
background: var(--ifm-color-primary-dark);
|
||||
}
|
||||
|
||||
.cancelButton {
|
||||
padding: 0.5rem 1rem;
|
||||
background: var(--ifm-color-emphasis-200);
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cancelButton:hover {
|
||||
background: var(--ifm-color-emphasis-300);
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// src/components/LanguageSwitcher.js
|
||||
import React from 'react';
|
||||
import { useDocusaurusContext } from '@docusaurus/useDocusaurusContext';
|
||||
|
||||
export default function LanguageSwitcher() {
|
||||
const { i18n } = useDocusaurusContext();
|
||||
|
||||
const locales = [
|
||||
{ code: 'en', label: 'English' },
|
||||
{ code: 'zh-Hans', label: '简体中文' }
|
||||
];
|
||||
|
||||
return (
|
||||
<div style={{ marginRight: '1rem' }}>
|
||||
<select
|
||||
value={i18n.currentLocale}
|
||||
onChange={(e) => {
|
||||
localStorage.setItem('preferredLocale', e.target.value);
|
||||
window.location.href = `/${e.target.value}/`;
|
||||
}}
|
||||
style={{
|
||||
padding: '0.5rem 1rem',
|
||||
border: '1px solid #ddd',
|
||||
borderRadius: '4px',
|
||||
backgroundColor: 'white',
|
||||
fontSize: '0.9rem',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
{locales.map((locale) => (
|
||||
<option key={locale.code} value={locale.code}>
|
||||
{locale.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -57,7 +57,6 @@ html[data-theme='dark'] .docusaurus-highlight-code-line {
|
|||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.footer__bottom .margin-bottom--sm{
|
||||
position: absolute;
|
||||
|
|
|
|||
|
|
@ -1,78 +0,0 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
export default function FeedbackDashboard() {
|
||||
const [feedbacks, setFeedbacks] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
// 从localStorage加载反馈
|
||||
const storedFeedbacks = JSON.parse(localStorage.getItem('docFeedbacks') || '[]');
|
||||
setFeedbacks(storedFeedbacks);
|
||||
}, []);
|
||||
|
||||
// 清除所有反馈
|
||||
const clearFeedbacks = () => {
|
||||
if (confirm('确定要清除所有反馈吗?')) {
|
||||
localStorage.setItem('docFeedbacks', '[]');
|
||||
setFeedbacks([]);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout title="反馈管理">
|
||||
<div className="container margin-vert--lg">
|
||||
<h1>反馈管理</h1>
|
||||
|
||||
<div className="margin-bottom--lg">
|
||||
<h2>总计: {feedbacks.length} 条反馈</h2>
|
||||
{feedbacks.length > 0 && (
|
||||
<button
|
||||
onClick={clearFeedbacks}
|
||||
className="button button--danger"
|
||||
>
|
||||
清除所有反馈
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="card-demo margin-bottom--lg">
|
||||
<div className="card">
|
||||
<div className="card__header">
|
||||
<h3>反馈列表</h3>
|
||||
</div>
|
||||
<div className="card__body">
|
||||
{feedbacks.length === 0 ? (
|
||||
<p>暂无反馈数据</p>
|
||||
) : (
|
||||
<table className="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>类型</th>
|
||||
<th>页面</th>
|
||||
<th>内容</th>
|
||||
<th>时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{feedbacks.map((feedback, index) => (
|
||||
<tr key={index}>
|
||||
<td>{feedback.type === 'vote' ? '投票' : '评论'}</td>
|
||||
<td>{feedback.page}</td>
|
||||
<td>
|
||||
{feedback.type === 'vote'
|
||||
? (feedback.isHelpful ? '👍 有帮助' : '👎 没有帮助')
|
||||
: feedback.content}
|
||||
</td>
|
||||
<td>{new Date(feedback.timestamp).toLocaleString('zh-CN')}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
title: 反馈管理
|
||||
---
|
||||
|
||||
import FeedbackDashboard from '@site/src/pages/feedback-dashboard';
|
||||
|
||||
<FeedbackDashboard />
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import Layout from '@theme/Layout';
|
||||
|
||||
export default function FeedbackManagement() {
|
||||
const [feedbacks, setFeedbacks] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
// 从localStorage加载反馈数据
|
||||
if (typeof window !== 'undefined') {
|
||||
try {
|
||||
const storedFeedbacks = JSON.parse(localStorage.getItem('docFeedbacks') || '[]');
|
||||
setFeedbacks(storedFeedbacks);
|
||||
} catch (error) {
|
||||
console.error('加载反馈数据时出错:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 清除所有反馈
|
||||
const handleClearFeedbacks = () => {
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.removeItem('docFeedbacks');
|
||||
setFeedbacks([]);
|
||||
}
|
||||
};
|
||||
|
||||
// 解码URL
|
||||
const decodeDocumentUrl = (url) => {
|
||||
try {
|
||||
return decodeURIComponent(url);
|
||||
} catch (error) {
|
||||
console.error('URL解码失败:', error);
|
||||
return url;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout title="反馈管理" description="查看文档反馈">
|
||||
<div className="container margin-vert--lg">
|
||||
<h1>反馈管理</h1>
|
||||
<p>总计: {feedbacks.length} 条反馈</p>
|
||||
|
||||
{loading ? (
|
||||
<p>加载中...</p>
|
||||
) : feedbacks.length > 0 ? (
|
||||
<>
|
||||
<button
|
||||
onClick={handleClearFeedbacks}
|
||||
className="button button--danger button--sm margin-bottom--md"
|
||||
>
|
||||
清除所有反馈
|
||||
</button>
|
||||
|
||||
<table className="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>文档URL</th>
|
||||
<th>类型</th>
|
||||
<th>内容</th>
|
||||
<th>时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{feedbacks.map((feedback, index) => (
|
||||
<tr key={index}>
|
||||
<td>{decodeDocumentUrl(feedback.documentUrl)}</td>
|
||||
<td>
|
||||
{feedback.feedbackType === 'vote'
|
||||
? (feedback.isHelpful ? '[+] 有帮助' : '[-] 没有帮助')
|
||||
: '详细反馈'}
|
||||
</td>
|
||||
<td>
|
||||
{feedback.feedbackType === 'vote'
|
||||
? (feedback.isHelpful ? '有帮助' : '没有帮助')
|
||||
: feedback.feedback}
|
||||
</td>
|
||||
<td>{new Date(feedback.timestamp).toLocaleString()}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
) : (
|
||||
<p>暂无反馈数据</p>
|
||||
)}
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import styles from './styles.module.css';
|
||||
|
||||
const BackToTop = () => {
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
|
||||
// 检测滚动位置,决定是否显示按钮
|
||||
useEffect(() => {
|
||||
const toggleVisibility = () => {
|
||||
if (window.pageYOffset > 300) {
|
||||
setIsVisible(true);
|
||||
} else {
|
||||
setIsVisible(false);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('scroll', toggleVisibility);
|
||||
return () => window.removeEventListener('scroll', toggleVisibility);
|
||||
}, []);
|
||||
|
||||
// 滚动到顶部的函数
|
||||
const scrollToTop = () => {
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{isVisible && (
|
||||
<button
|
||||
onClick={scrollToTop}
|
||||
className={styles.backToTop}
|
||||
title="返回顶部"
|
||||
aria-label="返回顶部"
|
||||
>
|
||||
↑
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BackToTop;
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
.backToTop {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background-color: var(--ifm-color-primary);
|
||||
color: white;
|
||||
border: none;
|
||||
font-size: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
z-index: 100;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.backToTop:hover {
|
||||
transform: translateY(-3px);
|
||||
background-color: var(--ifm-color-primary-darker);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.backToTop {
|
||||
bottom: 15px;
|
||||
right: 15px;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
|
||||
import React from 'react';
|
||||
import DocFeedback from '@site/src/components/DocFeedback';
|
||||
|
||||
export default function DocItemFooter() {
|
||||
return (
|
||||
<footer className="docusaurus-mt-lg">
|
||||
<DocFeedback />
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
.lastUpdated {
|
||||
margin-top: 0.2rem;
|
||||
font-style: italic;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
@media (min-width: 997px) {
|
||||
.lastUpdated {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import styles from './styles.module.css';
|
||||
|
||||
const TableOfContents = () => {
|
||||
const [headings, setHeadings] = useState([]);
|
||||
const [activeId, setActiveId] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
// 获取页面中所有的标题元素
|
||||
const elements = Array.from(document.querySelectorAll('h2, h3, h4, h5, h6'))
|
||||
.filter(element => element.id);
|
||||
|
||||
const headingsData = elements.map(element => ({
|
||||
id: element.id,
|
||||
text: element.textContent,
|
||||
level: Number(element.tagName.substring(1))
|
||||
}));
|
||||
|
||||
setHeadings(headingsData);
|
||||
|
||||
// 监听滚动事件,更新当前激活的标题
|
||||
const handleScroll = () => {
|
||||
const scrollPosition = window.scrollY;
|
||||
|
||||
// 找到当前视图中的标题
|
||||
const currentHeading = headingsData
|
||||
.filter(heading => {
|
||||
const element = document.getElementById(heading.id);
|
||||
if (!element) return false;
|
||||
return element.offsetTop <= scrollPosition + 100;
|
||||
})
|
||||
.pop();
|
||||
|
||||
if (currentHeading) {
|
||||
setActiveId(currentHeading.id);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
handleScroll(); // 初始化激活的标题
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('scroll', handleScroll);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 如果没有标题,不显示目录
|
||||
if (headings.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.tableOfContents}>
|
||||
<div className={styles.tocHeader}>目录</div>
|
||||
<nav>
|
||||
<ul className={styles.tocList}>
|
||||
{headings.map(heading => (
|
||||
<li
|
||||
key={heading.id}
|
||||
className={`${styles.tocItem} ${styles[`tocLevel${heading.level}`]} ${activeId === heading.id ? styles.tocItemActive : ''}`}
|
||||
>
|
||||
<a
|
||||
href={`#${heading.id}`}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
document.getElementById(heading.id).scrollIntoView({
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}}
|
||||
>
|
||||
{heading.text}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TableOfContents;
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
.tableOfContents {
|
||||
position: sticky;
|
||||
top: 70px;
|
||||
max-height: calc(100vh - 100px);
|
||||
overflow-y: auto;
|
||||
padding: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
border-left: 1px solid var(--ifm-color-emphasis-300);
|
||||
border-radius: 4px;
|
||||
background-color: var(--ifm-background-surface-color);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.tocHeader {
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--ifm-color-primary);
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.tocList {
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.tocItem {
|
||||
margin: 0.25rem 0;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.tocItem a {
|
||||
display: block;
|
||||
padding: 0.25rem 0;
|
||||
color: var(--ifm-color-content);
|
||||
text-decoration: none;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.tocItem a:hover {
|
||||
color: var(--ifm-color-primary);
|
||||
}
|
||||
|
||||
.tocItemActive a {
|
||||
color: var(--ifm-color-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tocLevel2 {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.tocLevel3 {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
.tocLevel4 {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
.tocLevel5 {
|
||||
padding-left: 3rem;
|
||||
}
|
||||
|
||||
.tocLevel6 {
|
||||
padding-left: 4rem;
|
||||
}
|
||||
|
||||
@media (max-width: 996px) {
|
||||
.tableOfContents {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
import React from 'react';
|
||||
import DocItem from '@theme-original/DocItem';
|
||||
import BackToTop from './BackToTop';
|
||||
import TableOfContents from './TableOfContents';
|
||||
import styles from './styles.module.css';
|
||||
|
||||
export default function DocItemWrapper(props) {
|
||||
return (
|
||||
<div className={styles.docItemContainer}>
|
||||
<div className={styles.docItemContent}>
|
||||
<DocItem {...props} />
|
||||
</div>
|
||||
<div className={styles.docItemSidebar}>
|
||||
<TableOfContents />
|
||||
</div>
|
||||
<BackToTop />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
.docItemContainer {
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.docItemContent {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.docItemSidebar {
|
||||
width: 240px;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
@media (max-width: 996px) {
|
||||
.docItemContainer {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.docItemSidebar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 151 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 178 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 233 KiB |
|
|
@ -69,6 +69,26 @@ GitLink(确实开源)是CCF官方指定的开源创新服务平台,旨在
|
|||
<h2 class="text--truncate cardTitle" title="第三方服务">第三方服务</h2>
|
||||
<p>第三方服务使用及设置[3个文档]</p>
|
||||
</a></article>
|
||||
<article class="col col--6 margin-bottom--lg">
|
||||
<a class="card padding--lg cardContainer" href="/通知/通知简介">
|
||||
<h2 class="text--truncate cardTitle" title="通知">通知</h2>
|
||||
<p>通知使用及设置[2个文档]</p>
|
||||
</a></article>
|
||||
<article class="col col--6 margin-bottom--lg">
|
||||
<a class="card padding--lg cardContainer" href="/个人主页建站/站点创建流程">
|
||||
<h2 class="text--truncate cardTitle" title="个人主页建站">个人主页建站</h2>
|
||||
<p>个人主页建站使用及设置[2个文档]</p>
|
||||
</a></article>
|
||||
<article class="col col--6 margin-bottom--lg">
|
||||
<a class="card padding--lg cardContainer" href="/平台公告/">
|
||||
<h2 class="text--truncate cardTitle" title="平台公告">平台公告</h2>
|
||||
<p>平台公告使用及设置</p>
|
||||
</a></article>
|
||||
<article class="col col--6 margin-bottom--lg">
|
||||
<a class="card padding--lg cardContainer" href="/服务协议/GitLink服务协议">
|
||||
<h2 class="text--truncate cardTitle" title="服务协议">服务协议</h2>
|
||||
<p>服务协议使用及设置[1个文档]</p>
|
||||
</a></article>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,11 +1,4 @@
|
|||
---
|
||||
sidebar_label: '代码提交'
|
||||
sidebar_position: 3
|
||||
---
|
||||
### **1. 代码提交入口**
|
||||
用户可以通过项目代码库中间的文件下的"上传文件"按键来上传文件。
|
||||
<br/>
|
||||
|
||||
### **2. 上传文件**
|
||||
进入上传文件页面后,如下图所示,拖动文件,选择提交变更的分支的单击"创建项目"按键即可完成创建。
|
||||
<br/>
|
||||
---
|
||||
|
|
@ -1,28 +1,4 @@
|
|||
---
|
||||
sidebar_label: '分支管理'
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
# 分支管理
|
||||
|
||||
### **1. 查看分支**
|
||||
在代码库栏下,如下图所示,用户可以点击代码库分支从而查看当前项目的所有分支,并且选择对其进行操作。
|
||||
<br/>
|
||||
|
||||
### **2. 合并分支**
|
||||
在"合并请求(PR)"下点击"新建合并请求"后,
|
||||
<br/>
|
||||
如下图所示,用户可以选择源分支与目标分支以及填写分支信息后提交分支合并请求。
|
||||
<br/>
|
||||
|
||||
### **3. 创建分支**
|
||||
用户可以在代码库页面通过点击分支选择器,然后点击"创建分支"按钮创建新的分支。
|
||||
创建分支时,需要指定基于哪个已有分支来创建新分支,并为新分支命名。
|
||||
|
||||
### **4. 删除分支**
|
||||
在分支列表页面,对于非保护分支,用户可以通过点击分支右侧的删除按钮来删除不再需要的分支。
|
||||
需要注意的是,删除分支操作不可逆,请确保分支上的工作已经合并到主分支或已不再需要。
|
||||
|
||||
### **5. 分支保护**
|
||||
对于重要的分支(如主分支),项目管理员可以设置分支保护规则,防止意外删除或直接推送代码。
|
||||
分支保护可以在项目设置中的"分支保护"选项中配置。
|
||||
---
|
||||
|
|
@ -1,19 +1,4 @@
|
|||
---
|
||||
sidebar_label: '文件管理'
|
||||
sidebar_position: 4
|
||||
---
|
||||
### **1. 文件管理位置**
|
||||
在代码库界面,可直接对代码库中该分支下的文件进行操作,如下图所示。
|
||||
<br/>
|
||||
|
||||
### **2. 进入目录**
|
||||
点击进入相关目录,找到要编辑的文件,如下图所示。
|
||||
<br/>
|
||||
|
||||
### **3. 进入文件编辑页面**
|
||||
在线编辑文件,单击文件,即可进入编辑文件页面,如下图所示。
|
||||
<br/>
|
||||
|
||||
### **4. 编辑文件**
|
||||
编辑界面右侧有三个按钮,分别是"下载"、"编辑"和"删除",点击下载即可将文件下载到本地,编辑则可在线编辑文档,删除则将文件从代码库中删除,按钮位置如下图所示。
|
||||
<br/>
|
||||
---
|
||||
|
|
@ -3,11 +3,4 @@ sidebar_label: '代码评审'
|
|||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# 代码评审
|
||||
### **1. 进入代码评审**
|
||||
如下图所示,点击"代码评审"按钮可以进入代码评审
|
||||
<br/>
|
||||
|
||||
### **2. 代码评审界面**
|
||||
如下图所示,用户可以在该界面下查看该PR操作要合并的新的代码,并对其进行评审。
|
||||
<br/>
|
||||
# 代码评审
|
||||
|
|
@ -1,21 +1,4 @@
|
|||
---
|
||||
sidebar_label: '组织成员管理'
|
||||
sidebar_position: 4
|
||||
---
|
||||
# 成员管理(Members Management)
|
||||
|
||||
在 个人所管理的项目当中的**仓库设置**当中的**成员管理**可以进入成员管理界面
|
||||
|
||||

|
||||
|
||||
## 成员查询和添加
|
||||
在成员管理界面当中,可以进行组织成员的查询和添加
|
||||
|
||||

|
||||
|
||||
## 成员邀请权限设置
|
||||
管理员可以对邀请成员的权限进行设置
|
||||

|
||||
此外,也可以复制邀请链接的方式来更方便地邀请成员加入到项目当中来
|
||||
|
||||
**注**:此项功能仅对管理员可见
|
||||
---
|
||||
|
|
@ -1,15 +1,4 @@
|
|||
---
|
||||
sidebar_label: '模板导入及导出'
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
# 确实开源帮助中心
|
||||
|
||||
## 模板的导入及导出管理
|
||||
#### 1.模板导入
|
||||
通过点击wiki界面的**导入模板**按钮即可导入本地的txt,markdown等格式文件进行Wiki文档的创建,当前平台此项功能尚在开发测试环节
|
||||
[](/img/wiki/img4.png)
|
||||
#### 2.模板导出
|
||||
当前平台此项功能尚在开发测试环节
|
||||
<br/>
|
||||
|
||||
---
|
||||
|
|
@ -1,23 +1,4 @@
|
|||
---
|
||||
sidebar_label: '维基页面管理'
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
|
||||
# 确实开源帮助中心
|
||||
|
||||
## 维基界面管理
|
||||
#### 1.维基界面
|
||||
GitLink项目安排了专门的**维基(Wiki)界面**来展示项目的一些情况
|
||||
[](/img/wiki/img1.png)
|
||||
|
||||
#### 2.创建维基内容
|
||||
在初始化的维基界面当中点击**创建Wiki文档**或者**导入模板**即可进行Wiki文档的编辑
|
||||
<br/>
|
||||
|
||||
#### 3.进行Wiki文档的编辑
|
||||
点击**创建Wiki文档**后即跳转到编辑界面,初始内容为空白的文档
|
||||
[](/img/wiki/img3.png)
|
||||
也可以通过勾选*添加模板*来进行模板的导入,平台提供的模板包括*周报*和*月报*的格式
|
||||
[](/img/wiki/img2.png)
|
||||
完成编辑后点击左下角的的保存即可
|
||||
---
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 252 KiB |
Loading…
Reference in New Issue