提交 c4f15b68 编写于 作者: 李少辉-开发者's avatar 李少辉-开发者 🎧

Init csdn workflow

Signed-off-by: 李少辉-开发者's avatarlish <lish@csdn.net>
上级 c30d9a98
node_modules
package-lock.json
.vscode-test/
.vsix
.history
......@@ -7,3 +8,5 @@ src/webview/dist/*.hot-update.js*
out
/coverage/
/reports/
.less
*.vsix
......@@ -489,7 +489,7 @@
# v3.2.0 - 2020-08-03
- Publish GitLab Workflow extension to Open VSX Registry [#205](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/205)
- Publish CSDN Workflow extension to Open VSX Registry [#205](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/205)
### Fixed
......@@ -720,7 +720,7 @@
### Added
- GitLab Workflow now supports multiple instances.
- CSDN Workflow now supports multiple instances.
- Implemented by [@csvn](https://gitlab.com/csvn) with [MR !5](https://gitlab.com/fatihacet/gitlab-vscode-extension/merge_requests/5) 👍
- ESLint and Prettier integration for dev environment.
- Added by [@alpcanaydin](https://gitlab.com/alpcanaydin) with [MR !6](https://gitlab.com/fatihacet/gitlab-vscode-extension/merge_requests/6) 👍
......
......@@ -17,9 +17,9 @@ _This notice should stay as the first item in the CONTRIBUTING.md file._
---
# Contributing to GitLab Workflow
# Contributing to CSDN Workflow
Thank you for your interest in contributing to GitLab Workflow! This guide details how to contribute
Thank you for your interest in contributing to CSDN Workflow! This guide details how to contribute
to this extension in a way that is easy for everyone. These are mostly guidelines, not rules.
Use your best judgement, and feel free to propose changes to this document in a merge request.
......@@ -48,14 +48,14 @@ as available [here](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issu
For general information how to develop and debug VS Code Extensions, please see the [official documentation](https://code.visualstudio.com/api).
The following instructions will help you run the GitLab Workflow Extension locally.
The following instructions will help you run the CSDN Workflow Extension locally.
Please review our [Coding guidelines](docs/developer/coding-guidelines.md) before writing new code.
#### Step - 1 : Installation Prerequisites
We're assuming that you already have [Visual Studio Code](https://code.visualstudio.com/) installed along
with [GitLab Workflow](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow) installed
with [CSDN Workflow](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow) installed
and configured, if not, do that first! If already done, proceed ahead.
* [Git](https://git-scm.com/)
......@@ -124,8 +124,8 @@ npm run lint
### Opening Merge Requests
Steps to opening a merge request to contribute code to GitLab Workflow is similar to any other open source project.
Steps to opening a merge request to contribute code to CSDN Workflow is similar to any other open source project.
You develop in a separate branch of your own fork and the merge request should have a related issue open in the project.
Any Merge Request you wish to open in order to contribute to GitLab Workflow, be sure you have followed through the steps from [Configuring Development Environment](#configuring-development-environment).
Any Merge Request you wish to open in order to contribute to CSDN Workflow, be sure you have followed through the steps from [Configuring Development Environment](#configuring-development-environment).
In this project, we don't [close issues automatically when the MR gets merged](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically). Instead, we close the issues when the MR change is [released](docs/developer/release-process.md). Please replace `Closes #<issueId>` in the MR description with `Relates to #<issueId>`.
# <img src="https://gitlab.com/gitlab-org/gitlab-vscode-extension/raw/main/src/assets/logo.png" width="64" align="center" /> [GitLab VS Code Extension](https://gitlab.com/gitlab-org/gitlab-vscode-extension)
# <img src="https://img-home.csdnimg.cn/images/20201124032511.png" width="64" align="center" /> [CSDN 工作流](https://plugin.csdn.net)
[![Marketplace Version](https://vsmarketplacebadge.apphb.com/version/GitLab.gitlab-workflow.svg)](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow) [![Installs](https://vsmarketplacebadge.apphb.com/installs/GitLab.gitlab-workflow.svg)](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow) [![Downloads](https://vsmarketplacebadge.apphb.com/downloads/GitLab.gitlab-workflow.svg)](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow) [![Rating](https://vsmarketplacebadge.apphb.com/rating/GitLab.gitlab-workflow.svg)](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow)
[![Marketplace Version](https://vsmarketplacebadge.apphb.com/version/CSDN.csdn-workflow.svg)](https://marketplace.visualstudio.com/items?itemName=CSDN.csdn-workflow) [![Installs](https://vsmarketplacebadge.apphb.com/installs/CSDN.csdn-workflow.svg)](https://marketplace.visualstudio.com/items?itemName=CSDN.csdn-workflow) [![Downloads](https://vsmarketplacebadge.apphb.com/downloads/CSDN.csdn-workflow.svg)](https://marketplace.visualstudio.com/items?itemName=CSDN.csdn-workflow) [![Rating](https://vsmarketplacebadge.apphb.com/rating/CSDN.csdn-workflow.svg)](https://marketplace.visualstudio.com/items?itemName=CSDN.csdn-workflow)
This extension integrates GitLab to VS Code. It helps you:
CSDN 工作流,让你在 VS Code 中畅享 CSDN 的多种服务。当前版本中,主要支持的功能包括:
- View issues.
- Create and review merge requests.
- Validate your GitLab CI configuration.
- View the status of your pipeline.
- Create and paste snippets to, and from, your editor.
- 代码笔记
- CODE CHINA 代码托管
- 开发者实用工具
- 更多 CSDN 服务接入中……敬请期待
## Minimum supported version
## 插件功能
GitLab Workflow requires GitLab 13.4 or later. To find your GitLab version, visit `/help` (like `https://gitlab.com/help`).
_在使用插件的**代码笔记**、**代码托管**服务前,你需要提供你的 CSDN 账号密码,并在完成登录验证后方可使用这两个服务。_
## Features
### 查看 Issues 及 合并请求
_You need to set up your access token(s) to use these features, please see [Setup](#setup) section below._
在 VS Code 的侧边栏,你可以通过专用的面板来查看你的 Issues、合并请求(包括合并请求中更改的文件)信息。[了解详情](#sidebar---details)
### Browse issues, review MRs
### 当前分支信息
See your issues, MRs (including changed files) and other [custom search results](https://gitlab.com/gitlab-org/gitlab-vscode-extension/docs/user/custom-queries.md) on a dedicated panel in the VS Code sidebar. [Read more](#sidebar---details)
在 VS Code 的状态栏,你可以查看当前分支信息,包括流水线任务状态、合并请求以及关闭的 issue。[了解详情](#sidebar---details)
### Information about your branch - pipelines, MR, closing issue
流水线任务的状态会自动更新,因此你不需要访问 CSDN 代码托管平台(CODE CHINA)就可以查看你的流水线任务运行状态。
See pipeline status, open MR and closing issue links in the status bar. [Read more](#status-bar---details).
This pipeline status automatically updates so you don't need to open GitLab to see your pipeline status.
### 常用命令
Advanced pipeline actions allow you to view pipeline on GitLab, create a new pipeline, retry or cancel current pipeline. [Read more](#pipeline-actions).
你可以通过[命令面板](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette)来运行一下命令:
![_status_bar.gif](https://gitlab.com/gitlab-org/gitlab-vscode-extension/raw/main/src/assets/_status-bar.gif)
- `CSDN: 查看分配给我的 Issues`
- `CSDN: 查看分配给我的合并请求`
- `CSDN: 在 CODE CHINA 上打开当前文件`
- `CSDN: 复制当前文件的 CODE CHINA 链接`
- `CSDN: 查看当前的合并请求`
- `CSDN: 新建 Issue`
- `CSDN: 新建合并请求`
- `CSDN: 查看项目详情`
- `CSDN: 创建代码补丁`
- `CSDN: 查看当前流水线`
- `CSDN: 流水线操作`
- `CSDN: 查找 Issue`
- `CSDN: 查找合并请求`
- `CSDN: 项目高级搜索`
- `CSDN: 比较当前分支`
- `CSDN: 创建项目代码片`
- `CSDN: 插入项目代码片`
- `CSDN: 验证 CI 配置`
- `CSDN: 查看输出`
- `CSDN: 刷新侧边栏`,
### Commands
此外,我们还提供了一些开发者日常会经常使用的实用工具,包括:
You can use [Command Palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) to run the commands.
- `CSDN: 创建笔记`
- `CSDN: 新建代码笔记编辑区`
- `CSDN: json 格式化`
- `CSDN: 模拟 HTTP 请求`
- `CSDN: 执行 HTTP 请求`
- `GitLab: Search project issues (Supports filters)`. [Read more](#search-with-filters)
- `GitLab: Search project merge requests (Supports filters)`. [Read more](#search-with-filters)
- `GitLab: Project Advanced Search (Issues, MR's, commits, comments...)`. [Read more](#search-with-advanced-search)
- `GitLab: Create snippet` - Create public, internal or private snippet from entire file or selection. [Read more](#create-snippet).
- `GitLab: Insert snippet` - Insert a project snippet, supports multi-file snippets. [Read more](#insert-snippet).
- `GitLab: Compare current branch with master` - Compare your branch with master and view changes on GitLab. [Read more](#compare-with-master).
- `GitLab: Open active file on GitLab` - View active file on GitLab with highlighting active line number and selected text block. [Read more](#open-active-file).
- `GitLab: Validate GitLab CI config` - Validate GitLab CI configuration file `.gitlab-ci.yml`. [Read more](#validate-gitlab-ci-configuration).
- `GitLab: Open merge request for current branch`
- `GitLab: Show issues assigned to me` - Open issues assigned to you on GitLab.
- `GitLab: Show merge requests assigned to me` - Open MRs assigned to you on GitLab.
- `GitLab: Open current pipeline on GitLab`
- `GitLab: Open current project on GitLab`
- `GitLab: Create new issue on current project`
- `GitLab: Create new merge request on current project` - Open the merge request page to create a merge request.
当然,我们也支持与 Git 命令的集成,包括:
Commands this extension extends/integrates with:
- `Git: Clone` - 从 CODE CHINA 上 Clone 项目 [官方文档](https://code.visualstudio.com/docs/editor/versioncontrol#_cloning-a-repository)
- `Git: 添加远程存储库` - 在当前仓库中增加一个 Remote 源
- `Git: Clone` - Search for and clone projects for every GitLab instance you set up. [Read more](#git-extension-integration), [Official Documentation](https://code.visualstudio.com/docs/editor/versioncontrol#_cloning-a-repository)
- `Git: Add Remote...` - Add existing projects as remote from every GitLab instance you set up.
## 用户验证
### Other features
在开始使用 CSDN 工作流 的代码笔记、代码托管功能之前,我们需要检验你的身份信息,你可以:
Supports multiple GitLab instances [Read more](#multiple-gitlab-instances).
- 通过个人访问令牌完成身份信息校验
- 通过账号/密码完成身份信息校验(**推荐**
Published also on [Open VSX Registry](https://open-vsx.org/extension/GitLab/gitlab-workflow).
### 第一步:在 CSDN CODE CHINA 上创建你的个人访问令牌
You can use [autocompletion of GitLab CI variables](#ci-variable-autocompletion) in your `.gitlab-ci.yml` pipeline file. If you have additional pipeline files you would like to use autocomplete with, it matches on any file beginning with `.gitlab-ci` and ending with `.yml` or `.yaml`. For example: `.gitlab-ci.production.yml`.
- 访问 [CODE CHINA](https://codechina.csdn.net/) 并登录
- 点击右上角的头像,并跳转到 **设置** **访问令牌**
-**添加一个个人访问令牌**表单中:
- 填写令牌名称
- 设置令牌过期时间
- 勾选 `api` 以及 `read_user` 权限
- 单击 **创建个人访问令牌** 按钮
- 复制创建好的个人访问令牌
## Setup
> 注意:个人访问令牌创建好之后,出于安全原因考虑,你将无法再次查看你的个人访问令牌的内容,请妥善保存。
To use this extension, you need to create a GitLab Personal Access Token and give it to the extension.
### 第二步:将你的个人访问令牌添加到 CSDN 工作流 插件
### Step 1: Create your Personal Access Token
- 打开命令面板,快捷键为 `Cmd+Shift+P`
- 输入并搜索 `CSDN: 设置你的个人访问令牌` 并按下回车键确认
- 在弹出框中复制你在上一步中生成并复制好的个人访问令牌
- If you are using
- GitLab.com [click to open Personal Access Tokens page](https://gitlab.com/-/profile/personal_access_tokens).
- Self-managed GitLab instance go to **Settings** and select **Access Tokens** on the left navigation menu
- On **Add a personal access token** form:
- Give a name to your token.
- Select an expiry date.
- Select `api` and `read_user` permissions.
- Select **Create personal access token**.
- Copy the token. _Remember you won't be able to see the value of this token ever again for security reasons._
以上就是通过个人访问令牌进行身份验证的过程了,之后,你就可以开始使用 CSDN 工作流 中的全部功能了。
### Step 2: Add token to GitLab Workflow Extension
相比用户名/密码的方式来说,个人访问令牌的方式可能稍微复杂了一点点。
- Open up Command Palette by pressing `Cmd+Shift+P`.
- Search for "GitLab: Set GitLab Personal Access Token" and hit Enter.
- Enter the URL to the GitLab instance the PAT should apply to and hit Enter.
- Extension will ask for your PAT. Paste your PAT and hit Enter. _It won't be visible and accessible to others._
- If you want to connect to GitLab hosted on a custom domain, additionally set
`gitlab.instanceUrl` in your user or workspace settings, otherwise the extension
will try to connect to gitlab.com. See [Extension settings](#extension-settings) for more information.
### 用户名/密码方式完成身份信息验证
That's it. 🏁
- 打开命令面板,快捷键为 `Cmd+Shift+P`
- 输入并搜索 `CSDN: 用户名密码登录` 并按下回车键确认
- 依次在弹出框中输入你的 CSDN 用户名以及密码
- 等待插件完成身份信息验证
You can start using this extension right away. If your project has a pipeline for last commit and a MR from your current branch, you should see them on VS Code status bar. 🎉
> 说明:通过用户名/密码的方式完成身份信息验证后,插件将会自动在你的账号中创建一个个人访问令牌,并使用该访问令牌作为后续其他功能使用的 token。
### Multiple GitLab instances
## 详细功能介绍
If you want to use multiple GitLab instances you may want to configure each workspace separately. See the `gitlab.instanceUrl` configuration option in [Extension settings](#extension-settings) section.
### 在 VS Code 中查看 Issue 以及合并请求详情(包括评论内容)
## Extension settings
![Issue 详情](https://codechina.csdn.net/codechina/operation-work/uploads/a8a6613617a0ece4fc64335cf191643a/image.png)
To learn how to change the VS Code Settings, read the official [Settings documentation](https://code.visualstudio.com/docs/getstarted/settings).
你可以直接在 CSDN 工作流 中查看项目中的 Issue 详情。单击侧边栏中的 Issue 链接,VS Code 会在工作区打开一个新的编辑器标签页并显示 Issue 的详细内容,你也可以在 VS Code 中直接给 Issue 发起评论。
**`gitlab.instanceUrl`** _(required: false, default: "https://gitlab.com")_
#### Review 合并请求
If you are using GitLab on a custom domain, you must add this to your user settings file. Example: `"gitlab.instanceUrl": "https://my-gitlab-domain.com"`
你也可以直接通过编辑器在 CSDN 工作流 中完成合并请求的 Review 工作:
To enable GitLab Workflow extension to work with different GitLab instances, each token is assigned to a GitLab instance URL. For the extension to select the correct token for a specific workspace, the option [`gitlab.instanceUrl`](#extension-settings) can be used. This option can be set in the current workspace's `.vscode/settings.json` file.
![合并请求详情](https://codechina.csdn.net/codechina/operation-work/uploads/9c3d887e0cf2aa9ef6d361e164e021de/image.png)
**`gitlab.showStatusBarLinks`** _(required: false, default: true)_
1. 在 CSDN 工作流 的左侧区域,单击并展开 ** ISSUE与合并请求** 面板
1. 选择一个你想要查看的合并请求列表类型(支持分配给你的合并请求、你创建的合并请求以及你正在 Review 的合并请求)
1. 打开一个你想要查看的合并请求,并查看合并请求描述以及修改的文件
1. 选择并打开一个修改过的文件,并查看文件的 diff
If you don't want to see GitLab-related links on the status bar, you can set this option to `false`. If you are using version 1.0.0 or later, you can also find the same links in sidebar. You should restart VS Code after updating this option.
在查看文件 diff 的时候,你可以:
**`gitlab.showIssueLinkOnStatusBar`** _(required: false, default: true)_
- Review 修改并发起讨论
- 解决/未解决这些讨论
- 删除或编辑评论内容
If you are not using the GitLab issue tracker, you can set this option to `false` to remove related issue links on the status bar. You should restart VS Code after updating this option.
### 侧边栏
**`gitlab.showMrStatusOnStatusBar`** _(required: false, default: true)_
插件安装完成后,会在 VS Code 侧边栏增加一个 CSDN 工作流的面板。通过这个面板,你可以查看当前仓库项目中的 issues 以及合并请求信息,你也可以查看与当前分支相关的流水线任务、合并请求以及 issues 信息。
You can toggle visibility of the merge request link in your sidebar. You can always find a merge request link in GitLab Workflow sidebar. You should restart VS Code after updating this option.
- 你可以单击 issue 标题 查看 issue 的详细信息
- 你可以展开 合并请求的内容
- 单击 **Overview** 查看合并请求介绍
- 可以查看到修改文件的列表
- 单击某个修改的文件,会打开合并请求 diff
**`gitlab.remoteName`** _(required: false, default: null)_
### 流水线任务
The name of the Git remote link corresponding to the GitLab repository with your merge request and issues. If no setting is provided, the extension will detect it. For example: `origin`.
除了以上常用功能外,你还可以通过插件来查看并操作流水线任务。你可以直接从 VS Code 底部的状态栏或命里面板中来进行流水线任务的操作,包括:
**`gitlab.pipelineGitRemoteName`** _(required: false, default: null)_
- 在 CODE CHINA 上查看最新的流水线任务
- 从当前分支创建一个新的流水线任务
- 重试流水线任务
- 取消流水线任务
The name of the Git remote link corresponding to the GitLab repository with your pipelines. If no setting is provided, the extension will detect it. For example: `origin`.
![查看流水线任务](https://codechina.csdn.net/codechina/operation-work/uploads/f8fc192f1ddca3a118b7de39372bd60f/pipeline.png)
**`gitlab.customQueries`** _(required: false)_
### 状态栏
Defines the search queries that retrieves the items shown on the GitLab Panel. See [Custom Queries documentation](https://gitlab.com/gitlab-org/gitlab-vscode-extension/docs/user/custom-queries.md) for more details.
如果你用 VS Code 打开了一个托管在 CSDN CODE CHINA 上的项目,CSDN 工作流插件将会:
### Self-signed certificates
- 获取上一次提交的流水线任务状态,并在状态栏上显示,单击的话则会打开流水线任务操作命令面板
- 在状态栏上显示开放中的合并请求信息,单击的话则会在 CODE CHINA 中打开该合并请求
- 获取与该合并请求相关的 Issue 信息,单击的话则会在 CODE CHINA 中打开该 Issue
To use self-signed certificates to connect to your GitLab instance, configure them using the following settings. These are community contributed because the GitLab team uses a public CA.
### 创建代码笔记
These settings don't work with [`http.proxy` setting for VS Code](https://code.visualstudio.com/docs/setup/network#_legacy-proxy-server-support) (see [open issue](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/314)).
通过 CSDN 工作流,你可以很方便的在 VS Code 中将代码片段内容保存为一个代码笔记,你可以随时在 CSDN 工作流或是网页中查看该代码笔记,也可以直接分享给你的朋友们。
**`gitlab.ca`** _(required: false, default: null)_
![创建代码笔记](https://codechina.csdn.net/codechina/operation-work/uploads/b1afdb43f4c7d0abd64fd2bc3c19bd2e/image.png)
If your self-managed GitLab instance has a self-signed SSL certificate you would probably need to set this option in to point your certificate file. Implemented in [this issue](https://gitlab.com/gitlab-org/gitlab-vscode-extension/issues/26).
- 在编辑器中选择你要保存的代码片段
- 右键并选择 **创建代码笔记**
- 在弹出框中输入代码笔记的名称
- 选择代码笔记的类型,公开或者私密
**`gitlab.cert`** _(required: false, default: null)_
代码笔记创建成功后,你可以在 VS Code 中直接查看该代码笔记,也可以将该代码笔记直接分享给你的朋友,你也可以直接在 CSDN 网页中查看代码笔记。
If your self-managed GitLab instance requires a custom cert/key pair you would probably need to set this option in to point your certificate file. Please also see `gitlab.certKey` option. For more information, [read this comment](https://gitlab.com/gitlab-org/gitlab-vscode-extension/merge_requests/29#note_132284448).
![代码笔记详情](https://codechina.csdn.net/codechina/operation-work/uploads/b9b31743e3dcbc0a8cdc6a6a9b2be6aa/image.png)
**`gitlab.certKey`** _(required: false, default: null)_
### 实用工具
If your self-managed GitLab instance requires a custom cert/key pair you would probably need to set this option in to point your certificate key file. Please also see `gitlab.cert` option. For more information, [read this comment](https://gitlab.com/gitlab-org/gitlab-vscode-extension/merge_requests/29#note_132284448).
实用工具是专门为开发者提供的一些小助手,目前我们提供了 `JSON 格式美化`以及 `模拟HTTP请求` 两个功能模块,我们也欢迎大家来为 CSDN 工作流贡献更多的实用小功能。
**`gitlab.ignoreCertificateErrors`** _(required: false, default: false)_
#### JSON 格式化
If you are using a self-managed GitLab instance with no SSL certificate or having certificate issues and unable to use the extension you may want to set this option to `true` to ignore certificate errors. For more information, [read this comment](https://gitlab.com/gitlab-org/gitlab-vscode-extension/issues/26#note_61312786).
![JSON格式化](https://codechina.csdn.net/codechina/operation-work/uploads/01082672dea8c2470d30b920155ee69d/image.png)
## Features in-depth
使用 JSON 格式化功能,你只需要:
### Issue and Merge Request details and comments in VS Code
- 在 VS Code 编辑器中打开并选中你要格式化的 `JSON` 内容
- 打开 CSDN 工作流面板,单击并展开 **实用工具**
- 单击并展开 **JSON 格式化**
- 点击 **格式化选中的 json 内容**,即可完成 JSON 格式化
![Issues in Visual Studio Code](https://gitlab.com/gitlab-org/gitlab-vscode-extension/raw/main/src/assets/_issues-in-vscode.png)
通过简单几步,就可以在 VS Code 中直接完成 JSON 格式化,非常的方便。
GitLab Workflow allows you to view issue details and comments right in the VS Code. Click an issue link from the sidebar and VS Code will open a new tab to show the issue details. You can also comment on the issue from VS Code.
#### 模拟 HTTP 请求
You can use [GitLab Slash Commands](https://docs.gitlab.com/ee/integration/slash_commands.html) to perform actions directly from VS Code. For example, to assign an issue to `@fatihacet`, simply add a comment `/assign @fatihacet` inside VS Code.
![模拟HTTP请求](https://codechina.csdn.net/codechina/operation-work/uploads/d5895dc0eab4135e8758a31472d74bc1/image.png)
#### Merge Request Reviews
使用 HTTP 模拟请求功能,你需要:
GitLab Workflow enables you to review merge requests directly inside the editor:
- 打开 CSDN 工作流面板,单击并展开 **实用工具**
- 单击并展开 **模拟 HTTP 请求**
- 单击 **打开请求配置文件**,并在配置文件中配置好各种请求参数(_所有参数都应在`value`中设置_),包括:
- `http_method` - 请求方法,如`GET` `POST` `PUT` `DELETE`
- `header` - 请求 header 信息
- `body` - 请求 body 信息
- `url` - 请求地址
- `proxy` - 代理设置
- 在完成参数设置后,单击 **执行请求**
- 这时候会打开 VS Code 的输出控制台,并在控制台中打印返回结果
![Animated gif showing how to review a merge request](https://gitlab.com/gitlab-org/gitlab-vscode-extension/raw/main/src/assets/_diff-comments.gif)
## 社区贡献
1. In the left-hand sidebar, go to **Issues and Merge Requests**.
1. Select the appropriate merge request filter to view a list of merge requests.
1. Expand a relevant merge request to view the description and files changed.
1. Select a file to open it, and view the diff.
From the diff, you can:
- Review and create discussions.
- Resolve and unresolve these discussions.
- Delete and edit individual comments.
### Sidebar - details
Extension will add a GitLab Workflow panel to sidebar of VS Code. The dedicated panel will allow you to see the list of your issues and MRs (you can decide the exact queries by using the [custom queries](https://gitlab.com/gitlab-org/gitlab-vscode-extension/docs/user/custom-queries.md)). Also you will be able to see pipeline, MR and issue links for your current branch.
You can see the issue and MR details by clicking on the issue item or by expanding the MR item and clicking on "Description". When you expand the MR, you can see all the changed files. When you click on a changed file, the extension opens the MR diff.
![_sidebar.gif](https://gitlab.com/gitlab-org/gitlab-vscode-extension/raw/main/src/assets/_sidebar.gif)
### Pipeline actions
One of the real power features of this extension is pipeline actions. This feature can be accessible from the status bar by clicking the pipeline status text or command palette and allows you to,
- View the latest pipeline on GitLab
- Create a new pipeline for your current branch
- Retry the last pipeline
- Cancel the last pipeline
![_pipeline_actions.gif](https://gitlab.com/gitlab-org/gitlab-vscode-extension/raw/main/src/assets/_pipeline_actions.gif)
### Status bar - details
If your current project is a GitLab project, the extension will do the following things:
- Fetch pipeline of the last commit and show it on the status bar. Clicking this item will open the pipeline actions menu.
- Show open MR for current branch and show it on the status bar. Clicking this item will open MR on GitLab.
- Fetch closing issue of that MR and show it on the status bar. Clicking this item will open Issue on GitLab.
### Search
GitLab Workflow extension provides you two types of search. Search with filters and Advanced Search.
#### Search with filters
It allows users to search issues/MRs against their title and description fields. In the search input, you can type your search term and hit Enter, for example, `Inconsistent line endings for HEX files` or `Pipelines should ignore retried builds`.
It can become more powerful by allowing you to filter issues/MRs by author, assignee, milestone, title etc. Below is the full list of supported filter tokens
| Token | Description | Example |
| --------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| title | Search issues/MRs against their title and description. You don't need to add quotes around multiple words. See Important notes section. | discussions refactor |
| labels | Comma separated label list for multiple labels. | `labels: frontend, Discussion, performance` |
| label | To search with a single label. You can also have multiple `label` tokens. | `label: frontend` or `label:frontend label: Discussion` |
| milestone | Milestone title without `%`. | `milestone: 9.5` |
| scope | Searches issues/MRs for the given scope. Values can be `created-by-me`, `assigned-to-me` or `all`. Defaults to `created-by-me`. | `scope: created-by-me` or `scope: assigned-to-me` or `scope: all`. |
| author | Username of the author without `@`. | `author: fatihacet` |
| assignee | Username of the assignee without `@`. | `assignee: timzallmann` |
**Examples**
- `title: new merge request widget author: fatihacet assignee: jschatz1 labels: frontend, performance milestone: 10.5`
- `title: multiple group page author: annabeldunstone assignee: timzallmann label: frontend`
**Important notes**
- `:` after the token name is necessary. `label :` is not a valid token name and may return parsing error. Hence `label:` should be used. However, space after the token name is optional. Both `label: frontend` and `label:frontend` is valid. This rule is valid for all tokens above.
- You don't need to add quotes around multiple words for `title` token. `title:"new merge request widget"` may return parsing error. `title: new merge request widget` should be used.
- You can have `labels` and `label` tokens at the same time. `labels: fronted discussion label: performance` is a valid query and all labels will be included in your search query. It's equal with `labels: fronted discussion performance`. You can also have multiple `label` tokens. `label: frontend label: discussion label: performance` is valid and equals to `labels: fronted discussion performance`.
![Advanced search](https://gitlab.com/gitlab-org/gitlab-vscode-extension/raw/main/src/assets/_advanced-search.gif)
#### Search with Advanced Search
GitLab provides [Advanced Search feature which is backed by Elasticsearch](https://docs.gitlab.com/ee/integration/elasticsearch.html). Please see [Advanced Search syntax](https://docs.gitlab.com/ee/user/search/advanced_search_syntax.html) for more details.
### Create snippet
You can create a snippet from selection or entire file. You can also select visibility level of your snippet.
![_create-snippet.gif](https://gitlab.com/gitlab-org/gitlab-vscode-extension/raw/main/src/assets/_create-snippet.gif)
### Insert snippet
You can insert public and private project snippets. The insert supports [multi-file snippets](https://docs.gitlab.com/ee/user/snippets.html#multiple-files-by-snippet).
![insert-multi-file-snippet](https://gitlab.com/gitlab-org/gitlab-vscode-extension/raw/main/src/assets/insert-multi-file-snippet.gif)
### Compare with master
You can see changes in your branch by comparing with `master` and see them on GitLab.
![_compare-with-master.gif](https://gitlab.com/gitlab-org/gitlab-vscode-extension/raw/main/src/assets/_compare-with-master.gif)
> Soon, the extension will support comparing your current branch with other branches.
### Open active file
This command allows you to see active file on GitLab. Extension sends active line number and selected text block to GitLab UI so you can see them highlighted.
![_open_active_file.gif](https://gitlab.com/gitlab-org/gitlab-vscode-extension/raw/main/src/assets/_open_active_file.gif)
### Validate GitLab CI Configuration
Using this command, you can quickly validate GitLab CI configuration.
![Validate CI configuration](https://gitlab.com/gitlab-org/gitlab-vscode-extension/raw/main/src/assets/_validate-ci-config.gif)
### CI variable autocompletion
Quickly find the CI variable you are looking for with the CI variable autocompletion.
![screenshot of the CI variable autocompletion](https://gitlab.com/gitlab-org/gitlab-vscode-extension/raw/main/src/assets/_ci_variable_autocomplete.png)
### Clone GitLab projects
This extension integrates with the built-in Git Extension and allows you to search for and clone projects from GitLab (command `Git: Clone`).
- You can search for projects on each GitLab instance for which you [added an access-token](#step-2-add-token-to-gitlab-workflow-extension).
- Only projects where you are a **member of** are displayed.
- You can clone with SSH or HTTPS
- With HTTPS your access-token will be used for cloning the repository and fetching/pushing commits. This is also the case for all GitLab projects that are cloned manually with HTTPS and then opened in VS Code.
![Demonstration of cloning a project from gitlab.com](https://gitlab.com/gitlab-org/gitlab-vscode-extension/raw/main/src/assets/_git-clone.gif)
> Note: Using the access-token for cloning with HTTPS does not work with VS Code version 1.53.x (See [discussion](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/merge_requests/172#note_513068345))
---
## Contribution
This extension is open source and [hosted on GitLab](https://gitlab.com/gitlab-org/gitlab-vscode-extension). Contributions are more than welcome. Feel free to fork and add new features or submit bug reports.
[A list of the great people](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/blob/main/CONTRIBUTORS.md) who contributed this project, and made it even more awesome, is available. Thank you all! 🎉
CSDN 工作流插件是一个开源的项目,你可以在[CODE CHINA]()上查看这个插件的源代码,如果你有任何问题或者是想向我们提交新的功能,我们将非常欢迎。🎉🎉🎉
\ No newline at end of file
{
"name": "gitlab-workflow",
"version": "3.25.0",
"name": "csdn-workflow",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
......@@ -1229,6 +1229,12 @@
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
"dev": true
},
"@types/marked": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@types/marked/-/marked-2.0.4.tgz",
"integrity": "sha512-L9VRSe0Id8xbPL99mUo/4aKgD7ZoRwFZqUQScNKHi2pFjF9ZYSMNShUHD6VlMT6J/prQq0T1mxuU25m3R7dFzg==",
"dev": true
},
"@types/minimist": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.1.tgz",
......@@ -2331,8 +2337,7 @@
"boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
"dev": true
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
},
"brace-expansion": {
"version": "1.1.11",
......@@ -2567,13 +2572,12 @@
"dev": true
},
"cheerio": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.9.tgz",
"integrity": "sha512-QF6XVdrLONO6DXRF5iaolY+odmhj2CLj+xzNod7INPWMi/x9X4SOylH0S/vaPpX+AUU6t04s34SQNh7DbkuCng==",
"dev": true,
"version": "1.0.0-rc.10",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz",
"integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==",
"requires": {
"cheerio-select": "^1.4.0",
"dom-serializer": "^1.3.1",
"cheerio-select": "^1.5.0",
"dom-serializer": "^1.3.2",
"domhandler": "^4.2.0",
"htmlparser2": "^6.1.0",
"parse5": "^6.0.1",
......@@ -2582,24 +2586,22 @@
},
"dependencies": {
"tslib": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
"integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==",
"dev": true
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
}
}
},
"cheerio-select": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.4.0.tgz",
"integrity": "sha512-sobR3Yqz27L553Qa7cK6rtJlMDbiKPdNywtR95Sj/YgfpLfy0u6CGJuaBKe5YE/vTc23SCRKxWSdlon/w6I/Ew==",
"dev": true,
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz",
"integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==",
"requires": {
"css-select": "^4.1.2",
"css-what": "^5.0.0",
"css-select": "^4.1.3",
"css-what": "^5.0.1",
"domelementtype": "^2.2.0",
"domhandler": "^4.2.0",
"domutils": "^2.6.0"
"domutils": "^2.7.0"
}
},
"chokidar": {
......@@ -3101,10 +3103,9 @@
"dev": true
},
"css-select": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.2.tgz",
"integrity": "sha512-nu5ye2Hg/4ISq4XqdLY2bEatAcLIdt3OYGFc9Tm9n7VSlFBcfRv0gBNksHRgSdUDQGtN3XrZ94ztW+NfzkFSUw==",
"dev": true,
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz",
"integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==",
"requires": {
"boolbase": "^1.0.0",
"css-what": "^5.0.0",
......@@ -3116,8 +3117,7 @@
"css-what": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz",
"integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==",
"dev": true
"integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg=="
},
"cssom": {
"version": "0.4.4",
......@@ -3358,21 +3358,19 @@
}
},
"dom-serializer": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.1.tgz",
"integrity": "sha512-Pv2ZluG5ife96udGgEDovOOOA5UELkltfJpnIExPrAk1LTvecolUGn6lIaoLh86d83GiB86CjzciMd9BuRB71Q==",
"dev": true,
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz",
"integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==",
"requires": {
"domelementtype": "^2.0.1",
"domhandler": "^4.0.0",
"domhandler": "^4.2.0",
"entities": "^2.0.0"
}
},
"domelementtype": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
"integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==",
"dev": true
"integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A=="
},
"domexception": {
"version": "2.0.1",
......@@ -3395,16 +3393,14 @@
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz",
"integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==",
"dev": true,
"requires": {
"domelementtype": "^2.2.0"
}
},
"domutils": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.6.0.tgz",
"integrity": "sha512-y0BezHuy4MDYxh6OvolXYsH+1EMGmFbwv5FKW7ovwMG6zTPWqNPq3WF9ayZssFq+UlKdffGLbOEaghNdaOm1WA==",
"dev": true,
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz",
"integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==",
"requires": {
"dom-serializer": "^1.0.1",
"domelementtype": "^2.2.0",
......@@ -3485,8 +3481,7 @@
"entities": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
"dev": true
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="
},
"error-ex": {
"version": "1.3.2",
......@@ -5289,6 +5284,11 @@
"integrity": "sha512-xAxZkM1dRyGV2Ou5bzMxBPNLoRCjcX+ya7KSWybQD2KwLphxsapUVK6x/02o7f4VU6GPSXch9vNY2+gkU8tYWQ==",
"dev": true
},
"highlight.js": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.2.0.tgz",
"integrity": "sha512-JOySjtOEcyG8s4MLR2MNbLUyaXqUunmSnL2kdV/KuGJOmHZuAR5xC54Ko7goAXBWNhf09Vy3B+U7vR62UZ/0iw=="
},
"hosted-git-info": {
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz",
......@@ -5334,7 +5334,6 @@
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
"integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==",
"dev": true,
"requires": {
"domelementtype": "^2.0.1",
"domhandler": "^4.0.0",
......@@ -6577,7 +6576,8 @@
},
"hosted-git-info": {
"version": "2.8.8",
"resolved": "",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
"dev": true
},
"normalize-package-data": {
......@@ -7485,6 +7485,11 @@
}
}
},
"marked": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/marked/-/marked-2.1.3.tgz",
"integrity": "sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA=="
},
"md5": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
......@@ -7531,7 +7536,8 @@
"dependencies": {
"hosted-git-info": {
"version": "2.8.8",
"resolved": "",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
"dev": true
},
"read-pkg": {
......@@ -8284,7 +8290,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz",
"integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==",
"dev": true,
"requires": {
"boolbase": "^1.0.0"
}
......@@ -8800,14 +8805,12 @@
"parse5": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
"dev": true
"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
},
"parse5-htmlparser2-tree-adapter": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz",
"integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==",
"dev": true,
"requires": {
"parse5": "^6.0.1"
}
......@@ -10999,6 +11002,11 @@
}
}
},
"timeago.js": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/timeago.js/-/timeago.js-4.0.2.tgz",
"integrity": "sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w=="
},
"tmp": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz",
......
{
"name": "gitlab-workflow",
"displayName": "GitLab Workflow",
"description": "GitLab VSCode integration",
"version": "3.25.0",
"publisher": "GitLab",
"name": "csdn-workflow",
"displayName": "CSDN 工作流",
"description": "CSDN CodeChina VSCode integration",
"version": "1.0.0",
"publisher": "CSDN",
"email": "code@csdn.net",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://gitlab.com/gitlab-org/gitlab-vscode-extension"
"url": "https://codechina.csdn.net/codechina_dev/csdn-workflow.git"
},
"engines": {
"vscode": "^1.52.0"
......@@ -17,23 +18,23 @@
],
"keywords": [
"git",
"gitlab",
"csdn",
"merge request",
"pipeline",
"ci cd"
"snippet",
"codechina"
],
"capabilities": {
"virtualWorkspaces": {
"supported": false,
"description": "GitLab Workflow doesn't support remote GitLab workspaces yet, please see https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/411 for more information."
"description": "CSDN Workflow doesn't support remote GitLab workspaces yet, please see https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/411 for more information."
}
},
"activationEvents": [
"*"
],
"bugs": {
"url": "https://gitlab.com/gitlab-org/gitlab-vscode-extension/issues",
"email": "incoming+gitlab-org-gitlab-vscode-extension-5261717-issue-@incoming.gitlab.com"
"url": "https://codechina.csdn.net/codechina_dev/csdn-workflow/-/issues",
"email": "lish@csdn.net"
},
"galleryBanner": {
"color": "#805DE7",
......@@ -44,313 +45,389 @@
"contributes": {
"commands": [
{
"command": "gl.setToken",
"title": "GitLab: Set GitLab Personal Access Token"
"command": "csdn.setToken",
"title": "CSDN: 设置你的个人访问令牌"
},
{
"command": "gl.removeToken",
"title": "GitLab: Remove your GitLab Personal Access Token"
"command": "csdn.openWebview",
"title": "CSDN: 访问代码片"
},
{
"command": "gl.showIssuesAssignedToMe",
"title": "GitLab: Show issues assigned to me"
"command": "csdn.jsonFormat",
"title": "CSDN: json 格式化"
},
{
"command": "gl.showMergeRequestsAssignedToMe",
"title": "GitLab: Show merge requests assigned to me"
"command": "csdn.httpRequest",
"title": "CSDN: 模拟 HTTP 请求"
},
{
"command": "gl.openActiveFile",
"title": "GitLab: Open active file on GitLab"
"command": "csdn.doHttpRequest",
"title": "CSDN: 执行 HTTP 请求"
},
{
"command": "gl.copyLinkToActiveFile",
"title": "GitLab: Copy link to active file on GitLab"
"command": "csdn.removeToken",
"title": "CSDN: 移除你的个人访问令牌"
},
{
"command": "gl.openCurrentMergeRequest",
"title": "GitLab: Open merge request for current branch"
"command": "csdn.showIssuesAssignedToMe",
"title": "CSDN: 查看分配给我的 Issues"
},
{
"command": "gl.openCreateNewIssue",
"title": "GitLab: Create new issue on current project"
"command": "csdn.showMergeRequestsAssignedToMe",
"title": "CSDN: 查看分配给我的合并请求"
},
{
"command": "gl.openCreateNewMR",
"title": "GitLab: Create new merge request on current project"
"command": "csdn.openActiveFile",
"title": "CSDN: 在 CODE CHINA 上打开当前文件"
},
{
"command": "gl.openProjectPage",
"title": "GitLab: Open current project on GitLab"
"command": "csdn.copyLinkToActiveFile",
"title": "CSDN: 复制当前文件的 CODE CHINA 链接"
},
{
"command": "gl.createSnippetPatch",
"title": "GitLab: Create snippet patch"
"command": "csdn.openCurrentMergeRequest",
"title": "CSDN: 查看当前的合并请求"
},
{
"command": "gl.openCurrentPipeline",
"title": "GitLab: Open current pipeline on GitLab"
"command": "csdn.openCreateNewIssue",
"title": "CSDN: 新建 Issue"
},
{
"command": "gl.pipelineActions",
"title": "GitLab: Pipeline actions - View, Create, Retry or Cancel"
"command": "csdn.openCreateNewMR",
"title": "CSDN: 新建合并请求"
},
{
"command": "gl.issueSearch",
"title": "GitLab: Search project issues (Supports filters)"
"command": "csdn.openProjectPage",
"title": "CSDN: 查看项目详情"
},
{
"command": "gl.mergeRequestSearch",
"title": "GitLab: Search project merge requests (Supports filters)"
"command": "csdn.createSnippetPatch",
"title": "CSDN: 创建代码补丁"
},
{
"command": "gl.projectAdvancedSearch",
"title": "GitLab: Project Advanced Search (Issues, MR's, commits, comments...)"
"command": "csdn.openCurrentPipeline",
"title": "CSDN: 查看当前流水线"
},
{
"command": "gl.compareCurrentBranch",
"title": "GitLab: Compare current branch with master"
"command": "csdn.pipelineActions",
"title": "CSDN: 流水线操作"
},
{
"command": "gl.createSnippet",
"title": "GitLab: Create snippet"
"command": "csdn.issueSearch",
"title": "CSDN: 查找 Issue"
},
{
"command": "gl.insertSnippet",
"title": "GitLab: Insert snippet"
"command": "csdn.mergeRequestSearch",
"title": "CSDN: 查找合并请求"
},
{
"command": "gl.validateCIConfig",
"title": "GitLab: Validate GitLab CI config"
"command": "csdn.projectAdvancedSearch",
"title": "CSDN: 项目高级搜索"
},
{
"command": "gl.showOutput",
"title": "GitLab: Show extension logs"
"command": "csdn.compareCurrentBranch",
"title": "CSDN: 比较当前分支"
},
{
"command": "gl.refreshSidebar",
"title": "GitLab: Refresh sidebar",
"command": "csdn.createSnippet",
"title": "CSDN: 创建项目代码片"
},
{
"command": "csdn.insertSnippet",
"title": "CSDN: 插入项目代码片"
},
{
"command": "csdn.createNote",
"title": "CSDN: 创建笔记"
},
{
"command": "csdn.openNoteDocument",
"title": "CSDN: 新建代码笔记编辑区"
},
{
"command": "csdn.validateCIConfig",
"title": "CSDN: 验证 CI 配置"
},
{
"command": "csdn.showOutput",
"title": "CSDN: 查看输出"
},
{
"command": "csdn.refreshSidebar",
"title": "CSDN: 刷新侧边栏",
"icon": {
"light": "src/assets/images/light/refresh.svg",
"dark": "src/assets/images/dark/refresh.svg"
}
},
{
"command": "gl.resolveThread",
"command": "csdn.resolveThread",
"title": "Resolve thread",
"category": "GitLab",
"icon": "$(pass)"
},
{
"command": "gl.unresolveThread",
"command": "csdn.unresolveThread",
"title": "Unresolve thread",
"category": "GitLab",
"icon": "$(pass-filled)"
},
{
"command": "gl.deleteComment",
"title": "Delete comment",
"command": "csdn.deleteComment",
"title": "删除评论",
"category": "GitLab",
"icon": "$(trash)"
},
{
"command": "gl.startEditingComment",
"title": "Edit Comment",
"command": "csdn.startEditingComment",
"title": "开始编辑评论",
"category": "GitLab",
"icon": "$(edit)"
},
{
"command": "gl.cancelEditingComment",
"title": "Cancel",
"command": "csdn.cancelEditingComment",
"title": "取消编辑",
"category": "GitLab"
},
{
"command": "gl.submitCommentEdit",
"title": "Save comment",
"command": "csdn.submitCommentEdit",
"title": "提交评论修改",
"category": "GitLab"
},
{
"command": "gl.createComment",
"title": "Add comment now",
"command": "csdn.createComment",
"title": "提交评论",
"category": "GitLab"
},
{
"command": "gl.checkoutMrBranch",
"title": "Checkout MR branch"
"command": "csdn.checkoutMrBranch",
"title": "检出主分支"
},
{
"command": "gl.cloneWiki",
"title": "Clone Wiki",
"command": "csdn.cloneWiki",
"title": "克隆 wiki",
"category": "GitLab"
},
{
"command": "csdn.openSnippet",
"title": "打开代码片"
},
{
"command": "csdn.openProjectSnippet",
"title": "打开项目代码片"
},
{
"command": "csdn.utilities",
"title": "实用工具"
}
],
"keybindings": [
{
"command": "csdn.createNote",
"key": "shift+alt+j",
"mac": "shift+alt+j"
},
{
"command": "csdn.jsonFormat",
"key": "shift+alt+d",
"mac": "shift+alt+d"
},
{
"command": "csdn.doHttpRequest",
"key": "shift+alt+r",
"mac": "shift+alt+r"
},
{
"command": "csdn.openActiveFile",
"key": "shift+alt+o",
"mac": "shift+alt+o"
}
],
"menus": {
"editor/context": [
{
"command": "csdn.createNote",
"group": "inline@1"
}
],
"commandPalette": [
{
"command": "gl.resolveThread",
"when": "false"
"command": "csdn.resolveThread",
"when": "true"
},
{
"command": "gl.unresolveThread",
"when": "false"
"command": "csdn.unresolveThread",
"when": "true"
},
{
"command": "gl.deleteComment",
"when": "false"
"command": "csdn.deleteComment",
"when": "true"
},
{
"command": "gl.startEditingComment",
"when": "false"
"command": "csdn.startEditingComment",
"when": "true"
},
{
"command": "gl.cancelEditingComment",
"when": "false"
"command": "csdn.cancelEditingComment",
"when": "true"
},
{
"command": "gl.submitCommentEdit",
"when": "false"
"command": "csdn.submitCommentEdit",
"when": "true"
},
{
"command": "gl.createComment",
"when": "false"
"command": "csdn.createComment",
"when": "true"
},
{
"command": "gl.checkoutMrBranch",
"when": "false"
"command": "csdn.checkoutMrBranch",
"when": "true"
},
{
"command": "gl.showIssuesAssignedToMe",
"command": "csdn.showIssuesAssignedToMe",
"when": "gitlab:validState"
},
{
"command": "gl.showMergeRequestsAssignedToMe",
"command": "csdn.showMergeRequestsAssignedToMe",
"when": "gitlab:validState"
},
{
"command": "gl.openActiveFile",
"command": "csdn.openActiveFile",
"when": "gitlab:validState && editorIsOpen"
},
{
"command": "gl.copyLinkToActiveFile",
"command": "csdn.copyLinkToActiveFile",
"when": "gitlab:validState && editorIsOpen"
},
{
"command": "gl.openCurrentMergeRequest",
"command": "csdn.openCurrentMergeRequest",
"when": "gitlab:validState"
},
{
"command": "gl.openCreateNewIssue",
"command": "csdn.openCreateNewIssue",
"when": "gitlab:validState"
},
{
"command": "gl.openCreateNewMR",
"command": "csdn.openCreateNewMR",
"when": "gitlab:validState"
},
{
"command": "gl.openProjectPage",
"command": "csdn.openProjectPage",
"when": "gitlab:validState"
},
{
"command": "gl.openCurrentPipeline",
"command": "csdn.openCurrentPipeline",
"when": "gitlab:validState"
},
{
"command": "gl.pipelineActions",
"command": "csdn.pipelineActions",
"when": "gitlab:validState"
},
{
"command": "gl.issueSearch",
"command": "csdn.issueSearch",
"when": "gitlab:validState"
},
{
"command": "gl.mergeRequestSearch",
"command": "csdn.mergeRequestSearch",
"when": "gitlab:validState"
},
{
"command": "gl.projectAdvancedSearch",
"command": "csdn.projectAdvancedSearch",
"when": "gitlab:validState"
},
{
"command": "gl.compareCurrentBranch",
"command": "csdn.compareCurrentBranch",
"when": "gitlab:validState"
},
{
"command": "gl.createSnippet",
"command": "csdn.createSnippet",
"when": "gitlab:validState && editorIsOpen"
},
{
"command": "gl.insertSnippet",
"command": "csdn.insertSnippet",
"when": "gitlab:validState && editorIsOpen"
},
{
"command": "gl.validateCIConfig",
"command": "csdn.validateCIConfig",
"when": "gitlab:validState && editorIsOpen"
},
{
"command": "gl.refreshSidebar",
"command": "csdn.refreshSidebar",
"when": "gitlab:validState"
},
{
"command": "gl.cloneWiki",
"command": "csdn.cloneWiki",
"when": "!gitlab:noToken"
},
{
"command": "gl.createSnippetPatch",
"command": "csdn.createSnippetPatch",
"when": "gitlab:validState"
},
{
"command": "csdn.openSnippet",
"when": "gitlab:validState"
},
{
"command": "csdn.openProjectSnippet",
"when": "gitlab:validState"
},
{
"command": "csdn.utilities",
"when": "gitlab:validState"
}
],
"view/title": [
{
"command": "gl.refreshSidebar",
"when": "view =~ /(currentBranchInfo|issuesAndMrs)/",
"command": "csdn.refreshSidebar",
"when": "view =~ /(currentBranchInfo|issuesAndMrs|snippetNotes|utilityTools)/",
"group": "navigation"
}
],
"view/item/context": [
{
"command": "gl.checkoutMrBranch",
"command": "csdn.checkoutMrBranch",
"when": "view =~ /issuesAndMrs/ && viewItem == mr-item-from-same-project"
}
],
"comments/comment/title": [
{
"command": "gl.startEditingComment",
"command": "csdn.startEditingComment",
"group": "inline@1",
"when": "commentController =~ /^gitlab-mr-/ && comment =~ /canAdmin/"
},
{
"command": "gl.deleteComment",
"command": "csdn.deleteComment",
"group": "inline@2",
"when": "commentController =~ /^gitlab-mr-/ && comment =~ /canAdmin/"
}
],
"comments/comment/context": [
{
"command": "gl.submitCommentEdit",
"command": "csdn.submitCommentEdit",
"group": "inline@1",
"when": "commentController =~ /^gitlab-mr-/"
},
{
"command": "gl.cancelEditingComment",
"command": "csdn.cancelEditingComment",
"group": "inline@2",
"when": "commentController =~ /^gitlab-mr-/"
}
],
"comments/commentThread/title": [
{
"command": "gl.resolveThread",
"command": "csdn.resolveThread",
"group": "inline@1",
"when": "commentController =~ /^gitlab-mr-/ && commentThread == unresolved"
},
{
"command": "gl.unresolveThread",
"command": "csdn.unresolveThread",
"group": "inline@2",
"when": "commentController =~ /^gitlab-mr-/ && commentThread == resolved"
}
],
"comments/commentThread/context": [
{
"command": "gl.createComment",
"command": "csdn.createComment",
"group": "inline",
"when": "commentController =~ /^gitlab-mr-/"
}
......@@ -360,103 +437,123 @@
"activitybar": [
{
"id": "gitlab-workflow",
"title": "GitLab Workflow",
"icon": "src/assets/images/light/gitlab-logo.svg"
"title": "CSDN 工作流",
"icon": "src/assets/images/light/c.svg"
}
]
},
"views": {
"gitlab-workflow": [
{
"id": "noticeLogin",
"name": "未登录",
"when": "gitlab:noTokens"
},
{
"id": "issuesAndMrs",
"name": "Issues and Merge Requests"
"name": "Issue 与合并请求",
"when": "gitlab:validState"
},
{
"id": "currentBranchInfo",
"name": "For current branch",
"name": "当前分支信息",
"when": "gitlab:validState"
},
{
"id": "snippetNotes",
"name": "代码笔记",
"when": "gitlab:hasAnyToken"
},
{
"id": "utilityTools",
"name": "实用工具"
}
]
},
"viewsWelcome": [
{
"view": "issuesAndMrs",
"contents": "Welcome to the GitLab Workflow extension!\nThis extension needs an access token with the 'api' and 'read_user' scopes.\n- GitLab.com users: [create a token on GitLab.com](https://gitlab.com/-/profile/personal_access_tokens).\n- Users on self-managed instances: in GitLab, click your avatar in the top right corner and select 'Preferences.' In the left sidebar, select 'Access Tokens,' then select 'Add a personal access token.'\nAfter you create a token, select 'Set Personal Access Token':\n[Set Personal Access Token](command:gl.setToken)\nTo learn more, read [the setup information](https://gitlab.com/gitlab-org/gitlab-vscode-extension#setup) for this extension.",
"when": "gitlab:noToken"
"view": "noticeLogin",
"contents": "欢迎使用 CSDN workflow 插件!\n本插件的代码管理、ISSUE、MR、CI/CD 等核心功能需要设置一个具备 'api' 和 'read_user' 权限的访问令牌。\n您可以在 codechina.csdn.net 上[创建访问令牌](https://codechina.csdn.net/-/profile/personal_access_tokens),然后复制生成的令牌点击:\n[设置用户访问令牌](command:csdn.setToken)\n如遇到问题,您可以点击 [这里](https://codechina.csdn.net/CoCo_Code_Op2/csdn-workflow/-/issues/new) 进行反馈。",
"when": "gitlab:noTokens"
},
{
"view": "issuesAndMrs",
"contents": "No Git repository available. To learn how to fix this, check the Source Control tab.\n[Open Source Control](command:workbench.view.scm)",
"contents": "没有可用的 Git 仓库. 点击版本关系标签了解如何解决此问题.\n[打开版本管理](command:workbench.view.scm)",
"when": "gitlab:noRepository"
},
{
"view": "issuesAndMrs",
"contents": "您的代码仓库尚未托管到 CSDN,所以暂时无法使用仓库相关功能.\n点击 [这里](https://codechina.csdn.net/projects/new) 在 CSDN 创建项目,按照引导将代码托管到 CSDN,即可畅快享受丰富的插件服务",
"when": "gitlab:noInstanceRemote"
}
],
"configuration": {
"title": "GitLab Workflow (GitLab VSCode Extension)",
"title": "CSDN Workflow (CSDN VSCode Extension)",
"properties": {
"gitlab.instanceUrl": {
"type": [
"string",
"null"
],
"default": null,
"description": "Your GitLab instance URL (default is https://gitlab.com)"
"default": "https://codechina.csdn.net",
"description": "Your CSDN workflow instance URL (default is https://codechina.csdn.net)"
},
"gitlab.showStatusBarLinks": {
"csdn.showStatusBarLinks": {
"type": "boolean",
"default": true,
"description": "Whether to display all GitLab related link in the status bar (Requires restart of VSCode)"
},
"gitlab.showIssueLinkOnStatusBar": {
"csdn.showIssueLinkOnStatusBar": {
"type": "boolean",
"default": true,
"description": "Whether to display the GitLab issue link in the status bar"
},
"gitlab.showMrStatusOnStatusBar": {
"csdn.showMrStatusOnStatusBar": {
"type": "boolean",
"default": true,
"description": "Whether to display the GitLab Merge Request status in the status bar"
},
"gitlab.ca": {
"csdn.ca": {
"type": "string",
"default": null,
"description": "Custom CA file to use (example: /etc/ssl/certs/ca-certificates.crt)"
},
"gitlab.cert": {
"csdn.cert": {
"type": "string",
"default": null,
"description": "Custom Certificate file to use (example: /etc/ssl/certs/certificate.crt)"
},
"gitlab.certKey": {
"csdn.certKey": {
"type": "string",
"default": null,
"description": "Custom Certificate Key file to use (example: /etc/ssl/certs/certificateKey.key)"
},
"gitlab.ignoreCertificateErrors": {
"csdn.ignoreCertificateErrors": {
"type": "boolean",
"default": false,
"description": "Ignore TLS/SSL certificate errors when calling the GitLab API"
},
"gitlab.remoteName": {
"csdn.remoteName": {
"type": "string",
"default": null,
"description": "Name of the git remote to use in order to locate the Gitlab project"
},
"gitlab.pipelineGitRemoteName": {
"csdn.pipelineGitRemoteName": {
"type": "string",
"default": null,
"description": "Name of the git remote to use in order to locate the Gitlab project for your pipeline. Keep empty for default"
},
"gitlab.showPipelineUpdateNotifications": {
"csdn.showPipelineUpdateNotifications": {
"type": "boolean",
"default": false,
"description": "Show notification in VSCode when pipeline status changed"
},
"gitlab.showProjectMergeRequests": {
"csdn.showProjectMergeRequests": {
"type": "boolean",
"default": true,
"description": "Enable the \"All Project Merge Requests\" sidebar pane"
},
"gitlab.customQueries": {
"csdn.customQueries": {
"type": "array",
"minItems": 1,
"items": {
......@@ -698,46 +795,108 @@
},
"default": [
{
"name": "Issues assigned to me",
"name": "分配给我的 issues",
"type": "issues",
"scope": "assigned_to_me",
"state": "opened",
"noItemText": "There is no issue assigned to you."
"noItemText": "没有分配给我的 issue"
},
{
"name": "Issues created by me",
"name": "我创建的 issues",
"type": "issues",
"scope": "created_by_me",
"state": "opened",
"noItemText": "There is no issue created by you."
"noItemText": "没有我创建的 issue"
},
{
"name": "Merge requests assigned to me",
"name": "分配给我的合并请求",
"type": "merge_requests",
"scope": "assigned_to_me",
"state": "opened",
"noItemText": "There is no MR assigned to you."
"noItemText": "没有分配给我的合并请求"
},
{
"name": "Merge requests I'm reviewing",
"name": "我正在审核的合并请求",
"type": "merge_requests",
"reviewer": "<current_user>",
"state": "opened",
"noItemText": "There is no MR for you to review."
"noItemText": "没有需要我审核的合并请求"
},
{
"name": "Merge requests created by me",
"name": "我创建的合并请求",
"type": "merge_requests",
"scope": "created_by_me",
"state": "opened",
"noItemText": "There is no MR created by you."
"noItemText": "没有我创建的合并请求"
},
{
"name": "All project merge requests",
"name": "所有合并请求",
"type": "merge_requests",
"scope": "all",
"state": "opened",
"noItemText": "The project has no merge requests"
"noItemText": "没有合并请求"
}
],
"description": "Custom views in the GitLab panel"
},
"csdn.utilities": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"title": "Custom GitLab Utility Tools",
"required": [
"name"
]
},
"default": [
{
"name": "JSON 格式化",
"type": "json_format"
},
{
"name": "模拟 HTTP 请求",
"type": "execute_request"
}
],
"description": "Custom views in the CSDN panel"
},
"csdn.executeRequestChildren": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"title": "Custom GitLab Utility Tools Children Item",
"required": [
"name"
]
},
"default": [
{
"name": "打开请求配置文件",
"type": "config_file"
},
{
"name": "执行请求",
"type": "execute_this_request"
}
],
"description": "Custom views in the GitLab panel"
},
"csdn.executeJsonChildren": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"title": "Custom GitLab Utility Tools Children Item",
"required": [
"name"
]
},
"default": [
{
"name": "格式化选中的 json 内容",
"type": "json_format"
}
],
"description": "Custom views in the GitLab panel"
......@@ -766,6 +925,7 @@
},
"devDependencies": {
"@types/jest": "^26.0.20",
"@types/marked": "^2.0.4",
"@types/node": "^13.13.45",
"@types/request-promise": "^4.1.47",
"@types/semver": "^7.3.6",
......@@ -795,14 +955,18 @@
"vscode-test": "^1.5.1"
},
"dependencies": {
"cheerio": "^1.0.0-rc.10",
"cross-fetch": "^3.0.6",
"dayjs": "^1.10.4",
"graphql": "^15.5.0",
"graphql-request": "^3.4.0",
"highlight.js": "^11.2.0",
"https-proxy-agent": "^5.0.0",
"marked": "^2.1.3",
"request": "^2.88.0",
"request-promise": "^4.2.6",
"semver": "^7.3.5",
"timeago.js": "^4.0.2",
"url": "^0.11.0"
}
}
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="5.089 0.358 500 500" xmlns="http://www.w3.org/2000/svg">
<path class="cls-1" d="M 429.4 366.69 C 424.876 362.417 418.875 360.063 412.654 360.114 C 406.642 360.158 400.938 362.774 396.987 367.302 C 361.553 407.839 299.956 412.223 274.8 412.223 C 228.619 412.223 193.257 400.508 169.718 377.435 C 147.367 355.514 135.652 323.206 134.899 281.447 C 133.316 184.632 188.013 84.476 282.849 84.476 C 328.168 84.476 363.313 116.606 376.287 130.44 C 380.742 135.199 386.945 137.937 393.466 138.023 C 399.839 138.206 405.95 135.45 410.032 130.548 L 413.625 126.199 C 421.197 117.228 424.689 105.506 423.256 93.856 C 421.802 81.655 415.67 70.498 406.15 62.735 C 372.77 35.011 330.657 19.999 287.27 20.365 C 228.873 20.365 171.23 47.245 129.148 94.072 C 84.764 143.342 61.117 210.328 62.448 282.706 C 63.525 340.818 82.572 389.654 117.611 424.047 C 155.201 460.99 210.329 480.358 277.064 480.358 C 355.262 480.358 403.743 457.215 430.659 437.811 C 441.044 430.24 447.357 418.308 447.766 405.467 C 448.136 392.059 442.73 379.141 432.924 369.996 Z" style=""/>
<path class="cls-1" d="M 414.119 356.49 C 409.991 352.595 404.516 350.444 398.839 350.49 C 393.355 350.533 388.152 352.919 384.546 357.047 C 352.217 394.03 296.022 398.03 273.071 398.03 C 230.941 398.03 198.68 387.342 177.205 366.293 C 156.811 346.293 146.123 316.818 145.435 278.721 C 143.991 190.394 193.892 99.019 280.416 99.019 C 321.76 99.019 353.825 128.33 365.66 140.953 C 369.726 145.293 375.385 147.792 381.333 147.87 C 387.149 148.041 392.722 145.526 396.446 141.051 L 399.726 137.084 C 406.634 128.9 409.821 118.209 408.511 107.576 C 407.184 96.448 401.59 86.268 392.906 79.183 C 362.454 53.892 324.032 40.197 284.448 40.528 C 231.17 40.528 178.582 65.052 140.188 107.773 C 99.697 152.723 78.124 213.837 79.338 279.868 C 80.321 332.884 97.697 377.44 129.665 408.817 C 163.959 442.521 214.253 460.193 275.137 460.193 C 346.481 460.193 390.708 439.079 415.266 421.374 C 424.742 414.472 430.499 403.584 430.872 391.866 C 431.213 379.637 426.278 367.85 417.332 359.506 Z" style="fill: rgb(218, 51, 51); fill-opacity: 0; fill-rule: evenodd; stroke: rgb(255, 255, 255); stroke-width: 5px; visibility: hidden;"/>
</svg>
\ No newline at end of file
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.22 128.02">
<path class="cls-1" d="M112.39,96.37a6.71,6.71,0,0,0-4.66-1.83,5.85,5.85,0,0,0-4.36,2c-9.86,11.28-27,12.5-34,12.5-12.85,0-22.69-3.26-29.24-9.68-6.22-6.1-9.48-15.09-9.69-26.71C30,45.71,45.22,17.84,71.61,17.84c12.61,0,22.39,8.94,26,12.79a6.67,6.67,0,0,0,4.78,2.11A5.78,5.78,0,0,0,107,30.66l1-1.21a11.73,11.73,0,0,0,2.68-9,13.19,13.19,0,0,0-4.76-8.66A51.1,51.1,0,0,0,72.84,0c-16.25,0-32.29,7.48-44,20.51C16.49,34.22,9.91,52.86,10.28,73c.3,16.17,5.6,29.76,15.35,39.33C36.09,122.61,51.43,128,70,128c21.76,0,35.25-6.44,42.74-11.84a11.59,11.59,0,0,0,4.76-9,13,13,0,0,0-4.13-9.87Z" transform="translate(-10.26 -0.02)"/>
</svg>
\ No newline at end of file
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="tanuki-logo" viewBox="0 0 586 559">
<path d="m 582.78692,311.92227 -30.5816,-93.9636 a 13.2784,13.2784 0 0 0 -0.7396,-2.5284 L 490.11332,26.574273 A 24.3896,24.3896 0 0 0 466.82452,9.9418725 23.9768,23.9768 0 0 0 443.81092,26.711873 l -58.48,179.963597 H 200.75772 L 142.19172,26.711873 A 23.9768,23.9768 0 0 0 119.28132,9.9418725 h -0.1376 A 24.4584,24.4584 0 0 0 95.923723,26.729073 l -61.404,189.079597 c 0,0.172 -0.1376,0.3096 -0.1892,0.4816 l -31.1319998,95.6492 a 34.8988,34.8988 0 0 0 12.6763998,39.0612 l 268.973597,195.4436 a 13.76,13.76 0 0 0 16.254,-0.086 l 269.0252,-195.3576 a 34.8816,34.8816 0 0 0 12.6592,-39.0784 m -402.05,-77.6236 74.9748,230.7552 -179.980797,-230.7552 m 254.645997,230.8068 71.896,-221.2264 3.096,-9.5804 h 105.092 l -162.8324,208.6016 m 119.4368,-398.472397 52.6836,162.247597 h -105.4532 m -37.8916,27.52 -52.2364,160.7512 -31.1664,95.7352 -83.2824,-256.4864 M 119.02332,44.427873 171.81012,206.67547 H 66.425723 m -34.3656,122.0684 a 7.4132,7.4132 0 0 1 -2.6832,-8.3076 l 23.1168,-71.036 169.540397,217.3564 m 331.9256,-138.0128 -189.9912,137.9612 0.6364,-0.8256 168.904,-216.4792 23.1168,71.0016 a 7.4132,7.4132 0 0 1 -2.666,8.3248"/>
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.22 128.02">
<defs><style>.cls-1{fill:#ea5504;}</style></defs><path class="cls-1" d="M112.39,96.37a6.71,6.71,0,0,0-4.66-1.83,5.85,5.85,0,0,0-4.36,2c-9.86,11.28-27,12.5-34,12.5-12.85,0-22.69-3.26-29.24-9.68-6.22-6.1-9.48-15.09-9.69-26.71C30,45.71,45.22,17.84,71.61,17.84c12.61,0,22.39,8.94,26,12.79a6.67,6.67,0,0,0,4.78,2.11A5.78,5.78,0,0,0,107,30.66l1-1.21a11.73,11.73,0,0,0,2.68-9,13.19,13.19,0,0,0-4.76-8.66A51.1,51.1,0,0,0,72.84,0c-16.25,0-32.29,7.48-44,20.51C16.49,34.22,9.91,52.86,10.28,73c.3,16.17,5.6,29.76,15.35,39.33C36.09,122.61,51.43,128,70,128c21.76,0,35.25-6.44,42.74-11.84a11.59,11.59,0,0,0,4.76-9,13,13,0,0,0-4.13-9.87Z" transform="translate(-10.26 -0.02)"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="5.089 0.358 500 500" xmlns="http://www.w3.org/2000/svg">
<path class="cls-1" d="M 429.4 366.69 C 424.875 362.417 418.874 360.064 412.653 360.114 C 406.642 360.158 400.938 362.774 396.986 367.303 C 361.552 407.839 299.955 412.224 274.799 412.224 C 228.618 412.224 193.256 400.509 169.717 377.435 C 147.366 355.514 135.651 323.207 134.898 281.448 C 133.315 184.632 188.012 84.476 282.848 84.476 C 328.167 84.476 363.312 116.606 376.286 130.44 C 380.742 135.199 386.945 137.937 393.466 138.023 C 399.839 138.206 405.949 135.45 410.031 130.549 L 413.625 126.199 C 421.196 117.229 424.688 105.506 423.255 93.856 C 421.802 81.655 415.669 70.498 406.149 62.735 C 372.769 35.011 330.656 19.999 287.269 20.365 C 228.872 20.365 171.229 47.245 129.147 94.072 C 84.763 143.342 61.116 210.329 62.447 282.707 C 63.524 340.818 82.571 389.654 117.61 424.048 C 155.2 460.991 210.328 480.358 277.064 480.358 C 355.262 480.358 403.743 457.215 430.659 437.811 C 441.044 430.24 447.357 418.309 447.766 405.468 C 448.135 392.059 442.729 379.141 432.924 369.996 Z" style="fill-rule: nonzero; stroke: rgb(255, 86, 55); stroke-linecap: round; paint-order: fill; fill: rgba(187, 218, 85, 0); stroke-width: 30px;"/>
<path class="cls-1" d="M 429.401 366.69 C 424.876 362.421 418.875 360.063 412.652 360.113 C 406.642 360.16 400.938 362.775 396.987 367.301 C 361.551 407.837 299.956 412.222 274.799 412.222 C 228.62 412.222 193.258 400.506 169.721 377.435 C 147.366 355.513 135.652 323.205 134.898 281.447 C 133.315 184.633 188.011 84.477 282.849 84.477 C 328.167 84.477 363.313 116.604 376.285 130.44 C 380.742 135.197 386.945 137.936 393.464 138.021 C 399.84 138.21 405.947 135.453 410.029 130.547 L 413.625 126.2 C 421.196 117.228 424.69 105.511 423.253 93.855 C 421.799 81.659 415.668 70.5 406.15 62.734 C 372.771 35.014 330.657 20.003 287.269 20.364 C 228.871 20.364 171.23 47.245 129.146 94.072 C 84.764 143.342 61.117 210.328 62.449 282.704 C 63.525 340.816 82.572 389.653 117.612 424.045 C 155.202 460.988 210.328 480.358 277.063 480.358 C 355.263 480.358 403.74 457.215 430.658 437.81 C 441.045 430.244 447.355 418.309 447.764 405.465 C 448.138 392.061 442.728 379.142 432.923 369.995 Z" style="fill: rgb(218, 51, 51); fill-opacity: 0; fill-rule: evenodd; stroke: rgb(255, 255, 255); stroke-width: 5px; visibility: hidden;"/>
</svg>
\ No newline at end of file
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.22 128.02">
<defs>
<style>
.cls-1{stroke: #ffffff;stroke-width:5;fill:#da3333;fill-opacity:0.0;fill-rule: evenodd;}
</style>
</defs>
<path class="cls-1" d="M112.39,96.37a6.71,6.71,0,0,0-4.66-1.83,5.85,5.85,0,0,0-4.36,2c-9.86,11.28-27,12.5-34,12.5-12.85,0-22.69-3.26-29.24-9.68-6.22-6.1-9.48-15.09-9.69-26.71C30,45.71,45.22,17.84,71.61,17.84c12.61,0,22.39,8.94,26,12.79a6.67,6.67,0,0,0,4.78,2.11A5.78,5.78,0,0,0,107,30.66l1-1.21a11.73,11.73,0,0,0,2.68-9,13.19,13.19,0,0,0-4.76-8.66A51.1,51.1,0,0,0,72.84,0c-16.25,0-32.29,7.48-44,20.51C16.49,34.22,9.91,52.86,10.28,73c.3,16.17,5.6,29.76,15.35,39.33C36.09,122.61,51.43,128,70,128c21.76,0,35.25-6.44,42.74-11.84a11.59,11.59,0,0,0,4.76-9,13,13,0,0,0-4.13-9.87Z" transform="translate(-10.26 -0.02)"/>
</svg>
\ No newline at end of file
pre code.hljs {
display: block;
overflow-x: auto;
padding: 0;
margin: 0;
}
code.hljs {
padding: 0;
}
.hljs {
color: #abb2bf;
background: transparent;
}
.hljs-comment,
.hljs-quote {
color: #5c6370;
font-style: italic;
}
.hljs-doctag,
.hljs-formula,
.hljs-keyword {
color: #c678dd;
}
.hljs-deletion,
.hljs-name,
.hljs-section,
.hljs-selector-tag,
.hljs-subst {
color: #e06c75;
}
.hljs-literal {
color: #56b6c2;
}
.hljs-addition,
.hljs-attribute,
.hljs-meta .hljs-string,
.hljs-regexp,
.hljs-string {
color: #98c379;
}
.hljs-attr,
.hljs-number,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-pseudo,
.hljs-template-variable,
.hljs-type,
.hljs-variable {
color: #d19a66;
}
.hljs-bullet,
.hljs-link,
.hljs-meta,
.hljs-selector-id,
.hljs-symbol,
.hljs-title {
color: #61aeee;
}
.hljs-built_in,
.hljs-class .hljs-title,
.hljs-title.class_ {
color: #e6c07b;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: 700;
}
.hljs-link {
text-decoration: underline;
}
pre code.hljs {
display: block;
overflow-x: auto;
padding: 1em;
}
code.hljs {
padding: 3px 5px;
} /*!
Theme: GitHub
Description: Light theme as seen on github.com
Author: github.com
Maintainer: @Hirse
Updated: 2021-05-15
Outdated base version: https://github.com/primer/github-syntax-light
Current colors taken from GitHub's CSS
*/
.hljs {
color: #24292e;
background: #fff;
}
.hljs-doctag,
.hljs-keyword,
.hljs-meta .hljs-keyword,
.hljs-template-tag,
.hljs-template-variable,
.hljs-type,
.hljs-variable.language_ {
color: #d73a49;
}
.hljs-title,
.hljs-title.class_,
.hljs-title.class_.inherited__,
.hljs-title.function_ {
color: #6f42c1;
}
.hljs-attr,
.hljs-attribute,
.hljs-literal,
.hljs-meta,
.hljs-number,
.hljs-operator,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-id,
.hljs-variable {
color: #005cc5;
}
.hljs-meta .hljs-string,
.hljs-regexp,
.hljs-string {
color: #032f62;
}
.hljs-built_in,
.hljs-symbol {
color: #e36209;
}
.hljs-code,
.hljs-comment,
.hljs-formula {
color: #6a737d;
}
.hljs-name,
.hljs-quote,
.hljs-selector-pseudo,
.hljs-selector-tag {
color: #22863a;
}
.hljs-subst {
color: #24292e;
}
.hljs-section {
color: #005cc5;
font-weight: 700;
}
.hljs-bullet {
color: #735c0f;
}
.hljs-emphasis {
color: #24292e;
font-style: italic;
}
.hljs-strong {
color: #24292e;
font-weight: 700;
}
.hljs-addition {
color: #22863a;
background-color: #f0fff4;
}
.hljs-deletion {
color: #b31d28;
background-color: #ffeef0;
}
.md_preview address,
.md_preview cite,
.md_preview dfn,
.md_preview em,
.md_preview i,
.md_preview span[lang],
.md_preview var {
font-style: italic;
}
.md_preview {
font-family: -apple-system, SF UI Text, Arial, PingFang SC, Hiragino Sans GB, Microsoft YaHei, WenQuanYi Micro Hei, sans-serif, SimHei, SimSun;
padding: 0 14px;
box-sizing: border-box;
word-break: break-all;
}
.md_preview code {
padding: 10px 14px !important;
box-sizing: border-box;
border: 1px solid #3794ff;
}
.md_preview img {
max-width: 100%;
height: auto;
}
.md_preview img.right {
border: 1px solid #ccc;
float: right;
margin-left: 15px;
padding: 5px;
}
.md_preview img.left {
border: 1px solid #ccc;
float: left;
margin-right: 15px;
padding: 5px;
}
.md_preview img.mathcode {
margin: 0 8px;
}
.md_preview .marker {
background-color: #ff0;
}
.md_preview figure {
text-align: center;
margin: 0 24px;
display: inline-block;
}
.md_preview figure > figcaption {
text-align: center;
margin: 8px;
color: #999;
font-size: 14px;
display: block;
}
.md_preview a {
color: #4ea1db;
text-decoration: none;
}
.md_preview a > img {
padding: 1px;
margin: 1px;
border: none;
outline: #0782c1 solid 1px;
}
.md_preview a:visited {
color: #6795b5;
}
.md_preview .code-featured {
border: 5px solid red;
}
.md_preview .math-featured {
padding: 20px;
box-shadow: 0 0 2px #c80000;
background-color: rgba(255, 0, 0, 0.05);
margin: 10px;
}
.md_preview .image-clean {
border: 0;
background: 0 0;
padding: 0;
}
.md_preview .image-clean > figcaption {
font-size: 0.9em;
text-align: right;
}
.md_preview .image-grayscale {
background-color: #fff;
color: #666;
}
.md_preview .embed-240p {
max-width: 426px;
max-height: 240px;
margin: 0 auto;
}
.md_preview .embed-360p {
max-width: 640px;
max-height: 360px;
margin: 0 auto;
}
.md_preview .embed-480p {
max-width: 854px;
max-height: 480px;
margin: 0 auto;
}
.md_preview .embed-720p {
max-width: 1280px;
max-height: 720px;
margin: 0 auto;
}
.md_preview .embed-1080p {
max-width: 1920px;
max-height: 1080px;
margin: 0 auto;
}
.md_preview p {
font-size: 16px;
color: var(--md-editor-text-color-active);
font-weight: 400;
line-height: 26px !important;
margin: 0 0 16px;
overflow-x: auto;
overflow-y: hidden;
}
.md_preview * {
box-sizing: border-box;
}
.md_preview ul ol {
margin: 0 0 24px 32px;
}
.md_preview ul li {
list-style-type: disc;
margin: 8px 0 0 32px;
}
.md_preview ol li {
list-style-type: decimal;
margin-left: 40px;
margin-top: 8px;
}
.md_preview h1 {
font-size: 28px;
line-height: 36px;
}
.md_preview h2 {
font-size: 24px;
line-height: 32px;
}
.md_preview h3 {
font-size: 22px;
line-height: 30px;
}
.md_preview h4 {
font-size: 20px;
line-height: 28px;
}
.md_preview h5 {
font-size: 18px;
line-height: 26px;
}
.md_preview h6 {
font-size: 16px;
line-height: 24px;
}
.md_preview blockquote {
display: block;
padding: 16px 16px 0;
margin: 0 0 24px;
border-left: 8px solid #dddfe4;
background: #eef0f4;
overflow: auto;
overflow-scrolling: touch;
word-wrap: normal;
word-break: normal;
}
.md_preview blockquote p {
font-size: 16px;
line-height: 26px;
font-weight: 400;
margin-bottom: 16px;
color: #4f4f4f;
}
.md_preview hr {
margin: 24px 0;
border: none;
border-bottom: solid #ccc 1px;
}
.md_preview table {
border-collapse: collapse;
display: table;
width: 100%;
text-align: left;
margin-bottom: 24px;
margin-left: auto;
margin-right: auto;
}
.md_preview table tr {
border: 0;
border-top: 1px solid #ddd;
background-color: #fff;
}
.md_preview table tr:nth-child(2n) {
background-color: #f7f7f7;
}
.md_preview table tr th {
font-weight: 700;
background-color: #eff3f5;
}
.md_preview table tr th p {
font-weight: 700;
}
.md_preview tbody {
border: 0;
}
.md_preview dl {
margin: 24px;
}
.md_preview dl dt {
margin: 8px;
font-weight: 700;
}
.md_preview dl dt dd {
margin: 8px;
}
.md_preview dl dd {
margin: 0 0 8px 40px;
}
.md_preview .initialism {
font-size: 90%;
text-transform: uppercase;
}
.md_preview pre {
white-space: pre-wrap;
word-wrap: break-word;
margin: 0 0 24px;
overflow-x: auto;
}
.md_preview pre code {
display: block;
line-height: 22px;
overflow-x: auto;
white-space: pre;
word-wrap: normal;
border-radius: 4px;
padding: 8px;
tab-size: 4;
}
.md_preview pre code code.md_hljs {
padding: 0;
}
.md_preview code {
border-radius: 4px;
display: inline-block;
padding: 2px 6px;
font-family: -apple-system, SF UI Text, Arial, PingFang SC, Hiragino Sans GB, Microsoft YaHei, WenQuanYi Micro Hei, sans-serif, SimHei, SimSun;
}
.md_preview code ol {
margin: 0;
overflow: hidden;
}
.md_preview code ol li {
list-style-type: none;
margin-left: 0;
margin-top: 0;
height: 22px;
}
.md_preview code ol li div.hljs-ln-code {
margin-left: 8px;
}
.md_preview code ol li div.hljs-ln-numbers {
width: 24px;
border-right: 1px solid #c5c5c5;
}
.md_preview code ol li div.hljs-ln-numbers .hljs-ln-line {
word-wrap: normal;
}
.md_preview code ol.hundred li div.hljs-ln-numbers {
width: 30px;
}
.md_preview code ol.thousand li div.hljs-ln-numbers {
width: 36px;
}
.md_preview .hot-keyword:visited {
color: #3399ea;
}
.md_preview .footnote {
vertical-align: top;
position: relative;
top: -4px;
font-size: 12px;
}
.md_preview .MathJax_SVG_Display {
text-align: center;
margin: 24px 0;
font-size: 18px;
font-weight: 400;
color: #4f4f4f;
position: relative;
text-indent: 0;
max-width: none;
max-height: none;
min-width: 0;
min-height: 0;
width: 100%;
}
.md_preview .prettyprint .pre-numbering {
position: absolute;
width: 48px;
background-color: #eef0f4;
top: 0;
left: 0;
margin: 0;
padding: 8px 0;
list-style: none;
text-align: right;
}
.md_preview .pre-numbering li {
padding: 0 8px;
list-style: none;
margin: 0;
}
.md_preview kbd {
padding: 2px 8px;
border: 1px solid rgba(63, 63, 63, 0.25);
box-shadow: 0 1px 0 rgba(63, 63, 63, 0.25);
background-color: #fff;
color: #333;
border-radius: 4px;
display: inline-block;
margin: 0 2px;
white-space: nowrap;
}
.md_preview .dp-highlighter {
font-size: 12px;
text-align: left;
margin: 0 0 24px;
}
.md_preview .csdn-data-video {
width: 200px;
}
.md_preview .csdn-data-video img {
margin: 0;
display: block;
width: 200px;
height: 112px;
}
.md_preview .csdn-data-video p {
margin-top: 10px;
margin-bottom: 0;
font-size: 14px;
}
.md_preview pre[data-from='code-for-outside'] {
overflow: hidden;
}
.md_preview pre[data-from='code-for-outside'] code {
overflow-x: auto;
overflow-y: hidden;
}
.md_preview pre[data-from='code-for-outside'] code * {
overflow: visible;
overflow-wrap: break-word;
}
.md_preview pre[data-from='code-for-outside'] p code {
padding: 0;
}
.cke_editable {
margin: 24px;
word-wrap: break-word;
}
.md_preview .image-grayscale img,
.md_preview img.image-grayscale {
filter: grayscale(100%);
}
p[align='center'] {
text-align: center;
}
.md_preview strong,
.md_preview strong span,
.md_preview strong em {
font-weight: 700;
}
.md_preview em strong {
font-style: italic;
}
.md_preview h1,
.md_preview h2,
.md_preview h3,
.md_preview h4,
.md_preview h5,
.md_preview h6 {
color: #4f4f4f;
margin: 8px 0 16px;
font-weight: 700;
}
.md_preview ol,
.md_preview ul {
margin: 0 0 24px;
padding: 0;
font-size: 16px;
}
.md_preview blockquote ol,
.md_preview blockquote ul {
margin-bottom: 16px;
padding: 0;
font-size: 16px;
line-height: 24px;
}
.md_preview blockquote ol li,
.md_preview blockquote ul li {
margin-bottom: 0;
}
.md_preview table tr td,
.md_preview table tr th {
border: 1px solid #ddd;
font-size: 14px;
color: #4f4f4f;
line-height: 22px;
padding: 8px;
text-align: left;
}
.md_preview table tr td p,
.md_preview table tr th p {
font-size: 14px;
color: #4f4f4f;
margin: 0;
padding: 0;
text-align: left;
line-height: 22px;
}
.md_preview table tr td code,
.md_preview table tr th code {
white-space: normal;
word-break: break-word;
}
.md_preview abbr[data-original-title],
.md_preview abbr[title] {
cursor: help;
border-bottom: 1px dotted #999;
}
.marker {
background-color: #ff0;
}
.md_preview pre {
overflow: hidden;
}
.md_preview pre code {
overflow-y: hidden;
}
.md_preview kbd,
.md_preview pre,
.md_preview samp {
font-family: Consolas, Inconsolata, Courier, monospace;
font-size: 14px;
line-height: 22px;
}
.md_preview code ol li div.hljs-ln-code,
.md_preview code ol li div.hljs-ln-numbers,
.md_preview pre code,
.md_preview pre code div,
.md_preview pre code span {
font-family: 'Source Code Pro', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Anonymous Pro', 'Droid Sans Mono', Menlo, Monaco, Consolas, Inconsolata, Courier, monospace, 'PingFang SC', 'Microsoft YaHei', sans-serif;
}
.md_preview a:focus,
.md_preview a:hover {
color: #ca0c16;
}
.md_preview .flow-chart,
.md_preview .sequence-diagram {
text-align: center;
margin-bottom: 24px;
font-size: 14px !important;
}
.md_preview .flow-chart [fill='#000'],
.md_preview .flow-chart [fill='#000000'],
.md_preview .flow-chart [fill='black'],
.md_preview .sequence-diagram [fill='#000'],
.md_preview .sequence-diagram [fill='#000000'],
.md_preview .sequence-diagram [fill='black'] {
fill: #4f4f4f;
}
.md_preview .flow-chart [stroke='#000000'],
.md_preview .sequence-diagram [stroke='#000000'] {
stroke: #4f4f4f;
}
.md_preview pre code,
.md_preview pre code div,
.md_preview pre code span {
font-size: 14px;
}
.md_preview .prettyprint,
.md_preview pre.prettyprint {
margin: 0 0 24px;
padding: 8px 16px 4px 56px;
background-color: #f6f8fa;
border: none;
}
.md_preview code ol li div.hljs-ln-code,
.md_preview code ol li div.hljs-ln-numbers {
float: left;
height: 22px;
}
.md_preview pre code .hljs-comment {
color: green;
}
.md_preview address,
.md_preview cite,
.md_preview dfn,
.md_preview em,
.md_preview i,
.md_preview span[lang],
.md_preview var {
font-style: italic;
}
.md_preview {
font-family: -apple-system, SF UI Text, Arial, PingFang SC, Hiragino Sans GB, Microsoft YaHei,
WenQuanYi Micro Hei, sans-serif, SimHei, SimSun;
padding: 0 14px;
box-sizing: border-box;
word-break: break-all;
code {
padding: 10px 14px !important;
box-sizing: border-box;
border: 1px solid #3794ff;
}
img {
max-width: 100%;
height: auto;
&.right {
border: 1px solid #ccc;
float: right;
margin-left: 15px;
padding: 5px;
}
&.left {
border: 1px solid #ccc;
float: left;
margin-right: 15px;
padding: 5px;
}
&.mathcode {
margin: 0 8px;
}
}
.marker {
background-color: #ff0;
}
figure {
text-align: center;
margin: 0 24px;
display: inline-block;
& > figcaption {
text-align: center;
margin: 8px;
color: #999;
font-size: 14px;
display: block;
}
}
a {
color: #4ea1db;
text-decoration: none;
& > img {
padding: 1px;
margin: 1px;
border: none;
outline: #0782c1 solid 1px;
}
&:visited {
color: #6795b5;
}
}
.code-featured {
border: 5px solid red;
}
.math-featured {
padding: 20px;
box-shadow: 0 0 2px rgba(200, 0, 0, 1);
background-color: rgba(255, 0, 0, 0.05);
margin: 10px;
}
.image-clean {
border: 0;
background: 0 0;
padding: 0;
& > figcaption {
font-size: 0.9em;
text-align: right;
}
}
.image-grayscale {
background-color: #fff;
color: #666;
}
.embed-240p {
max-width: 426px;
max-height: 240px;
margin: 0 auto;
}
.embed-360p {
max-width: 640px;
max-height: 360px;
margin: 0 auto;
}
.embed-480p {
max-width: 854px;
max-height: 480px;
margin: 0 auto;
}
.embed-720p {
max-width: 1280px;
max-height: 720px;
margin: 0 auto;
}
.embed-1080p {
max-width: 1920px;
max-height: 1080px;
margin: 0 auto;
}
p {
font-size: 16px;
color: var(--md-editor-text-color-active);
font-weight: 400;
line-height: 26px !important;
margin: 0 0 16px;
overflow-x: auto;
overflow-y: hidden;
}
* {
box-sizing: border-box;
}
ul {
ol {
margin: 0 0 24px 32px;
}
li {
list-style-type: disc;
margin: 8px 0 0 32px;
}
}
ol {
li {
list-style-type: decimal;
margin-left: 40px;
margin-top: 8px;
}
}
h1 {
font-size: 28px;
line-height: 36px;
}
h2 {
font-size: 24px;
line-height: 32px;
}
h3 {
font-size: 22px;
line-height: 30px;
}
h4 {
font-size: 20px;
line-height: 28px;
}
h5 {
font-size: 18px;
line-height: 26px;
}
h6 {
font-size: 16px;
line-height: 24px;
}
blockquote {
display: block;
padding: 16px 16px 0;
margin: 0 0 24px;
border-left: 8px solid #dddfe4;
background: #eef0f4;
overflow: auto;
overflow-scrolling: touch;
word-wrap: normal;
word-break: normal;
p {
font-size: 16px;
line-height: 26px;
font-weight: 400;
margin-bottom: 16px;
color: #4f4f4f;
}
}
hr {
margin: 24px 0;
border: none;
border-bottom: solid #ccc 1px;
}
table {
border-collapse: collapse;
display: table;
width: 100%;
text-align: left;
margin-bottom: 24px;
margin-left: auto;
margin-right: auto;
tr {
border: 0;
border-top: 1px solid #ddd;
background-color: #fff;
&:nth-child(2n) {
background-color: #f7f7f7;
}
th {
font-weight: 700;
background-color: #eff3f5;
p {
font-weight: 700;
}
}
}
}
tbody {
border: 0;
}
dl {
margin: 24px;
dt {
margin: 8px;
font-weight: 700;
dd {
margin: 8px;
}
}
dd {
margin: 0 0 8px 40px;
}
}
.initialism {
font-size: 90%;
text-transform: uppercase;
}
pre {
white-space: pre-wrap;
word-wrap: break-word;
margin: 0 0 24px;
overflow-x: auto;
// padding: 8px;
code {
display: block;
line-height: 22px;
overflow-x: auto;
white-space: pre;
word-wrap: normal;
border-radius: 4px;
padding: 8px;
tab-size: 4;
code {
&.md_hljs {
padding: 0;
}
}
&:not(.md_hljs) {
// background-color: var(--md-editor-code-bg-color);
}
}
}
code {
border-radius: 4px;
display: inline-block;
// background-color: var(--md-editor-code-bg-color);
padding: 2px 6px;
font-family: -apple-system, SF UI Text, Arial, PingFang SC, Hiragino Sans GB, Microsoft YaHei,
WenQuanYi Micro Hei, sans-serif, SimHei, SimSun;
ol {
margin: 0;
overflow: hidden;
li {
list-style-type: none;
margin-left: 0;
margin-top: 0;
height: 22px;
div {
&.hljs-ln-code {
margin-left: 8px;
}
&.hljs-ln-numbers {
width: 24px;
border-right: 1px solid #c5c5c5;
.hljs-ln-line {
word-wrap: normal;
}
}
}
}
&.hundred {
li {
div {
&.hljs-ln-numbers {
width: 30px;
}
}
}
}
&.thousand {
li {
div {
&.hljs-ln-numbers {
width: 36px;
}
}
}
}
}
}
.hot-keyword {
&:visited {
color: #3399ea;
}
}
.footnote {
vertical-align: top;
position: relative;
top: -4px;
font-size: 12px;
}
.MathJax_SVG_Display {
text-align: center;
margin: 24px 0;
font-size: 18px;
font-weight: 400;
color: #4f4f4f;
position: relative;
text-indent: 0;
max-width: none;
max-height: none;
min-width: 0;
min-height: 0;
width: 100%;
}
.prettyprint {
.pre-numbering {
position: absolute;
width: 48px;
background-color: #eef0f4;
top: 0;
left: 0;
margin: 0;
padding: 8px 0;
list-style: none;
text-align: right;
}
}
.pre-numbering {
li {
padding: 0 8px;
list-style: none;
margin: 0;
}
}
kbd {
padding: 2px 8px;
border: 1px solid rgba(63, 63, 63, 0.25);
box-shadow: 0 1px 0 rgba(63, 63, 63, 0.25);
background-color: #fff;
color: #333;
border-radius: 4px;
display: inline-block;
margin: 0 2px;
white-space: nowrap;
}
.dp-highlighter {
font-size: 12px;
text-align: left;
margin: 0 0 24px;
}
.csdn-data-video {
width: 200px;
img {
margin: 0;
display: block;
width: 200px;
height: 112px;
}
p {
margin-top: 10px;
margin-bottom: 0;
font-size: 14px;
}
}
pre[data-from='code-for-outside'] {
overflow: hidden;
code {
overflow-x: auto;
overflow-y: hidden;
* {
overflow: visible;
overflow-wrap: break-word;
}
}
p {
code {
padding: 0;
}
}
}
}
.cke_editable {
margin: 24px;
word-wrap: break-word;
}
.md_preview .image-grayscale img,
.md_preview img.image-grayscale {
filter: grayscale(100%);
}
p[align='center'] {
text-align: center;
}
.md_preview strong,
.md_preview strong span,
.md_preview strong em {
font-weight: 700;
}
.md_preview em strong {
font-style: italic;
}
.md_preview h1,
.md_preview h2,
.md_preview h3,
.md_preview h4,
.md_preview h5,
.md_preview h6 {
color: #4f4f4f;
margin: 8px 0 16px;
font-weight: 700;
}
.md_preview ol,
.md_preview ul {
margin: 0 0 24px;
padding: 0;
font-size: 16px;
}
.md_preview blockquote ol,
.md_preview blockquote ul {
margin-bottom: 16px;
padding: 0;
font-size: 16px;
line-height: 24px;
}
.md_preview blockquote ol li,
.md_preview blockquote ul li {
margin-bottom: 0;
}
.md_preview table tr td,
.md_preview table tr th {
border: 1px solid #ddd;
font-size: 14px;
color: #4f4f4f;
line-height: 22px;
padding: 8px;
text-align: left;
}
.md_preview table tr td p,
.md_preview table tr th p {
font-size: 14px;
color: #4f4f4f;
margin: 0;
padding: 0;
text-align: left;
line-height: 22px;
}
.md_preview table tr td code,
.md_preview table tr th code {
white-space: normal;
word-break: break-word;
}
.md_preview abbr[data-original-title],
.md_preview abbr[title] {
cursor: help;
border-bottom: 1px dotted #999;
}
.marker {
background-color: #ff0;
}
.md_preview pre {
overflow: hidden;
code {
overflow-y: hidden;
}
}
.md_preview kbd,
.md_preview pre,
.md_preview samp {
font-family: Consolas, Inconsolata, Courier, monospace;
font-size: 14px;
line-height: 22px;
// color: #000;
}
.md_preview code ol li div.hljs-ln-code,
.md_preview code ol li div.hljs-ln-numbers,
.md_preview pre code,
.md_preview pre code div,
.md_preview pre code span {
font-family: 'Source Code Pro', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Anonymous Pro',
'Droid Sans Mono', Menlo, Monaco, Consolas, Inconsolata, Courier, monospace, 'PingFang SC',
'Microsoft YaHei', sans-serif;
}
.md_preview a:focus,
.md_preview a:hover {
color: #ca0c16;
}
.md_preview .flow-chart,
.md_preview .sequence-diagram {
text-align: center;
margin-bottom: 24px;
font-size: 14px !important;
}
.md_preview .flow-chart [fill='#000'],
.md_preview .flow-chart [fill='#000000'],
.md_preview .flow-chart [fill='black'],
.md_preview .sequence-diagram [fill='#000'],
.md_preview .sequence-diagram [fill='#000000'],
.md_preview .sequence-diagram [fill='black'] {
fill: #4f4f4f;
}
.md_preview .flow-chart [stroke='#000000'],
.md_preview .sequence-diagram [stroke='#000000'] {
stroke: #4f4f4f;
}
.md_preview pre code,
.md_preview pre code div,
.md_preview pre code span {
font-size: 14px;
}
.md_preview .prettyprint,
.md_preview pre.prettyprint {
margin: 0 0 24px;
padding: 8px 16px 4px 56px;
background-color: #f6f8fa;
border: none;
}
.md_preview code ol li div.hljs-ln-code,
.md_preview code ol li div.hljs-ln-numbers {
float: left;
height: 22px;
}
.md_preview pre code .hljs-comment {
color: green;
}
.snippet_header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 0;
box-sizing: border-box;
border-bottom: 1px solid #4c4c4c;
}
.snippet_header img {
width: 20px;
height: 20px;
border-radius: 50%;
}
.snippet_header .flex-1 {
flex: 1;
margin: 0 14px;
}
.snippet_header a {
margin: 0 6px;
outline: none;
}
.snippet_title {
font-size: 20px;
}
.snippet_desc {
color: #ccc;
}
.snippet_desc.md_preview {
padding: 0;
}
.snippet_item_container {
border: 1px solid #3794ff;
border-radius: 4px;
margin: 20px 0;
}
.snippet_item_container .snippet_item_header {
border-bottom: 1px solid #3794ff;
font-size: 16px;
padding: 6px 14px;
box-sizing: border-box;
}
.snippet_item_container .snippet_item_header .snippet_item_title {
display: inline-block;
font-weight: 600;
}
.snippet_item_container .snippet_item_header .snippet_item_size {
display: inline-block;
margin: 0 20px 0 10px;
font-size: 12px;
color: #ccc;
}
.snippet_item_container .snippet_item_header .snippet_item_copy {
font-size: 12px;
outline: none;
}
.snippet_item_container .snippet_item_body .snippet_content pre {
white-space: pre-wrap;
word-wrap: break-word;
overflow-x: auto;
margin: 0;
padding: 0;
}
.snippet_item_container .snippet_item_body .snippet_content pre code {
display: block;
line-height: 1.2;
overflow-x: auto;
white-space: pre;
word-wrap: normal;
tab-size: 2;
padding: 0 6px;
box-sizing: border-box;
margin: 0;
}
.snippet_item_container .snippet_item_body .snippet_content pre code ul {
list-style: decimal;
margin: 0 0 0 40px;
padding: 0;
}
.snippet_item_container .snippet_item_body .snippet_content pre code ul li {
list-style: decimal;
border-left: 1px solid #3794ff;
padding: 2px 5px;
margin: 0;
line-height: 14px;
width: 100%;
box-sizing: border-box;
}
.snippet_item_container .snippet_item_body .snippet_content pre code ul li:first-child {
padding-top: 6px;
}
.snippet_item_container .snippet_item_body .snippet_content pre code ul li:last-child {
padding-bottom: 6px;
}
.snippet_item_container .snippet_item_body .snippet_content pre code ul li::marker {
content: counter(list-item) ' ';
color: #808080;
}
@color-blue: #3794ff;
.snippet_header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 0;
box-sizing: border-box;
border-bottom: 1px solid #4c4c4c;
img {
width: 20px;
height: 20px;
border-radius: 50%;
}
.flex-1 {
flex: 1;
margin: 0 14px;
}
a {
margin: 0 6px;
outline: none;
}
}
.snippet_title {
font-size: 20px;
}
.snippet_desc {
color: #ccc;
&.md_preview {
padding: 0;
}
}
.snippet_item_container {
border: 1px solid @color-blue;
border-radius: 4px;
margin: 20px 0;
.snippet_item_header {
border-bottom: 1px solid @color-blue;
font-size: 16px;
padding: 6px 14px;
box-sizing: border-box;
.snippet_item_title {
display: inline-block;
font-weight: 600;
}
.snippet_item_size {
display: inline-block;
margin: 0 20px 0 10px;
font-size: 12px;
color: #ccc;
}
.snippet_item_copy {
font-size: 12px;
outline: none;
}
}
.snippet_item_body {
.snippet_content {
pre {
// border-left: 1px solid @color-blue;
white-space: pre-wrap;
word-wrap: break-word;
overflow-x: auto;
margin: 0;
padding: 0;
code {
display: block;
line-height: 1.2;
overflow-x: auto;
white-space: pre;
word-wrap: normal;
tab-size: 2;
padding: 0 6px;
box-sizing: border-box;
margin: 0;
ul {
list-style: decimal;
margin: 0 0 0 40px;
padding: 0;
li {
list-style: decimal;
border-left: 1px solid @color-blue;
padding: 2px 5px;
margin: 0;
line-height: 14px;
width: 100%;
box-sizing: border-box;
&:first-child {
padding-top: 6px;
}
&:last-child {
padding-bottom: 6px;
}
&::marker {
content: counter(list-item) ' ';
color: #808080;
}
// &:nth-of-type(even) {
// background-color: rgba(255, 255, 255, 0.015);
// color: inherit;
// }
}
}
}
}
}
}
}
......@@ -6,7 +6,7 @@ export async function validate(): Promise<void> {
const editor = vscode.window.activeTextEditor;
if (!editor) {
await vscode.window.showInformationMessage('GitLab Workflow: No open file.');
await vscode.window.showInformationMessage('CSDN Workflow: No open file.');
return;
}
......@@ -18,7 +18,7 @@ export async function validate(): Promise<void> {
if (!response) {
await vscode.window.showInformationMessage(
'GitLab Workflow: Failed to validate CI configuration.',
'CSDN Workflow: Failed to validate CI configuration.',
);
return;
}
......@@ -26,16 +26,16 @@ export async function validate(): Promise<void> {
const { status, errors, error } = response;
if (status === 'valid') {
await vscode.window.showInformationMessage('GitLab Workflow: Your CI configuration is valid.');
await vscode.window.showInformationMessage('CSDN Workflow: Your CI configuration is valid.');
} else if (status === 'invalid') {
if (errors[0]) {
await vscode.window.showErrorMessage(errors[0]);
}
await vscode.window.showErrorMessage('GitLab Workflow: Invalid CI configuration.');
await vscode.window.showErrorMessage('CSDN Workflow: Invalid CI configuration.');
} else if (error) {
await vscode.window.showErrorMessage(
`GitLab Workflow: Failed to validate CI configuration. Reason: ${error}`,
`CSDN Workflow: Failed to validate CI configuration. Reason: ${error}`,
);
}
}
......@@ -3,45 +3,54 @@
These commands must be exactly the same as the contributed commands in package.json.
*/
export const USER_COMMANDS = {
SET_TOKEN: 'gl.setToken',
REMOVE_TOKEN: 'gl.removeToken',
SHOW_ISSUES_ASSIGNED_TO_ME: 'gl.showIssuesAssignedToMe',
SHOW_MERGE_REQUESTS_ASSIGNED_TO_ME: 'gl.showMergeRequestsAssignedToMe',
OPEN_ACTIVE_FILE: 'gl.openActiveFile',
COPY_LINK_TO_ACTIVE_FILE: 'gl.copyLinkToActiveFile',
OPEN_CURRENT_MERGE_REQUEST: 'gl.openCurrentMergeRequest',
OPEN_CREATE_NEW_ISSUE: 'gl.openCreateNewIssue',
OPEN_CREATE_NEW_MR: 'gl.openCreateNewMR',
OPEN_PROJECT_PAGE: 'gl.openProjectPage',
OPEN_CURRENT_PIPELINE: 'gl.openCurrentPipeline',
PIPELINE_ACTIONS: 'gl.pipelineActions',
ISSUE_SEARCH: 'gl.issueSearch',
MERGE_REQUEST_SEARCH: 'gl.mergeRequestSearch',
PROJECT_ADVANCED_SEARCH: 'gl.projectAdvancedSearch',
COMPARE_CURRENT_BRANCH: 'gl.compareCurrentBranch',
CREATE_SNIPPET: 'gl.createSnippet',
INSERT_SNIPPET: 'gl.insertSnippet',
VALIDATE_CI_CONFIG: 'gl.validateCIConfig',
SHOW_OUTPUT: 'gl.showOutput',
REFRESH_SIDEBAR: 'gl.refreshSidebar',
RESOLVE_THREAD: 'gl.resolveThread',
UNRESOLVE_THREAD: 'gl.unresolveThread',
DELETE_COMMENT: 'gl.deleteComment',
START_EDITING_COMMENT: 'gl.startEditingComment',
CANCEL_EDITING_COMMENT: 'gl.cancelEditingComment',
SUBMIT_COMMENT_EDIT: 'gl.submitCommentEdit',
CREATE_COMMENT: 'gl.createComment',
CHECKOUT_MR_BRANCH: 'gl.checkoutMrBranch',
CLONE_WIKI: 'gl.cloneWiki',
CREATE_SNIPPET_PATCH: 'gl.createSnippetPatch',
SET_TOKEN: 'csdn.setToken',
WEBVIEW: 'csdn.openWebview',
JSON_FORMAT: 'csdn.jsonFormat',
HTTP_REQUEST: 'csdn.httpRequest',
DO_HTTP_REQUEST: 'csdn.doHttpRequest',
REMOVE_TOKEN: 'csdn.removeToken',
SHOW_ISSUES_ASSIGNED_TO_ME: 'csdn.showIssuesAssignedToMe',
SHOW_MERGE_REQUESTS_ASSIGNED_TO_ME: 'csdn.showMergeRequestsAssignedToMe',
OPEN_ACTIVE_FILE: 'csdn.openActiveFile',
COPY_LINK_TO_ACTIVE_FILE: 'csdn.copyLinkToActiveFile',
OPEN_CURRENT_MERGE_REQUEST: 'csdn.openCurrentMergeRequest',
OPEN_CREATE_NEW_ISSUE: 'csdn.openCreateNewIssue',
OPEN_CREATE_NEW_MR: 'csdn.openCreateNewMR',
OPEN_PROJECT_PAGE: 'csdn.openProjectPage',
OPEN_CURRENT_PIPELINE: 'csdn.openCurrentPipeline',
PIPELINE_ACTIONS: 'csdn.pipelineActions',
ISSUE_SEARCH: 'csdn.issueSearch',
MERGE_REQUEST_SEARCH: 'csdn.mergeRequestSearch',
PROJECT_ADVANCED_SEARCH: 'csdn.projectAdvancedSearch',
COMPARE_CURRENT_BRANCH: 'csdn.compareCurrentBranch',
CREATE_SNIPPET: 'csdn.createSnippet',
INSERT_SNIPPET: 'csdn.insertSnippet',
CREATE_NOTE: 'csdn.createNote',
OPEN_NOTE_DOCUMENT: 'csdn.openNoteDocument',
VALIDATE_CI_CONFIG: 'csdn.validateCIConfig',
SHOW_OUTPUT: 'csdn.showOutput',
REFRESH_SIDEBAR: 'csdn.refreshSidebar',
RESOLVE_THREAD: 'csdn.resolveThread',
UNRESOLVE_THREAD: 'csdn.unresolveThread',
DELETE_COMMENT: 'csdn.deleteComment',
START_EDITING_COMMENT: 'csdn.startEditingComment',
CANCEL_EDITING_COMMENT: 'csdn.cancelEditingComment',
SUBMIT_COMMENT_EDIT: 'csdn.submitCommentEdit',
CREATE_COMMENT: 'csdn.createComment',
CHECKOUT_MR_BRANCH: 'csdn.checkoutMrBranch',
CLONE_WIKI: 'csdn.cloneWiki',
CREATE_SNIPPET_PATCH: 'csdn.createSnippetPatch',
OPEN_SNIPPET: 'csdn.openSnippet',
OPEN_PROJECT_SNIPPET: 'csdn.openProjectSnippet',
UTILITY: 'csdn.utilities',
};
/*
User can't trigger these commands directly. We use them from within the code.
*/
export const PROGRAMMATIC_COMMANDS = {
SHOW_RICH_CONTENT: 'gl.showRichContent',
NO_IMAGE_REVIEW: 'gl.noImageReview',
SHOW_RICH_CONTENT: 'csdn.showRichContent',
NO_IMAGE_REVIEW: 'csdn.noImageReview',
};
export const VS_COMMANDS = {
......
import * as vscode from 'vscode';
import * as openers from '../openers';
import * as gitLabService from '../gitlab_service';
import { gitExtensionWrapper } from '../git/git_extension_wrapper';
type VisibilityItem = vscode.QuickPickItem & { type: string };
const PRIVATE_VISIBILITY_ITEM: VisibilityItem = {
label: '$(lock) 私有',
type: 'private',
description: '创建私有笔记',
};
const PUBLIC_VISIBILITY_ITEM: VisibilityItem = {
label: '$(globe) 公开',
type: 'public',
description: '创建公开笔记',
};
export const VISIBILITY_OPTIONS = [PRIVATE_VISIBILITY_ITEM, PUBLIC_VISIBILITY_ITEM];
async function uploadNote(
editor: vscode.TextEditor,
visibility: string,
title?: string
) {
let content = '';
const fileName = editor.document.fileName.split('/').reverse()[0];
const { start, end } = editor.selection;
if (start.line === end.line) {
await vscode.window.showInformationMessage('CSDN Workflow: 您未选取任何内容');
return;
}
const repository = await gitExtensionWrapper.getActiveRepositoryOrSelectOne();
const fileAbsPath = editor.document.uri.path
let fileRelativePath
if (repository && fileAbsPath.indexOf(repository.rootFsPath)!==-1) {
fileRelativePath = fileAbsPath.replace(repository.rootFsPath, ".")
}
const noteTitle = `${fileRelativePath || fileName}#L${start.line}-${end.line}`
const endLine = end.line + 1;
const startPos = new vscode.Position(start.line, 0);
const endPos = new vscode.Position(endLine, 0);
const range = new vscode.Range(startPos, endPos);
content = editor.document.getText(range);
const data = {
title: title || noteTitle,
description: noteTitle,
file_name: fileName,
visibility,
content,
};
const note = await gitLabService.createNote(data);
await openers.openSnippet(note.id);
}
/**
*
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function createNote() {
const editor = vscode.window.activeTextEditor;
if (!editor) {
await vscode.window.showInformationMessage('CSDN Workflow: 您需要先打开文件然后选中要添加到笔记的内容,才能执行保存笔记的操作');
return;
}
const title = await vscode.window.showInputBox({
ignoreFocusOut: true,
placeHolder: 'E.g. 图片上传-update.js',
prompt: '代码笔记标题',
});
const visibility = await vscode.window.showQuickPick(VISIBILITY_OPTIONS);
if (!visibility) return;
await uploadNote(editor, visibility.type, title);
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function newNoteTextDocument() {
const sampleText = `/**
* 您可在此处书写全新的笔记,然后选择需要保存的内容,执行快捷键:shift+alt+j 保存笔记;
* 也可以在其他已存在内容的文件中,选择要保存的内容,执行快捷键:shift+alt+j 保存笔记。
*/
`
const doc = await vscode.workspace.openTextDocument({ language: 'plaintext', content: sampleText });
await vscode.window.showTextDocument(doc);
}
......@@ -69,7 +69,7 @@ export async function createSnippet() {
const editor = vscode.window.activeTextEditor;
if (!editor) {
await vscode.window.showInformationMessage('GitLab Workflow: No open file.');
await vscode.window.showInformationMessage('CSDN Workflow: No open file.');
return;
}
const repository = await gitExtensionWrapper.getActiveRepositoryOrSelectOne();
......@@ -78,7 +78,7 @@ export async function createSnippet() {
if (!project) {
await vscode.window.showInformationMessage(
'GitLab Workflow: Repository does not contain GitLab project.',
'CSDN Workflow: Repository does not contain GitLab project.',
);
return;
}
......
......@@ -14,7 +14,7 @@ This snippet contains suggested changes for branch ${branch} (commit: ${commit})
Apply this snippet:
- In VS Code with the GitLab Workflow extension installed:
- In VS Code with the CSDN Workflow extension installed:
- Run \`GitLab: Apply snippet patch\` and select this snippet
- Using the \`git\` command:
- Download the \`${patchFileName}\` file to your project folder
......@@ -24,7 +24,7 @@ Apply this snippet:
git apply '${patchFileName}'
~~~
*This snippet was created with the [GitLab Workflow VS Code extension](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow).*
*This snippet was created with the [CSDN Workflow VS Code extension](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow).*
`;
export const createSnippetPatch = async (): Promise<void> => {
......
import * as vscode from 'vscode';
import * as request from 'request-promise';
import { handleError, log } from '../log';
import { UserFriendlyError } from '../errors/user_friendly_error';
import { getUserAgentHeader } from '../utils/get_user_agent_header';
import { USER_COMMANDS } from '../command_names';
async function httpRequest() {
const editor = vscode.window.activeTextEditor;
if (editor) {
const content = editor.document.getText();
try{
const userConfig = JSON.parse(content)
const hmethod: string = userConfig?.http_method?.value || 'GET'
const headers = userConfig?.header?.value || {
"Content-Type": "application/json;charset=utf-8",
...getUserAgentHeader(),
}
const body = userConfig?.body?.value || {}
const url = userConfig.url.value
const proxy = userConfig.proxy.value
await vscode.commands.executeCommand(USER_COMMANDS.SHOW_OUTPUT);
const result = await fetch(url, hmethod, headers, body, proxy)
log(`Response body:\n${result.response}`)
}catch(err){
handleError(
new UserFriendlyError(
'CSDN Workflow: 配置文件解析失败,点击查看详情',
err
),
);
}
}else{
await vscode.window.showInformationMessage('CSDN Workflow: 未找到配置文件,请保持配置文件处于打开状态');
}
}
async function showHttpConfig(): Promise<void> {
// eslint-disable-next-line no-use-before-define
const sampleText = httpConfig()
const doc = await vscode.workspace.openTextDocument({ language: 'json', content: sampleText });
await vscode.window.showTextDocument(doc);
}
async function fetch(url: string, method = 'GET', headers:Record<string, unknown>, data?: Record<string, unknown>, proxy?: string) {
const config: request.RequestPromiseOptions = {
method,
headers
};
if (data) {
config.formData = data;
}
if(proxy){
config.proxy = proxy
}
config.transform = (body, response) => {
try {
return {
response: body,
headers: response.headers,
};
} catch (e) {
handleError(
new UserFriendlyError(
'Failed to parse API response',
e,
`Response body: ${body}\nRequest URL: ${url}`,
),
);
return { error: e };
}
};
return await request(url, config);
}
module.exports = {
showHttpConfig,
httpRequest
}
function httpConfig(): string {
const config = {
"note": "以下内容为 http 请求的临时配置文件,您可以直接进行编辑,我们会根据配置文件内容执行 http 请求。使用快捷键 shift+alt+r 运行。",
"http_method": {
"note": "请求方式,如:GET,POST,DELETE,PUT",
"value": "GET"
},
"header": {
"note": "http headers",
"value": {
"Content-Type": "application/json;charset=utf-8",
...getUserAgentHeader(),
}
},
"body": {
"note": "http body(选填)",
"value": {}
},
"url": {
"note": "请求地址",
"value": "https://codechina.csdn.net/api/v4/templates/gitignores"
},
"proxy": {
"note": "代理设置",
"value": null
}
}
return JSON.stringify(config, null, '\t')
}
import * as vscode from 'vscode';
import { handleError } from '../log';
import { UserFriendlyError } from '../errors/user_friendly_error';
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function jsonFormat() {
const editor = vscode.window.activeTextEditor;
if (editor) {
const document = editor?.document
const selection = editor?.selection
const word = document?.getText(selection);
if (word) {
try {
const jsonResult = JSON.parse(word)
const strResult = JSON.stringify(jsonResult, null, '\t')
await editor.edit(editBuilder => {
editBuilder.replace(selection, strResult);
});
} catch (e) {
handleError(
new UserFriendlyError(
'CSDN Workflow: 格式化失败,点击查看详情',
e
),
);
}
} else {
await vscode.window.showInformationMessage('CSDN Workflow: 没有已经选中的 json 内容');
}
}else{
await vscode.window.showInformationMessage('CSDN Workflow: 没有已经打开的文件');
}
}
export const GITLAB_COM_URL = 'https://gitlab.com';
// ~/Library/Application Support/Code/User/settings.json
export const GITLAB_COM_URL = 'https://codechina.csdn.net';
export const REVIEW_URI_SCHEME = 'gl-review';
export const CONFIG_NAMESPACE = 'gitlab';
export const CONFIG_NAMESPACE = 'csdn';
export const CONFIG_CUSTOM_QUERIES = 'customQueries';
export const UTILITIES = 'utilities';
export const EXECUTE_REQUEST_CHILDREN = 'executeRequestChildren';
export const EXECUTE_JSON_CHILDREN = 'executeJsonChildren';
export const ADDED = 'added';
export const DELETED = 'deleted';
export const RENAMED = 'renamed';
......
......@@ -31,7 +31,7 @@ class DataProvider implements vscode.TreeDataProvider<ItemModel | vscode.TreeIte
// eslint-disable-next-line class-methods-use-this
async createPipelineItem(pipeline: RestPipeline | null, project: GitLabProject) {
if (!pipeline) {
return new vscode.TreeItem('No pipeline found');
return new vscode.TreeItem('没有流水线');
}
const statusText = pipeline.status === 'success' ? 'passed' : pipeline.status;
const actions = {
......@@ -53,7 +53,7 @@ class DataProvider implements vscode.TreeDataProvider<ItemModel | vscode.TreeIte
async createMrItem(mr: RestMr | null, repository: WrappedRepository) {
if (!mr) {
return new vscode.TreeItem('No merge request found');
return new vscode.TreeItem('没有合并请求');
}
this.mr = mr;
const item = new MrItemModel(mr, repository);
......@@ -69,7 +69,7 @@ class DataProvider implements vscode.TreeDataProvider<ItemModel | vscode.TreeIte
return issues.map(issue => new IssueItem(issue, repository.rootFsPath));
}
}
return [new vscode.TreeItem('No closing issue found')];
return [new vscode.TreeItem('没有结束的 issue')];
}
async getChildren(item: ItemModel | undefined): Promise<ItemModel[] | vscode.TreeItem[]> {
......
......@@ -46,7 +46,7 @@ export class DataProvider implements vscode.TreeDataProvider<ItemModel | vscode.
logError(e);
return [new ErrorItem('Fetching Issues and MRs failed')];
}
if (repositories.length === 0) return [new vscode.TreeItem('No projects found')];
if (repositories.length === 0) return [new vscode.TreeItem('未发现代码仓库')];
// FIXME: if you are touching this configuration statement, move the configuration to get_extension_configuration.ts
const customQueries =
vscode.workspace
......
import { TreeItem } from 'vscode';
import { PROGRAMMATIC_COMMANDS } from '../../command_names';
// 打开富文本
export class IssueItem extends TreeItem {
constructor(issue: RestIssuable, repositoryPath: string) {
super(`#${issue.iid} · ${issue.title}`);
......
import * as vscode from 'vscode';
import { USER_COMMANDS } from '../../command_names';
export class SnippetItem extends vscode.TreeItem {
constructor(
id: number,
name: string
) {
super(vscode.Uri.file(name));
this.command = {
title: 'Open Snippet',
command: USER_COMMANDS.OPEN_SNIPPET,
arguments: [id],
};
}
}
import * as vscode from 'vscode';
import { USER_COMMANDS } from '../../command_names';
export class UnilityJsonChildrenItem extends vscode.TreeItem {
constructor(
name: string,
type: string,
) {
super(vscode.Uri.file(name));
this.command = {
title: 'Utility Tools',
command: USER_COMMANDS.UTILITY,
arguments: [type],
};
}
}
\ No newline at end of file
import * as vscode from 'vscode';
import { USER_COMMANDS } from '../../command_names';
export class UnilityRequestChildrenItem extends vscode.TreeItem {
constructor(
name: string,
type: string,
) {
super(vscode.Uri.file(name));
this.command = {
title: 'Utility Tools',
command: USER_COMMANDS.UTILITY,
arguments: [type],
};
}
}
\ No newline at end of file
import * as vscode from 'vscode';
import { USER_COMMANDS } from '../../command_names';
import { EXECUTE_JSON_CHILDREN, CONFIG_NAMESPACE, EXECUTE_REQUEST_CHILDREN } from '../../constants';
import { UtilityQuery } from '../../gitlab/utility_query';
import { ItemModel } from './../items/item_model';
import { UnilityJsonChildrenItem } from './unility_json_children_item';
import { UnilityRequestChildrenItem } from './unility_request_children_item';
export class UtilityItem extends ItemModel {
private name: string;
private type: string;
constructor(
name: string,
type: string,
) {
super();
this.name = name;
this.type = type;
}
getTreeItem(): vscode.TreeItem {
const item = new vscode.TreeItem(
this.name,
vscode.TreeItemCollapsibleState.Collapsed,
);
item.iconPath = new vscode.ThemeIcon('filter');
return item;
}
async getChildren(): Promise<UnilityJsonChildrenItem[] | UnilityRequestChildrenItem[]> {
if (this.type == 'json_format'){
const customQueries =
vscode.workspace
.getConfiguration(CONFIG_NAMESPACE)
.get<UtilityQuery[]>(EXECUTE_JSON_CHILDREN) || [];
const items = customQueries.map(q => new UnilityJsonChildrenItem(q.name, q.type));
return items;
}else {
const customQueries =
vscode.workspace
.getConfiguration(CONFIG_NAMESPACE)
.get<UtilityQuery[]>(EXECUTE_REQUEST_CHILDREN) || [];
const items = customQueries.map(q => new UnilityRequestChildrenItem(q.name, q.type));
return items;
}
}
}
import * as vscode from 'vscode';
import * as gitLabService from '../gitlab_service';
import { ErrorItem } from './items/error_item';
import { handleError } from '../log';
import { ItemModel } from './items/item_model';
import { extensionState } from '../extension_state';
import { gitExtensionWrapper } from '../git/git_extension_wrapper';
import { SnippetItem } from './items/snippet_item';
export class DataProvider implements vscode.TreeDataProvider<ItemModel | vscode.TreeItem> {
private eventEmitter = new vscode.EventEmitter<void>();
private disposableChildren: vscode.Disposable[] = [];
onDidChangeTreeData = this.eventEmitter.event;
constructor() {
extensionState.onDidChangeValid(this.refresh, this);
}
async getChildren(item: ItemModel | undefined): Promise<ItemModel[] | vscode.TreeItem[] | undefined> {
if (item) return item.getChildren();
this.disposableChildren.forEach(s => s.dispose());
this.disposableChildren = [];
const repository = gitExtensionWrapper.getActiveRepository();
if (!extensionState.isValid() || !repository) {
return [];
}
try {
const gitlabProject = await repository.getProject();
if (!gitlabProject) {
return [];
}
const projectCodeSnippets = await gitLabService.fetchSnippetForCurrentUser();
if (projectCodeSnippets.length === 0){
return [new vscode.TreeItem('未在当前项目下发现代码笔记')];
}
const snippets = projectCodeSnippets.map((s: RestCodeSnippet) => new SnippetItem(s.id, s.title));
return snippets;
} catch (e) {
handleError(e);
return [new ErrorItem()];
}
}
// eslint-disable-next-line class-methods-use-this
getParent(): null {
return null;
}
// eslint-disable-next-line class-methods-use-this
getTreeItem(item: vscode.TreeItem | ItemModel) {
if (item instanceof ItemModel) return item.getTreeItem();
return item;
}
refresh(): void {
this.eventEmitter.fire();
}
}
import * as vscode from 'vscode';
import * as dayjs from 'dayjs';
import * as relativeTime from 'dayjs/plugin/relativeTime';
import { ItemModel } from './items/item_model';
import { extensionState } from '../extension_state';
dayjs.extend(relativeTime);
class DataProvider implements vscode.TreeDataProvider<ItemModel | vscode.TreeItem> {
private eventEmitter = new vscode.EventEmitter<void>();
onDidChangeTreeData = this.eventEmitter.event;
private mr: RestMr | null = null;
private disposableChildren: vscode.Disposable[] = [];
constructor() {
extensionState.onDidChangeValid(this.refresh, this);
}
async fetchSnippetNote() {
if (this.mr) {
return [new vscode.TreeItem('笔记')];
}
return [new vscode.TreeItem('笔记')];
}
async getChildren(item: ItemModel | undefined): Promise<ItemModel[] | vscode.TreeItem[]> {
if (item) return item.getChildren();
const pipelineItem = await this.fetchSnippetNote();
return [pipelineItem] as vscode.TreeItem[];
}
// eslint-disable-next-line class-methods-use-this
getTreeItem(item: ItemModel | vscode.TreeItem) {
if (item instanceof ItemModel) return item.getTreeItem();
return item;
}
refresh() {
this.eventEmitter.fire();
}
}
exports.DataProvider = DataProvider;
import * as vscode from 'vscode';
import { UtilityItem } from './items/utility_item';
import { UtilityQuery } from '../gitlab/utility_query';
import { ItemModel } from './items/item_model';
import { UTILITIES, CONFIG_NAMESPACE } from '../constants';
import { extensionState } from '../extension_state';
import { gitExtensionWrapper } from '../git/git_extension_wrapper';
import { WrappedRepository } from '../git/wrapped_repository';
async function getAllGitlabRepositories(): Promise<WrappedRepository[]> {
const projectsWithUri = gitExtensionWrapper.repositories.map(async repository => {
await repository.getProject(); // make sure we tried to fetch the project
return repository;
});
return Promise.all(projectsWithUri);
}
export class DataProvider implements vscode.TreeDataProvider<ItemModel | vscode.TreeItem> {
private eventEmitter = new vscode.EventEmitter<void>();
private children: UtilityItem[] = [];
onDidChangeTreeData = this.eventEmitter.event;
constructor() {
extensionState.onDidChangeValid(this.refresh, this);
}
async getChildren(el: ItemModel | undefined): Promise<UtilityItem[] | ItemModel[] | vscode.TreeItem[]> {
if (el) return el.getChildren();
const customQueries =
vscode.workspace
.getConfiguration(CONFIG_NAMESPACE)
.get<UtilityQuery[]>(UTILITIES) || [];
this.children = customQueries.map(q => new UtilityItem(q.name, q.type));
return this.children;
}
// eslint-disable-next-line class-methods-use-this
getParent(): null {
return null;
}
// eslint-disable-next-line class-methods-use-this
getTreeItem(item: vscode.TreeItem | ItemModel) {
if (item instanceof ItemModel) return item.getTreeItem();
return item;
}
refresh(): void {
this.eventEmitter.fire();
}
}
import * as vscode from 'vscode';
import { ItemModel } from './items/item_model';
export class DataProvider implements vscode.TreeDataProvider<ItemModel | vscode.TreeItem> {
private eventEmitter = new vscode.EventEmitter<void>();
private children: ItemModel[] = [];
onDidChangeTreeData = this.eventEmitter.event;
// constructor() {
// extensionState.onDidChangeValid(this.refresh, this);
// }
async getChildren(el: ItemModel | undefined): Promise<ItemModel[] | vscode.TreeItem[]> {
if (el) return el.getChildren();
this.children.forEach(ch => ch.dispose());
this.children = [];
return this.children;
}
// eslint-disable-next-line class-methods-use-this
getParent(): null {
return null;
}
// eslint-disable-next-line class-methods-use-this
getTreeItem(item: vscode.TreeItem | ItemModel) {
if (item instanceof ItemModel) return item.getTreeItem();
return item;
}
refresh(): void {
this.eventEmitter.fire();
}
}
const vscode = require('vscode');
const openers = require('./openers');
const utility = require('./utility');
const tokenInput = require('./token_input');
const { tokenService } = require('./services/token_service');
const tokenServiceWrapper = require('./token_service_wrapper');
......@@ -8,11 +9,18 @@ const pipelineActionsPicker = require('./pipeline_actions_picker');
const searchInput = require('./search_input');
const { createSnippet } = require('./commands/create_snippet');
const { insertSnippet } = require('./commands/insert_snippet');
const { createNote, newNoteTextDocument } = require('./commands/create_note');
const { jsonFormat } = require('./commands/json_format')
const { httpRequest, showHttpConfig } = require('./commands/http_request')
const sidebar = require('./sidebar');
const ciConfigValidator = require('./ci_config_validator');
const { webviewController } = require('./webview_controller');
const { snippetWebviewController } = require('./snippet_webview_controller')
const IssuableDataProvider = require('./data_providers/issuable').DataProvider;
const CurrentBranchDataProvider = require('./data_providers/current_branch').DataProvider;
const SnippetNoteDataProvider = require('./data_providers/snippet_note_data_provider').DataProvider;
// const UtilityToolsDataProvider = require('./data_providers/utility_tools').DataProvider;
const UtilityToolsDataProvider = require('./data_providers/utility').DataProvider;
const { initializeLogging, handleError } = require('./log');
const { GitContentProvider } = require('./review/git_content_provider');
const { REVIEW_URI_SCHEME } = require('./constants');
......@@ -51,6 +59,10 @@ const registerSidebarTreeDataProviders = () => {
const currentBranchDataProvider = new CurrentBranchDataProvider();
const snippetNoteDataProvider = new SnippetNoteDataProvider();
const utilityToolsDataProvider = new UtilityToolsDataProvider()
const register = (name, provider) => {
vscode.window.registerTreeDataProvider(name, provider);
vscode.gitLabWorkflow.sidebarDataProviders.push(provider);
......@@ -58,6 +70,8 @@ const registerSidebarTreeDataProviders = () => {
register('issuesAndMrs', issuableDataProvider);
register('currentBranchInfo', currentBranchDataProvider);
register('snippetNotes', snippetNoteDataProvider);
register('utilityTools', utilityToolsDataProvider);
};
const registerCommands = (context, outputChannel) => {
......@@ -65,6 +79,10 @@ const registerCommands = (context, outputChannel) => {
[USER_COMMANDS.SHOW_ISSUES_ASSIGNED_TO_ME]: openers.showIssues,
[USER_COMMANDS.SHOW_MERGE_REQUESTS_ASSIGNED_TO_ME]: openers.showMergeRequests,
[USER_COMMANDS.SET_TOKEN]: tokenInput.showInput,
[USER_COMMANDS.WEBVIEW]: openers.openSnippet,
[USER_COMMANDS.JSON_FORMAT]: jsonFormat,
[USER_COMMANDS.HTTP_REQUEST]: showHttpConfig,
[USER_COMMANDS.DO_HTTP_REQUEST]: httpRequest,
[USER_COMMANDS.REMOVE_TOKEN]: tokenInput.removeTokenPicker,
[USER_COMMANDS.OPEN_ACTIVE_FILE]: openers.openActiveFile,
[USER_COMMANDS.COPY_LINK_TO_ACTIVE_FILE]: openers.copyLinkToActiveFile,
......@@ -80,6 +98,8 @@ const registerCommands = (context, outputChannel) => {
[USER_COMMANDS.COMPARE_CURRENT_BRANCH]: openers.compareCurrentBranch,
[USER_COMMANDS.CREATE_SNIPPET]: createSnippet,
[USER_COMMANDS.INSERT_SNIPPET]: insertSnippet,
[USER_COMMANDS.CREATE_NOTE]: createNote,
[USER_COMMANDS.OPEN_NOTE_DOCUMENT]: newNoteTextDocument,
[USER_COMMANDS.VALIDATE_CI_CONFIG]: ciConfigValidator.validate,
[USER_COMMANDS.REFRESH_SIDEBAR]: sidebar.refresh,
[PROGRAMMATIC_COMMANDS.SHOW_RICH_CONTENT]: webviewController.open.bind(webviewController),
......@@ -94,6 +114,9 @@ const registerCommands = (context, outputChannel) => {
[USER_COMMANDS.CHECKOUT_MR_BRANCH]: checkoutMrBranch,
[USER_COMMANDS.CLONE_WIKI]: cloneWiki,
[USER_COMMANDS.CREATE_SNIPPET_PATCH]: createSnippetPatch,
[USER_COMMANDS.OPEN_SNIPPET]: openers.openSnippet,
[USER_COMMANDS.OPEN_PROJECT_SNIPPET]: openers.openProjectSnippet,
[USER_COMMANDS.UTILITY]: utility.executeCommand,
[PROGRAMMATIC_COMMANDS.NO_IMAGE_REVIEW]: () =>
vscode.window.showInformationMessage("GitLab MR review doesn't support images yet."),
};
......@@ -119,12 +142,13 @@ const registerCiCompletion = context => {
* @param {vscode.ExtensionContext} context
*/
const activate = context => {
const outputChannel = vscode.window.createOutputChannel('GitLab Workflow');
const outputChannel = vscode.window.createOutputChannel('CSDN Workflow');
initializeLogging(line => outputChannel.appendLine(line));
vscode.workspace.registerTextDocumentContentProvider(REVIEW_URI_SCHEME, new GitContentProvider());
registerCommands(context, outputChannel);
const isDev = process.env.NODE_ENV === 'development';
webviewController.init(context, isDev);
snippetWebviewController.init(context);
tokenService.init(context);
tokenServiceWrapper.init(context);
extensionState.init(tokenService);
......
......@@ -4,6 +4,7 @@ import { TokenService } from './services/token_service';
import { gitExtensionWrapper } from './git/git_extension_wrapper';
const hasOpenRepositories = (): boolean => gitExtensionWrapper.repositories.length > 0;
const hasInstanceRemote = (): boolean => gitExtensionWrapper.repositories.map(r=>r.instanceUrl).length > 0
export class ExtensionState {
private changeValidEmitter = new vscode.EventEmitter<void>();
......@@ -37,7 +38,10 @@ export class ExtensionState {
'gitlab:noRepository',
!hasOpenRepositories(),
);
await vscode.commands.executeCommand('setContext', 'gitlab:noInstanceRemote', !hasInstanceRemote());
await vscode.commands.executeCommand('setContext', 'gitlab:validState', this.isValid());
await vscode.commands.executeCommand('setContext', 'gitlab:noTokens', !this.hasAnyTokens());
await vscode.commands.executeCommand('setContext', 'gitlab:hasAnyToken', this.hasAnyTokens());
if (this.lastValid !== this.isValid()) {
this.lastValid = this.isValid();
this.changeValidEmitter.fire();
......
export interface UtilityQuery {
name: string;
type: string;
}
import * as vscode from 'vscode';
import * as request from 'request-promise';
import * as assert from 'assert';
import { tokenService } from './services/token_service';
import { UserFriendlyError } from './errors/user_friendly_error';
import { ApiError } from './errors/api_error';
......@@ -14,6 +13,7 @@ import { getInstanceUrl } from './utils/get_instance_url';
import { GitLabProject } from './gitlab/gitlab_project';
import { gitExtensionWrapper } from './git/git_extension_wrapper';
import { getExtensionConfiguration } from './utils/get_extension_configuration';
import { GITLAB_COM_URL } from './constants';
export interface RestJob {
name: string;
......@@ -51,7 +51,7 @@ async function fetch(
if (!glToken) {
let err = `
GitLab Workflow: Cannot make request.
CSDN Workflow: Cannot make request.
GitLab URL for this workspace is set to ${instanceUrl}
and there is no matching token for this URL.
`;
......@@ -98,6 +98,70 @@ async function fetch(
return await request(`${apiRoot}${path}`, config);
}
async function userFetch(
path: string,
method = 'GET',
data?: Record<string, unknown>,
notParseJson?: boolean
) {
const instanceUrl = GITLAB_COM_URL;
const apiRoot = `${instanceUrl}/api/v4`;
const glToken = tokenService.getToken(instanceUrl);
const tokens = tokenService.getInstanceUrls().join(', ');
if (!glToken) {
let err = `
CSDN Workflow: 无法执行此操作,没有读取用户登陆信息
`;
if (tokens.length) {
err = `${err} You have configured tokens for ${tokens}.`;
}
await vscode.window.showInformationMessage(err);
throw new Error(err);
}
const config: request.RequestPromiseOptions = {
method,
headers: {
'PRIVATE-TOKEN': glToken,
...getUserAgentHeader(),
},
...getHttpAgentOptions(),
};
if (data) {
config.formData = data;
}
config.transform = (body, response) => {
try {
if (notParseJson) {
return {
response: body,
headers: response.headers,
};
}
return {
response: JSON.parse(body),
headers: response.headers,
};
} catch (e) {
handleError(
new UserFriendlyError(
'Failed to parse API response',
e,
`Response body: ${body}\nRequest URL: ${apiRoot}${path}`,
),
);
return { error: e };
}
};
return await request(`${apiRoot}${path}`, config);
}
async function fetchCurrentProject(repositoryRoot: string): Promise<GitLabProject | null> {
try {
const repository = gitExtensionWrapper.getRepository(repositoryRoot);
......@@ -155,6 +219,7 @@ async function fetchFirstUserByUsername(repositoryRoot: string, userName: string
}
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function fetchVersion(repositoryRoot: string) {
try {
if (!versionCache) {
......@@ -189,6 +254,7 @@ async function fetchLastPipelineForCurrentBranch(
type QueryValue = string | boolean | string[] | number | undefined;
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function fetchIssuables(params: CustomQuery, repositoryRoot: string) {
const { type, scope, state, author, assignee, wip } = params;
let { searchIn, pipelineId, reviewer } = params;
......@@ -349,6 +415,7 @@ export async function fetchIssuables(params: CustomQuery, repositoryRoot: string
return issuable.map(normalizeAvatarUrl(await getInstanceUrl(repositoryRoot)));
}
export async function fetchLastJobsForCurrentBranch(
repositoryRoot: string,
pipeline: RestPipeline,
......@@ -429,6 +496,7 @@ export async function fetchPipelineAndMrForCurrentBranch(
*
* @param {string} action create|retry|cancel
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function handlePipelineAction(action: string, repositoryRoot: string) {
const { pipeline } = await fetchPipelineAndMrForCurrentBranch(repositoryRoot);
const project = await fetchCurrentProjectSwallowError(repositoryRoot);
......@@ -450,7 +518,7 @@ export async function handlePipelineAction(action: string, repositoryRoot: strin
throw new UserFriendlyError(`Failed to ${action} pipeline.`, e);
}
} else {
await vscode.window.showErrorMessage('GitLab Workflow: No project or pipeline found.');
await vscode.window.showErrorMessage('CSDN Workflow: No project or pipeline found.');
return undefined;
}
}
......@@ -475,6 +543,7 @@ export async function fetchMRIssues(mrId: number, repositoryRoot: string): Promi
}
// TODO specify the correct interface when we convert `create_snippet.js`
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function createSnippet(repositoryRoot: string, data: { id: number }) {
try {
const { response } = await fetch(repositoryRoot, `/projects/${data.id}/snippets`, 'POST', data);
......@@ -483,6 +552,57 @@ export async function createSnippet(repositoryRoot: string, data: { id: number }
throw new UserFriendlyError('Failed to create your snippet.', e);
}
}
// 创建笔记
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function createNote(data: { content: string }) {
try {
const { response } = await userFetch(`/snippets`, 'POST', data);
return response;
} catch (e) {
throw new UserFriendlyError('Failed to create your snippet.', e);
}
}
async function fetchSnippetContent(snippetId: number, filePath: string): Promise<CodeSnippetFile> {
const fileContent: CodeSnippetFile = {
size: 0,
file_path: filePath,
content: ''
}
try {
const { response, headers: { 'content-length': size } } = await userFetch(`/snippets/${snippetId}/files/master/${filePath}/raw`, 'GET', undefined, true);
fileContent.size = size
fileContent.content = response
return fileContent
} catch (e) {
return fileContent
}
}
export async function fetchSnippet(snippetId: number): Promise<RestCodeSnippet> {
const { response } = await userFetch(`/snippets/${snippetId}`, 'GET');
console.log(response)
try {
const snippet: RestCodeSnippet = {
id: snippetId,
author: response.author,
file_name: response.file_name,
title: response.title,
web_url: response.web_url,
visibility: response.visibility,
description: response.description,
ssh_url_to_repo: response.ssh_url_to_repo,
http_url_to_repo: response.http_url_to_repo,
updated_at: response.updated_at
}
snippet.files = await Promise.all(response.files.map(async (f: SnippetFile) => {
return fetchSnippetContent(snippetId, f.path)
}))
return snippet;
} catch (e) {
throw new UserFriendlyError('Failed to open this snippet.', e);
}
}
interface ValidationResponse {
status?: string;
......@@ -505,6 +625,7 @@ export async function validateCIConfig(
}
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function renderMarkdown(markdown: string, repositoryRoot: string) {
let rendered = { html: markdown };
const version = await fetchVersion(repositoryRoot);
......@@ -532,3 +653,34 @@ export async function renderMarkdown(markdown: string, repositoryRoot: string) {
return rendered.html;
}
export async function fetchSnippetForCurrentProject(
repositoryRoot: string,
): Promise<Array<RestCodeSnippet> | []> {
const project = await fetchCurrentProject(repositoryRoot);
let projectCodeSnippets = [];
const path = `/projects/${project?.restId}/snippets`;
const { response } = await fetch(repositoryRoot, path);
projectCodeSnippets = response;
if (projectCodeSnippets.length > 0) {
return projectCodeSnippets;
}
return [];
}
export async function fetchSnippetForCurrentUser(): Promise<Array<RestCodeSnippet> | []> {
let projectCodeSnippets = [];
const path = `/snippets`;
const { response } = await userFetch(path);
projectCodeSnippets = response;
if (projectCodeSnippets.length > 0) {
return projectCodeSnippets;
}
return [];
}
......@@ -6,6 +6,7 @@ import { handleError } from './log';
import { VS_COMMANDS } from './command_names';
import { gitExtensionWrapper } from './git/git_extension_wrapper';
import { WrappedRepository } from './git/wrapped_repository';
import { snippetWebviewController } from './snippet_webview_controller'
export const openUrl = async (url: string): Promise<void> =>
vscode.commands.executeCommand(VS_COMMANDS.OPEN, vscode.Uri.parse(url));
......@@ -48,7 +49,7 @@ export async function showMergeRequests(): Promise<void> {
async function getActiveFile() {
const editor = vscode.window.activeTextEditor;
if (!editor) {
await vscode.window.showInformationMessage('GitLab Workflow: No open file.');
await vscode.window.showInformationMessage('CSDN Workflow: No open file.');
return undefined;
}
......@@ -56,7 +57,7 @@ async function getActiveFile() {
if (!repository) {
await vscode.window.showInformationMessage(
'GitLab Workflow: Open file isn’t part of a repository.',
'CSDN Workflow: Open file isn’t part of a repository.',
);
return undefined;
}
......@@ -148,3 +149,12 @@ export async function compareCurrentBranch(): Promise<void> {
await openUrl(`${project.webUrl}/compare/master...${repository.lastCommitSha}`);
}
}
export async function openSnippet(snippetId: number): Promise<void> {
const snippet = await gitLabService.fetchSnippet(snippetId);
await snippetWebviewController.open(snippet);
}
export async function openProjectSnippet(snippetId: number): Promise<void> {
await openTemplatedLink('$projectUrl/snippets/$snippetId');
}
......@@ -7,7 +7,7 @@ const { instance: statusBar } = require('./status_bar');
async function showPicker() {
const items = [
{
label: 'View latest pipeline on GitLab',
label: 'View latest pipeline on CSDN',
action: 'view',
},
{
......
import * as fs from 'fs';
import * as path from 'path';
import * as vscode from 'vscode';
import * as assert from 'assert';
import * as crypto from 'crypto';
import * as cheerio from 'cheerio';
import * as timeago from 'timeago.js';
import * as hljs from 'highlight.js';
import * as marked from 'marked';
class SnippetWebviewController {
context?: vscode.ExtensionContext;
openedPanels: Record<string, vscode.WebviewPanel | undefined> = {};
hash?: string;
init(context: vscode.ExtensionContext) {
this.context = context;
}
private getIndexPath() {
assert(this.context);
return 'src/webview/public/index.html';
}
private replaceResources() {
assert(this.context);
const nonce = crypto.randomBytes(20).toString('hex');
this.hash = nonce;
return fs
.readFileSync(path.join((this.context?.extensionPath || './'), this.getIndexPath()), 'UTF-8')
.replace(/{{nonce}}/gm, this.hash)
}
private createPanel(snippet: RestCodeSnippet) {
assert(this.context);
const title = `${snippet.title.slice(0, 20)}...`;
return vscode.window.createWebviewPanel('glWorkflow', title, vscode.ViewColumn.One, {
enableScripts: true,
localResourceRoots: [vscode.Uri.file(path.join((this.context?.extensionPath || './'), 'src'))],
retainContextWhenHidden: true,
});
}
async open(snippet: RestCodeSnippet) {
const panelKey = `snippets-${snippet.id}`;
const openedPanel = this.openedPanels[panelKey];
if (openedPanel) {
openedPanel.reveal();
return openedPanel;
}
const newPanel = await this.create(snippet);
this.openedPanels[panelKey] = newPanel;
newPanel.onDidDispose(() => {
this.openedPanels[panelKey] = undefined;
});
newPanel.webview.onDidReceiveMessage(
async message => {
switch (message.command) {
case 'copySnippet':
await this.copySnippet((snippet.files || []), message.text);
break;
case 'copyShareLink':
await this.copyShareLink(snippet.web_url)
break;
default:
break;
}
}
);
return newPanel;
}
private async create(snippet: RestCodeSnippet) {
assert(this.context);
const panel = this.createPanel(snippet);
const html = this.replaceResources();
panel.webview.html = this.fillInApp(html, this.getSnippetHtml(snippet));
return panel;
}
getSnippetHtml(snippet: RestCodeSnippet): string {
assert(this.context)
const snippetStyle = fs.readFileSync(path.join((this.context?.extensionPath || './'), 'src/assets/styles/snippet.css'), 'UTF-8').toString()
const html = `
<style>${snippetStyle}</style>
${this.getSnippetHeaderHtml(snippet)}
<h1 class="snippet_title">${snippet.title}</h1>
<div class="snippet_desc md_preview">${this.marked(snippet.description)}</div>
${this.getSnippetFileHtml(snippet.files || [])}
`
return html
}
highlightCode(content: string) {
assert(this.context);
if (!content) return ''
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const highlightContent = (hljs as any).highlightAuto(content).value;
return this.generateCodeLineNum(highlightContent);
}
marked(content: string) {
assert(this.context);
if (!content) return ''
marked.setOptions({
breaks: false,
gfm: true,
langPrefix: "language-",
// eslint-disable-next-line func-names
'highlight': function (code) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const html = (hljs as any).highlightAuto(code).value;
return html;
}
});
const html = marked(content); // 解析markdown
return html
}
generateCodeLineNum(content: string) {
assert(this.context);
if (!content) return ''
return `<ul><li>${content.replace(/\n/g, "\n</li><li>")}\n</li></ul>`
}
getSnippetHeaderHtml(snippet: RestCodeSnippet): string {
assert(this.context)
const {
author: { avatar_url: avatar, name },
updated_at: updatedAt,
web_url: url
} = snippet
const html = `
<header class="snippet_header">
<img src="${avatar}">
<span class="flex-1">
${timeago.format(updatedAt, 'zh_CN')}由 <b>${name}</b> 创建
</span>
<a href="${url}">在 CSDN 中打开并查看</a>
<a href="javascript:void(0)" id="shareLink">分享</a>
</header>
<script nonce="${this.hash}">
document.getElementById("shareLink").onclick = function() {
vscode.postMessage({
command: 'copyShareLink',
text: ''
})
}
</script>
`
// <a>编辑</a>
// <a>删除</a>
return html
}
getSnippetFileHtml(files: CodeSnippetFile[]): string {
assert(this.context)
const hightlightStyle = fs.readFileSync(path.join((this.context?.extensionPath || './'), 'src/assets/styles/highlight-dark.css'), 'UTF-8').toString()
const mdStyle = fs.readFileSync(path.join((this.context?.extensionPath || './'), 'src/assets/styles/marked.css'), 'UTF-8').toString()
return `
<style>
${hightlightStyle}
${mdStyle}
</style>
<div id="snippet_list">
${files.map((f, i) => {
const isMd = f.file_path.split('.').pop() === 'md'
return `
<div class="snippet_item_container">
<div class="snippet_item_header">
<div class="snippet_item_title">${f.file_path}</div>
<div class="snippet_item_size">${f.size}字节</div>
<a href="javascript:void(0)" data-index="${i}" class="snippet_item_copy">复制代码</a>
</div>
<div class="snippet_item_body">
<div class="snippet_content">
${isMd ? `<div class="md_preview">${this.marked(f.content)}</div>` : `<pre><code class="hljs">${this.highlightCode(f.content)}</code></pre>`}
</div>
</div>
</div>`
}).join('')}
</div>
<script nonce="${this.hash}">
const vscode = acquireVsCodeApi();
document.getElementById("snippet_list").addEventListener("click", function(e) {
const target = e.target || e.srcElement
const snippetIndex = target.dataset.index
vscode.postMessage({
command: 'copySnippet',
text: snippetIndex
})
})
</script>
`
}
async copySnippet(files: CodeSnippetFile[], index: number) {
assert(this.context);
const snippetContent = files[index]?.content
await vscode.env.clipboard.writeText(snippetContent)
await vscode.window.showInformationMessage('代码已复制到剪切板')
}
async copyShareLink(link: string) {
assert(this.context);
await vscode.env.clipboard.writeText(link)
await vscode.window.showInformationMessage('分享链接已复制到剪切板')
}
fillInApp(templateHtml: string, html: string): string {
assert(this.context)
const $ = cheerio.load(templateHtml)
$('div#app').html(html)
return $.html()
}
}
export const snippetWebviewController = new SnippetWebviewController();
......@@ -15,7 +15,7 @@ const {
showIssueLinkOnStatusBar,
showMrStatusOnStatusBar,
showPipelineUpdateNotifications,
} = vscode.workspace.getConfiguration('gitlab');
} = vscode.workspace.getConfiguration('csdn');
const iconForStatus: Record<string, { icon: string; text?: string } | undefined> = {
running: { icon: 'pulse' },
......@@ -71,7 +71,7 @@ export class StatusBar {
firstRun = true;
async refresh() {
async refresh(): Promise<void> {
const repository = gitExtensionWrapper.getActiveRepository();
if (!repository) return;
......@@ -100,7 +100,7 @@ export class StatusBar {
async updatePipelineItem(pipeline: RestPipeline | null, repositoryRoot: string): Promise<void> {
if (!this.pipelineStatusBarItem) return;
if (!pipeline) {
this.pipelineStatusBarItem.text = 'GitLab: No pipeline.';
this.pipelineStatusBarItem.text = 'CSDN: No pipeline.';
this.pipelineStatusBarItem.show();
this.firstRun = false;
return;
......@@ -119,7 +119,7 @@ export class StatusBar {
}
}
const msg = `$(${iconForStatus[status]?.icon}) GitLab: Pipeline ${statusText}`;
const msg = `$(${iconForStatus[status]?.icon}) CSDN: Pipeline ${statusText}`;
if (
showPipelineUpdateNotifications &&
......@@ -146,12 +146,12 @@ export class StatusBar {
if (!this.mrIssueStatusBarItem) return;
if (mr) {
const issues = await gitLabService.fetchMRIssues(mr.iid, repositoryRoot);
let text = `$(code) GitLab: No issue.`;
let text = `$(code) CSDN: No issue.`;
let command;
const firstIssue = issues[0];
if (firstIssue) {
text = `$(code) GitLab: Issue #${firstIssue.iid}`;
text = `$(code) CSDN: Issue #${firstIssue.iid}`;
command = openIssuableOnTheWebCommand(firstIssue);
}
......@@ -169,21 +169,21 @@ export class StatusBar {
? openIssuableOnTheWebCommand(mr)
: USER_COMMANDS.OPEN_CREATE_NEW_MR;
this.mrStatusBarItem.text = mr
? `$(git-pull-request) GitLab: MR !${mr.iid}`
: '$(git-pull-request) GitLab: Create MR.';
? `$(git-pull-request) CSDN: MR !${mr.iid}`
: '$(git-pull-request) CSDN: Create MR.';
}
async init() {
async init(): Promise<void> {
if (showStatusBarLinks) {
this.pipelineStatusBarItem = createStatusBarItem(
'$(info) GitLab: Fetching pipeline...',
'$(info) CSDN: Fetching pipeline...',
USER_COMMANDS.PIPELINE_ACTIONS,
);
if (showMrStatusOnStatusBar) {
this.mrStatusBarItem = createStatusBarItem('$(info) GitLab: Finding MR...');
this.mrStatusBarItem = createStatusBarItem('$(info) CSDN: Finding MR...');
if (showIssueLinkOnStatusBar) {
this.mrIssueStatusBarItem = createStatusBarItem(
'$(info) GitLab: Fetching closing issue...',
'$(info) CSDN: Fetching closing issue...',
);
}
}
......@@ -195,7 +195,7 @@ export class StatusBar {
}
}
dispose() {
dispose(): void {
if (showStatusBarLinks) {
this.pipelineStatusBarItem?.dispose();
......
......@@ -3,21 +3,15 @@ const { GITLAB_COM_URL } = require('./constants');
const { tokenService } = require('./services/token_service');
async function showInput() {
const instance = await vscode.window.showInputBox({
ignoreFocusOut: true,
value: GITLAB_COM_URL,
placeHolder: 'E.g. https://gitlab.com',
prompt: 'URL to Gitlab instance',
});
const token = await vscode.window.showInputBox({
ignoreFocusOut: true,
password: true,
placeHolder: 'Paste your GitLab Personal Access Token...',
placeHolder: '请在此处粘贴您在 CSDN codechina 平台的用户访问令牌',
});
if (instance && token) {
await tokenService.setToken(instance, token);
if (token) {
await tokenService.setToken(GITLAB_COM_URL, token);
}
}
......@@ -25,7 +19,7 @@ async function removeTokenPicker() {
const instanceUrls = tokenService.getInstanceUrls();
const selectedInstanceUrl = await vscode.window.showQuickPick(instanceUrls, {
ignoreFocusOut: true,
placeHolder: 'Select Gitlab instance for PAT removal',
placeHolder: '点击 URL 以确认删除用户访问令牌',
});
if (selectedInstanceUrl) {
......
......@@ -8,7 +8,7 @@ let active = false;
// FIXME: if you are touching this configuration statement, move the configuration to get_extension_configuration.ts
const currentInstanceUrl = () =>
vscode.workspace.getConfiguration('gitlab').instanceUrl || GITLAB_COM_URL;
vscode.workspace.getConfiguration('csdn').instanceUrl || GITLAB_COM_URL;
const getToken = () => tokenService.getToken(currentInstanceUrl());
......@@ -27,7 +27,7 @@ const updateExtensionStatus = () => {
const watchConfigurationChanges = () => {
vscode.workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('gitlab')) {
if (e.affectsConfiguration('csdn')) {
updateExtensionStatus();
}
});
......
......@@ -28,13 +28,6 @@ interface RestMr extends RestIssuable {
source_branch: string;
}
interface RestMrVersion {
head_commit_sha: string;
base_commit_sha: string;
start_commit_sha: string;
diffs: RestDiffFile[];
}
interface RestDiffFile {
new_path: string;
old_path: string;
......@@ -44,6 +37,13 @@ interface RestDiffFile {
diff: string;
}
interface RestMrVersion {
head_commit_sha: string;
base_commit_sha: string;
start_commit_sha: string;
diffs: RestDiffFile[];
}
interface RestVulnerability {
location?: {
file: string;
......@@ -68,3 +68,37 @@ interface RestUser {
email: string;
state: string;
}
interface CodeSnippetFile {
size: number,
file_path: string;
content: string;
}
interface SnippetFile {
size: number,
path: string;
raw_url: string;
}
interface SnippetAuthor {
id: number;
name: string;
user_name: string;
avatar_url: string;
web_url: string;
}
interface RestCodeSnippet {
id: number;
author: SnippetAuthor;
file_name: string;
title: string;
web_url: string;
visibility: string;
description: string;
files?: CodeSnippetFile[];
ssh_url_to_repo?: string;
http_url_to_repo?: string;
updated_at: Date;
}
import * as vscode from 'vscode';
import { USER_COMMANDS} from './command_names';
export const executeCommand = async (type: string): Promise<void> =>
vscode.commands.executeCommand(await getCommandByType(type));
async function getCommandByType(type: string) : Promise<string> {
if (type === 'json_format'){
return USER_COMMANDS.JSON_FORMAT;
}
if (type === 'execute_this_request'){
return USER_COMMANDS.DO_HTTP_REQUEST;
}
if (type === 'config_file'){
return USER_COMMANDS.HTTP_REQUEST;
}
return '';
}
......@@ -15,7 +15,7 @@ export const getHttpAgentOptions = (): GitLabHttpAgentOptions => {
const result: GitLabHttpAgentOptions = {};
// FIXME: if you are touching this configuration statement, move the configuration to get_extension_configuration.ts
const { ignoreCertificateErrors, ca, cert, certKey } = vscode.workspace.getConfiguration(
'gitlab',
'csdn',
);
result.rejectUnauthorized = !ignoreCertificateErrors;
......
......@@ -2,12 +2,12 @@ import * as vscode from 'vscode';
export const getUserAgentHeader = (): Record<string, string> => {
const extension = vscode.extensions.getExtension('GitLab.gitlab-workflow');
const extensionVersion = extension?.packageJSON?.version;
const extensionVersion = extension?.packageJSON?.version || "default";
const nodePlatform = `Node.js/${process.version.substr(1)} (${process.platform}; ${
process.arch
})`;
const vsCodeVersion = vscode.version;
return {
'User-Agent': `vs-code-gitlab-workflow/${extensionVersion} VSCode/${vsCodeVersion} ${nodePlatform}`,
'User-Agent': `vs-code-csdn-workflow/${extensionVersion} VSCode/${vsCodeVersion} ${nodePlatform}`,
};
};
......@@ -2259,17 +2259,6 @@
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
"dev": true,
"optional": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
......@@ -2302,31 +2291,12 @@
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"optional": true
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true
},
"loader-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
"dev": true,
"optional": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
},
"ssri": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
......@@ -2347,28 +2317,6 @@
"strip-ansi": "^6.0.0"
}
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"optional": true,
"requires": {
"has-flag": "^4.0.0"
}
},
"vue-loader-v16": {
"version": "npm:vue-loader@16.2.0",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.2.0.tgz",
"integrity": "sha512-TitGhqSQ61RJljMmhIGvfWzJ2zk9m1Qug049Ugml6QP3t0e95o0XJjk29roNEiPKJQBEi8Ord5hFuSuELzSp8Q==",
"dev": true,
"optional": true,
"requires": {
"chalk": "^4.1.0",
"hash-sum": "^2.0.0",
"loader-utils": "^2.0.0"
}
},
"wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
......@@ -13945,6 +13893,87 @@
}
}
},
"vue-loader-v16": {
"version": "npm:vue-loader@16.5.0",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.5.0.tgz",
"integrity": "sha512-WXh+7AgFxGTgb5QAkQtFeUcHNIEq3PGVQ8WskY5ZiFbWBkOwcCPRs4w/2tVyTbh2q6TVRlO3xfvIukUtjsu62A==",
"dev": true,
"optional": true,
"requires": {
"chalk": "^4.1.0",
"hash-sum": "^2.0.0",
"loader-utils": "^2.0.0"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"optional": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"optional": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"optional": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
"optional": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"optional": true
},
"loader-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
"dev": true,
"optional": true,
"requires": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
}
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"optional": true,
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"vue-resize": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-0.4.5.tgz",
......
......@@ -2,9 +2,10 @@
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src vscode-resource: https:; script-src 'nonce-{{nonce}}' 'unsafe-eval'; style-src 'unsafe-inline';">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src vscode-resource: https:; script-src 'nonce-{{nonce}}' 'unsafe-eval'; style-src 'unsafe-inline' 'nonce-{{nonce}}';">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>GitLab Workflow</title>
<title>CSDN Workflow</title>
<link nonce="{{nonce}}" href="{{styleUri}}" rel="stylesheet" type="text/css">
</head>
<body>
<div id="app"></div>
......
......@@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy" content="img-src vscode-resource: https:; script-src 'nonce-{{nonce}}';">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>GitLab Workflow</title>
<title>CSDN Workflow</title>
<link href="{{styleUri}}" rel="stylesheet" type="text/css">
</head>
<body>
......
export default {
gitLabLogo:
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M29.782 199.732L256 493.714 8.074 309.699c-6.856-5.142-9.712-13.996-7.141-21.993l28.849-87.974zm75.405-174.806c-3.142-8.854-15.709-8.854-18.851 0L29.782 199.732h131.961L105.187 24.926zm56.556 174.806L256 493.714l94.257-293.982H161.743zm349.324 87.974l-28.849-87.974L256 493.714l247.926-184.015c6.855-5.142 9.711-13.996 7.141-21.993zm-85.404-262.78c-3.142-8.854-15.709-8.854-18.851 0l-56.555 174.806h131.961L425.663 24.926z"></path></svg>',
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="currentColor" d="M 12.767 12.046 C 12.608 11.896 12.399 11.814 12.183 11.816 C 11.972 11.817 11.776 11.909 11.636 12.066 C 10.404 13.478 8.26 13.631 7.384 13.631 C 5.779 13.631 4.55 13.222 3.733 12.419 C 2.955 11.656 2.546 10.534 2.524 9.08 C 2.469 5.713 4.372 2.23 7.671 2.23 C 9.248 2.23 10.468 3.346 10.921 3.829 C 11.075 3.994 11.289 4.09 11.52 4.092 C 11.741 4.099 11.953 4.002 12.095 3.834 L 12.221 3.681 C 12.482 3.37 12.605 2.96 12.554 2.556 C 12.505 2.132 12.292 1.744 11.961 1.473 C 10.801 0.51 9.336 -0.014 7.826 0 C 5.796 0 3.792 0.934 2.326 2.565 C 0.78 4.277 -0.043 6.608 0.002 9.125 C 0.037 11.145 0.7 12.846 1.92 14.04 C 3.227 15.325 5.14 16 7.462 16 C 10.184 16 11.872 15.193 12.807 14.519 C 13.168 14.255 13.389 13.841 13.402 13.394 C 13.414 12.928 13.229 12.48 12.886 12.162 Z"/></path></svg>',
label:
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="currentColor" d="M15 1H9.828a2 2 0 0 0-1.414.586L1.586 8.414a2 2 0 0 0 0 2.828l3.172 3.172a2 2 0 0 0 2.828 0l6.828-6.828A2 2 0 0 0 15 6.172V1zm-4 5a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"></path></svg>',
comment_dots:
......
......@@ -68,7 +68,7 @@ export default {
by
<user-avatar :user="issuable.author" :show-handle="false" />
<a :href="issuable.web_url" class="view-link">
Open in GitLab
在 CSDN 中打开并查看
</a>
</div>
<div class="title">
......
因为 它太大了无法显示 source diff 。你可以改为 查看blob
......@@ -58,7 +58,7 @@ describe('Validate CI config', async () => {
const informationMessageMock = sandbox
.mock(vscode.window)
.expects('showInformationMessage')
.withArgs('GitLab Workflow: Your CI configuration is valid.')
.withArgs('CSDN Workflow: Your CI configuration is valid.')
.resolves();
await insertTextIntoActiveEditor(VALID_CI_CONFIG);
......@@ -78,7 +78,7 @@ describe('Validate CI config', async () => {
assert.deepStrictEqual(errorMessages, [
'jobs:test config contains unknown keys: scccript',
'GitLab Workflow: Invalid CI configuration.',
'CSDN Workflow: Invalid CI configuration.',
]);
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册