Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/hungry-meals-start.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"myst-cli": minor
"mystmd": minor
---

Add support for `--readthedocs` flag on `myst init` to generate ReadTheDocs configuration files
5 changes: 4 additions & 1 deletion packages/myst-cli/src/init/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { selectors } from '../store/index.js';
import type { ISession } from '../session/types.js';
import { startServer } from '../build/site/start.js';
import { githubCurvenoteAction, githubPagesAction } from './gh-actions/index.js';
import { readTheDocsAction } from './readthedocs/index.js';
import { getGithubUrl } from '../utils/github.js';
import { checkFolderIsGit, checkIgnore } from '../utils/git.js';
import { upgradeJupyterBook } from './jupyter-book/upgrade.js';
Expand Down Expand Up @@ -45,6 +46,7 @@ export type InitOptions = {
writeTOC?: boolean;
ghPages?: boolean;
ghCurvenote?: boolean;
readthedocs?: boolean;
};

const WELCOME = () => `
Expand Down Expand Up @@ -77,10 +79,11 @@ async function writeGitignore(session: ISession) {
}

export async function init(session: ISession, opts: InitOptions) {
const { project, site, writeTOC, ghPages, ghCurvenote } = opts;
const { project, site, writeTOC, ghPages, ghCurvenote, readthedocs } = opts;

if (ghPages) return githubPagesAction(session);
if (ghCurvenote) return githubCurvenoteAction(session);
if (readthedocs) return readTheDocsAction(session);

if (!project && !site && !writeTOC) {
session.log.info(WELCOME());
Expand Down
123 changes: 123 additions & 0 deletions packages/myst-cli/src/init/readthedocs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import fs from 'node:fs';
import inquirer from 'inquirer';
import chalk from 'chalk';
import type { ISession } from 'myst-cli-utils';
import { writeFileToFolder } from 'myst-cli-utils';
import { checkFolderIsGit, checkAtGitRoot } from '../../utils/git.js';
import { npmBinaryName, npmPackageName } from '../../utils/whiteLabelling.js';

const READTHEDOCS_FILENAME = '.readthedocs.yaml';

function createReadTheDocsConfig({
pythonVersion = '3.12',
nodeVersion = '22',
}: {
pythonVersion?: string;
nodeVersion?: string;
} = {}) {
return `# Read the Docs configuration file for ${npmBinaryName()}
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# This file was created automatically with \`${npmBinaryName()} init --readthedocs\`

# Required
version: 2

# Set the OS, Python version, and Node.js version
build:
os: ubuntu-22.04
tools:
python: "${pythonVersion}"
nodejs: "${nodeVersion}"
commands:
# Install ${npmBinaryName()}
- npm install -g ${npmPackageName()}
# Build the site
- ${npmBinaryName()} build --html
# Copy the output to Read the Docs expected location
- mkdir -p $READTHEDOCS_OUTPUT/html/
- cp -r _build/html/. "$READTHEDOCS_OUTPUT/html"
# Clean up build artifacts
- rm -rf _build
`;
}

export async function readTheDocsAction(session: ISession) {
// Check if we're in a git repo (warn but don't fail)
const inGitRepo = await checkFolderIsGit();
if (!inGitRepo) {
session.log.warn(
`${chalk.yellow(
'Not a git repository',
)}\n\nThe .readthedocs.yaml file is typically used in a git repository.`,
);
}

// Check if we're at the git root
if (inGitRepo) {
const inRoot = await checkAtGitRoot();
if (!inRoot) {
session.log.info(
`${chalk.redBright(
'Please Run From Root',
)}\n\nPlease run this command from the root of the git repository.`,
);
process.exit(1);
}
}

// Check if config already exists
if (fs.existsSync(READTHEDOCS_FILENAME)) {
const promptOverwrite = await inquirer.prompt([
{
name: 'overwrite',
message: `The file ${chalk.yellow(
READTHEDOCS_FILENAME,
)} already exists. Do you want to overwrite it?`,
type: 'confirm',
default: false,
},
]);
if (!promptOverwrite.overwrite) {
session.log.info('Aborted.');
return;
}
}

session.log.info(`📝 Creating a ${chalk.yellow(READTHEDOCS_FILENAME)} configuration file\n`);

const prompt = await inquirer.prompt([
{
name: 'pythonVersion',
message: 'What Python version would you like to use?',
default: '3.12',
},
{
name: 'nodeVersion',
message: 'What Node.js version would you like to use?',
default: '22',
},
]);

const config = createReadTheDocsConfig({
pythonVersion: prompt.pythonVersion,
nodeVersion: prompt.nodeVersion,
});

writeFileToFolder(READTHEDOCS_FILENAME, config);

session.log.info(`
🎉 Read the Docs configuration is ready:

${READTHEDOCS_FILENAME}

✅ ${chalk.bold.green('Next Steps')}

1. Create an account on ${chalk.blue('https://readthedocs.org')} if you don't have one
2. Import your project from GitHub/GitLab/Bitbucket
3. Commit and push the ${chalk.yellow(READTHEDOCS_FILENAME)} file to your repository
4. Read the Docs will automatically build your documentation on each push
5. 🎉 Your documentation will be available at ${chalk.blue('https://YOUR-PROJECT.readthedocs.io')}

For more information, see: ${chalk.blue('https://docs.readthedocs.com/platform/stable/intro/mystmd.html')}
`);
}
2 changes: 2 additions & 0 deletions packages/mystmd/src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
makeWriteTOCOption,
makeGithubPagesOption,
makeGithubCurvenoteOption,
makeReadTheDocsOption,
} from './options.js';

export function makeInitCLI(program: Command) {
Expand All @@ -17,6 +18,7 @@ export function makeInitCLI(program: Command) {
.addOption(makeWriteTOCOption())
.addOption(makeGithubPagesOption())
.addOption(makeGithubCurvenoteOption())
.addOption(makeReadTheDocsOption())
.action(clirun(Session, init, program, { keepAlive: true }));
return command;
}
Expand Down
7 changes: 7 additions & 0 deletions packages/mystmd/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,10 @@ export function makeGithubCurvenoteOption() {
'Creates a GitHub action that will deploy your site to Curvenote',
).default(false);
}

export function makeReadTheDocsOption() {
return new Option(
'--readthedocs',
'Creates a .readthedocs.yaml configuration file for deploying to Read the Docs',
).default(false);
}