# Knowledge Base

This repository holds content for the Knowledge Base available to PingCAP customers and others who have been given access.

This content is published to the PingCAP support portal at <https://support.pingcap.com/hc/>.

## Style guidelines

This repository should contain Markdown files. They'll be processed by pandoc to convert them to HTML and apply syntax highlighting and other useful transformations.

To mark a code block with a certain language, write the name of the language after the opening backticks of the code block to apply the correct class.

Notes:

- Use the **`bash`** class for shell code (not `shell` or `sh`).
  - Do **not** include a leading prompt character (`$` or `#`) -- that will be added automatically
- Use **`sql`** for SQL statements
  - Do **not** include a leading `mysql>` or `MySQL>` prompt -- that will be added automatically
- Consult [`highlightLanguages.txt`](highlightLanguages.txt) for the full list of supported highlight languages

### Code block highlighting and classes

If you want the code block to be copyable, give it the "`copyable`" class. This will (eventually) cause a nice clipboard widget to be added to the rendered HTML.

To apply multiple classes, you must use a somewhat different syntax. For example:

````
```bash
if [[ -f /tmp/file ]]
then
   echo "File exists"
fi
```

```{.bash .copyable}
if [[ -f /tmp/file ]]
then
   echo "File exists"
fi
```
````

If your code block shows the output of a command (rather than something a user should copy and execute), please give it the "output" class:

````
```{.bash .copyable}
echo "This is the output of some program"
```

```output
This is the output of some program
```
````

#### Custom prompts

If you want to use a custom prompt, for example to distinguish between an "upstream" and "downstream" cluster, or between "MySQL" and "TiDB", or similar, you can!

- Shell

  If you want a "root" prompt, with a `#` prefix instead of `$`, add the `prompt-root` class to your block:

  ````
  ```{.bash .copyable .prompt-root}
  reboot
  ```
  ````

- MySQL

  ````
  ```{.sql .copyable .custom-prompt .prompt-MySQL}
  select version();
  ```

  ```{.sql .copyable .custom-prompt .prompt-TiDB}
  select @@tidb_version\G
  ```
  ````

  Will be rendered like this:

  ```
  MySQL> select version();

  TiDB> select @@tidb_version\G
  ```

This is done using JS and CSS, found in [`assets/copy.js`](assets/copy.js) and [`assets/copy.css`](assets/copy.css), respectively.

### Links

To link to other articles in the Knowledge Base, use a format like `/hc/<locale>/articles/<id>` where `<locale>` is either `en-us` or `zh-cn` and `<id>` is the ID of the article in Zendesk, either taken from `article_map.json` or from the Zendesk URL/API/etc.

## Markdown format

The Markdown content in this repository is rendered into HTML using [pandoc](https://pandoc.org/).

The format used for Markdown in this repository, as is the case for Markdown used nearly anywhere, diverges a bit from some standards you may have seen in the past. Crucially, a few Pandoc extensions are used to properly transform our Markdown format in the HTML that can be published to Zendesk and stylized appropriately: `markdown_github+gfm_auto_identifiers+fenced_code_attributes`.

## Help Center organization

To manage articles in the Guide Admin Web UI, visit <https://pingcap.zendesk.com/knowledge/lists/default/1/1?brand_id=360004187474>.

The Help Center is organized into Sections ("FAQ", "PoC Guide", etc.). Each Section has its own ID number. Section subdirectories of the `knowledge-base` repository root should contain a `section.id` file with the section ID in it. That allows API clients to correctly identify the section the Markdown files belong to.

Each subdirectory/section should contain a `article_map.json` file that maps between filenames in the locale subdirectories of section subdirectories and article IDs in Zendesk. If a new article is added to Zendesk, its ID should be put into `article_map.json` along with the filename in the repository.

The subdirectories of each section subdirectory are "locales" that correspond to "translations" in Zendesk. They contain the actual files referred to in `article_map.json`. The filenames in both/all of the locale directories should be the same (in other words, the filenames themselves should not be localized, and the Chinese translation of en-us/htap.md should be in zh-cn/htap.md).

To interact with existing article content via the Zendesk API, you have to interact with the "translation" rather than the "article" itself.

## Translations

In Zendesk Guide, everything needs to have an appropriate translation in order for it to show up in the UI for the end user. That includes Categories, Sections, and Articles. <https://support.zendesk.com/hc/en-us/articles/203664336#topic_3zx_52h_xw>

For _anything_ in the "General" category (<https://support.pingcap.com/hc/en-us/categories/360003289394-General>) to show up, the Category _itself_ has to have a translation for the name. The same is true for each Section. Even if you have Chinese-language Articles published, they won't show up unless both the Section and Category have translated names.

That's done in the "[Arrange content](https://pingcap.zendesk.com/knowledge/arrange/)" interface in Zendesk Guide Admin. Find the Category or Section that needs a translated name, click the stacked-dots menu, Edit, choose the correct language on the left, and add the translated Name for the Category or Section.

If you view an individual Article under [Manage articles](https://pingcap.zendesk.com/knowledge/lists/default/1/1?brand_id=360004187474), in the right sidebar under "Publish in section", you'll see "Missing Translations" if there are any problems with the Section or Category of the Article.

## Publishing Changes

### Linting

To make sure your Markdown follows good style rules, please lint it before syncing it to Help Center.

```
docker run --rm -v "$PWD"/.markdownlint.yaml:/markdownlint.yaml -i \
    avtodev/markdown-lint:v1 -c /markdownlint.yaml -s < poc-guide/en-us/htap.md
```

If you really need to override some linting rule, you can try to consult <https://github.com/DavidAnson/markdownlint#configuration>.

### Previewing

You can preview rendered Markdown in [Visual Studio Code|https://code.visualstudio.com/] or any other Markdown rendering tool. This will not show the final styling and functinality that will be provided by the CSS classes in the Zendesk Help Center.

You can also preview your "rendered" content by using the pandoc Docker image to create a `preview.html` file that you can open in your browser; this should give an idea of whether it's even possible for pandoc to complete and whether the content can be displayed correctly.

```
docker run --rm --volume "$PWD:/data" pandoc/minimal \
        -f markdown_github+gfm_auto_identifiers+fenced_code_attributes \
        -o preview.html poc-guide/en-us/deploy-a-tidb-cluster.md
```

### Access Permissions

The shell scripts here use curl to interact with the Zendesk REST API. You must have an OAuth token in your shell environment for the scripts to function.

To maintain some kind of order over who is pushing content to the KB, Kolbe has the "client secret" that is required in order to get an API token.

1. To get a token, open this URL in your browser:

   <https://pingcap.zendesk.com/oauth/authorizations/new?response_type=code&redirect_url=http://localhost:9999/pingcap/oauth&client_id=pingcap_kb_syncer&scope=hc:read%20hc:write&state=50696e67434150204b42>

2. Click "Allow"

3. Copy the "code" value from the URL you're forwarded to (The "This site can’t be reached" error is expected!)

4. Fetch the OAuth token

   ```
   code="<code from browser>"
   secret="<secret from Kolbe>"

   curl -sS https://pingcap.zendesk.com/oauth/tokens -H "Content-Type: application/json" -d "$(
       jq --arg code "$code" --arg secret "$secret" '.code = $code | .client_secret=$secret' \
           <<<'{"grant_type":"authorization_code","code":"","client_id":"pingcap_kb_syncer",
               "client_secret":"","redirect_uri":"https://localhost:9999/pingcap/oauth","scope":"hc:read hc:write"}'
   )" | jq .
   ```

### Syncing

The [`sync_articles.bash`](sync_articles.bash) script runs Markdown through the Pandoc Docker image, generates HTML output, and uses `curl` to push the update to the appropriate translation.

Export `ZENDESK_TOKEN` to your environment before executing the script.

To execute the script, first change to the directory of the Section you want to update. Then execute the script with an argument of one or more`.md` file(s) with a leading locale directory component, like this:

```
cd poc-guide
bash ../sync_articles.bash en-us/htap.md
```

## Adding Articles

To add a new article to the KB, use either the Zendesk Guide web UI at <https://pingcap.zendesk.com/knowledge/articles/new> or use the Zendesk API.

- Make sure you create the Article in the correct **Section**
- Make sure you create the Article with the correct **Locale**
- Make sure you add the new Article's **ID** and the **filename** you're using to the `article_map.json` file in the appropriate Section subdirectory
- The only thing you need to add at creation time is the article's **Title**
- Leave the body empty, it will be created when you run `sync_articles.bash`

You can use the [`add_articles.bash`](add_articles.bash) script to do this, which might be helpful if you are trying to add a large number of articles. You must execute it from the section subdirectory of the repository root (`poc-guide` for example).

```
poc-guide $ bash ../add_articles.bash en-us/test.md
```

## Assets

The `assets` subdirectory contains important JS and CSS files that must be saved to the [Zendesk Guide Theme](https://support.pingcap.com/theming/editor/193c0a3d-1503-43d8-b91b-8ae06f152a13). Any changes to files in [`assets`](assets/) must be manually updated in the Zendesk Guide Theme by opening the corresponding file in the "assets" folder in the editor and choosing "Replace" from the ellipsis (…) menu.

Some supporting customization has also been done to the [`article_page.hbs` template](https://support.pingcap.com/theming/editor/193c0a3d-1503-43d8-b91b-8ae06f152a13/templates/article_page.hbs). It's best to keep track of that in [`assets/_article_page.hbs`](assets/_article_page.hbs), even though that file is not actually synced to the theme.

## Using Github Workflow

There're two workflows(`.github/workflows/post.yml` and `.github/workflows/update.yml`) for publishing and updating articles on Zendesk.

### Post an article on Zendesk by workflow

1. Create a new MD file under specified section folder like `TEST/en-us/demo-20221207.md`;

2. Make sure that the corresponding `article_map.json` under section folder exists and with content(the content should be in `json` format, use `{}` as content if empty);

3. After article content finished, create a PR ([example](https://github.com/pingcap-inc/knowledge-base/pull/87));

4. `CI` workflow will check markdown lint;

5. Manually fulfill the workflow form on `Action` page;

   a. Visit `post` workflow page ([url](https://github.com/pingcap-inc/knowledge-base/actions/workflows/post.yml));

   b. Click `Run Workflow` button;

   c. Choose the branch you want to run `post` scripts on;

   d. Input the MD file path;

   e. Input the Zendesk OAuth token;

   f. Click `Run workflow`;

   g. ![image](https://user-images.githubusercontent.com/56986964/206078816-b6eff8e6-f225-4238-bcd0-e5c9d921a980.png)

6. After workflow finished, check the article on [Zendesk](https://pingcap.zendesk.com/knowledge/lists/default/1);

### Update an article on Zendesk by workflow

The `update` workflow will automatically run after any PR **merged**. It will check if any **modified** MD files and try to update them on Zendesk.
