Merge branch 'master' into docs-wording-improvements
This commit is contained in:
commit
5b6733e711
14
Dockerfile
14
Dockerfile
@ -5,20 +5,24 @@ WORKDIR /app
|
|||||||
COPY requirements.txt .
|
COPY requirements.txt .
|
||||||
RUN pip install -r requirements.txt
|
RUN pip install -r requirements.txt
|
||||||
|
|
||||||
# Run tests to validate app
|
|
||||||
FROM node:12-alpine AS app-base
|
FROM node:12-alpine AS app-base
|
||||||
RUN apk add --no-cache python g++ make
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY app/package.json app/yarn.lock ./
|
COPY app/package.json app/yarn.lock ./
|
||||||
RUN yarn install
|
|
||||||
COPY app/spec ./spec
|
COPY app/spec ./spec
|
||||||
COPY app/src ./src
|
COPY app/src ./src
|
||||||
|
|
||||||
|
# Run tests to validate app
|
||||||
|
FROM app-base AS test
|
||||||
|
RUN apk add --no-cache python3 g++ make
|
||||||
|
RUN yarn install
|
||||||
RUN yarn test
|
RUN yarn test
|
||||||
|
|
||||||
# Clear out the node_modules and create the zip
|
# Clear out the node_modules and create the zip
|
||||||
FROM app-base AS app-zip-creator
|
FROM app-base AS app-zip-creator
|
||||||
RUN rm -rf node_modules && \
|
COPY app/package.json app/yarn.lock ./
|
||||||
apk add zip && \
|
COPY app/spec ./spec
|
||||||
|
COPY app/src ./src
|
||||||
|
RUN apk add zip && \
|
||||||
zip -r /app.zip /app
|
zip -r /app.zip /app
|
||||||
|
|
||||||
# Dev-ready container - actual files will be mounted in
|
# Dev-ready container - actual files will be mounted in
|
||||||
|
@ -9,13 +9,15 @@
|
|||||||
"dev": "nodemon src/index.js"
|
"dev": "nodemon src/index.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"body-parser": "^1.19.0",
|
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"mysql": "^2.17.1",
|
"mysql": "^2.17.1",
|
||||||
"sqlite3": "^4.1.0",
|
"sqlite3": "^5.0.0",
|
||||||
"uuid": "^3.3.3",
|
"uuid": "^3.3.3",
|
||||||
"wait-port": "^0.2.2"
|
"wait-port": "^0.2.2"
|
||||||
},
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"ansi-regex": "5.0.1"
|
||||||
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"trailingComma": "all",
|
"trailingComma": "all",
|
||||||
"tabWidth": 4,
|
"tabWidth": 4,
|
||||||
@ -24,8 +26,8 @@
|
|||||||
"singleQuote": true
|
"singleQuote": true
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"jest": "^24.9.0",
|
"jest": "^27.2.5",
|
||||||
"nodemon": "^1.19.2",
|
"nodemon": "^2.0.13",
|
||||||
"prettier": "^1.18.2"
|
"prettier": "^1.18.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
const db = require('../../src/persistence/sqlite');
|
const db = require('../../src/persistence/sqlite');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
const location = process.env.SQLITE_DB_LOCATION || '/etc/todos/todo.db';
|
||||||
|
|
||||||
const ITEM = {
|
const ITEM = {
|
||||||
id: '7aef3d7c-d301-4846-8358-2a91ec9d6be3',
|
id: '7aef3d7c-d301-4846-8358-2a91ec9d6be3',
|
||||||
@ -8,8 +9,8 @@ const ITEM = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
if (fs.existsSync('/etc/todos/todo.db')) {
|
if (fs.existsSync(location)) {
|
||||||
fs.unlinkSync('/etc/todos/todo.db');
|
fs.unlinkSync(location);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ const addItem = require('./routes/addItem');
|
|||||||
const updateItem = require('./routes/updateItem');
|
const updateItem = require('./routes/updateItem');
|
||||||
const deleteItem = require('./routes/deleteItem');
|
const deleteItem = require('./routes/deleteItem');
|
||||||
|
|
||||||
app.use(require('body-parser').json());
|
app.use(express.json());
|
||||||
app.use(express.static(__dirname + '/static'));
|
app.use(express.static(__dirname + '/static'));
|
||||||
|
|
||||||
app.get('/items', getItems);
|
app.get('/items', getItems);
|
||||||
|
5081
app/yarn.lock
5081
app/yarn.lock
File diff suppressed because it is too large
Load Diff
@ -4,12 +4,12 @@ application stack. The following question often arises - "Where will MySQL run?
|
|||||||
container or run it separately?" In general, **each container should do one thing and do it well.** A few
|
container or run it separately?" In general, **each container should do one thing and do it well.** A few
|
||||||
reasons:
|
reasons:
|
||||||
|
|
||||||
- There's a good chance you'd have to scale APIs and front-ends differently than databases
|
- There's a good chance you'd have to scale APIs and front-ends differently than databases.
|
||||||
- Separate containers let you version and update versions in isolation
|
- Separate containers let you version and update versions in isolation.
|
||||||
- While you may use a container for the database locally, you may want to use a managed service
|
- While you may use a container for the database locally, you may want to use a managed service
|
||||||
for the database in production. You don't want to ship your database engine with your app then.
|
for the database in production. You don't want to ship your database engine with your app then.
|
||||||
- Running multiple processes will require a process manager (the container only starts one process),
|
- Running multiple processes will require a process manager (the container only starts one process),
|
||||||
which adds complexity to container startup/shutdown
|
which adds complexity to container startup/shutdown.
|
||||||
|
|
||||||
And there are more reasons. So, we will update our application to work like this:
|
And there are more reasons. So, we will update our application to work like this:
|
||||||
|
|
||||||
@ -67,6 +67,20 @@ For now, we will create the network first and attach the MySQL container at star
|
|||||||
where MySQL stores its data. However, we never ran a `docker volume create` command. Docker recognizes we want
|
where MySQL stores its data. However, we never ran a `docker volume create` command. Docker recognizes we want
|
||||||
to use a named volume and creates one automatically for us.
|
to use a named volume and creates one automatically for us.
|
||||||
|
|
||||||
|
!!! info "Troubleshooting"
|
||||||
|
If you see a `docker: no matching manifest` error, it's because you're trying to run the container in a different
|
||||||
|
architecture than amd64, which is the only supported architecture for the mysql image at the moment. To solve this
|
||||||
|
add the flag `--platform linux/amd64` in the previous command. So your new command should look like this:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d \
|
||||||
|
--network todo-app --network-alias mysql --platform linux/amd64 \
|
||||||
|
-v todo-mysql-data:/var/lib/mysql \
|
||||||
|
-e MYSQL_ROOT_PASSWORD=secret \
|
||||||
|
-e MYSQL_DATABASE=todos \
|
||||||
|
mysql:5.7
|
||||||
|
```
|
||||||
|
|
||||||
1. To confirm we have the database up and running, connect to the database and verify it connects.
|
1. To confirm we have the database up and running, connect to the database and verify it connects.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@ -97,6 +111,8 @@ For now, we will create the network first and attach the MySQL container at star
|
|||||||
|
|
||||||
Hooray! We have our `todos` database and it's ready for us to use!
|
Hooray! We have our `todos` database and it's ready for us to use!
|
||||||
|
|
||||||
|
To exit the sql terminal type `exit` in the terminal.
|
||||||
|
|
||||||
|
|
||||||
## Connecting to MySQL
|
## Connecting to MySQL
|
||||||
|
|
||||||
@ -190,6 +206,20 @@ With all of that explained, let's start our dev-ready container!
|
|||||||
sh -c "yarn install && yarn run dev"
|
sh -c "yarn install && yarn run dev"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you updated your docker file in the Bind Mount section of the tutorial use the updated command:
|
||||||
|
|
||||||
|
```bash hl_lines="3 4 5 6 7"
|
||||||
|
docker run -dp 3000:3000 \
|
||||||
|
-w /app -v "$(pwd):/app" \
|
||||||
|
--network todo-app \
|
||||||
|
-e MYSQL_HOST=mysql \
|
||||||
|
-e MYSQL_USER=root \
|
||||||
|
-e MYSQL_PASSWORD=secret \
|
||||||
|
-e MYSQL_DB=todos \
|
||||||
|
node:12-alpine \
|
||||||
|
sh -c "apk --no-cache --virtual build-dependencies add python2 make g++ && yarn install && yarn run dev"
|
||||||
|
```
|
||||||
|
|
||||||
If you are using PowerShell then use this command.
|
If you are using PowerShell then use this command.
|
||||||
|
|
||||||
```powershell hl_lines="3 4 5 6 7"
|
```powershell hl_lines="3 4 5 6 7"
|
||||||
|
@ -38,6 +38,8 @@ see a few flaws in the Dockerfile below. But, don't worry! We'll go over them.
|
|||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
FROM node:12-alpine
|
FROM node:12-alpine
|
||||||
|
# Adding build tools to make yarn install work on Apple silicon / arm64 machines
|
||||||
|
RUN apk add --no-cache python2 g++ make
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN yarn install --production
|
RUN yarn install --production
|
||||||
|
@ -54,7 +54,10 @@ What you'll see is that the files created in one container aren't available in a
|
|||||||
And look! There's no `data.txt` file there! That's because it was written to the scratch space for
|
And look! There's no `data.txt` file there! That's because it was written to the scratch space for
|
||||||
only the first container.
|
only the first container.
|
||||||
|
|
||||||
1. Go ahead and remove the first container using the `docker rm -f` command.
|
1. Go ahead and remove the first container using the `docker rm -f <container-id>` command.
|
||||||
|
```bash
|
||||||
|
docker rm -f <container-id>
|
||||||
|
```
|
||||||
|
|
||||||
## Container Volumes
|
## Container Volumes
|
||||||
|
|
||||||
@ -91,7 +94,7 @@ Every time you use the volume, Docker will make sure the correct data is provide
|
|||||||
docker volume create todo-db
|
docker volume create todo-db
|
||||||
```
|
```
|
||||||
|
|
||||||
1. Stop the todo app container once again in the Dashboard (or with `docker rm -f <id>`), as it is still running without using the persistent volume.
|
1. Stop the todo app container once again in the Dashboard (or with `docker rm -f <container-id>`), as it is still running without using the persistent volume.
|
||||||
|
|
||||||
1. Start the todo app container, but add the `-v` flag to specify a volume mount. We will use the named volume and mount
|
1. Start the todo app container, but add the `-v` flag to specify a volume mount. We will use the named volume and mount
|
||||||
it to `/etc/todos`, which will capture all files created at the path.
|
it to `/etc/todos`, which will capture all files created at the path.
|
||||||
@ -105,7 +108,7 @@ Every time you use the volume, Docker will make sure the correct data is provide
|
|||||||
![Items added to todo list](items-added.png){: style="width: 55%; " }
|
![Items added to todo list](items-added.png){: style="width: 55%; " }
|
||||||
{: .text-center }
|
{: .text-center }
|
||||||
|
|
||||||
1. Remove the container for the todo app. Use the Dashboard or `docker ps` to get the ID and then `docker rm -f <id>` to remove it.
|
1. Remove the container for the todo app. Use the Dashboard or `docker ps` to get the ID and then `docker rm -f <container-id>` to remove it.
|
||||||
|
|
||||||
1. Start a new container using the same command from above.
|
1. Start a new container using the same command from above.
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ an example command that you will need to run to push to this repo.
|
|||||||
Now that our image has been built and pushed into a registry, let's try running our app on a brand
|
Now that our image has been built and pushed into a registry, let's try running our app on a brand
|
||||||
new instance that has never seen this container image! To do this, we will use Play with Docker.
|
new instance that has never seen this container image! To do this, we will use Play with Docker.
|
||||||
|
|
||||||
1. Open your browser to [Play with Docker](http://play-with-docker.com).
|
1. Open your browser to [Play with Docker](https://labs.play-with-docker.com/).
|
||||||
|
|
||||||
1. Log in with your Docker Hub account.
|
1. Log in with your Docker Hub account.
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ changes and then restart the application. There are equivalent tools in most oth
|
|||||||
## Quick Volume Type Comparisons
|
## Quick Volume Type Comparisons
|
||||||
|
|
||||||
Bind mounts and named volumes are the two main types of volumes that come with the Docker engine. However, additional
|
Bind mounts and named volumes are the two main types of volumes that come with the Docker engine. However, additional
|
||||||
volume drivers are available to support other uses cases ([SFTP](https://github.com/vieux/docker-volume-sshfs), [Ceph](https://ceph.com/geen-categorie/getting-started-with-the-docker-rbd-volume-plugin/), [NetApp](https://netappdvp.readthedocs.io/en/stable/), [S3](https://github.com/elementar/docker-s3-volume), and more).
|
volume drivers are available to support other use cases ([SFTP](https://github.com/vieux/docker-volume-sshfs), [Ceph](https://ceph.com/geen-categorie/getting-started-with-the-docker-rbd-volume-plugin/), [NetApp](https://netappdvp.readthedocs.io/en/stable/), [S3](https://github.com/elementar/docker-s3-volume), and more).
|
||||||
|
|
||||||
| | Named Volumes | Bind Mounts |
|
| | Named Volumes | Bind Mounts |
|
||||||
| - | ------------- | ----------- |
|
| - | ------------- | ----------- |
|
||||||
@ -36,7 +36,7 @@ So, let's do it!
|
|||||||
|
|
||||||
1. Make sure you don't have any previous `getting-started` containers running.
|
1. Make sure you don't have any previous `getting-started` containers running.
|
||||||
|
|
||||||
1. Run the following command. We'll explain what's going on afterwards:
|
1. Run the following command from the source code folder. We'll explain what's going on afterwards:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -dp 3000:3000 \
|
docker run -dp 3000:3000 \
|
||||||
@ -55,8 +55,8 @@ So, let's do it!
|
|||||||
```
|
```
|
||||||
|
|
||||||
- `-dp 3000:3000` - same as before. Run in detached (background) mode and create a port mapping
|
- `-dp 3000:3000` - same as before. Run in detached (background) mode and create a port mapping
|
||||||
- `-w /app` - sets the "working directory" or the current directory that the command will run from
|
- `-w /app` - sets the container's present working directory where the command will run from
|
||||||
- `-v "$(pwd):/app"` - bind mount the current directory from the host in the container into the `/app` directory
|
- `-v "$(pwd):/app"` - bind mount (link) the host's present working directory to the container's `/app` directory
|
||||||
- `node:12-alpine` - the image to use. Note that this is the base image for our app from the Dockerfile
|
- `node:12-alpine` - the image to use. Note that this is the base image for our app from the Dockerfile
|
||||||
- `sh -c "yarn install && yarn run dev"` - the command. We're starting a shell using `sh` (alpine doesn't have `bash`) and
|
- `sh -c "yarn install && yarn run dev"` - the command. We're starting a shell using `sh` (alpine doesn't have `bash`) and
|
||||||
running `yarn install` to install _all_ dependencies and then running `yarn run dev`. If we look in the `package.json`,
|
running `yarn install` to install _all_ dependencies and then running `yarn run dev`. If we look in the `package.json`,
|
||||||
@ -78,7 +78,7 @@ So, let's do it!
|
|||||||
When you're done watching the logs, exit out by hitting `Ctrl`+`C`.
|
When you're done watching the logs, exit out by hitting `Ctrl`+`C`.
|
||||||
|
|
||||||
1. Now, let's make a change to the app. In the `src/static/js/app.js` file, let's change the "Add Item" button to simply say
|
1. Now, let's make a change to the app. In the `src/static/js/app.js` file, let's change the "Add Item" button to simply say
|
||||||
"Add". This change will be on line 109.
|
"Add". This change will be on line 109 - remember to save the file.
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
- {submitting ? 'Adding...' : 'Add Item'}
|
- {submitting ? 'Adding...' : 'Add Item'}
|
||||||
|
@ -33,13 +33,13 @@ docker-compose version
|
|||||||
for the current schema versions and the compatibility matrix.
|
for the current schema versions and the compatibility matrix.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
version: "3.7"
|
version: "3.8"
|
||||||
```
|
```
|
||||||
|
|
||||||
1. Next, we'll define the list of services (or containers) we want to run as part of our application.
|
1. Next, we'll define the list of services (or containers) we want to run as part of our application.
|
||||||
|
|
||||||
```yaml hl_lines="3"
|
```yaml hl_lines="3"
|
||||||
version: "3.7"
|
version: "3.8"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
```
|
```
|
||||||
@ -81,7 +81,7 @@ docker run -dp 3000:3000 `
|
|||||||
The name will automatically become a network alias, which will be useful when defining our MySQL service.
|
The name will automatically become a network alias, which will be useful when defining our MySQL service.
|
||||||
|
|
||||||
```yaml hl_lines="4 5"
|
```yaml hl_lines="4 5"
|
||||||
version: "3.7"
|
version: "3.8"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
@ -92,7 +92,7 @@ docker run -dp 3000:3000 `
|
|||||||
So, let's go ahead and move that into our file.
|
So, let's go ahead and move that into our file.
|
||||||
|
|
||||||
```yaml hl_lines="6"
|
```yaml hl_lines="6"
|
||||||
version: "3.7"
|
version: "3.8"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
@ -102,11 +102,11 @@ docker run -dp 3000:3000 `
|
|||||||
|
|
||||||
|
|
||||||
1. Let's migrate the `-p 3000:3000` part of the command by defining the `ports` for the service. We will use the
|
1. Let's migrate the `-p 3000:3000` part of the command by defining the `ports` for the service. We will use the
|
||||||
[short syntax](https://docs.docker.com/compose/compose-file/#short-syntax-1) here, but there is also a more verbose
|
[short syntax](https://docs.docker.com/compose/compose-file/compose-file-v3/#short-syntax-1) here, but there is also a more verbose
|
||||||
[long syntax](https://docs.docker.com/compose/compose-file/#long-syntax-1) available as well.
|
[long syntax](https://docs.docker.com/compose/compose-file/compose-file-v3/#long-syntax-1) available as well.
|
||||||
|
|
||||||
```yaml hl_lines="7 8"
|
```yaml hl_lines="7 8"
|
||||||
version: "3.7"
|
version: "3.8"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
@ -117,12 +117,12 @@ docker run -dp 3000:3000 `
|
|||||||
```
|
```
|
||||||
|
|
||||||
1. Next, we'll migrate both the working directory (`-w /app`) and the volume mapping (`-v "$(pwd):/app"`) by using
|
1. Next, we'll migrate both the working directory (`-w /app`) and the volume mapping (`-v "$(pwd):/app"`) by using
|
||||||
the `working_dir` and `volumes` definitions. Volumes also has a [short](https://docs.docker.com/compose/compose-file/#short-syntax-3) and [long](https://docs.docker.com/compose/compose-file/#long-syntax-3) syntax.
|
the `working_dir` and `volumes` definitions. Volumes also has a [short](https://docs.docker.com/compose/compose-file/compose-file-v3/#short-syntax-3) and [long](https://docs.docker.com/compose/compose-file/compose-file-v3/#long-syntax-3) syntax.
|
||||||
|
|
||||||
One advantage of Docker Compose volume definitions is we can use relative paths from the current directory.
|
One advantage of Docker Compose volume definitions is we can use relative paths from the current directory.
|
||||||
|
|
||||||
```yaml hl_lines="9 10 11"
|
```yaml hl_lines="9 10 11"
|
||||||
version: "3.7"
|
version: "3.8"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
@ -138,7 +138,7 @@ docker run -dp 3000:3000 `
|
|||||||
1. Finally, we need to migrate the environment variable definitions using the `environment` key.
|
1. Finally, we need to migrate the environment variable definitions using the `environment` key.
|
||||||
|
|
||||||
```yaml hl_lines="12 13 14 15 16"
|
```yaml hl_lines="12 13 14 15 16"
|
||||||
version: "3.7"
|
version: "3.8"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
@ -185,7 +185,7 @@ docker run -d `
|
|||||||
go ahead and specify the image to use as well.
|
go ahead and specify the image to use as well.
|
||||||
|
|
||||||
```yaml hl_lines="6 7"
|
```yaml hl_lines="6 7"
|
||||||
version: "3.7"
|
version: "3.8"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
@ -197,10 +197,10 @@ docker run -d `
|
|||||||
1. Next, we'll define the volume mapping. When we ran the container with `docker run`, the named volume was created
|
1. Next, we'll define the volume mapping. When we ran the container with `docker run`, the named volume was created
|
||||||
automatically. However, that doesn't happen when running with Compose. We need to define the volume in the top-level
|
automatically. However, that doesn't happen when running with Compose. We need to define the volume in the top-level
|
||||||
`volumes:` section and then specify the mountpoint in the service config. By simply providing only the volume name,
|
`volumes:` section and then specify the mountpoint in the service config. By simply providing only the volume name,
|
||||||
the default options are used. There are [many more options available](https://docs.docker.com/compose/compose-file/#volume-configuration-reference) though.
|
the default options are used. There are [many more options available](https://docs.docker.com/compose/compose-file/compose-file-v3/#volume-configuration-reference) though.
|
||||||
|
|
||||||
```yaml hl_lines="8 9 10 11 12"
|
```yaml hl_lines="8 9 10 11 12"
|
||||||
version: "3.7"
|
version: "3.8"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
@ -217,7 +217,7 @@ docker run -d `
|
|||||||
1. Finally, we only need to specify the environment variables.
|
1. Finally, we only need to specify the environment variables.
|
||||||
|
|
||||||
```yaml hl_lines="10 11 12"
|
```yaml hl_lines="10 11 12"
|
||||||
version: "3.7"
|
version: "3.8"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
@ -238,7 +238,7 @@ At this point, our complete `docker-compose.yml` should look like this:
|
|||||||
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
version: "3.7"
|
version: "3.8"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
mkdocs==1.0.4
|
mkdocs==1.2.3
|
||||||
mkdocs-material==4.6.3
|
mkdocs-material==4.6.3
|
||||||
mkdocs-minify-plugin==0.2.3
|
mkdocs-minify-plugin==0.2.3
|
||||||
pygments==2.6.1
|
pygments==2.7.4
|
||||||
pymdown-extensions==7.0
|
pymdown-extensions==7.0
|
||||||
|
Loading…
Reference in New Issue
Block a user