diff --git a/.vortex/docs/content/contributing/maintenance/release.mdx b/.vortex/docs/content/contributing/maintenance/release.mdx index ab6a75719c..7948014db0 100644 --- a/.vortex/docs/content/contributing/maintenance/release.mdx +++ b/.vortex/docs/content/contributing/maintenance/release.mdx @@ -50,6 +50,7 @@ When creating a new release, determine the version based on the changes: Promoting a new major version is a single action: set the `VORTEX_CURRENT_MAJOR` repository variable to its number. The documentation default and the installer's bare `/install` URL both follow it, while the per-major docs and `/v{N}/install` pins are always published. When `main` advances to a new major version: + 1. The upcoming major's branch (for example `2.x`) is merged into `main` 2. The superseded major continues on its own branch (for example `1.x`) for maintenance @@ -80,9 +81,11 @@ The following rules apply to every release: Follow the steps below to release a new version of the Vortex: 1. Run renovate bot locally to update all dependencies outside of the schedule: -``` -renovate --schedule= --force-cli=true drevops/vortex -``` + + ```shell + renovate --schedule= --force-cli=true drevops/vortex + ``` + 2. Update container images to the latest versions and check that `@see` links are working. - After bumping the `uselagoon/solr-9-drupal` image, update `solr.luceneMatchVersion` in `.docker/config/solr/config-set/solrcore.properties` to match the Lucene version bundled in that image (shown by the `lucene-core-*.jar` filename inside the image). The value in `search_api_solr`'s jump-start config-set lags the image, so it must not be copied verbatim. 3. Update PHP version in `composer.json` for `config.platform`. diff --git a/.vortex/docs/content/contributing/maintenance/template.mdx b/.vortex/docs/content/contributing/maintenance/template.mdx index 514ed68ab9..21cf5a0b53 100644 --- a/.vortex/docs/content/contributing/maintenance/template.mdx +++ b/.vortex/docs/content/contributing/maintenance/template.mdx @@ -20,13 +20,14 @@ in [this issue](https://github.com/drevops/vortex/issues/1192). :::note - Please refer to [RFC2119](https://www.ietf.org/rfc/rfc2119.txt) for meaning of words `MUST`, `SHOULD` and `MAY`. +Please refer to [RFC2119](https://www.ietf.org/rfc/rfc2119.txt) for meaning of words `MUST`, `SHOULD` and `MAY`. ::: 1. MUST adhere to [POSIX standard](https://en.wikipedia.org/wiki/POSIX). 2. MUST pass Shellcheck code analysis scan 3. MUST start with: + ```shell #!/usr/bin/env bash ## @@ -39,17 +40,23 @@ in [this issue](https://github.com/drevops/vortex/issues/1192). set -eu [ "${VORTEX_DEBUG-}" = "1" ] && set -x ``` + 4. MUST list all variables with their default values and descriptions. i.e.: + ```shell # Deployment reference, such as a git SHA. VORTEX_NOTIFY_REF="${VORTEX_NOTIFY_REF:-}" ``` + 5. MUST include a delimiter between variables and the script body preceded and followed by an empty line (3 lines in total): + ```shell # ------------------------------------------------------------------------------ ``` + 6. SHOULD include formatting helper functions: + ```shell # @formatter:off note() { printf " %s\n" "${1}"; } @@ -58,22 +65,31 @@ in [this issue](https://github.com/drevops/vortex/issues/1192). fail() { [ "${TERM:-}" != "dumb" ] && tput colors >/dev/null 2>&1 && printf "\033[31m[FAIL] %s\033[0m\n" "${1}" || printf "[FAIL] %s\n" "${1}"; } # @formatter:on ``` -7. SHOULD include variable values checks with errors and early exist, i.e.: + +7. SHOULD include variable values checks with errors and early exit, i.e.: + ```shell [ -z "${VORTEX_NOTIFY_REF}" ] && fail "Missing required value for VORTEX_NOTIFY_REF." && exit 1 ``` + 8. SHOULD include binaries checks if the script relies on them, i.e.: + ```shell command -v curl > /dev/null || ( fail "curl command is not available." && exit 1 ) ``` + 9. MUST contain an `info` message about the start of the script body, e.g.: + ```shell info "Started GitHub notification for operation ${VORTEX_NOTIFY_EVENT}." ``` + 10. MUST contain an `pass` message about the finish of the script body, e.g.: + ```shell pass "Finished GitHub notification for operation ${VORTEX_NOTIFY_EVENT}." ``` + 11. MUST use uppercase global variables 12. MUST use lowercase local variables. 13. MUST use long options instead of short options for readability. I.e., `drush cache:rebuild` instead of `drush cr`. @@ -90,7 +106,6 @@ in [this issue](https://github.com/drevops/vortex/issues/1192). 18. SHOULD use `note` messages for informing about the script progress. 19. MUST use variables in the form of `${VAR}`. - ### Variables Follow these guidelines when creating or updating **Vortex** variables. diff --git a/.vortex/docs/content/support.mdx b/.vortex/docs/content/support.mdx index 5f8b7034cb..ffd54f0943 100644 --- a/.vortex/docs/content/support.mdx +++ b/.vortex/docs/content/support.mdx @@ -1,5 +1,4 @@ --- -title: Support description: Get help with Vortex - multiple support channels and resources available --- @@ -11,7 +10,6 @@ Get help with **Vortex** through our comprehensive support channels and resource New to **Vortex**? Start with our [Installation Guide](/docs/installation) and then explore the [Features](/docs/features). ::: - ## 🛟 Getting Help ### Quick Self-Help @@ -24,13 +22,14 @@ Start with these resources to solve common issues quickly: ### Community Support -**Slack Community** +#### Slack Community - Join the [`#vortex-project-template`](https://drupal.slack.com/archives/CRE86HQTW) Slack channel - Get help from the community and core maintainers - Share ideas and collaborate with other users -**GitHub Discussions** +#### GitHub Discussions + - [GitHub Issues](https://github.com/drevops/vortex/issues) for bug reports and feature requests - [Project Board](https://github.com/orgs/drevops/projects/2/views/1) to track development progress - Check existing issues before submitting new ones @@ -60,6 +59,7 @@ For organizations requiring dedicated support, we offer professional services: ### How to Report When reporting issues, please include: + - System information (`ahoy doctor info`) - Steps to reproduce the problem - Error messages and logs diff --git a/.vortex/docs/cspell.json b/.vortex/docs/cspell.json index 06bc75ce0f..44d008f7e6 100644 --- a/.vortex/docs/cspell.json +++ b/.vortex/docs/cspell.json @@ -20,6 +20,7 @@ "Runsheets", "Upsun", "acquia", + "alexskrypnyk", "amazee", "amazeeio", "apikey", @@ -41,6 +42,8 @@ "ddev", "dealerdirect", "devel", + "didi", + "downloaders", "drevops", "drupalcode", "drush", diff --git a/.vortex/docs/package.json b/.vortex/docs/package.json index bf1117746a..360d997de6 100644 --- a/.vortex/docs/package.json +++ b/.vortex/docs/package.json @@ -11,7 +11,7 @@ "serve": "docusaurus serve", "write-translations": "docusaurus write-translations", "write-heading-ids": "docusaurus write-heading-ids", - "spellcheck": "cspell content/*.mdx content/**/*.mdx", + "spellcheck": "cspell \"content/**/*.mdx\"", "update-variables": "./.utils/update-docs.sh", "test": "jest", "test:watch": "jest --watch", @@ -20,8 +20,8 @@ "lint-fix": "yarn lint-js-fix && yarn lint-docs-fix", "lint-js": "eslint src/ tests/ && prettier --check src/ tests/", "lint-js-fix": "eslint src/ tests/ --fix && prettier --write src/ tests/", - "lint-docs": "markdownlint-cli2 content/**/*.mdx", - "lint-docs-fix": "markdownlint-cli2 content/**/*.mdx --fix" + "lint-docs": "markdownlint-cli2 \"content/**/*.mdx\"", + "lint-docs-fix": "markdownlint-cli2 \"content/**/*.mdx\" --fix" }, "dependencies": { "@docusaurus/core": "^3.5", diff --git a/.vortex/docs/tests/unit/lint-globs.test.js b/.vortex/docs/tests/unit/lint-globs.test.js new file mode 100644 index 0000000000..f4ed016d4f --- /dev/null +++ b/.vortex/docs/tests/unit/lint-globs.test.js @@ -0,0 +1,84 @@ +import fs from 'fs'; +import path from 'path'; + +// Yarn runs package scripts through 'sh', which has no 'globstar': an unquoted +// '**' collapses to a single '*', so the linters receive a shell-expanded list +// that stops one directory below 'content/'. Both tools then exit 0 and report +// a plausible file count, leaving deeper pages unchecked with no signal. +const DOCS_ROOT = path.resolve(__dirname, '../..'); +const CONTENT_DIR = 'content'; +const SCRIPTS = ['spellcheck', 'lint-docs', 'lint-docs-fix']; + +const packageJson = JSON.parse( + fs.readFileSync(path.join(DOCS_ROOT, 'package.json'), 'utf8') +); + +const tokenize = script => (script || '').match(/"[^"]*"|\S+/g) || []; + +const isQuoted = token => token.startsWith('"') && token.endsWith('"'); + +const isGlob = token => /[*?]/.test(token); + +// '**/' spans any number of directories, '*' stops at the separator. +const globToRegExp = glob => { + const source = glob.replace(/\*\*\/|\*|[.+^${}()|[\]\\?]/g, match => { + if (match === '**/') { + return '(?:[^/]+/)*'; + } + + if (match === '*') { + return '[^/]*'; + } + + return `\\${match}`; + }); + + return new RegExp(`^${source}$`); +}; + +const collectPages = (dir, pages = []) => { + const entries = fs.readdirSync(path.join(DOCS_ROOT, dir), { + withFileTypes: true, + }); + + for (const entry of entries) { + const relative = `${dir}/${entry.name}`; + + if (entry.isDirectory()) { + collectPages(relative, pages); + continue; + } + + if (entry.name.endsWith('.mdx')) { + pages.push(relative); + } + } + + return pages; +}; + +describe('Documentation lint globs', () => { + const pages = collectPages(CONTENT_DIR); + + test('documentation pages are discoverable', () => { + expect(pages.length).toBeGreaterThan(0); + }); + + describe.each(SCRIPTS)('%s', name => { + const args = tokenize(packageJson.scripts[name]); + + test('passes globs quoted so the tool expands them, not the shell', () => { + expect(args.filter(arg => !isQuoted(arg) && isGlob(arg))).toEqual([]); + }); + + test('covers every documentation page', () => { + const globs = args + .filter(isQuoted) + .map(arg => globToRegExp(arg.slice(1, -1))); + + expect( + pages.filter(page => !globs.some(glob => glob.test(page))) + ).toEqual([]); + }); + }); +});