Skip to content

Commit

Permalink
Make link checker more precise (#1937)
Browse files Browse the repository at this point in the history
Closes #495. 

We are checking every Runtime and qiskit-ibm-transpiler version, plus
Qiskit 0.46+. This PR makes it more explicit and precise which links we
have to ignore to get that green. That reduces the risk of false
positives.

This PR also now has the external link checker check every single Qiskit
version, whereas before it skipped historical links. It's important we
don't have 404s, even for old docs. Note that the external link checker
doesn't check GitHub source code links, which makes this change much
less expensive.

The remaining issues are tracked by
#1938.
  • Loading branch information
Eric-Arellano authored and frankharkins committed Sep 18, 2024
1 parent 2266c10 commit f8c4ffc
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 98 deletions.
5 changes: 1 addition & 4 deletions .github/workflows/weekly-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,7 @@ jobs:
- name: Check external links
env:
GITHUB_TOKEN: ${{ github.token }}
run: >
npm run check:external-links --
'docs/**/*.{md,mdx,ipynb}'
'!docs/api/qiskit/[0-9]*/*'
run: npm run check:external-links -- 'docs/**/*.{md,mdx,ipynb}'

make_issue:
name: Make issue on failure
Expand Down
275 changes: 181 additions & 94 deletions scripts/js/lib/links/ignores.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,36 +21,9 @@ export const IGNORED_FILES = new Set([
]);

// -----------------------------------------------------------------------------------
// Always ignored URLs
// Always ignored URLs - prefer to use more precise ignores
// -----------------------------------------------------------------------------------

const _QISKIT_UTILS = [
"#qiskit.utils.optionals.HAS_TESTTOOLS",
"#qiskit.utils.optionals.HAS_GRAPHVIZ",
"#qiskit.utils.optionals.HAS_PYDOT",
"https://github.com/python-constraint/python-constraint%3E__",
];

const _PATTERNS_REORG_IGNORES = [
"/run/primitives-examples",
"/run/sessions",
"/build/circuit-construction",
"/start/configure-qiskit-local#environment-variables",
"/build/pulse",
"/run",
"/transpile",
"/run/max-execution-time",
"/run/configure-runtime-compilation",
"/run/configure-error-mitigation",
"/start/install#qiskit-versioning",
"/start/configure-qiskit-local",
"/run/primitives-get-started#3-initialize-the-qiskit-runtime-sampler",
"/run/primitives-get-started#3-initialize-qiskit-runtime-estimator",
"/run/run-jobs-batch",
"/api/migration-guides/qiskit-runtime",
"/api/migration-guides/v2-primitives",
];

const ALWAYS_IGNORED_URLS__EXPECTED = [
"https://auth.quantum-computing.ibm.com/api",
"https://www.cs.tau.ac.il/~nogaa/PDFS/r.pdf",
Expand All @@ -65,12 +38,7 @@ const ALWAYS_IGNORED_URLS__EXPECTED = [
"mailto:tellibm@us.ibm.com",
];

const ALWAYS_IGNORED_URLS__SHOULD_FIX = [
// Bad anchor in qiskit_ibm_runtime.options.Options.md for 0.14 - 0.16.
"/run/max-execution-time#maximum-execution-time",
..._QISKIT_UTILS,
..._PATTERNS_REORG_IGNORES,
];
const ALWAYS_IGNORED_URLS__SHOULD_FIX: string[] = [];

export const ALWAYS_IGNORED_URLS = new Set([
...ALWAYS_IGNORED_URLS__EXPECTED,
Expand All @@ -84,8 +52,22 @@ export const ALWAYS_IGNORED_URLS = new Set([
// A mapping of files to lists of links that will not be searched.
type FilesToIgnores = { [id: string]: string[] };

const _QPY_IGNORES = Object.fromEntries(
["", "dev/", "0.46/", "1.0/", "1.1/"].map((vers) => [
function mergeFilesToIgnores(...mappings: FilesToIgnores[]): FilesToIgnores {
const result: FilesToIgnores = {};
mappings.forEach((mapping) => {
Object.entries(mapping).forEach(([file, ignores]) => {
if (result[file]) {
result[file].push(...ignores);
} else {
result[file] = ignores;
}
});
});
return result;
}

const _QISKIT_QPY_IGNORES = Object.fromEntries(
["", "dev/", "0.46/", "1.0/", "1.1/", "1.2/"].map((vers) => [
`docs/api/qiskit/${vers}qpy.mdx`,
[
"#f1",
Expand Down Expand Up @@ -134,43 +116,152 @@ const _RUNTIME_OBJECT_INV = Object.fromEntries(
]),
);

function _qiskitUtilsData(): FilesToIgnores {
// Qiskit docs used .. py:data:: incorrectly. We didn't fix these versions of the docs
// because it is too tedious.
const objectsInv = Object.fromEntries(
["0.46/", "1.0/", "1.1/"].map((vers) => [
`public/api/qiskit/${vers}objects.inv`,
[
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_AER`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_CONSTRAINT`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_CPLEX`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_CVXPY`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_DOCPLEX`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_FIXTURES`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_GRAPHVIZ`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_IBMQ`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_IGNIS`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_IPYTHON`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_IPYWIDGETS`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_JAX`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_JUPYTER`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_MATPLOTLIB`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_NETWORKX`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_NLOPT`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_PDFLATEX`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_PDFTOCAIRO`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_PIL`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_PYDOT`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_PYGMENTS`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_PYLATEX`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_QASM3_IMPORT`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_SEABORN`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_SKLEARN`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_SKQUANT`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_SKSNFIT`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_SQSNOBFIT`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_SYMENGINE`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_TESTTOOLS`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_TOQM`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_TWEEDLEDUM`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_Z3`,
],
]),
);
const utilsFile = Object.fromEntries(
["0.46/", "1.0/", "1.1/"].map((vers) => [
`docs/api/qiskit/${vers}utils.mdx`,
[
"#qiskit.utils.optionals.HAS_TESTTOOLS",
"#qiskit.utils.optionals.HAS_GRAPHVIZ",
"#qiskit.utils.optionals.HAS_PYDOT",
],
]),
);
return {
"docs/api/qiskit/release-notes/1.0.mdx": [
"/api/qiskit/1.0/utils#qiskit.utils.optionals.HAS_SYMENGINE",
],
...objectsInv,
...utilsFile,
};
}

function _patternsReorg(): FilesToIgnores {
// We have redirects for all these files. It's best to update API docs to point directly to the new URL,
// but we don't bother updating old docs.
const qiskit = Object.fromEntries(
["", "0.46/", "1.0/", "1.1/"].flatMap((vers) => [
[
`docs/api/qiskit/${vers}qiskit.circuit.QuantumCircuit.mdx`,
["/build/circuit-construction"],
],
[
`docs/api/qiskit/${vers}qiskit.transpiler.passes.ValidatePulseGates.mdx`,
["/build/pulse"],
],
[`docs/api/qiskit/${vers}qpy.mdx`, ["/build/pulse"]],
]),
);
const runtime = Object.fromEntries(
[14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26].flatMap((vers) => [
[
`docs/api/qiskit-ibm-runtime/0.${vers}/qiskit_ibm_runtime.Batch.mdx`,
["/run/run-jobs-batch", "/run/max-execution-time"],
],
[
`docs/api/qiskit-ibm-runtime/0.${vers}/qiskit_ibm_runtime.Session.mdx`,
["/run/max-execution-time"],
],
[
`docs/api/qiskit-ibm-runtime/0.${vers}/qiskit_ibm_runtime.options.Options.mdx`,
[
"/run/max-execution-time",
"/run/configure-error-mitigation",
"/run/max-execution-time#maximum-execution-time",
],
],
[
`docs/api/qiskit-ibm-runtime/0.${vers}/qiskit_ibm_runtime.options.EstimatorOptions.mdx`,
[
"/run/configure-error-mitigation",
"/run/configure-runtime-compilation",
],
],
[
`docs/api/qiskit-ibm-runtime/0.${vers}/qiskit_ibm_runtime.EstimatorV1.mdx`,
["/api/migration-guides/v2-primitives"],
],
[
`docs/api/qiskit-ibm-runtime/0.${vers}/qiskit_ibm_runtime.SamplerV1.mdx`,
["/api/migration-guides/v2-primitives"],
],
[
`docs/api/qiskit-ibm-runtime/0.${vers}/qiskit_ibm_runtime.EstimatorV2.mdx`,
["/run"],
],
[
`docs/api/qiskit-ibm-runtime/0.${vers}/qiskit_ibm_runtime.SamplerV2.mdx`,
["/run"],
],
[
`docs/api/qiskit-ibm-runtime/0.${vers}/qiskit_ibm_runtime.noise_learner.NoiseLearner.mdx`,
["/run"],
],
[`docs/api/qiskit-ibm-runtime/0.${vers}/transpiler.mdx`, ["/transpile"]],
]),
);
return {
...qiskit,
...runtime,
"docs/api/qiskit/release-notes/1.0.mdx": [
"/start/install#qiskit-versioning",
"/start/configure-qiskit-local",
],
"docs/api/qiskit/release-notes/0.46.mdx": [
"/start/install#qiskit-versioning",
],
"docs/api/qiskit/1.1/qiskit.quantum_info.SparsePauliOp.mdx": [
"/start/configure-qiskit-local#environment-variables",
],
};
}

const _QISKIT_OBJECT_INV = Object.fromEntries(
["", "dev/", "0.46/", "1.0/", "1.1/"].map((vers) => [
`public/api/qiskit/${vers}objects.inv`,
[
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_AER`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_CONSTRAINT`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_CPLEX`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_CVXPY`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_DOCPLEX`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_FIXTURES`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_GRAPHVIZ`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_IBMQ`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_IGNIS`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_IPYTHON`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_IPYWIDGETS`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_JAX`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_JUPYTER`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_MATPLOTLIB`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_NETWORKX`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_NLOPT`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_PDFLATEX`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_PDFTOCAIRO`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_PIL`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_PYDOT`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_PYGMENTS`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_PYLATEX`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_QASM3_IMPORT`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_SEABORN`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_SKLEARN`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_SKQUANT`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_SKSNFIT`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_SQSNOBFIT`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_SYMENGINE`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_TESTTOOLS`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_TOQM`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_TWEEDLEDUM`,
`/api/qiskit/${vers}utils#qiskit.utils.optionals.HAS_Z3`,
`/api/qiskit/${vers}qiskit.visualization.timeline_drawer#style-dict-doc`,
`/api/qiskit/${vers}qiskit.pulse.library.SymbolicPulse#symbolic-pulse-constraints`,
`/api/qiskit/${vers}qiskit.pulse.library.SymbolicPulse#symbolic-pulse-envelope`,
Expand All @@ -181,28 +272,24 @@ const _QISKIT_OBJECT_INV = Object.fromEntries(
]),
);

const FILES_TO_IGNORES__EXPECTED: FilesToIgnores = {};

const FILES_TO_IGNORES__SHOULD_FIX: FilesToIgnores = {
// Qiskit
"docs/api/qiskit/release-notes/1.0.mdx": [
"/api/qiskit/1.0/utils#qiskit.utils.optionals.HAS_SYMENGINE",
],
"docs/api/qiskit/0.46/qiskit.algorithms.optimizers.NFT.mdx": ["#id1", "#id2"],
..._QPY_IGNORES,
// Runtime
"docs/api/qiskit-ibm-runtime/release-notes.mdx": [
"/api/qiskit-ibm-runtime/qiskit_ibm_runtime.QiskitRuntimeService#runtime",
"/api/qiskit-ibm-runtime/qiskit_ibm_runtime.Sampler#run",
"/api/qiskit-ibm-runtime/qiskit_ibm_runtime.RuntimeOptions",
"/api/qiskit-ibm-runtime/qiskit_ibm_runtime.options.ResilienceOptions",
],
// objects.inv
..._RUNTIME_OBJECT_INV,
..._QISKIT_OBJECT_INV,
};

export const FILES_TO_IGNORES: FilesToIgnores = {
...FILES_TO_IGNORES__EXPECTED,
...FILES_TO_IGNORES__SHOULD_FIX,
};
const FILES_TO_IGNORES__EXPECTED: FilesToIgnores = mergeFilesToIgnores(
_qiskitUtilsData(),
_patternsReorg(),
{
"docs/api/qiskit/0.46/qiskit.algorithms.optimizers.NFT.mdx": [
"#id1",
"#id2",
],
},
);

const FILES_TO_IGNORES__SHOULD_FIX: FilesToIgnores = mergeFilesToIgnores(
_QISKIT_QPY_IGNORES,
_RUNTIME_OBJECT_INV,
_QISKIT_OBJECT_INV,
);

export const FILES_TO_IGNORES: FilesToIgnores = mergeFilesToIgnores(
FILES_TO_IGNORES__EXPECTED,
FILES_TO_IGNORES__SHOULD_FIX,
);

0 comments on commit f8c4ffc

Please sign in to comment.