I'm afraid I don't really have an idea how to do this - I want to use variables in a Gitlab Wiki page. is this possible at all using html? Can I run scripts on a page?
For example, this question on using a javascript variable in html - would something like this be possible?
For my specific example, I want a page with a table where the first column is numbers, and I want to take the largest value and display it at the top of the page. So for example the table might have rows like:
1 X
22 Y
15 Z
So at the top of the page I would display "largest number is 22". Does this make sense?
You cannot have a script in your Wikipage, since they sanitize the HTML (See what they allow here). To do what you want, you could generate that page in Gitlab-CI as part of your project's deploy pipeline, using whatever rendering engine and putting that variable in there, and update it automatically using Gitlab's Wiki APIs.
I created a demo NodeJS project here, which, when I push to the master
branch, auto-generates the Wiki pages. You can look at the code to see how it works.
This example app exposes a function to get a list of fruit and quantities in stock. We'll automatically add that data in the Wiki.
You can add templates to your project for your Wiki pages. In my example, I used MustacheJS. And I put everything in a wiki
folder (see folder structure at the end of step 5). Your template can look something like this:
wiki/templates/home.mst
# Welcome to the supermarket
The biggest quantity we have in stock is for **{{topProduct.label}}**,
with a total of **{{topProduct.stock}}**!
| Fruit | Quantity |
|-----------|--------------|
{{#inventory}}
| {{label}} | {{stock}} |
{{/inventory}}
In this example, the data will come from the project code itself.
Note: The scripts I wrote as a demo use
axios
to make requests to the Gitlab API,mustache
to render the pages, andqs
to format the data as a query string before posting it to Gitlab. You can use other ones or install them as dev dependencies:npm install --save-dev axios mustache qs
Create a js file which will get the data from your app, and render the templates into a build
directory. Something like this:
wiki/build.js
const fs = require('fs');
const Mustache = require('mustache');
const myApp = require('../src/index.js');
const inventory = myApp.getInventory();
// Get the Mustache template
const homeTemplate = fs.readFileSync(__dirname + '/templates/home.mst', 'utf-8');
// Get the fruit with the highest quantity
const topProduct = inventory.reduce((acc, curr) => {
if (acc === null || curr.stock > acc.stock) {
return curr;
} else {
return acc;
}
}, null);
// Render the page using your variables
const homeContent = Mustache.render(homeTemplate, { inventory, topProduct });
// Write the file in a build directory
const buildDir = __dirname + '/../build';
if (!fs.existsSync(buildDir)) {
fs.mkdirSync(buildDir);
}
fs.writeFileSync(buildDir + '/home.md', homeContent);
And in your package.json
, add a command to run that script:
"scripts": {
// ...
"wiki:build": "node wiki/build.js"
}
Create a script which will upload the pages to your Wiki. This may work as-is without much modification, if you're also using NodeJS.
wiki/deploy.js
const fs = require('fs');
const Axios = require('axios');
const qs = require('qs');
const config = {
gitlabBaseUrl: 'https://gitlab.com', // Update this if you're on a private Gitlab
projectId: process.env.CI_PROJECT_ID, // Provided by Gitlab-CI
privateToken: process.env.WIKI_DEPLOY_TOKEN, // Added through Gitlab interface
buildDir: __dirname + '/../build'
};
const axios = Axios.create({
baseURL: config.gitlabBaseUrl,
headers: { 'Private-Token': config.privateToken, Accept: 'application/json' }
});
(async function deploy() {
const existingPages = await getExistingWikiPages();
const updatedPages = getUpdatedPages();
// Pages which existed but are no longer in the build (obsolete)
const pagesToDelete = existingPages.filter(p1 => updatedPages.every(p2 => p2.slug !== p1.slug));
// Pages which didn't exist before
const pagesToCreate = updatedPages.filter(p1 => existingPages.every(p2 => p2.slug !== p1.slug));
// Pages which already exist
const pagesToUpdate = updatedPages.filter(p1 => existingPages.some(p2 => p2.slug === p1.slug));
console.log(
`Found ${pagesToDelete.length} pages to delete, ${pagesToCreate.length} pages to create, ${pagesToUpdate.length} pages to update.`
);
for (let page of pagesToDelete) {
await deletePage(page);
}
for (let page of pagesToCreate) {
await createPage(page);
}
for (let page of pagesToUpdate) {
await updatePage(page);
}
console.log('Deploy complete!');
})();
function getExistingWikiPages() {
return axios.get(`/api/v4/projects/${config.projectId}/wikis`).then(res => res.data);
}
function getUpdatedPages() {
const files = fs.readdirSync(config.buildDir);
return files.map(file => {
const name = file // Remove the file extension
.split('.')
.slice(0, -1)
.join('.');
return {
format: 'markdown', // You could make this depend on the file extension
slug: name,
title: name,
content: fs.readFileSync(`${config.buildDir}/${file}`, 'utf-8')
};
});
}
function deletePage(page) {
console.log(`Deleting ${page.slug}...`);
return axios.delete(`/api/v4/projects/${config.projectId}/wikis/${page.slug}`);
}
function createPage(page) {
console.log(`Creating ${page.slug}...`);
return axios.post(`/api/v4/projects/${config.projectId}/wikis`, qs.stringify(page));
}
function updatePage(page) {
console.log(`Updating ${page.slug}...`);
return axios.put(`/api/v4/projects/${config.projectId}/wikis/${page.slug}`, qs.stringify(page));
}
In the config
at the top, you need to specify which URL your Gitlab is using. CI_PROJECT_ID
will be provided by Gitlab-CI itself as an environment variable. WIKI_DEPLOY_TOKEN
, however, will not. Set it up in step 4.
And in your package.json
, add a command to run that script:
"scripts": {
// ...
"wiki:build": "node wiki/build.js",
"wiki:deploy": "node wiki/deploy.js"
}
Note: This example will delete obsolete pages, and update or create new ones depending on files it finds in the build folder and the ones the Wiki already contains. If you want to have attachments as well (images), you'll need to make use of this API also.
WIKI_DEPLOY_TOKEN
For this, you'll need to click on your profile picture at the top right corner > Settings. Then in the left menu, Access Tokens, and create a token with the api scope. The name does not matter. Copy this token now, since it will only be shown once.
Then, go to your project. In the menu on the left, click Settings > CI/CD. Expand the Variables section, and use the previously copied token to create a variable called WIKI_DEPLOY_TOKEN
, make it Masked so that it does not appear in any logs, and Save variables:
This will make that token available only in your pipelines, as an environment variable.
If you don't already have a pipeline, all you need to do is create a .gitlab-ci.yml
file at the root of your project. Declare a generate_wiki
stage:
.gitlab-ci.yml
stages:
# - tests
# - deploy
# ...
- generate_wiki
generate_wiki:
image: node:10
stage: generate_wiki
script:
- npm install
- npm run wiki:build # build the wiki in a directory
- npm run wiki:deploy # update it in Gitlab
only:
- master # Only when merging or pushing to master branch
# ... rest of your pipeline ...
As you can see, we use the commands wiki:build
and wiki:deploy
declared in steps 2 and 3.
Now, your project structure should look something like this:
/
├───src
│ └── index.js
├───wiki
│ ├── templates
│ │ └── home.mst
│ ├── build.js
│ └── deploy.js
├── .gitlab-ci.yml
└── package.json
After pushing, if everything went right, you can click on CI/CD in the left menu, and you should see your pipeline running:
If you click on the little circle, you should see the logs:
And if you go to your Wiki pages, they should be up to date, automagically: