├── .appveyor.yml ├── .github ├── dependabot.yml └── workflows │ └── CI.yml ├── .gitignore ├── .yo-rc.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── doc ├── docs │ ├── about │ │ ├── compatibility.md │ │ ├── history.md │ │ ├── license.md │ │ └── migration.md │ ├── examples.md │ ├── getting-started.md │ ├── guide │ │ ├── configuration.md │ │ ├── multi-version.md │ │ ├── pip.md │ │ ├── publication.md │ │ ├── tasks.md │ │ ├── theme.md │ │ └── vars.md │ └── index.md └── mkdocs.yml ├── main ├── groovy │ └── ru │ │ └── vyarus │ │ └── gradle │ │ └── plugin │ │ └── mkdocs │ │ ├── GitPublishExtension.groovy │ │ ├── MkdocsBuildPlugin.groovy │ │ ├── MkdocsExtension.groovy │ │ ├── MkdocsPlugin.groovy │ │ ├── service │ │ └── GrgitService.groovy │ │ ├── source │ │ └── RepoUriValueSource.groovy │ │ ├── task │ │ ├── GitVersionsTask.groovy │ │ ├── MkdocsBuildTask.groovy │ │ ├── MkdocsInitTask.groovy │ │ ├── MkdocsTask.groovy │ │ └── publish │ │ │ ├── GitPublishCommit.groovy │ │ │ ├── GitPublishPush.groovy │ │ │ └── GitPublishReset.groovy │ │ └── util │ │ ├── MkdocsConfig.groovy │ │ ├── TemplateUtils.groovy │ │ ├── VersionsComparator.groovy │ │ └── VersionsFileUtils.groovy └── resources │ └── ru │ └── vyarus │ └── gradle │ └── plugin │ └── mkdocs │ └── template │ ├── init │ ├── docs │ │ ├── about │ │ │ └── history.md │ │ ├── guide │ │ │ └── installation.md │ │ └── index.md │ └── mkdocs.yml │ └── publish │ └── index.html └── test └── groovy └── ru └── vyarus └── gradle └── plugin └── mkdocs ├── AbstractKitTest.groovy ├── AbstractTest.groovy ├── ConfigurationCacheSupportKitTest.groovy ├── ConfigurationCacheSupportPushKitTest.groovy ├── CustomThemeKitTest.groovy ├── DocsInModuleAndRootKitTest.groovy ├── DocsInModuleKitTest.groovy ├── LegacyKitTest.groovy ├── MkdocsBuildKitTest.groovy ├── MkdocsBuildPluginTest.groovy ├── MkdocsPluginKitTest.groovy ├── MkdocsPluginTest.groovy ├── UpstreamKitTest.groovy ├── UpstreamPublishKitTest.groovy ├── VersionsUpdateKitTest.groovy ├── docker └── DockerKitTest.groovy ├── task ├── BuildTaskKitTest.groovy ├── ExtraVarsKitTest.groovy ├── InitTaskKitTest.groovy ├── PublishJavadocKitTest.groovy ├── PushTaskKitTest.groovy ├── ServeTaskKitTest.groovy ├── UrlChangeKitTest.groovy ├── VersionAliasTest.groovy └── VersionsFileTest.groovy └── util ├── MkdocsConfigTest.groovy ├── TemplateUtilsTest.groovy └── VersionComparatorTest.groovy /.appveyor.yml: -------------------------------------------------------------------------------- 1 | version: '{build}' 2 | image: Visual Studio 2019 3 | 4 | environment: 5 | matrix: 6 | - job_name: Java 8, python 3.8 7 | JAVA_HOME: C:\Program Files\Java\jdk1.8.0 8 | PYTHON: "C:\\Python38-x64" 9 | - job_name: Java 11, python 3.11 10 | JAVA_HOME: C:\Program Files\Java\jdk11 11 | PYTHON: "C:\\Python311-x64" 12 | - job_name: Java 17, python 3.12 13 | JAVA_HOME: C:\Program Files\Java\jdk17 14 | appveyor_build_worker_image: Visual Studio 2019 15 | PYTHON: "C:\\Python312-x64" 16 | 17 | install: 18 | - set PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH% 19 | - python --version 20 | - python -m pip install -U virtualenv==20.25.1 21 | 22 | build_script: 23 | - ./gradlew assemble --no-daemon 24 | test_script: 25 | - ./gradlew check --no-daemon 26 | 27 | on_success: 28 | - ./gradlew jacocoTestReport --no-daemon 29 | - ps: | 30 | $ProgressPreference = 'SilentlyContinue' 31 | Invoke-WebRequest -Uri https://uploader.codecov.io/latest/windows/codecov.exe -Outfile codecov.exe 32 | .\codecov.exe -f build\reports\jacoco\test\jacocoTestReport.xml -F windows 33 | 34 | cache: 35 | - C:\Users\appveyor\.gradle\caches 36 | - C:\Users\appveyor\.gradle\wrapper -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gradle 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "23:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | name: Java ${{ matrix.java }}, python ${{ matrix.python }} 11 | strategy: 12 | matrix: 13 | java: [8, 11, 17] 14 | python: ['3.8', '3.11', '3.12'] 15 | 16 | exclude: 17 | - java: 8 18 | python: '3.11' 19 | - java: 8 20 | python: '3.12' 21 | - java: 11 22 | python: '3.8' 23 | - java: 11 24 | python: '3.12' 25 | - java: 17 26 | python: '3.8' 27 | - java: 17 28 | python: '3.11' 29 | 30 | steps: 31 | - uses: actions/checkout@v4 32 | 33 | - name: Set up JDK ${{ matrix.java }} 34 | uses: actions/setup-java@v4 35 | with: 36 | distribution: 'zulu' 37 | java-version: ${{ matrix.java }} 38 | 39 | - name: Set up Python ${{ matrix.python }} 40 | uses: actions/setup-python@v4 41 | with: 42 | python-version: ${{matrix.python}} 43 | 44 | - name: Setup Gradle 45 | uses: gradle/actions/setup-gradle@v3 46 | 47 | - name: Build 48 | run: | 49 | chmod +x gradlew 50 | python --version 51 | pip --version 52 | ./gradlew assemble --no-daemon 53 | 54 | - name: Test 55 | env: 56 | GH_ACTIONS: true 57 | run: ./gradlew check --no-daemon 58 | 59 | - name: Build coverage report 60 | if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' 61 | run: ./gradlew jacocoTestReport --no-daemon 62 | 63 | - uses: codecov/codecov-action@v4 64 | if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' 65 | with: 66 | files: build/reports/jacoco/test/jacocoTestReport.xml 67 | flags: LINUX 68 | fail_ci_if_error: true 69 | token: ${{ secrets.CODECOV_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created with https://www.gitignore.io 2 | 3 | ### Gradle ### 4 | .gradle/ 5 | build/ 6 | 7 | # Ignore Gradle GUI config 8 | gradle-app.setting 9 | 10 | ### JetBrains ### 11 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 12 | 13 | /*.iml 14 | 15 | ## Directory-based project format: 16 | .idea/ 17 | 18 | ## File-based project format: 19 | *.ipr 20 | *.iws 21 | 22 | ## Plugin-specific files: 23 | 24 | # IntelliJ 25 | out/ 26 | 27 | # mpeltonen/sbt-idea plugin 28 | .idea_modules/ 29 | 30 | # JIRA plugin 31 | atlassian-ide-plugin.xml 32 | 33 | # Crashlytics plugin (for Android Studio and IntelliJ) 34 | com_crashlytics_export_strings.xml 35 | 36 | 37 | ### Eclipse ### 38 | *.pydevproject 39 | .metadata 40 | bin/ 41 | tmp/ 42 | *.tmp 43 | *.bak 44 | *.swp 45 | *~.nib 46 | local.properties 47 | .settings/ 48 | .loadpath 49 | 50 | # External tool builders 51 | .externalToolBuilders/ 52 | 53 | # Locally stored "Eclipse launch configurations" 54 | *.launch 55 | 56 | # CDT-specific 57 | .cproject 58 | 59 | # PDT-specific 60 | .buildpath 61 | 62 | # sbteclipse plugin 63 | .target 64 | 65 | # TeXlipse plugin 66 | .texlipse 67 | 68 | ### Java ### 69 | *.class 70 | 71 | # Mobile Tools for Java (J2ME) 72 | .mtj.tmp/ 73 | 74 | # Package Files # 75 | *.war 76 | *.ear 77 | 78 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 79 | hs_err_pid* 80 | 81 | 82 | ### NetBeans ### 83 | nbproject/private/ 84 | nbbuild/ 85 | dist/ 86 | nbdist/ 87 | nbactions.xml 88 | nb-configuration.xml 89 | 90 | 91 | ### OSX ### 92 | .DS_Store 93 | .AppleDouble 94 | .LSOverride 95 | 96 | # Icon must end with two \r 97 | Icon 98 | 99 | 100 | # Thumbnails 101 | ._* 102 | 103 | # Files that might appear on external disk 104 | .Spotlight-V100 105 | .Trashes 106 | 107 | # Directories potentially created on remote AFP share 108 | .AppleDB 109 | .AppleDesktop 110 | Network Trash Folder 111 | Temporary Items 112 | .apdisk 113 | 114 | 115 | ### Windows ### 116 | # Windows image file caches 117 | Thumbs.db 118 | ehthumbs.db 119 | 120 | # Folder config file 121 | Desktop.ini 122 | 123 | # Recycle Bin used on file shares 124 | $RECYCLE.BIN/ 125 | 126 | # Windows Installer files 127 | *.cab 128 | *.msi 129 | *.msm 130 | *.msp 131 | 132 | # Windows shortcuts 133 | *.lnk 134 | 135 | 136 | ### Linux ### 137 | *~ 138 | 139 | # KDE directory preferences 140 | .directory 141 | 142 | ### JEnv ### 143 | # JEnv local Java version configuration file 144 | .java-version 145 | 146 | # Used by previous versions of JEnv 147 | .jenv-version 148 | -------------------------------------------------------------------------------- /.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-gradle-plugin": { 3 | "githubUser": "xvik", 4 | "authorName": "Vyacheslav Rusakov", 5 | "authorEmail": "vyarus@gmail.com", 6 | "projectName": "gradle-mkdocs-plugin", 7 | "projectGroup": "ru.vyarus", 8 | "projectPackage": "ru.vyarus.gradle.plugin.mkdocs", 9 | "projectVersion": "0.1.0", 10 | "projectDesc": "Mkdocs documentation plugin", 11 | "pluginPortalDesc": "Mkdocs documentation generation and publishing plugin", 12 | "pluginPortalTags": "documentation, mkdocs", 13 | "pluginPortalUseCustomGroup": true, 14 | "usedGeneratorVersion": "2.0.0", 15 | "centralPublish": true 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### 4.0.1 (2024-04-15) 2 | * Fix non-strict build (#88) 3 | * Fix emoji plugin in default mkdocs.yml (emoji support moved from material extensions to mkdocs directly) 4 | 5 | ### 4.0.0 (2024-04-14) 6 | * (breaking) Drop gradle 5 and 6 support 7 | * All tasks properties replaced with lazy properties 8 | * Remove git-publish plugin. Plugin functions added directly with required modifications 9 | so usage will be the same (compatible). The Author of the original plugin deprecated it 10 | (together with grgit). Still, grgit will be used for now (because of its feature completeness) 11 | - Authorization properties support remains for backwards compatibility, but auth could 12 | be specified now directly in gitPublish.username (and password). 13 | * Configuration cache compatibility 14 | * Update packages: 15 | - mkdocs 1.4.1 -> 1.5.3 16 | - mkdocs-material 8.5.7 -> 9.5.17 17 | - pygments 2.13.0 -> 2.17.2 18 | - pymdown-extensions 9.7 -> 10.7.1 19 | * Support hiding versions in versions file: 20 | - mkdocs.publish.hideVersions - set versions to hide 21 | - mkdocs.publish.hideOldBugfixVersions - automatically hide bugfix versions (disabled by default) 22 | 23 | ### 3.0.0 (2022-11-01) 24 | * (breaking) Drop gradle 5.0-5.2 support (minimum required gradle is 5.3) 25 | * Python plugin related changes: 26 | - Add docker support (with raw python container by default) 27 | - Add python requirements.txt file support 28 | - Add cleanPython task to easily cleanup local environment 29 | * Dev server port number is now configurable: devPort property 30 | (this required for proper docker support when non-local ip must be specified) 31 | * mkdocs.resolveDocPath() never return null: 32 | for single version docs '.' is returned now instead of null (#41) 33 | * Update packages: 34 | - mkdocs 1.3.0 -> 1.4.1 35 | - mkdocs-material 8.3.6 -> 8.5.7 36 | - pygments 2.12.0 -> 2.13.0 37 | - pymdown-extensions 9.4 -> 9.7 38 | * Ignore all git errors during plugin initialization (git used to resolve repoUrl on initialization) (#45) 39 | * Split plugin into 2 plugins to let users use plugin without custom publication implementation: 40 | - mkdocs-build - everything without publication (and no grgit plugin activation) 41 | - mkdocs - same as before (registers mkdocs-build plugin and configures publication tasks) 42 | * mkdocsBuild task could now update existing versions file (even download from URL) (#31) 43 | - To enable specify existing versions file location: mkdocs.publish.existingVersionsFile = '...' 44 | - When target file not found new (empty) one would be created 45 | - Ideal for incremental publishing when each publication just adds a new version to existing file 46 | (when git publication is not used) 47 | 48 | WARNING: minimum recommended python is 3.8 49 | 50 | ### 2.4.0 (2022-06-17) 51 | * Fix variables support for gradle 7.4 (#34) 52 | * Update packages: 53 | - mkdocs-material 8.2.8 -> 8.3.6 54 | - pygments 2.11.2 -> 2.12.0 55 | - pymdown-extensions 9.1 -> 9.4 56 | 57 | WARNING: since mkdocs-material [8.2.13](https://squidfunk.github.io/mkdocs-material/changelog/#8.2.13) 58 | minimum required python is 3.7! 59 | 60 | ### 2.3.0 (2022-04-02) 61 | * Update packages: 62 | - mkdocs 1.2.3 -> 1.3.0 (fixes #29: jinja2 3.1.0 support) 63 | - mkdocs-material 8.0.2 -> 8.2.8 64 | - pygments 2.10.0 -> 2.11.2 65 | - mkdocs-markdownextradata-plugin 0.2.4 -> 0.2.5 66 | 67 | ### 2.2.0 (2021-12-08) 68 | * Update packages: 69 | - mkdocs 1.1.2 -> 1.2.3 70 | See breaking changes: https://www.mkdocs.org/about/release-notes/#backward-incompatible-changes-in-12 71 | * site_url is now required 72 | * google_analytics option deprecated - theme specific configurations used instead (see below) 73 | - mkdocs-material 7.0.6 -> 8.0.2 74 | Migration notes: https://squidfunk.github.io/mkdocs-material/upgrade/#upgrading-from-7x-to-8x 75 | * instead of google_analytics extra.analytics must be used 76 | * replace codehilite extension with pymdownx.highlight 77 | * to activate light/dark theme toggle (#12) 78 | https://squidfunk.github.io/mkdocs-material/setup/changing-the-colors/#color-palette-toggle 79 | - pygments 2.8.0 -> 2.10.0 80 | - pymdown-extensions 8.1.1 -> 9.1 81 | * Update mkdocs.yaml generated by init task with most useful options commented 82 | * Add support for version switcher (without mike tool usage), by generating versions.json from publish repository folders (#10) 83 | - New option mkdocs.publish.generateVersionsFile could disable versions.json file generation 84 | - File generated by new mkdocsVersionsFile task which may be used instead of mkdocsBuild to test switcher 85 | * Add aliases support (same way as in mike), declared with new option mkdocs.publish.versionAliases 86 | * Add mkdocs.publish.rootRedirectTo option to be able to configure root redirection into alias 87 | 88 | ### 2.1.2 (2021-12-01) 89 | * Fix java 8 support, dropped due to jgit 6 transitive dependency (#13) 90 | 91 | ### 2.1.1 (2021-03-18) 92 | * Fix variables support ignore 'docs_dir' configuration from mkdocs.yml (#8) 93 | 94 | ### 2.1.0 (2021-03-17) 95 | * Support python installed from Windows Store (use-python-plugin 2.3.0) 96 | * Update packages: 97 | - mkdocs 1.1 -> 1.1.2 98 | - mkdocs-material 4.6.3 -> 7.0.6 99 | - pygments 2.6.1 -> 2.8.0 100 | - pymdown-extensions 6.3.0 -> 8.1.1 101 | * Optional variables support for all mkdocs tasks: there is no (and not planned) native support for 102 | variables in mkdocs, but often it is very handful. It is only possible to have it with a plugin. (#7) 103 | - Added mkdocs-markdownextradata-plugin 0.2.4 as installed module (no harm, you must active it manually!) 104 | - Added mkdocs.extras configuration option: map to declare additional variables 105 | - When extra variables declared, plugin would generate a special file, containing all declared variables, 106 | which markdownextradata plugin would recognize and use automatically. 107 | - Variables must be used with 'gradle' prefix: {{ gradle.declared_var_name }} 108 | 109 | WARNING: there were some scheme changes in mkdocs-material. 110 | Most likely you may face social links change: 111 | 112 | Before: 113 | social: 114 | - type: github 115 | link: https://github.com/xvik 116 | 117 | After: 118 | social: 119 | - icon: fontawesome/brands/github 120 | link: https://github.com/xvik 121 | 122 | See [mkdocs-material upgrade guide](https://squidfunk.github.io/mkdocs-material/upgrading/#extrasocial) for details 123 | 124 | ### 2.0.1 (2020-04-06) 125 | * Fix relative virtualenv paths support (don't rely on gradle work dir) (#5) 126 | 127 | ### 2.0.0 (2020-03-13) 128 | * (breaking) Drop java 7 support 129 | * (breaking) Drop gradle 4 support 130 | * Fix jgit dependency conflict (#4) (plugin now use jgit 5) 131 | * Update packages: 132 | - mkdocs 1.0.4 -> 1.1 133 | - mkdocs-material 3.0.4 -> 4.6.3 134 | - pygments 2.2.0 -> 2.6.1 135 | - pymdown-extensions 6.0.0 -> 6.3.0 136 | * Use gradle tasks configuration avoidance for lazy tasks initialization (no init when tasks not needed) 137 | 138 | ### 1.1.0 (2018-10-14) 139 | * Default template's mkdocs.yml changes: 140 | - fixed `edit_uri` (missed "/docs" ending) 141 | - `pages` changed to `nav` 142 | - change parameters syntax in `markdown_extensions` section 143 | * Fix documentation in sub module support (use-python plugin 1.2.0) 144 | * Support Mkdocks 1.0: 145 | - Update default mkdocs 0.17.3 -> 1.0.4 146 | - Update default mkdocs-material 2.7.2 -> 3.0.4 147 | - Update default pymdown-extensions 4.9.2 -> 6.0.0 148 | 149 | [Mkdocs 1.0](https://www.mkdocs.org/about/release-notes/#version-10-2018-08-03) migration notes (for existing docs): 150 | 151 | - Rename `pages` section into `nav` 152 | - Make sure `site_url` set correctly (otherwise sitemap will contain None instead of urls) 153 | - Change `markdown_extensions` section from using `something(arg=val)` syntax into: 154 | 155 | ```yaml 156 | markdown_extensions: 157 | - admonition 158 | - codehilite: 159 | guess_lang: false 160 | - footnotes 161 | - meta 162 | - toc: 163 | permalink: true 164 | - pymdownx.betterem: 165 | smart_enable: all 166 | - pymdownx.caret 167 | - pymdownx.inlinehilite 168 | - pymdownx.magiclink 169 | - pymdownx.smartsymbols 170 | - pymdownx.superfences 171 | ``` 172 | 173 | ### 1.0.1 (2018-04-23) 174 | * Fix pip 10 compatibility (use-python plugin 1.0.2) 175 | * Update default mkdocs 0.17.2 -> 0.17.3 176 | * Update default mkdocs-material 2.2.1 -> 2.7.2 177 | * Update default pymdown-extensions 4.6 -> 4.9.2 178 | 179 | ### 1.0.0 (2017-12-30) 180 | * Initial release -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017-2024, Vyacheslav Rusakov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gradle Mkdocs plugin 2 | [![License](https://img.shields.io/badge/license-MIT-blue.svg)](http://www.opensource.org/licenses/MIT) 3 | [![CI](https://github.com/xvik/gradle-mkdocs-plugin/actions/workflows/CI.yml/badge.svg)](https://github.com/xvik/gradle-mkdocs-plugin/actions/workflows/CI.yml) 4 | [![Appveyor build status](https://ci.appveyor.com/api/projects/status/github/xvik/gradle-mkdocs-plugin?svg=true)](https://ci.appveyor.com/project/xvik/gradle-mkdocs-plugin) 5 | [![codecov](https://codecov.io/gh/xvik/gradle-mkdocs-plugin/branch/master/graph/badge.svg)](https://codecov.io/gh/xvik/gradle-mkdocs-plugin) 6 | 7 | **DOCUMENTATION** https://xvik.github.io/gradle-mkdocs-plugin/ 8 | 9 | ### About 10 | 11 | Generates project documentation with [Mkdocs](http://www.mkdocs.org/) python tool. 12 | 13 | Ideal for open source projects: 14 | 15 | * Easy start: initial docs source generation 16 | * Markdown syntax (with handy extensions) 17 | * Great look from [material theme](https://squidfunk.github.io/mkdocs-material/) (used by default) with extra features: 18 | - Mobile friendly 19 | - Embedded search 20 | - Syntax highlighting 21 | - Dark theme switcher 22 | * Easy documentation contribution (jump to source) 23 | * Multi-version documentation publishing to github pages 24 | - Support version aliases (latest, dev, etc) 25 | - Support mkdocs-material version switcher without mike tool usage 26 | * Variables support 27 | * Could work with direct python or docker. 28 | * Could use requirements.txt file 29 | * Compatible with gradle configuration cache 30 | 31 | ##### Summary 32 | 33 | * `mkdocs-build` plugin: 34 | - Configuration: `mkdocs` 35 | - Tasks: 36 | - `mkdocsInit` - generate initial site 37 | - `mkdocsServe` - livereload server (dev) 38 | - `mkdocsBuild` - build documentation 39 | - `type:MkdocsTask` to call custom mkdocs commands 40 | 41 | * `mkdocs` plugin adds: 42 | - Configuration: `gitPublish` 43 | - Tasks: 44 | - `gitPublishReset` - checkout repository 45 | - `mkdocsVersionsFile` - generate versions.json file for version switcher 46 | - `gitPublishCopy` - copy (and add) files into repository 47 | - `gitPublishCommit` - commit updates into repository 48 | - `gitPublishPush` - push commit 49 | - `mkdocsPublish` - publish to github pages (main task) 50 | 51 | * Enable plugins: [use-python](https://github.com/xvik/gradle-use-python-plugin) 52 | 53 | NOTE: plugin is based on [use-python plugin](https://github.com/xvik/gradle-use-python-plugin) see python-specific 54 | tasks there. 55 | 56 | ### Setup 57 | 58 | [![Maven Central](https://img.shields.io/maven-central/v/ru.vyarus/gradle-mkdocs-plugin.svg)](https://maven-badges.herokuapp.com/maven-central/ru.vyarus/gradle-mkdocs-plugin) 59 | [![Gradle Plugin Portal](https://img.shields.io/maven-metadata/v/https/plugins.gradle.org/m2/ru/vyarus/mkdocs/ru.vyarus.mkdocs.gradle.plugin/maven-metadata.xml.svg?colorB=007ec6&label=plugins%20portal)](https://plugins.gradle.org/plugin/ru.vyarus.mkdocs) 60 | 61 | ```groovy 62 | buildscript { 63 | repositories { 64 | mavenCentral() 65 | } 66 | dependencies { 67 | classpath 'ru.vyarus:gradle-mkdocs-plugin:4.0.1' 68 | } 69 | } 70 | apply plugin: 'ru.vyarus.mkdocs' 71 | ``` 72 | 73 | OR 74 | 75 | ```groovy 76 | plugins { 77 | id 'ru.vyarus.mkdocs' version '4.0.1' 78 | } 79 | ``` 80 | 81 | #### Lightweight setup 82 | 83 | There is also a lightweight plugin version without publication tasks: 84 | 85 | ```groovy 86 | plugins { 87 | id 'ru.vyarus.mkdocs-build' version '4.0.1' 88 | } 89 | ``` 90 | 91 | Lightweight plugin is suitable if you don't need git publication and don't want extra 92 | tasks to appear. 93 | 94 | #### Compatibility 95 | 96 | Plugin compiled for java 8, compatible with java 11. 97 | 98 | Gradle | Version 99 | --------|------- 100 | 7.0 | 4.0.1 101 | 5.3 | [3.0.0](https://xvik.github.io/gradle-mkdocs-plugin/3.0.0/) 102 | 5-5.2 | [2.3.0](https://xvik.github.io/gradle-mkdocs-plugin/2.3.0/) 103 | 4.x | [1.1.0](https://github.com/xvik/gradle-mkdocs-plugin/tree/1.1.0) 104 | 105 | **Requires installed python** 3.8 and above with pip. 106 | 107 | [Check and install python if required](https://xvik.github.io/gradle-use-python-plugin/2.3.0/guide/python/). 108 | 109 | 110 | #### Snapshots 111 | 112 |
113 | Snapshots may be used through JitPack 114 | 115 | * Go to [JitPack project page](https://jitpack.io/#ru.vyarus/gradle-mkdocs-plugin) 116 | * Select `Commits` section and click `Get it` on commit you want to use 117 | or use `master-SNAPSHOT` to use the most recent snapshot 118 | 119 | * Add to `settings.gradle` (top most!) (exact commit hash might be used as version): 120 | 121 | ```groovy 122 | pluginManagement { 123 | resolutionStrategy { 124 | eachPlugin { 125 | if (requested.id.id == 'ru.vyarus.mkdocs') { 126 | useModule('ru.vyarus:gradle-mkdocs-plugin:master-SNAPSHOT') 127 | } 128 | } 129 | } 130 | repositories { 131 | gradlePluginPortal() 132 | maven { url 'https://jitpack.io' } 133 | } 134 | } 135 | ``` 136 | * Use plugin without declaring version: 137 | 138 | ```groovy 139 | plugins { 140 | id 'ru.vyarus.mkdocs' 141 | } 142 | ``` 143 | 144 |
145 | 146 | 147 | ### Usage 148 | 149 | Read [documentation](https://xvik.github.io/gradle-mkdocs-plugin/) 150 | 151 | ### Might also like 152 | 153 | * [quality-plugin](https://github.com/xvik/gradle-quality-plugin) - java and groovy source quality checks 154 | * [animalsniffer-plugin](https://github.com/xvik/gradle-animalsniffer-plugin) - java compatibility checks 155 | * [pom-plugin](https://github.com/xvik/gradle-pom-plugin) - improves pom generation 156 | * [java-lib-plugin](https://github.com/xvik/gradle-java-lib-plugin) - avoid boilerplate for java or groovy library project 157 | * [github-info-plugin](https://github.com/xvik/gradle-github-info-plugin) - pre-configure common plugins with github related info 158 | * [yaml-updater](https://github.com/xvik/yaml-updater) - yaml configuration update tool, preserving comments and whitespaces 159 | 160 | 161 | --- 162 | [![gradle plugin generator](http://img.shields.io/badge/Powered%20by-%20Gradle%20plugin%20generator-green.svg?style=flat-square)](https://github.com/xvik/generator-gradle-plugin) 163 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.gradle.plugin-publish' version '1.3.1' 3 | id 'java-gradle-plugin' 4 | id 'groovy' 5 | id 'jacoco' 6 | id 'signing' 7 | id 'net.researchgate.release' version '3.1.0' 8 | id 'ru.vyarus.quality' version '5.0.0' 9 | id 'io.github.gradle-nexus.publish-plugin' version '2.0.0' 10 | id 'ru.vyarus.java-lib' version '3.0.0' 11 | id 'ru.vyarus.github-info' version '2.0.0' 12 | id 'com.github.ben-manes.versions' version '0.52.0' 13 | id "pl.droidsonroids.jacoco.testkit" version "1.0.12" 14 | id 'ru.vyarus.mkdocs' version '4.0.1' 15 | } 16 | 17 | java { 18 | sourceCompatibility = 1.8 19 | } 20 | 21 | wrapper { 22 | gradleVersion = '8.6' 23 | distributionType = Wrapper.DistributionType.BIN 24 | } 25 | 26 | ext.pythonPlugin = '4.1.0' 27 | 28 | repositories { mavenLocal(); mavenCentral(); gradlePluginPortal() } 29 | dependencies { 30 | implementation "ru.vyarus:gradle-use-python-plugin:$pythonPlugin" 31 | 32 | // jgit 5.x is still supported so no need to update to 6.x yet 33 | // Also, no need to update to grgit 5.x as there are no important updates 34 | implementation 'org.ajoberstar.grgit:grgit-core:4.1.1' 35 | implementation 'org.eclipse.jgit:org.eclipse.jgit:5.13.3.202401111512-r' 36 | 37 | testImplementation('org.spockframework:spock-core:2.3-groovy-3.0') { 38 | exclude group: 'org.codehaus.groovy' 39 | } 40 | } 41 | 42 | group = 'ru.vyarus' 43 | description = 'Mkdocs documentation plugin' 44 | 45 | github { 46 | user 'xvik' 47 | license 'MIT' 48 | } 49 | 50 | mkdocs { 51 | extras = [ 52 | 'version': '4.0.1', 53 | 'pythonPlugin': pythonPlugin 54 | ] 55 | publish { 56 | docPath = mkdocs.extras['version'] 57 | rootRedirect = true 58 | rootRedirectTo = 'latest' 59 | versionAliases = ['latest'] 60 | hideOldBugfixVersions = true 61 | } 62 | } 63 | afterEvaluate { 64 | python.modules.each { 65 | def mod = it.split(':') 66 | mkdocs.extras[mod[0]] = mod[1] 67 | } 68 | } 69 | 70 | maven.pom { 71 | developers { 72 | developer { 73 | id = 'xvik' 74 | name = 'Vyacheslav Rusakov' 75 | email = 'vyarus@gmail.com' 76 | } 77 | } 78 | } 79 | 80 | nexusPublishing { 81 | repositories { 82 | sonatype { 83 | username = findProperty('sonatypeUser') 84 | password = findProperty('sonatypePassword') 85 | } 86 | } 87 | } 88 | 89 | // skip signing for jitpack (snapshots) 90 | tasks.withType(Sign) {onlyIf { !System.getenv('JITPACK') }} 91 | 92 | // Required signing properties for release: signing.keyId, signing.password and signing.secretKeyRingFile 93 | // (https://docs.gradle.org/current/userguide/signing_plugin.html#sec:signatory_credentials) 94 | 95 | javaLib { 96 | // don't publish gradle metadata artifact 97 | withoutGradleMetadata() 98 | } 99 | 100 | 101 | gradlePlugin { 102 | plugins { 103 | mkdocsPlugin { 104 | id = 'ru.vyarus.mkdocs' 105 | displayName = project.description 106 | description = 'Mkdocs documentation generation and publishing plugin' 107 | tags.set(['documentation', 'mkdocs']) 108 | implementationClass = 'ru.vyarus.gradle.plugin.mkdocs.MkdocsPlugin' 109 | } 110 | mkdocsBuildPlugin { 111 | id = 'ru.vyarus.mkdocs-build' 112 | displayName = "${project.description} (without publication)" 113 | description = 'Mkdocs documentation generation plugin' 114 | tags.set(['documentation', 'mkdocs']) 115 | implementationClass = 'ru.vyarus.gradle.plugin.mkdocs.MkdocsBuildPlugin' 116 | } 117 | } 118 | } 119 | 120 | release.git.requireBranch.set('master') 121 | 122 | afterReleaseBuild { 123 | dependsOn = [ 124 | 'publishMavenPublicationToSonatypeRepository', 125 | 'closeAndReleaseSonatypeStagingRepository', 126 | publishPlugins] 127 | doLast { 128 | logger.warn "RELEASED $project.group:$project.name:$project.version" 129 | } 130 | } 131 | 132 | test { 133 | useJUnitPlatform() 134 | testLogging { 135 | events 'skipped', 'failed' 136 | exceptionFormat 'full' 137 | } 138 | maxHeapSize = '512m' 139 | doLast { 140 | sleep(1000) 141 | } 142 | } 143 | 144 | dependencyUpdates.revision = 'release' 145 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | version=4.0.2-SNAPSHOT -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xvik/gradle-mkdocs-plugin/6b4f51a17dcdacb84af86771dd09ce8a783cf3ee/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 87 | APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit 88 | 89 | # Use the maximum available, or set MAX_FD != -1 to use that value. 90 | MAX_FD=maximum 91 | 92 | warn () { 93 | echo "$*" 94 | } >&2 95 | 96 | die () { 97 | echo 98 | echo "$*" 99 | echo 100 | exit 1 101 | } >&2 102 | 103 | # OS specific support (must be 'true' or 'false'). 104 | cygwin=false 105 | msys=false 106 | darwin=false 107 | nonstop=false 108 | case "$( uname )" in #( 109 | CYGWIN* ) cygwin=true ;; #( 110 | Darwin* ) darwin=true ;; #( 111 | MSYS* | MINGW* ) msys=true ;; #( 112 | NONSTOP* ) nonstop=true ;; 113 | esac 114 | 115 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 116 | 117 | 118 | # Determine the Java command to use to start the JVM. 119 | if [ -n "$JAVA_HOME" ] ; then 120 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 121 | # IBM's JDK on AIX uses strange locations for the executables 122 | JAVACMD=$JAVA_HOME/jre/sh/java 123 | else 124 | JAVACMD=$JAVA_HOME/bin/java 125 | fi 126 | if [ ! -x "$JAVACMD" ] ; then 127 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 128 | 129 | Please set the JAVA_HOME variable in your environment to match the 130 | location of your Java installation." 131 | fi 132 | else 133 | JAVACMD=java 134 | if ! command -v java >/dev/null 2>&1 135 | then 136 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | fi 142 | 143 | # Increase the maximum file descriptors if we can. 144 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 145 | case $MAX_FD in #( 146 | max*) 147 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 148 | # shellcheck disable=SC2039,SC3045 149 | MAX_FD=$( ulimit -H -n ) || 150 | warn "Could not query maximum file descriptor limit" 151 | esac 152 | case $MAX_FD in #( 153 | '' | soft) :;; #( 154 | *) 155 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 156 | # shellcheck disable=SC2039,SC3045 157 | ulimit -n "$MAX_FD" || 158 | warn "Could not set maximum file descriptor limit to $MAX_FD" 159 | esac 160 | fi 161 | 162 | # Collect all arguments for the java command, stacking in reverse order: 163 | # * args from the command line 164 | # * the main class name 165 | # * -classpath 166 | # * -D...appname settings 167 | # * --module-path (only if needed) 168 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 169 | 170 | # For Cygwin or MSYS, switch paths to Windows format before running java 171 | if "$cygwin" || "$msys" ; then 172 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 173 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 174 | 175 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 176 | 177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 178 | for arg do 179 | if 180 | case $arg in #( 181 | -*) false ;; # don't mess with options #( 182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 183 | [ -e "$t" ] ;; #( 184 | *) false ;; 185 | esac 186 | then 187 | arg=$( cygpath --path --ignore --mixed "$arg" ) 188 | fi 189 | # Roll the args list around exactly as many times as the number of 190 | # args, so each arg winds up back in the position where it started, but 191 | # possibly modified. 192 | # 193 | # NB: a `for` loop captures its iteration list before it begins, so 194 | # changing the positional parameters here affects neither the number of 195 | # iterations, nor the values presented in `arg`. 196 | shift # remove old arg 197 | set -- "$@" "$arg" # push replacement arg 198 | done 199 | fi 200 | 201 | 202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 204 | 205 | # Collect all arguments for the java command: 206 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 207 | # and any embedded shellness will be escaped. 208 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 209 | # treated as '${Hostname}' itself on the command line. 210 | 211 | set -- \ 212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 213 | -classpath "$CLASSPATH" \ 214 | org.gradle.wrapper.GradleWrapperMain \ 215 | "$@" 216 | 217 | # Stop when "xargs" is not available. 218 | if ! command -v xargs >/dev/null 2>&1 219 | then 220 | die "xargs is not available" 221 | fi 222 | 223 | # Use "xargs" to parse quoted args. 224 | # 225 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 226 | # 227 | # In Bash we could simply go: 228 | # 229 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 230 | # set -- "${ARGS[@]}" "$@" 231 | # 232 | # but POSIX shell has neither arrays nor command substitution, so instead we 233 | # post-process each arg (as a line of input to sed) to backslash-escape any 234 | # character that might be a shell metacharacter, then use eval to reverse 235 | # that process (while maintaining the separation between arguments), and wrap 236 | # the whole thing up as a single "set" statement. 237 | # 238 | # This will of course break if any of these variables contains a newline or 239 | # an unmatched quote. 240 | # 241 | 242 | eval "set -- $( 243 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 244 | xargs -n1 | 245 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 246 | tr '\n' ' ' 247 | )" '"$@"' 248 | 249 | exec "$JAVACMD" "$@" 250 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 1>&2 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 48 | echo. 1>&2 49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 50 | echo location of your Java installation. 1>&2 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 1>&2 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 62 | echo. 1>&2 63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 64 | echo location of your Java installation. 1>&2 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | mavenLocal() 4 | gradlePluginPortal() 5 | } 6 | } 7 | 8 | rootProject.name = 'gradle-mkdocs-plugin' 9 | -------------------------------------------------------------------------------- /src/doc/docs/about/compatibility.md: -------------------------------------------------------------------------------- 1 | # Gradle compatibility 2 | 3 | Plugin compiled for java 8, compatible with java 11. Works on windows and linux (and macos). 4 | 5 | Gradle | Version 6 | --------|------- 7 | 7.0 | 4.0.1 8 | 5.3 | [3.0.0](https://xvik.github.io/gradle-mkdocs-plugin/3.0.0/) 9 | 5-5.2 | [2.3.0](https://xvik.github.io/gradle-mkdocs-plugin/2.3.0/) 10 | 4.x | [1.1.0](https://github.com/xvik/gradle-mkdocs-plugin/tree/1.1.0) 11 | -------------------------------------------------------------------------------- /src/doc/docs/about/history.md: -------------------------------------------------------------------------------- 1 | ### [4.0.1](http://xvik.github.io/gradle-mkdocs-plugin/4.0.1) (2024-04-15) 2 | * Fix non-strict build (#88) 3 | * Fix emoji plugin in default mkdocs.yml (emoji support moved from material extensions to mkdocs directly) 4 | 5 | ### [4.0.0](http://xvik.github.io/gradle-mkdocs-plugin/4.0.0) (2024-04-14) 6 | * (breaking) Drop gradle 5 and 6 support 7 | * All tasks properties replaced with lazy properties 8 | * Remove git-publish plugin. Plugin functions added directly with required modifications 9 | so usage will be the same (compatible). The Author of the original plugin deprecated it 10 | (together with grgit). Still, grgit will be used for now (because of its feature completeness) 11 | - Authorization properties support remains for backwards compatibility, but auth could 12 | be specified now directly in gitPublish.username (and password). 13 | * Configuration cache compatibility 14 | * Update packages: 15 | - mkdocs 1.4.1 -> 1.5.3 16 | - mkdocs-material 8.5.7 -> 9.5.17 17 | - pygments 2.13.0 -> 2.17.2 18 | - pymdown-extensions 9.7 -> 10.7.1 19 | * Support hiding versions in versions file: 20 | - mkdocs.publish.hideVersions - set versions to hide 21 | - mkdocs.publish.hideOldBugfixVersions - automatically hide bugfix versions (disabled by default) 22 | 23 | ### [3.0.0](http://xvik.github.io/gradle-mkdocs-plugin/3.0.0) (2022-11-01) 24 | * (breaking) Drop gradle 5.0-5.2 support (minimum required gradle is 5.3) 25 | * Python plugin related changes: 26 | - Add docker support (with raw python container by default) 27 | - Add python requirements.txt file support 28 | - Add cleanPython task to easily cleanup local environment 29 | * Dev server port number is now configurable: devPort property 30 | (this required for proper docker support when non-local ip must be specified) 31 | * mkdocs.resolveDocPath() never return null: 32 | for single version docs '.' is returned now instead of null (#41) 33 | * Update packages: 34 | - mkdocs 1.3.0 -> 1.4.1 35 | - mkdocs-material 8.3.6 -> 8.5.7 36 | - pygments 2.12.0 -> 2.13.0 37 | - pymdown-extensions 9.4 -> 9.7 38 | * Ignore all git errors during plugin initialization (git used to resolve repoUrl on initialization) (#45) 39 | * Split plugin into 2 plugins to let users use plugin without custom publication implementation: 40 | - mkdocs-build - everything without publication (and no grgit plugin activation) 41 | - mkdocs - same as before (registers mkdocs-build plugin and configures publication tasks) 42 | * mkdocsBuild task could now update existing versions file (even download from URL) (#31) 43 | - To enable specify existing versions file location: mkdocs.publish.existingVersionsFile = '...' 44 | - When target file not found new (empty) one would be created 45 | - Ideal for incremental publishing when each publication just adds a new version to existing file 46 | (when git publication is not used) 47 | 48 | ### [2.4.0](http://xvik.github.io/gradle-mkdocs-plugin/2.4.0) (2022-06-17) 49 | * Fix variables support for gradle 7.4 (#34) 50 | * Update packages: 51 | - mkdocs-material 8.2.8 -> 8.3.6 (drops python 3.6 support) 52 | - pygments 2.11.2 -> 2.12.0 53 | - pymdown-extensions 9.1 -> 9.4 54 | 55 | ### [2.3.0](http://xvik.github.io/gradle-mkdocs-plugin/2.3.0) (2022-04-02) 56 | * Update packages: 57 | - mkdocs 1.2.3 -> 1.3.0 (fixes #29: jinja2 3.1.0 support) 58 | - mkdocs-material 8.0.2 -> 8.2.8 59 | - pygments 2.10.0 -> 2.11.2 60 | - mkdocs-markdownextradata-plugin 0.2.4 -> 0.2.5 61 | 62 | ### [2.2.0](http://xvik.github.io/gradle-mkdocs-plugin/2.2.0) (2021-12-08) 63 | * Update packages: 64 | - mkdocs 1.1.2 -> 1.2.3 65 | See [breaking changes](https://www.mkdocs.org/about/release-notes/#backward-incompatible-changes-in-12): 66 | * site_url is now required 67 | * google_analytics option deprecated - theme specific configurations used instead (see below) 68 | - mkdocs-material 7.0.6 -> 8.0.2 69 | [Migration notes](https://squidfunk.github.io/mkdocs-material/upgrade/#upgrading-from-7x-to-8x): 70 | * instead of google_analytics extra.analytics must be used 71 | * replace codehilite extension with pymdownx.highlight 72 | * to [activate light/dark theme toggle](https://squidfunk.github.io/mkdocs-material/setup/changing-the-colors/#color-palette-toggle) ([#12](https://github.com/xvik/gradle-mkdocs-plugin/issues/12)) 73 | - pygments 2.8.0 -> 2.10.0 74 | - pymdown-extensions 8.1.1 -> 9.1 75 | * Update mkdocs.yaml generated by init task with most useful options commented 76 | * Add support for version switcher (without mike tool usage), by generating versions.json from publish repository folders ([#10](https://github.com/xvik/gradle-mkdocs-plugin/issues/11)) 77 | - New option `mkdocs.publish.generateVersionsFile` could disable versions.json file generation 78 | - File generated by new mkdocsVersionsFile task which may be used instead of mkdocsBuild to test switcher 79 | * Add aliases support (same way as in mike), declared with new option `mkdocs.publish.versionAliases` 80 | * Add `mkdocs.publish.rootRedirectTo` option to be able to configure root redirection into alias 81 | 82 | ### [2.1.2](http://xvik.github.io/gradle-mkdocs-plugin/2.1.2) (2021-12-01) 83 | * Fix java 8 support, dropped due to jgit 6 transitive dependency ([#13](https://github.com/xvik/gradle-mkdocs-plugin/issues/13)) 84 | 85 | ### [2.1.1](http://xvik.github.io/gradle-mkdocs-plugin/2.1.1) (2021-03-18) 86 | * Fix variables support ignore 'docs_dir' configuration from mkdocs.yml ([#8](https://github.com/xvik/gradle-mkdocs-plugin/issues/8)) 87 | 88 | ### [2.1.0](http://xvik.github.io/gradle-mkdocs-plugin/2.1.0) (2021-03-17) 89 | * Support python installed from Windows Store (use-python-plugin 2.3.0) 90 | * Update packages: 91 | - mkdocs 1.1 -> 1.1.2 92 | - mkdocs-material 4.6.3 -> 7.0.6 93 | - pygments 2.6.1 -> 2.8.0 94 | - pymdown-extensions 6.3.0 -> 8.1.1 95 | * Optional variables support for all mkdocs tasks: there is no (and not planned) native support for 96 | variables in mkdocs, but often it is very handful. It is only possible to have it with a plugin. ([#7](https://github.com/xvik/gradle-mkdocs-plugin/issues/7)) 97 | - Added mkdocs-markdownextradata-plugin 0.2.4 as installed module (no harm, you must active it manually!) 98 | - Added mkdocs.extras configuration option: map to declare additional variables 99 | - When extra variables declared, plugin would generate a special file, containing all declared variables, 100 | which markdownextradata plugin would recognize and use automatically. 101 | - Variables must be used with 'gradle' prefix: {% raw %} {{ gradle.declared_var_name }} {% endraw %} 102 | 103 | WARNING: there were some scheme changes in mkdocs-material. 104 | Most likely you may face social links change: 105 | 106 | Before: 107 | social: 108 | - type: github 109 | link: https://github.com/xvik 110 | 111 | After: 112 | social: 113 | - icon: fontawesome/brands/github 114 | link: https://github.com/xvik 115 | 116 | See [mkdocs-material upgrade guide](https://squidfunk.github.io/mkdocs-material/upgrading/#extrasocial) for details 117 | 118 | ### [2.0.1](http://xvik.github.io/gradle-mkdocs-plugin/2.0.1) (2020-04-06) 119 | * Fix relative virtualenv paths support (don't rely on gradle work dir) (#5) 120 | 121 | ### [2.0.0](http://xvik.github.io/gradle-mkdocs-plugin/2.0.0) (2020-03-13) 122 | * (breaking) Drop java 7 support 123 | * (breaking) Drop gradle 4 support 124 | * Fix jgit dependency conflict (#4) (plugin now use jgit 5) 125 | * Update packages: 126 | - mkdocs 1.0.4 -> 1.1 127 | - mkdocs-material 3.0.4 -> 4.6.3 128 | - pygments 2.2.0 -> 2.6.1 129 | - pymdown-extensions 6.0.0 -> 6.3.0 130 | * Use gradle tasks configuration avoidance for lazy tasks initialization (no init when tasks not needed) 131 | 132 | ### [1.1.0](http://xvik.github.io/gradle-mkdocs-plugin/1.1.0) (2018-10-14) 133 | * Default template's mkdocs.yml changes: 134 | - fixed `edit_uri` (missed "/docs" ending) 135 | - `pages` changed to `nav` 136 | - change parameters syntax in `markdown_extensions` section 137 | * Fix documentation in sub module support (use-python plugin 1.2.0) 138 | * Support Mkdocks 1.0: 139 | - Update default mkdocs 0.17.3 -> 1.0.4 140 | - Update default mkdocs-material 2.7.2 -> 3.0.4 141 | - Update default pymdown-extensions 4.9.2 -> 6.0.0 142 | 143 | [Mkdocs 1.0](https://www.mkdocs.org/about/release-notes/#version-10-2018-08-03) migration notes (for existing docs): 144 | 145 | - Rename `pages` section into `nav` 146 | - Make sure `site_url` set correctly (otherwise sitemap will contain None instead of urls) 147 | - Change `markdown_extensions` section from using `something(arg=val)` syntax into: 148 | 149 | ```yaml 150 | markdown_extensions: 151 | - admonition 152 | - codehilite: 153 | guess_lang: false 154 | - footnotes 155 | - meta 156 | - toc: 157 | permalink: true 158 | - pymdownx.betterem: 159 | smart_enable: all 160 | - pymdownx.caret 161 | - pymdownx.inlinehilite 162 | - pymdownx.magiclink 163 | - pymdownx.smartsymbols 164 | - pymdownx.superfences 165 | ``` 166 | 167 | 168 | ### [1.0.1](http://xvik.github.io/gradle-mkdocs-plugin/1.0.1) (2018-04-23) 169 | * Fix pip 10 compatibility (use-python plugin 1.0.2) 170 | * Update default mkdocs 0.17.2 -> 0.17.3 171 | * Update default mkdocs-material 2.2.1 -> 2.7.2 172 | * Update default pymdown-extensions 4.6 -> 4.9.2 173 | 174 | ### [1.0.0](https://github.com/xvik/gradle-mkdocs-plugin/tree/1.0.0) (2017-12-30) 175 | * Initial release -------------------------------------------------------------------------------- /src/doc/docs/about/license.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017-2024, Vyacheslav Rusakov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/doc/docs/about/migration.md: -------------------------------------------------------------------------------- 1 | # Migration notes 2 | 3 | !!! summary 4 | This section mostly describes main changes in updated mkdocs and material 5 | versions, assuming you'll use default versions (provided by plugin). 6 | 7 | ## 4.0.0 8 | 9 | Gradle 5-6 not supported anymore. 10 | 11 | [material-mkdocs-extensions](https://pypi.org/project/mkdocs-material-extensions/) module was deprecated because 12 | emoji support was added directly into mkdocs. So, you need to change in your mkdocs.yml this: 13 | 14 | ```yaml 15 | - pymdownx.emoji: 16 | emoji_index: !!python/name:materialx.emoji.twemoji 17 | emoji_generator: !!python/name:materialx.emoji.to_svg 18 | ``` 19 | 20 | into this: 21 | 22 | ```yaml 23 | - pymdownx.emoji: 24 | emoji_index: !!python/name:material.extensions.emoji.twemoji 25 | emoji_generator: !!python/name:material.extensions.emoji.to_svg 26 | ``` 27 | 28 | ## 3.0.0 29 | 30 | Gradle 5.0-5.2 is not supported anymore. 31 | 32 | Use python 3.8 and above: there might be problem with `importlib-metadata 5.0` package 33 | installed by version range (transitive dependency) and incompatible with python < 3.8 34 | 35 | Plugin can use docker now instead of local python: `mkdocs.docker.use = true` 36 | 37 | New configuration `mkdocs.devPort` overrides `dev_addr` configuration in your mkdocs.yml 38 | (this was required for proper docker support). 39 | If you need to change default port (3000), use gradle config to change it 40 | 41 | If you don't need git publication tasks, you can now use lightweight plugin version: 42 | ```gradle 43 | id 'ru.vyarus.mkdocs-build' version '3.0.0' 44 | ``` 45 | 46 | There is also a way now to update existing versions.json file in case when git publication not used: 47 | configure current file location with `mkdocs.publish.existingVersionsFile = 'https://xvik.github.io/gradle-mkdocs-plugin/versions.json'` 48 | (or local path) and `mkdocsBuild` would generate updated versions.json inside mkdocs build dir. 49 | 50 | ## 2.4.0 51 | 52 | Python 3.6 is not supported anymore, use python 3.7 - 3.10. 53 | 54 | ## 2.3.0 55 | 56 | There is no breaking changes since 2.2.0, but if you're migrating from earlier version please see 57 | [2.2.0 migration notes](https://xvik.github.io/gradle-mkdocs-plugin/2.2.0/about/migration/). 58 | -------------------------------------------------------------------------------- /src/doc/docs/examples.md: -------------------------------------------------------------------------------- 1 | # Example configurations 2 | 3 | Common configurations cheat-sheet. 4 | 5 | ## Single version 6 | 7 | ```groovy 8 | mkdocs.publish.docPath = '' 9 | ``` 10 | 11 | Documentation always published into root folder: 12 | 13 | ``` 14 | gh-pages root/ 15 | generated docs 16 | ``` 17 | 18 | Very specific option, suitable for some site, blog etc. 19 | Project documentation requires multi-version publication so users could 20 | always consult with old docs. 21 | 22 | ## Simple multi-version 23 | 24 | ```java 25 | mkdocs.publish { 26 | docPath = '$version' 27 | rootRedirect = true 28 | } 29 | ``` 30 | 31 | Documentation published into sub-folder. Only this sub folder would be updated on 32 | publication - other folders remain untouched. 33 | 34 | !!! tip 35 | It's better to specify exact version in `docPath`, because usually documentation site being 36 | updated after release and with default `$version` you would publish snapshot version instead. 37 | 38 | ``` 39 | docPath = '1.0' 40 | ``` 41 | 42 | Each publication would publish: 43 | 44 | ``` 45 | gh-pages root/ 46 | version/ 47 | generated docs 48 | index.html 49 | versions.json 50 | ``` 51 | 52 | Root index.html required to redirect use to the latest version when it opens site root. 53 | 54 | To activate [version switcher component](https://squidfunk.github.io/mkdocs-material/setup/setting-up-versioning/#versioning) 55 | add in mkdocs.yml: 56 | 57 | ```yaml 58 | extra: 59 | version: 60 | provider: mike 61 | ``` 62 | 63 | (component requires only versions.json file generated at site root) 64 | 65 | ## Using latest alias 66 | 67 | It is quite common for projects to allow user to put `latest` in doc url 68 | instead of exact version: this way user could put link in his own code/docs which 69 | would always lead to up-to-date page. 70 | 71 | ```groovy 72 | mkdocs.publish { 73 | docPath = '1.0' 74 | rootRedirect = true 75 | versionAliases = ['latest'] 76 | } 77 | ``` 78 | 79 | Everything as before, but on publication new folder would appear: 80 | 81 | ``` 82 | gh-pages root/ 83 | version/ 84 | generated docs 85 | latest/ 86 | generated docs 87 | index.html 88 | versions.json 89 | ``` 90 | 91 | ## Root redirect to alias 92 | 93 | In the example above root is still redirecting to exact version. To redirect into `latest` alias: 94 | 95 | ```groovy 96 | mkdocs.publish { 97 | docPath = '1.0' 98 | rootRedirect = true 99 | rootRedirectTo = 'latest' 100 | versionAliases = ['latest'] 101 | } 102 | ``` 103 | 104 | And now site root will lead to `latest` directory. 105 | See [plugin site](https://xvik.github.io/gradle-mkdocs-plugin/) as an example. 106 | 107 | ## Reference project version in docs 108 | 109 | It is a very common need to reference project version instead of changing it everywhere before each release. 110 | It is possible with [variables support](guide/vars.md). 111 | 112 | In mkdocs.yml add plugins: 113 | 114 | ```yaml 115 | plugins: 116 | - search 117 | - markdownextradata 118 | ``` 119 | 120 | In build.gradle declare variables: 121 | 122 | ```groovy 123 | mkdocs { 124 | extras = [ 125 | 'version': "${-> project.version}" 126 | ] 127 | } 128 | ``` 129 | 130 | Now you can reference version as: 131 | 132 | ``` 133 | {% raw %} 134 | {{ gradle.version }} 135 | {% endraw %} 136 | ``` 137 | 138 | But, as mentioned before, it is more common to put raw version instead of relying on project version (because release docs could be updated after release): 139 | 140 | ```groovy 141 | mkdocs { 142 | publish.docPath = '1.0' 143 | extras = [ 144 | 'version': '1.0' 145 | ] 146 | } 147 | ``` 148 | 149 | Or, to avoid duplication: 150 | 151 | ```groovy 152 | mkdocs { 153 | extras = [ 154 | 'version': '1.0' 155 | ] 156 | publish.docPath = mkdocs.extras['version'] 157 | } 158 | ``` 159 | 160 | ## Old version publish 161 | 162 | You can always change and re-publish any old documentation version: it works 163 | the same as with new version publication. 164 | 165 | EXCEPT: 166 | 167 | * **Remember** to switch off root redirection with `mkdocs.publish.rootRedirect = false`: 168 | otherwise root index.html would be overridden and site root would point to wrong docs version 169 | * **Remember** to remove aliases (remove `mkdocs.publish.versionAliases`): 170 | otherwise alias folders would be overridden (e.g. latest would contain old version) 171 | * **Use** `mkdocsVersionsFile` task to validate old version correctness: 172 | It would try to warn you if it can detect more recent versions override 173 | 174 | ## Incremental versions update 175 | 176 | When plugin used only for documentation generation and publication task is not used, then 177 | versions.json file can be updated incrementally (by adding new version on each release): 178 | 179 | ```groovy 180 | mkdocs.publish { 181 | docPath = '1.0' 182 | rootRedirect = true 183 | rootRedirectTo = 'latest' 184 | versionAliases = ['latest'] 185 | existingVersionsFile = 'https://xvik.github.io/gradle-mkdocs-plugin/versions.json' 186 | } 187 | ``` 188 | 189 | On `mkdocsBuild` it would load remote json (it might be local path) and add new version, so build dir would contain: 190 | 191 | ``` 192 | build/mkdocs/ 193 | /1.0/ - mkdocs site 194 | /latest/ - alias (copy) 195 | index.html - redirect to 'latest' 196 | versions.json - updated remote versions file 197 | ``` 198 | 199 | After that built folder might be simply uploaded, for example into some ftp with other versions 200 | (append). -------------------------------------------------------------------------------- /src/doc/docs/guide/configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | !!! important 4 | Plugin based on [python plugin](https://github.com/xvik/gradle-use-python-plugin) which manage all 5 | python-related staff like virtualenv creation, pip installation and python executions. 6 | For python-related configurations refer to [python plugin documentation](https://xvik.github.io/gradle-use-python-plugin/{{ gradle.pythonPlugin }}/) 7 | 8 | !!! tip 9 | For docker configuration see [python plugin documentation](https://xvik.github.io/gradle-use-python-plugin/{{ gradle.pythonPlugin }}/guide/docker) 10 | 11 | !!! important 12 | There are two plugin versions: 13 | 14 | - `ru.vyarus.mkdocs` - full plugin 15 | - `ru.vyarus.mkdocs-build` - without publication tasks (lightweight) 16 | 17 | Both versions are equal in functionality, except publication stage. 18 | 19 | Configuration properties with default values: 20 | 21 | ```groovy 22 | mkdocs { 23 | // mkdocs sources 24 | sourcesDir = 'src/doc' 25 | // strict build (fail on build errors) 26 | strict = true 27 | // target build directory (publication root) 28 | buildDir = 'build/mkdocs' 29 | // automatically update site_url in mkdocs.yml before mkdocsBuild 30 | updateSiteUrl = true 31 | // optional variables declaration (to bypass gradle data to docs) 32 | extras = [:] 33 | // dev server port (mkdocsServe task), overrides dev_addr from mkdocs.yml 34 | devPort = 3000 35 | 36 | publish { 37 | // publication sub-folder (by default project version) 38 | docPath = '$version' 39 | // generate versions.json file for versions switcher 40 | // [used by publication task] 41 | generateVersionsFile = true 42 | // specify path to or URL to existing versions.json file in order to update it (add new version); 43 | // executed by mkdocsBuild, suitable when git publication not used 44 | existingVersionsFile 45 | // custom version name shown in version switcher (by default version folder name) 46 | versionTitle = '$docPath' 47 | // one or more alias folders to copy generated docs to (e.g. 'latest' or 'dev') 48 | versionAliases = [] 49 | // specify versions to hide in version switcher without removing actual version folders 50 | hideVersions = [] 51 | // when enabled it would automatically detect old bugfix versions and hide them 52 | // (because documentation for bugfix versions usually the same) 53 | // e.g. for versions 1.1.0, 1.1.1, 1.2.0, 1.2.0.1, 1.2.0.2 54 | // it would hide 1.1.0 and 1.2.0.1 55 | hideOldBugfixVersions = false 56 | // generate index.html' for root redirection to the last published version 57 | rootRedirect = true 58 | // allows changing root redirection to alias folder instead of exact version 59 | rootRedirectTo = '$docPath' 60 | // publish repository uri (bu default the same as current repository) 61 | // [used by publication task] 62 | repoUri = null 63 | // publication branch 64 | // [used by publication task] 65 | branch = 'gh-pages' 66 | // publication comment 67 | // [used by publication task] 68 | comment = 'Publish $docPath documentation' 69 | // directory publication repository checkout, update and push 70 | // [used by publication task] 71 | repoDir = '.gradle/gh-pages' 72 | } 73 | } 74 | ``` 75 | 76 | !!! tip 77 | Options marked as `[used by publication task]` used ONLY during publication and so 78 | would be ignored when build-only plugin version (`ru.vyarus.mkdocs-build`) used. 79 | 80 | Not marked publication propeties used by `mkdocsBuild` 81 | 82 | By default: 83 | 84 | - All documentation sources located in `src/doc` (and `mkdocsInit` task generate stubs there) 85 | - `mkdocsBuild` task will build site into `build/mkdocs` 86 | - Current project version is used as documentation folder (`build/mkdocs/$version`) 87 | - Github repository is assumed by default, so publication will be performed into `gh-pages` branch (where github will automatically detect it) 88 | - Variables plugin is not configured. See [variables section](vars.md) for details. 89 | 90 | !!! note 91 | In order to include something else into published docks (e.g. javadoc) see [publication](publication.md). 92 | 93 | ## Single version site 94 | 95 | If you don't want to use multi-version support at all then: 96 | 97 | ``` 98 | mkdocs.publish.docPath = '' // or null 99 | ``` 100 | 101 | This way, mkdocs site will always be published at the root (in case of publish it will always replace 102 | previous site version). 103 | 104 | ## Docs as module 105 | 106 | Example of moving documentation into separate gradle module: 107 | 108 | ```groovy 109 | plugins { 110 | id 'ru.vyarus.mkdocs' version '{{ gradle.version }}' apply false 111 | } 112 | 113 | version = '1.0-SNAPSHOT' 114 | 115 | project(':doc') { 116 | apply plugin: 'ru.vyarus.mkdocs' 117 | 118 | mkdocs { 119 | sourcesDir = 'src' 120 | } 121 | } 122 | ``` 123 | 124 | Default docs location simplified to simple `src` because of no other sources in this module. 125 | 126 | If we call `:doc:mkdocsInit` it will generate documentation stubs like this: 127 | 128 | Project structure: 129 | 130 | ``` 131 | / 132 | /doc/ 133 | src/ 134 | docs/ 135 | ... 136 | index.md 137 | mkdocs.yml 138 | build.gradle 139 | settings.gradle 140 | ``` 141 | 142 | For simplicity, gradle configuration for `doc` module is declared in the main file, 143 | but it could be declared inside doc's own build.gradle. -------------------------------------------------------------------------------- /src/doc/docs/guide/multi-version.md: -------------------------------------------------------------------------------- 1 | # Multi-version documentation 2 | 3 | By default, plugin assume multi-version documentation publishing. 4 | 5 | Configuration, responsible for versioning: 6 | 7 | ```groovy 8 | mkdocs.publish { 9 | docPath = '$version' 10 | rootRedirect = true 11 | rootRedirectTo = '$docPath' 12 | 13 | versionTitle = '$docPath' 14 | versionAliases = [] 15 | hideVersions = [] 16 | hideOldBugfixVersions = false 17 | generateVersionsFile = true 18 | } 19 | ``` 20 | 21 | !!! tip 22 | Usually it is more handy to manually set current doc version and not rely on project version because 23 | often documentation for currently released version is updated multiple times after release. 24 | 25 | !!! important 26 | Mkdocs-material [suggests mike tool usage](https://squidfunk.github.io/mkdocs-material/setup/setting-up-versioning/) for publication. 27 | Gradle plugin implements absolutely the same workflow as mike, but much easier 28 | customizable (as gradle plugin). Material theme would still be able to show version switcher because 29 | plugin generates required versions.json file. 30 | 31 | ## Workflow 32 | 33 | Usually you work on documentation for current version only. When new version released - you publish 34 | new documentation version and continue evolving it. Old version stays published for the legacy users. 35 | 36 | ### Older version update 37 | 38 | When older documentation version needs to be updated switch off redirection `index.html` generation 39 | (so it would not override redirection to the latest version): 40 | 41 | ```groovy 42 | mkdocs.publish { 43 | docPath = '0.9' 44 | rootRedirect = false // site root must still redirect to '1.0' (assume it's already published) 45 | } 46 | ``` 47 | 48 | Will build (without root index.html): 49 | 50 | ``` 51 | build/mkdocs/ 52 | /0.9/ - mkdocs site for old version 53 | ``` 54 | 55 | Also, do not use `versionAliases` when publishing old version because it may override 56 | more recent docs version. Plugin would try to warn you in such cases: 57 | 58 | ```java 59 | WARNING: Publishing version '1.0' is older then the latest published '1.1' and the following overrides might not be desired: 60 | root redirect override to '1.0' 61 | existing alias 'latest' override 62 | existing alias '1.x' override 63 | ``` 64 | 65 | !!! important 66 | This warning is produced by `mkdocsVersionsFile` file and only when versions.json file 67 | generation is not disabled. This check can't be done under `mkdocsBuild` because publishing repository is required 68 | for validation. 69 | 70 | So please, when releasing an **old** version use `mkdocsVersionsFile` to see all possible 71 | warnings before actual publication. 72 | 73 | ## Publication layouts 74 | 75 | You may define whatever layout you want, e.g.: 76 | 77 | ``` 78 | mkdocs.publish.docPath = 'en/1.0/' 79 | ``` 80 | 81 | Here generated site will be published into `/en/1.0/` folder (not just version) and 82 | index.html generated at the root with correct redirection. 83 | 84 | !!! warning 85 | If you want to use [version switcher](#doc-version-switcher) then you should not use 86 | long version paths, because mkdocs-material would look for versions file [only at one level up](https://github.com/squidfunk/mkdocs-material/blob/87df85def83535b54dc74ea7d86e8c41aa9db97a/src/assets/javascripts/integrations/version/index.ts#L46). 87 | 88 | ## Aliases 89 | 90 | It is possible to publish version not only into version folder, but also into 91 | aliased folders. 92 | 93 | Could be useful for: 94 | 95 | - Publishing the latest documentation under `latest` alias, so users could always 96 | reference the latest docs with the same link. 97 | - Publishing docs for developing version under `dev` alias, so users could easily find dev docs. 98 | - Serving the latest (patch) version for some mojor version: e.g. `5.x` alias could serve the latest 99 | published bugfix. 100 | 101 | For example, to add `latest` alias: 102 | 103 | ```groovy 104 | mkdocs.publish { 105 | docPath = '1.0' 106 | rootRedirect = true 107 | versionAliases = ['latest'] 108 | } 109 | ``` 110 | 111 | Will build: 112 | 113 | ``` 114 | build/mkdocs/ 115 | /0.9/ 116 | /latest/ 117 | index.html 118 | ``` 119 | 120 | !!! note 121 | Alias folder contains a *copy* of generated documentation, which means 122 | that sitemap links would lead to path of exact version. 123 | 124 | If same version is re-published - aliases would be correctly updated too. 125 | 126 | It is also possible to *redirect root into alias* instead of exact version with `rootRedirectTo` option: 127 | 128 | ```groovy 129 | mkdocs.publish { 130 | versionAliases = ['latest'] 131 | rootRedirectTo = 'latest' 132 | } 133 | ``` 134 | 135 | !!! tip 136 | In case of root redirection to alias it is better to enable version switcher to clearly show what version 137 | is active now (otherwise it would be not obvious) 138 | 139 | 140 | ## Doc version switcher 141 | 142 | Version switcher might be enabled in mkdocs.yml [exactly as described in docs](https://squidfunk.github.io/mkdocs-material/setup/setting-up-versioning/#versioning): 143 | 144 | ```yaml 145 | extra: 146 | version: 147 | provider: mike 148 | ``` 149 | 150 | !!! important 151 | You don't need [mike](https://github.com/jimporter/mike) itself! 152 | 153 | !!! important 154 | You will not see switcher under `mkdocsServe` command, but if you call `mkdocsVersionsFile` (which would also call 155 | `mkdocsBuild`), and manually open new version it would show switcher with all versions (using generated versions.json) 156 | 157 | Mkdocs-material requires only `versions.json` file stored at docs root. Plugin would automatically 158 | generate such file (following mike syntax): 159 | 160 | - Plugin verifies actually existing directories in gh-pages repository and would 161 | add them to generated versions file. So if you already have many versions published, just publish 162 | new version with enabled versions support and you'll see all of them in the version switcher. 163 | - Theme folders are detected by using `\d+(\..*)?` regexp (version folder must start with a number) 164 | and it must contain 404.html file. 165 | - Deeper versions folders are also supported: e.g. if `mkdocs.publish.docPath = 'en/1.0/'` then 166 | `en/1.0' folder would be recognized as version 167 | - Existing records in versions.json file are preserved for found version folders. 168 | - You can modify file manually (e.g. to modify version title) and it will not be overridden on next publication 169 | - You can manually remove version folder in repository and on next publication versions.json would be corrected 170 | - If aliases used, they would be correctly updated (e.g. `latest` removed from previous latest version.) 171 | 172 | If you do not want to generate versions file: 173 | 174 | `mkdocs.publish.generateVersionsFile = false` 175 | 176 | To customize version title (shown in dropdown selection) use: 177 | 178 | `mkdocs.publish.versionTitle = '1.0 (important fix)'` 179 | 180 | ### Incremental versions 181 | 182 | There is an alternative way for versions.json file generation for cases when publishing task 183 | is not used (e.g. when lightweight `ru.vyarus.mkdocs-build` plugin used). 184 | 185 | The idea is to use existing versions file and add new version into it (in contrast, git based publication 186 | could detect removed version folders and remove versions from file accordingly). 187 | 188 | !!! tip 189 | Version aliases would be also correctly processed. 190 | 191 | To enable incremental versions generation, specify current versions file location: 192 | 193 | ```groovy 194 | mkdocs.publish.existingVersionsFile = 'path/to/actual/versions.json' 195 | ``` 196 | 197 | You can also use a URL (http, ftp or anything that URL could handle): 198 | 199 | ```groovy 200 | mkdocs.publish.existingVersionsFile = 'https://xvik.github.io/gradle-mkdocs-plugin/versions.json' 201 | ``` 202 | 203 | When file specified, `mkdocsBuild` would load current file and apply new version there (if required). 204 | Updated versions file would be available in target build directory (same as with git publication). 205 | 206 | !!! important 207 | There will not be an error if file not found or due to download error - instead plugin 208 | would consider current file as not existing and would create a fresh versions file. 209 | 210 | This is useful for the first publication. 211 | 212 | !!! note 213 | When git publication used, incremental versions file, generated by mkdocsBuild would be 214 | overridden by versions file, generated by publishing task. If required, it could 215 | be disabled with `mkdocs.publish.generateVersionsFile = false`, but keep in mind that 216 | publication mechanism is safer to use. 217 | 218 | ### Hide versions 219 | 220 | If you publish documentation for each released version, after some time you may notice too 221 | many versions in the version selector. Often some versions become not relevant and could be hidden 222 | (it would not be correct to remove old version folder). 223 | 224 | For example, suppose we have: 1.0, 1.1.0, 1.1.1, 1.1.2, 1.1.3. 225 | It makes no sense to keep old bugfix versions in the version chooser: 226 | 227 | ```groovy 228 | mkdocs.publish.hideVersions = ['1.1.0', '1.1.1', '1.1.2'] 229 | ``` 230 | 231 | Now version selector would show only '1.0' and '1.1.3' versions, but all hidden versions 232 | would still be accessible by direct link. 233 | 234 | !!! important 235 | Version hiding does not work for [incremental versions](#incremental-versions) 236 | (where the current version is just appended into some existing versions file inside mkdocsBuild task). 237 | 238 | For bugfix versions (like in the example above) plugin could hide versions automatically: 239 | 240 | ```groovy 241 | mkdocs.publish.hideOldBugfixVersions = true 242 | ``` 243 | 244 | !!! note 245 | Automatic versions hiding does not try to be too smart: 246 | 1. It looks only versions with the same "base" part (same number of dots). 247 | E.g. 2.0.0, 2.0.1 or 2.0.0.1, 2.0.0.2, but would not compare 2.0.0 and 2.0.0.1 248 | 2. Ignore versions not ending digit (like 1.0.2.final) 249 | 250 | All hidden versions could be seen in the logs. You can always execute `mkdocsVersionsFile` 251 | to verify versions file updates correctness before actual publication. -------------------------------------------------------------------------------- /src/doc/docs/guide/pip.md: -------------------------------------------------------------------------------- 1 | # Pip modules 2 | 3 | Plugin will install by default the following pip modules: 4 | 5 | * [mkdocs:{{ gradle.mkdocs }}](https://pypi.python.org/pypi/mkdocs) 6 | * [mkdocs-material:{{ gradle.mkdocs_material }}](https://pypi.python.org/pypi/mkdocs-material) 7 | * [pygments:{{ gradle.pygments }}](https://pypi.python.org/pypi/Pygments) 8 | * [pymdown-extensions:{{ gradle.pymdown_extensions }}](https://pypi.python.org/pypi/pymdown-extensions) 9 | * [mkdocs-markdownextradata-plugin:{{ gradle.mkdocs_markdownextradata_plugin }}](https://pypi.org/project/mkdocs-markdownextradata-plugin/) 10 | 11 | By default, modules are installed into project specific [virtualenv](https://xvik.github.io/gradle-use-python-plugin/{{ gradle.pythonPlugin }}/guide/configuration/#virtualenv) 12 | (located in `.gradle/python`). 13 | You can see all installed modules with `pipList` task. 14 | 15 | If you want to use other python modules (e.g. other theme): 16 | 17 | ```groovy 18 | python.pip 'other-module:12', 'and-other:1.0' 19 | ``` 20 | 21 | Also, you can override default modules versions: 22 | 23 | ```groovy 24 | python.pip 'mkdocs:1.1' 25 | ``` 26 | 27 | And even downgrade: 28 | 29 | ```groovy 30 | python.pip 'mkdocs:1.0.3' 31 | ``` 32 | 33 | !!! tip 34 | All default modules are simply implicitly configured in `python.pip` and any 35 | manual module declaration will override the default. 36 | Read more about possible pip modules configuration in 37 | [python plugin documentation](https://xvik.github.io/gradle-use-python-plugin/{{ gradle.pythonPlugin }}/guide/modules/) 38 | 39 | !!! note 40 | You can also use requirements.txt file for version management. 41 | Read more in [python plugin documentation](https://xvik.github.io/gradle-use-python-plugin/{{ gradle.pythonPlugin }}/guide/modules/#requirementstxt) 42 | 43 | You can use `pipUpdates` task to check if newer module [versions are available](https://xvik.github.io/gradle-use-python-plugin/{{ gradle.pythonPlugin }}/guide/pip/#check-modules-updates). 44 | -------------------------------------------------------------------------------- /src/doc/docs/guide/tasks.md: -------------------------------------------------------------------------------- 1 | # Tasks 2 | 3 | ## Init 4 | 5 | `mkdocsInit` task generate initial site version into `src/doc` (or custom location). 6 | 7 | !!! note 8 | Plugin does not use [mkdocs new](http://www.mkdocs.org/#getting-started) command for site generation: custom template used 9 | with pre-configured plugins and enabled material theme. 10 | 11 | Task will do nothing if target folder exists and not empty. 12 | 13 | ## Dev server 14 | 15 | `mkdocsServe` task start live reload server (used during development) on 16 | [http://127.0.0.1:8000/](http://127.0.0.1:8000/). 17 | 18 | !!! warning 19 | Python process may not be killed after you stop gradle execution (search and kill python process manually). This is a [known gradle problem](https://github.com/gradle/gradle/issues/1128) 20 | and the only known workaround is to start task without daemon: `gradlew mkdocsServe --no-daemon`. 21 | Another alternative is to start serve command directly: copy console command from task execution log and use it directly. 22 | 23 | When docker used, container should be properly shut down, but not immediately (about 10s). 24 | 25 | ## Build 26 | 27 | `mkdocsBuild` task will generate (suppose project version is '1.0-SNAPSHOT'): 28 | 29 | ``` 30 | build/mkdocs/ 31 | /1.0-SNAPSHOT/ - mkdocs site 32 | index.html - redirect to correct site 33 | ``` 34 | 35 | Plugin is configured for multi-version documentation publishing: each version is in its own folder 36 | and special `index.html` at the root will redirect to the latest version (when published). 37 | 38 | Everything in `build/mkdocs/` is assumed to be published into github pages. 39 | 40 | !!! tip 41 | As documentation is often updated for already released version, it makes sense to define 42 | current version manually (or define it when you need to publish to exact version): 43 | 44 | ```groovy 45 | mkdocs.publish.docPath = '1.0' 46 | ``` 47 | 48 | For multi-module documentation, `mkdocsVersionsFile` may be called instead of `mkdocsBuild` 49 | in order to generate versions.json and be able to test version switcher 50 | (ofc. it would not be able to actually switch version, but will correctly show all available versions (after publication list would be the same)) 51 | 52 | !!! note 53 | `mkdocsVersionsFile` task if available only if full plugin version used (with git publication task), 54 | for `mkdocs-build` plugin it would not be available. With lightweight plugin, versions.json file could 55 | be generated in incremental way [from existing one](multi-version.md#incremental-versions) 56 | 57 | ### Update old documentation 58 | 59 | When older documentation version needs to be updated switch off redirection `index.html` generation 60 | (so it would not override redirection to the latest version): 61 | 62 | ```groovy 63 | mkdocs.publish { 64 | docPath = '0.9' 65 | rootRedirect = false // site root must still redirect to '1.0' (assume it's already published) 66 | } 67 | ``` 68 | 69 | Will build: 70 | 71 | ``` 72 | build/mkdocs/ 73 | /0.9/ - mkdocs site for old version 74 | ``` 75 | 76 | ## Publish 77 | 78 | `mkdocsPublish` calls `mkdocsBuild` and publish contents of `build/mkdocs/` into git repo 79 | (by default, `gh-pages` branch in current repo). 80 | 81 | Also `mkdocsVersionsFile` task could be called to verify versions.json generation correctness. 82 | 83 | See [publication](publication.md) for more details. 84 | 85 | ## Custom Mkdocs task 86 | 87 | If you need to use custom mkdocs command: 88 | 89 | ```groovy 90 | task doSomething(type: MkdocsTask) { 91 | command = '--help' 92 | } 93 | ``` 94 | 95 | !!! note 96 | Full task package is not required because `MkdocsTask` is actually a property, registered 97 | by plugin with the full class name in value. 98 | 99 | `:doSomething` task call will do: `python -m mkdocs --help`. 100 | -------------------------------------------------------------------------------- /src/doc/docs/guide/theme.md: -------------------------------------------------------------------------------- 1 | # Themes 2 | 3 | By default, plugin assumes [material](https://github.com/squidfunk/mkdocs-material) theme usage, but 4 | you can use [any other theme](https://github.com/mkdocs/mkdocs/wiki/MkDocs-Themes) if you want. 5 | 6 | ## Changing theme 7 | 8 | To apply a new theme you'll need: 9 | 10 | * Add theme package 11 | * Apply new theme in mkdocs.yml 12 | * (optional) Remove material-related configurations in mkdocs.yml 13 | 14 | For example, lets configure [ivory theme](https://github.com/daizutabi/mkdocs-ivory). 15 | 16 | First, we need to declare it's package in build.gradle: 17 | 18 | ```groovy 19 | python.pip 'mkdocs-ivory:0.4.6' 20 | ``` 21 | 22 | !!! note 23 | Additional optional packages may be required for theme (e.g. like for material theme). 24 | Just add all required packages: 25 | 26 | ```groovy 27 | python.pip 'mkdocs-ivory:0.4.6', 28 | 'some-additional-package:1.0' 29 | ``` 30 | 31 | 32 | Then changing theme in mkdocs.yml: 33 | 34 | ```yaml 35 | theme: 36 | name: 'ivory' 37 | ``` 38 | 39 | ## Material-related configurations 40 | 41 | Default mkdocs.yml ([generated by plugin](tasks.md#init)) contains special configurations 42 | related to material theme, which may be removed (in case of other theme used): 43 | 44 | ```yaml 45 | theme: 46 | name: 'material' 47 | palette: 48 | - media: "(prefers-color-scheme: light)" 49 | scheme: default 50 | toggle: 51 | icon: material/toggle-switch-off-outline 52 | name: Switch to dark mode 53 | - media: "(prefers-color-scheme: dark)" 54 | scheme: slate 55 | toggle: 56 | icon: material/toggle-switch 57 | name: Switch to light mode 58 | features: 59 | - navigation.tracking 60 | - navigation.top 61 | 62 | extra: 63 | # palette: 64 | # primary: 'indigo' 65 | # accent: 'indigo' 66 | 67 | version: 68 | provider: mike 69 | 70 | social: 71 | - icon: fontawesome/brands/github 72 | link: https://github.com/xvik 73 | - icon: fontawesome/brands/twitter 74 | link: https://twitter.com/vyarus 75 | 76 | # Google Analytics 77 | # analytics: 78 | # provider: google 79 | # property: UA-XXXXXXXX-X 80 | 81 | plugins: 82 | - search 83 | - markdownextradata 84 | 85 | markdown_extensions: 86 | # Python Markdown 87 | - abbr 88 | - admonition 89 | - attr_list 90 | - def_list 91 | - footnotes 92 | - meta 93 | - md_in_html 94 | - toc: 95 | permalink: true 96 | 97 | # Python Markdown Extensions 98 | - pymdownx.arithmatex: 99 | generic: true 100 | - pymdownx.betterem: 101 | smart_enable: all 102 | - pymdownx.caret 103 | - pymdownx.details 104 | - pymdownx.emoji: 105 | emoji_index: !!python/name:material.extensions.emoji.twemoji 106 | emoji_generator: !!python/name:material.extensions.emoji.to_svg 107 | - pymdownx.highlight 108 | - pymdownx.inlinehilite 109 | - pymdownx.keys 110 | - pymdownx.mark 111 | - pymdownx.smartsymbols 112 | - pymdownx.superfences 113 | - pymdownx.tabbed: 114 | alternate_style: true 115 | - pymdownx.tasklist: 116 | custom_checkbox: true 117 | - pymdownx.tilde 118 | 119 | nav: 120 | - Home: index.md 121 | - Getting started: getting-started.md 122 | - User guide: 123 | - Configuration: guide/configuration.md 124 | - Pip: guide/pip.md 125 | - Variables: guide/vars.md 126 | - Multi-version: guide/multi-version.md 127 | - Publication: guide/publication.md 128 | - Tasks: guide/tasks.md 129 | - Themes: guide/theme.md 130 | - About: 131 | - Release notes: about/history.md 132 | - Migration notes: about/migration.md 133 | - License: about/license.md 134 | 135 | ``` 136 | 137 | !!! note 138 | I don't know if `markdown_extensions` would work with your theme. 139 | You can experiment if you need these extra features (see [material theme guide](https://squidfunk.github.io/mkdocs-material/reference/abbreviations/) 140 | for extensions usage examples). -------------------------------------------------------------------------------- /src/doc/docs/guide/vars.md: -------------------------------------------------------------------------------- 1 | # Variables 2 | 3 | You can declare variables as: 4 | 5 | ```groovy 6 | mkdocs { 7 | extras = [ 8 | 'version': "${-> project.version}", 9 | 'something': 'something else' 10 | ] 11 | } 12 | ``` 13 | 14 | !!! warning 15 | You'll have to use lazy evaluation syntax for sensitive properties. In the example above 16 | actual version (`"${-> project.version}"`) would be resolved only just before mkdocs task execution. 17 | 18 | As an alternative, you can declare some properties just before task execution: 19 | ```groovy 20 | mkdocsBuild.doFirst { 21 | extras.prop = ... some value calculation 22 | } 23 | ``` 24 | But this will apply property only for one task (e.g. mkdocsServe will not see this property)! 25 | 26 | Variables applied with [markdownextradata](https://github.com/rosscdh/mkdocs-markdownextradata-plugin) mkdocs plugin. 27 | The plugin is installed, but not activated by default. To use variables it must be enabled: 28 | 29 | ```yaml 30 | plugins: 31 | - search 32 | - markdownextradata 33 | ``` 34 | 35 | (search plugin is enabled by default when plugins section is not declared and so have to be manually specified) 36 | 37 | Now you can use variables in markdown files: 38 | 39 | ``` 40 | {% raw %} 41 | {{ gradle.version }} and {{ gradle.something }} 42 | {% endraw %} 43 | ``` 44 | 45 | !!! note 46 | Variables will work for all mkdocs tasks (`MkdocsTask`), including `mkdocsServe`! 47 | 48 | !!! tip 49 | All generated variables are also printed in console (for reference). 50 | 51 | ## Keys 52 | 53 | Plugin will automatically replace ' ' and '-' in variable keys into '_'. 54 | 55 | For example: 56 | 57 | ```groovy 58 | mkdocs { 59 | extras = [ 60 | 'something-else other': 'something else' 61 | ] 62 | } 63 | ``` 64 | 65 | Will appear as `gradle.something_else_other` variable. 66 | 67 | ## Automation example 68 | 69 | Variables addition may be scripted. For example, mkdocs plugin's build use this to 70 | store used pip modules versions as vars: 71 | 72 | ```groovy 73 | afterEvaluate { 74 | // iterating over modules declared with python.pip 75 | python.modules.each { 76 | def mod = it.split(':') 77 | // storing module name as-is: plugin will auto correct '-' to '_' 78 | mkdocs.extras[mod[0]] = mod[1] 79 | } 80 | } 81 | ``` 82 | 83 | And version reference in docs looks like: 84 | 85 | ```markdown 86 | * [mkdocs:{% raw %} {{ gradle.mkdocs }} {% endraw %}](https://pypi.python.org/pypi/mkdocs) 87 | * [mkdocs-material:{% raw %} {{ gradle.mkdocs_material }} {% endraw %}](https://pypi.python.org/pypi/mkdocs-material) 88 | ``` 89 | 90 | `afterEvaluate` block is not required in this case, but it's usually safer to use it 91 | to avoid "configuration property not yet ready" errors. 92 | 93 | ## Show template syntax in doc 94 | 95 | If you want to prevent replacing variable, for example: 96 | 97 | ``` 98 | {% raw %} 99 | {{ not_var }} 100 | {% endraw %} 101 | ``` 102 | 103 | Then simply apply text "as variable" : 104 | 105 | ``` 106 | {{ '{{ \'{{ not_var }}\' }}' }} 107 | ``` 108 | 109 | or use [jinja raw block syntax](https://jinja.palletsprojects.com/en/2.11.x/templates/#escaping) 110 | 111 | ``` 112 | {{ '{% raw %}' }} 113 | {{ '{{ not_var }}' }} 114 | {{ '{% endraw %}' }} 115 | ``` 116 | 117 | ## How it works 118 | 119 | When variables declared (`mkdocs.extras`), plugin will generate a special data file before mkdocs task execution: 120 | 121 | ``` 122 | [mkdocs.yml location]/docs/_data/gradle.yml 123 | ``` 124 | 125 | Markdownextradata plugin loads all yaml files in `_data` directory by default and so it would 126 | recognize and load gradle-declared properties automatically. 127 | 128 | After task execution, file is removed (because it located inside sources). 129 | 130 | You can declare additinoal (not gradle-related) variables directly in mkdocs.yml's `extra` section 131 | or using additinoal `_data` files: see [plugin documentation](https://github.com/rosscdh/mkdocs-markdownextradata-plugin#use-extra-variables-in-your-markdown-files). 132 | 133 | !!! tip 134 | To update plugin version (for example, in case of bugs): 135 | ```groovy 136 | python.pip 'mkdocs-markdownextradata-plugin:0.2.5' 137 | ``` 138 | 139 | ## Potential problem on linux 140 | 141 | Markdownextradata plugin requires PyYaml 5.1 or above. If you use older version, you may face 142 | the following error: 143 | 144 | ``` 145 | ... 146 | File "/home/travis/.local/lib/python3.6/site-packages/markdownextradata/plugin.py", line 90, in on_pre_build 147 | if filename.suffix in [".yml", ".yaml"] 148 | AttributeError: module 'yaml' has no attribute 'FullLoader' 149 | ``` 150 | 151 | To workaround it either upgrade global PyYaml: 152 | 153 | ``` 154 | pip3 install --ignore-installed pyyaml 155 | ``` 156 | 157 | (`--ignore-installed` required!) 158 | 159 | Or specify exact pyyaml version for installation inside environment: 160 | 161 | ```groovy 162 | python.pip 'pyyaml:5.4.1' 163 | ``` 164 | 165 | !!! note 166 | PyYaml module not declared by default because it's a system module, installed with python. 167 | It may require additional packages for installation (`python3-dev`) and so it could 168 | cause more problems if it would be updated by default. 169 | But, this problem affects only old python versions, and you may never face this. 170 | 171 | ### Travis ci 172 | 173 | Pyyaml problem might be faced on travis: even `bionic` shipped with python 3.6 brings old pyyaml version. 174 | 175 | Workaround: 176 | 177 | ```yaml 178 | language: java 179 | dist: bionic 180 | addons: 181 | apt: 182 | packages: 183 | - "python3" 184 | - "python3-pip" 185 | - "python3-setuptools" 186 | 187 | matrix: 188 | include: 189 | - jdk: openjdk8 190 | - jdk: openjdk11 191 | 192 | before_install: 193 | - chmod +x gradlew 194 | - pip3 install --upgrade pip 195 | # markdownextradata plugin requires at least pyyaml 5.1 196 | - pip3 install --ignore-installed pyyaml 197 | ``` -------------------------------------------------------------------------------- /src/doc/docs/index.md: -------------------------------------------------------------------------------- 1 | # Welcome to gradle-mkdocs-plugin 2 | 3 | !!! summary "" 4 | [Mkdocs](http://www.mkdocs.org/) (python tool) documentation generation and publishing plugin 5 | 6 | [Release notes](about/history.md) - [Migration notes](about/migration.md) - [License](about/license.md) 7 | 8 | ## Ideal for open source projects 9 | 10 | * Easy start: initial docs source generation 11 | * Markdown syntax (with handy extensions) 12 | * Great look from [material theme](https://squidfunk.github.io/mkdocs-material/) (used by default) with extra features: 13 | - Mobile friendly 14 | - Embedded search 15 | - Syntax highlighting 16 | - Dark theme switcher 17 | * Easy documentation contribution (jump to source directly from doc) 18 | * **Multi-version** documentation publishing to github pages 19 | - Support version aliases (latest, dev, etc) 20 | - Support mkdocs-material version switcher without mike tool usage 21 | * Variables support 22 | * Could work with direct python or docker. 23 | * Could use requirements.txt file 24 | * Compatible with gradle configuration cache 25 | 26 | **[Common configurations](examples.md)** (cheat sheet) 27 | 28 | ## Example usages: 29 | 30 | * [mkdocs-gradle-plugin](http://xvik.github.io/gradle-mkdocs-plugin/) (self) 31 | * [use-python-gradle-plugin](http://xvik.github.io/gradle-use-python-plugin/) (base plugin) 32 | * [dropwizard-guicey](http://xvik.github.io/dropwizard-guicey/) 33 | * [gradle-quality-plugin](http://xvik.github.io/gradle-quality-plugin/) 34 | 35 | -------------------------------------------------------------------------------- /src/doc/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Gradle-mkdocs-plugin 2 | 3 | # Meta tags (placed in header) 4 | site_description: Mkdocs documentation plugin 5 | site_author: Vyacheslav Rusakov 6 | site_url: https://xvik.github.io/gradle-mkdocs-plugin 7 | 8 | # Repository (add link to repository on each page) 9 | repo_name: gradle-mkdocs-plugin 10 | repo_url: http://github.com/xvik/gradle-mkdocs-plugin 11 | edit_uri: edit/master/src/doc/docs/ 12 | 13 | #Copyright (shown at the footer) 14 | copyright: 'Copyright © 2017-2024 Vyacheslav Rusakov' 15 | 16 | # Meterial theme 17 | theme: 18 | name: 'material' 19 | palette: 20 | - media: "(prefers-color-scheme: light)" 21 | scheme: default 22 | toggle: 23 | icon: material/toggle-switch-off-outline 24 | name: Switch to dark mode 25 | - media: "(prefers-color-scheme: dark)" 26 | scheme: slate 27 | toggle: 28 | icon: material/toggle-switch 29 | name: Switch to light mode 30 | features: 31 | - navigation.tracking 32 | - navigation.top 33 | 34 | extra: 35 | # palette: 36 | # primary: 'indigo' 37 | # accent: 'indigo' 38 | 39 | version: 40 | provider: mike 41 | 42 | social: 43 | - icon: fontawesome/brands/github 44 | link: https://github.com/xvik 45 | - icon: fontawesome/brands/twitter 46 | link: https://twitter.com/vyarus 47 | 48 | # Google Analytics 49 | # analytics: 50 | # provider: google 51 | # property: UA-XXXXXXXX-X 52 | 53 | plugins: 54 | - search 55 | - markdownextradata 56 | 57 | markdown_extensions: 58 | # Python Markdown 59 | - abbr 60 | - admonition 61 | - attr_list 62 | - def_list 63 | - footnotes 64 | - meta 65 | - md_in_html 66 | - toc: 67 | permalink: true 68 | 69 | # Python Markdown Extensions 70 | - pymdownx.arithmatex: 71 | generic: true 72 | - pymdownx.betterem: 73 | smart_enable: all 74 | - pymdownx.caret 75 | - pymdownx.details 76 | - pymdownx.emoji: 77 | emoji_index: !!python/name:material.extensions.emoji.twemoji 78 | emoji_generator: !!python/name:material.extensions.emoji.to_svg 79 | - pymdownx.highlight 80 | - pymdownx.inlinehilite 81 | - pymdownx.keys 82 | - pymdownx.mark 83 | - pymdownx.smartsymbols 84 | - pymdownx.superfences 85 | - pymdownx.tabbed: 86 | alternate_style: true 87 | - pymdownx.tasklist: 88 | custom_checkbox: true 89 | - pymdownx.tilde 90 | 91 | nav: 92 | - Home: index.md 93 | - Getting started: getting-started.md 94 | - Examples: examples.md 95 | - User guide: 96 | - Configuration: guide/configuration.md 97 | - Pip: guide/pip.md 98 | - Variables: guide/vars.md 99 | - Multi-version: guide/multi-version.md 100 | - Publication: guide/publication.md 101 | - Tasks: guide/tasks.md 102 | - Themes: guide/theme.md 103 | - About: 104 | - Release notes: about/history.md 105 | - Migration notes: about/migration.md 106 | - Compatibility: about/compatibility.md 107 | - License: about/license.md 108 | 109 | dev_addr: 127.0.0.1:3001 -------------------------------------------------------------------------------- /src/main/groovy/ru/vyarus/gradle/plugin/mkdocs/GitPublishExtension.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs 2 | 3 | import groovy.transform.CompileStatic 4 | import org.gradle.api.Action 5 | import org.gradle.api.Project 6 | import org.gradle.api.file.CopySpec 7 | import org.gradle.api.file.DirectoryProperty 8 | import org.gradle.api.provider.Property 9 | import org.gradle.api.tasks.util.PatternFilterable 10 | import org.gradle.api.tasks.util.PatternSet 11 | 12 | /** 13 | * Git publication extension. Based on https://github.com/ajoberstar/gradle-git-publish. 14 | * Note: plugin features preserved almost entirely to keep backwards compatibility for customization cases. 15 | * 16 | * @author Vyacheslav Rusakov 17 | * @since 08.04.2024 18 | */ 19 | @CompileStatic 20 | @SuppressWarnings(['AbstractClassWithPublicConstructor', 'ConfusingMethodName']) 21 | abstract class GitPublishExtension { 22 | 23 | /** 24 | * Repository directory. For example, {@code file("$buildDir/something")}. 25 | */ 26 | abstract DirectoryProperty getRepoDir() 27 | /** 28 | * Repository to publish into (must exists). For example, {@code 'git@github.com:user/test-repo.git'} 29 | */ 30 | abstract Property getRepoUri() 31 | /** 32 | * (Optional) Where to fetch from prior to fetching from the remote (i.e. a local repo to save time). 33 | */ 34 | abstract Property getReferenceRepoUri() 35 | /** 36 | * Target branch (would be created if does not exists). 37 | */ 38 | abstract Property getBranch() 39 | /** 40 | * Commit message. 41 | */ 42 | abstract Property getCommitMessage() 43 | /** 44 | * Signing commits. Omit to use the default from your gitconfig. 45 | */ 46 | abstract Property getSign() 47 | 48 | /** 49 | * Repository user name (for authorization) or github token. See "org.ajoberstar.grgit.auth.username" property 50 | * https://ajoberstar.org/grgit/main/grgit-authentication.html 51 | */ 52 | abstract Property getUsername() 53 | /** 54 | * Repository password. See "org.ajoberstar.grgit.auth.password" property 55 | * https://ajoberstar.org/grgit/main/grgit-authentication.html 56 | */ 57 | abstract Property getPassword() 58 | 59 | /** 60 | * {@link CopySpec} content to add into repository. 61 | * 62 | * contents { 63 | * from 'src/pages' 64 | * from(javadoc) { 65 | * into 'api' 66 | * } 67 | * } 68 | * 69 | * @see gradle docs 70 | */ 71 | CopySpec contents 72 | /** 73 | * What to keep (or remote) in existing branch. 74 | * E.g. to keep version 1.0.0 files except temp.txt file: 75 | * 76 | * preserve { 77 | * include '1.0.0/**' 78 | * exclude '1.0.0/temp.txt' 79 | * } 80 | * 81 | *

82 | * By default, only ".git" folder preserved. 83 | * 84 | * @see 85 | * gradle doc 86 | */ 87 | PatternFilterable preserve 88 | 89 | GitPublishExtension(Project project) { 90 | this.contents = project.copySpec() 91 | this.preserve = new PatternSet() 92 | this.preserve.include('.git/**/*') 93 | } 94 | 95 | void contents(Action action) { 96 | action.execute(contents) 97 | } 98 | 99 | void preserve(Action action) { 100 | action.execute(preserve) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/groovy/ru/vyarus/gradle/plugin/mkdocs/MkdocsBuildPlugin.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs 2 | 3 | import groovy.transform.CompileStatic 4 | import groovy.transform.TypeCheckingMode 5 | import org.gradle.api.Plugin 6 | import org.gradle.api.Project 7 | import ru.vyarus.gradle.plugin.mkdocs.task.MkdocsBuildTask 8 | import ru.vyarus.gradle.plugin.mkdocs.task.MkdocsInitTask 9 | import ru.vyarus.gradle.plugin.mkdocs.task.MkdocsTask 10 | import ru.vyarus.gradle.plugin.python.PythonExtension 11 | import ru.vyarus.gradle.plugin.python.PythonPlugin 12 | 13 | /** 14 | * Base mkdocs plugin without publishing tasks (and so without grgit plugin registration). May be used in cases when 15 | * publication is not required or when there are problems with grgit plugin. 16 | *

17 | * Provides tasks: 18 | *

    19 | *
  • mkdocsInit - create documentation site 20 | *
  • mkdocsBuild - build site 21 | *
  • mkdocsServe - start livereload server (for development) 22 | *
23 | *

24 | * mkdocksInit not use 'mkdocs new', instead more advanced template used with pre-initialized material theme. 25 | *

26 | * Plugin will also apply all required pip modules to use mkdocks with material theme and basic plugins 27 | * (see {@link ru.vyarus.gradle.plugin.mkdocs.MkdocsExtension#DEFAULT_MODULES}). 28 | * 29 | * @author Vyacheslav Rusakov 30 | * @since 28.10.2022 31 | */ 32 | @CompileStatic 33 | class MkdocsBuildPlugin implements Plugin { 34 | 35 | private static final List STRICT = ['-s'] 36 | private static final String DEV_ADDR = '--dev-addr' 37 | 38 | public static final String MKDOCS_BUILD_TASK = 'mkdocsBuild' 39 | public static final String DOCUMENTATION_GROUP = 'documentation' 40 | 41 | @Override 42 | void apply(Project project) { 43 | MkdocsExtension extension = project.extensions.create('mkdocs', MkdocsExtension, project) 44 | 45 | project.plugins.apply(PythonPlugin) 46 | applyDefaults(project) 47 | configureMkdocsTasks(project, extension) 48 | configureServe(project, extension) 49 | } 50 | 51 | private void applyDefaults(Project project) { 52 | // apply default mkdocs, material and minimal plugins 53 | // user will be able to override versions, if required 54 | project.extensions.getByType(PythonExtension).pip(MkdocsExtension.DEFAULT_MODULES) 55 | } 56 | 57 | @SuppressWarnings('AbcMetric') 58 | private void configureMkdocsTasks(Project project, MkdocsExtension extension) { 59 | project.tasks.register(MKDOCS_BUILD_TASK, MkdocsBuildTask) { task -> 60 | task.description = 'Build mkdocs documentation' 61 | task.group = DOCUMENTATION_GROUP 62 | task.extraArgs.convention project.provider { extension.strict ? STRICT : [] } 63 | task.outputDir.convention(project.file("${getBuildOutputDir(extension)}")) 64 | task.updateSiteUrl.convention(extension.updateSiteUrl) 65 | task.versionPath.convention(extension.resolveDocPath()) 66 | task.versionName.convention(extension.resolveVersionTitle()) 67 | task.rootRedirectPath 68 | .convention(extension.publish.rootRedirect ? extension.resolveRootRedirectionPath() : null) 69 | task.versionAliases.convention(extension.publish.versionAliases 70 | ? extension.publish.versionAliases as List : []) 71 | task.buildDir.convention(project.file(extension.buildDir)) 72 | task.existingVersionFile.convention(extension.publish.existingVersionsFile) 73 | } 74 | 75 | project.tasks.register('mkdocsInit', MkdocsInitTask) { task -> 76 | task.description = 'Create mkdocs documentation' 77 | task.group = DOCUMENTATION_GROUP 78 | task.sourcesDir.convention(extension.sourcesDir) 79 | } 80 | 81 | project.tasks.withType(MkdocsTask).configureEach { task -> 82 | task.workDir.convention(extension.sourcesDir) 83 | task.sourcesDir.convention(extension.sourcesDir) 84 | task.extras.convention(project.provider { 85 | // resolving lazy gstrings ("${-> something}") because they can't be serialized 86 | Map res = [:] 87 | extension.extras.each { 88 | res.put(it.key, it.value?.toString()) 89 | } 90 | res 91 | }) 92 | } 93 | 94 | // simplify direct task usage 95 | project.extensions.extraProperties.set(MkdocsTask.simpleName, MkdocsTask) 96 | } 97 | 98 | @CompileStatic(TypeCheckingMode.SKIP) 99 | private void configureServe(Project project, MkdocsExtension extension) { 100 | project.tasks.register('mkdocsServe', MkdocsTask) { task -> 101 | task.description = 'Start mkdocs live reload server' 102 | task.group = DOCUMENTATION_GROUP 103 | task.command.set('serve') 104 | if (dockerUsed) { 105 | // mkdocs in strict mode does not allow external mappings, so avoid strict, event if configured 106 | // also ip must be changed, otherwise server would be invisible outside docker 107 | task.extraArgs DEV_ADDR, "0.0.0.0:${extension.devPort}" 108 | } else { 109 | List args = extension.strict ? new ArrayList<>(STRICT) : [] 110 | args += [DEV_ADDR, "127.0.0.1:${extension.devPort}"] 111 | task.extraArgs.addAll(args) 112 | } 113 | // docker activation is still up to global configuration - here just required tuning 114 | // task would be started in exclusive container in order to stream output immediately 115 | task.docker.exclusive.set(true) 116 | task.docker.ports extension.devPort 117 | } 118 | } 119 | 120 | private String getBuildOutputDir(MkdocsExtension extension) { 121 | return extension.buildDir + (extension.multiVersion ? '/' + extension.resolveDocPath() : '') 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/main/groovy/ru/vyarus/gradle/plugin/mkdocs/service/GrgitService.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs.service 2 | 3 | import groovy.transform.CompileStatic 4 | import org.ajoberstar.grgit.Grgit 5 | import org.gradle.api.services.BuildService 6 | import org.gradle.api.services.BuildServiceParameters 7 | import org.gradle.tooling.events.FinishEvent 8 | import org.gradle.tooling.events.OperationCompletionListener 9 | 10 | /** 11 | * Git service to manage single grgit instance between publish tasks. 12 | * 13 | * @author Vyacheslav Rusakov 14 | * @since 09.04.2024 15 | */ 16 | @CompileStatic 17 | @SuppressWarnings(['AbstractClassWithoutAbstractMethod', 'ConfusingMethodName']) 18 | abstract class GrgitService implements BuildService, 19 | OperationCompletionListener, AutoCloseable { 20 | 21 | /** 22 | * Grgit instance. Initiated by gitReset task and used by other git tasks. 23 | */ 24 | Grgit grgit 25 | 26 | @Override 27 | @SuppressWarnings('EmptyMethodInAbstractClass') 28 | void onFinish(FinishEvent finishEvent) { 29 | // not used, just to keep service alive 30 | } 31 | 32 | @Override 33 | void close() throws Exception { 34 | if (grgit != null) { 35 | grgit.close() 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/groovy/ru/vyarus/gradle/plugin/mkdocs/source/RepoUriValueSource.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs.source 2 | 3 | import groovy.transform.CompileStatic 4 | import org.ajoberstar.grgit.Configurable 5 | import org.ajoberstar.grgit.Grgit 6 | import org.ajoberstar.grgit.operation.OpenOp 7 | import org.gradle.api.provider.Property 8 | import org.gradle.api.provider.ValueSource 9 | import org.gradle.api.provider.ValueSourceParameters 10 | 11 | /** 12 | * Git repository detection in project root. Custom value source is required for configuration cache support because 13 | * all external processes must be wrapped (even if this values could be easily cached). 14 | * 15 | * @author Vyacheslav Rusakov 16 | * @since 10.04.2024 17 | */ 18 | @CompileStatic 19 | @SuppressWarnings('AbstractClassWithoutAbstractMethod') 20 | abstract class RepoUriValueSource implements ValueSource { 21 | 22 | @SuppressWarnings(['UnnecessaryCast', 'CatchException']) 23 | String obtain() { 24 | try { 25 | Grgit repo = Grgit.open({ OpenOp op -> op.dir = parameters.rootDir.get() } as Configurable) 26 | return repo.remote.list().find { it.name == 'origin' }?.url 27 | } catch (Exception ignored) { 28 | // repository not initialized case - do nothing (most likely user is just playing with the plugin) 29 | } 30 | return null 31 | } 32 | 33 | interface Params extends ValueSourceParameters { 34 | Property getRootDir() 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/groovy/ru/vyarus/gradle/plugin/mkdocs/task/MkdocsBuildTask.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs.task 2 | 3 | import groovy.transform.CompileStatic 4 | import groovy.transform.TypeCheckingMode 5 | import org.apache.tools.ant.taskdefs.condition.Os 6 | import org.gradle.api.GradleException 7 | import org.gradle.api.file.Directory 8 | import org.gradle.api.provider.ListProperty 9 | import org.gradle.api.provider.Property 10 | import org.gradle.api.provider.Provider 11 | import org.gradle.api.tasks.* 12 | import ru.vyarus.gradle.plugin.mkdocs.MkdocsExtension 13 | import ru.vyarus.gradle.plugin.mkdocs.util.MkdocsConfig 14 | import ru.vyarus.gradle.plugin.mkdocs.util.TemplateUtils 15 | import ru.vyarus.gradle.plugin.mkdocs.util.VersionsFileUtils 16 | 17 | /** 18 | * Builds mkdocs site. If version is configured as default for publication, then generate extra index.html. 19 | * If mkdocs.yml contains site_url value then current path will applied in config (original config reverted after 20 | * the build). 21 | * 22 | * @author Vyacheslav Rusakov 23 | * @since 14.11.2017 24 | */ 25 | @CompileStatic 26 | @SuppressWarnings(['DuplicateStringLiteral', 'AbstractClassWithoutAbstractMethod', 27 | 'AbstractClassWithPublicConstructor']) 28 | abstract class MkdocsBuildTask extends MkdocsTask { 29 | 30 | private static final String SITE_URL = 'site_url' 31 | 32 | /** 33 | * Output directory. 34 | */ 35 | @OutputDirectory 36 | abstract Property getOutputDir() 37 | 38 | /** 39 | * Update 'site_url' in mkdocs configuration to correct path. Required for multi-version publishing to 40 | * correctly update version url. 41 | */ 42 | @Input 43 | abstract Property getUpdateSiteUrl() 44 | 45 | /** 46 | * Version directory path. "." if no version directories used. 47 | * @see {@link ru.vyarus.gradle.plugin.mkdocs.MkdocsExtension.Publish#docPath} 48 | */ 49 | @Input 50 | abstract Property getVersionPath() 51 | 52 | /** 53 | * Version name (what to show in version dropdown). 54 | * @see {@link ru.vyarus.gradle.plugin.mkdocs.MkdocsExtension.Publish#versionTitle} 55 | */ 56 | @Input 57 | @Optional 58 | abstract Property getVersionName() 59 | 60 | /** 61 | * Root redirection path or null to disable root redirection. 62 | */ 63 | @Input 64 | @Optional 65 | abstract Property getRootRedirectPath() 66 | 67 | /** 68 | * Version aliases. 69 | */ 70 | @Input 71 | @Optional 72 | abstract ListProperty getVersionAliases() 73 | 74 | /** 75 | * Mkdocs build directory. 76 | */ 77 | @OutputDirectory 78 | abstract Property getBuildDir() 79 | 80 | /** 81 | * Versions file to update (when publish tasks not used). 82 | */ 83 | @Input 84 | @Optional 85 | abstract Property getExistingVersionFile() 86 | 87 | @Internal 88 | Provider projectBuildDir = project.layout.buildDirectory 89 | 90 | MkdocsBuildTask() { 91 | command.set(project.provider { 92 | boolean isWindows = Os.isFamily(Os.FAMILY_WINDOWS) 93 | String path = outputDir.get().canonicalPath 94 | if (isWindows) { 95 | // always wrap into quotes for windows 96 | path = "\"$path\"" 97 | } 98 | // use array to avoid escaping spaces in path (and consequent args parsing) 99 | return ['build', '-c', '-d', path] 100 | }) 101 | } 102 | 103 | @Override 104 | void run() { 105 | String path = versionPath.get() 106 | boolean multiVersion = path != MkdocsExtension.SINGLE_VERSION_PATH 107 | Closure action = { super.run() } 108 | 109 | if (updateSiteUrl.get() && multiVersion) { 110 | // update mkdocs.yml site_url from global to published folder (in order to build correct sitemap) 111 | withModifiedConfig(path, action) 112 | } else { 113 | action.call() 114 | } 115 | 116 | // output directory must be owned by current user, not root, otherwise clean would fail 117 | dockerChown(outputDir.get().toPath()) 118 | 119 | // optional remote versions file update 120 | updateVersions() 121 | 122 | if (multiVersion) { 123 | // add root index.html 124 | copyRedirect(path) 125 | copyAliases(path) 126 | } 127 | } 128 | 129 | @InputDirectory 130 | File getSourcesDirectory() { 131 | return fs.file(sourcesDir.get()) 132 | } 133 | 134 | private void withModifiedConfig(String path, Closure action) { 135 | MkdocsConfig conf = new MkdocsConfig(fs, sourcesDir.get()) 136 | String url = conf.find(SITE_URL) 137 | 138 | // site_url not defined or already points to correct location 139 | if (!url || url.endsWith(path) || url.endsWith("$path/")) { 140 | action.call() 141 | return 142 | } 143 | 144 | File backup = conf.backup() 145 | try { 146 | String slash = '/' 147 | String folderUrl = (url.endsWith(slash) ? url : (url + slash)) + path 148 | conf.set(SITE_URL, folderUrl) 149 | logger.lifecycle("Modified ${fs.relativePath(conf.config)}: '$SITE_URL: $folderUrl'") 150 | action.call() 151 | } finally { 152 | conf.restoreBackup(backup) 153 | logger.lifecycle("Original ${fs.relativePath(conf.config)} restored") 154 | } 155 | } 156 | 157 | private void updateVersions() { 158 | String versions = existingVersionFile.orNull 159 | if (versions) { 160 | File target 161 | if (versions.contains(':')) { 162 | target = new File(projectBuildDir.get().asFile, 'old-versions.json') 163 | download(versions, target) 164 | } else { 165 | target = fs.file(versions) 166 | } 167 | File res = VersionsFileUtils.getTarget(buildDir.get()) 168 | logger.lifecycle('Creating versions file: {}', fs.relativePath(res)) 169 | Map> parse = VersionsFileUtils.parse(target) 170 | if (target.exists()) { 171 | logger.lifecycle("\tExisting versions file '{}' loaded with {} versions", versions, parse.size()) 172 | } else { 173 | logger.warn("\tWARNING: configured versions file '{}' does not exist - creating new file instead", 174 | versions) 175 | } 176 | 177 | String currentVersion = versionPath.get() 178 | if (VersionsFileUtils.addVersion(parse, currentVersion)) { 179 | logger.lifecycle('\tNew version added: {}', currentVersion) 180 | } 181 | VersionsFileUtils.updateVersion(parse, 182 | currentVersion, versionName.get(), versionAliases.get()) 183 | VersionsFileUtils.write(parse, res) 184 | logger.lifecycle('\tVersions written to file: {}', parse.keySet().join(', ')) 185 | } 186 | } 187 | 188 | @CompileStatic(TypeCheckingMode.SKIP) 189 | private void download(String src, File target) { 190 | // ignore all errors (create new file if failed to load) 191 | ant.get(src: src, dest: target, maxtime: 5, skipexisting: true, ignoreerrors: true) 192 | } 193 | 194 | private void copyRedirect(String path) { 195 | if (rootRedirectPath.orNull) { 196 | String target = rootRedirectPath.get() 197 | List possible = [path] 198 | possible.addAll(versionAliases.get()) 199 | if (!possible.contains(target)) { 200 | throw new GradleException("Invalid mkdocs.publish.rootRedirectTo option value: '$target'. " + 201 | "Possible values are: ${possible.join(', ')} ('\$docPath' for actual version)") 202 | } 203 | // create root redirection file 204 | TemplateUtils.copy(fs, '/ru/vyarus/gradle/plugin/mkdocs/template/publish/', 205 | fs.relativePath(buildDir.get()), [docPath: target]) 206 | logger.lifecycle('Root redirection enabled to: {}', target) 207 | } else { 208 | // remove stale index.html (to avoid unintentional redirect override) 209 | // of course, build always must be called after clean, but at least minimize damage on incorrect usage 210 | File index = new File(buildDir.get(), 'index.html') 211 | if (index.exists()) { 212 | index.delete() 213 | } 214 | } 215 | } 216 | 217 | @CompileStatic(TypeCheckingMode.SKIP) 218 | private void copyAliases(String version) { 219 | File baseDir = buildDir.get() 220 | 221 | List aliases = versionAliases.get() 222 | if (aliases) { 223 | aliases.each { String alias -> 224 | fs.copy { spec -> 225 | spec.from new File(baseDir, version) 226 | spec.into new File(baseDir, alias) 227 | } 228 | } 229 | logger.lifecycle('Version aliases added: {}', aliases.join(', ')) 230 | } 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /src/main/groovy/ru/vyarus/gradle/plugin/mkdocs/task/MkdocsInitTask.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs.task 2 | 3 | import groovy.transform.CompileStatic 4 | import org.gradle.api.DefaultTask 5 | import org.gradle.api.GradleException 6 | import org.gradle.api.internal.file.FileOperations 7 | import org.gradle.api.provider.Property 8 | import org.gradle.api.provider.Provider 9 | import org.gradle.api.tasks.Input 10 | import org.gradle.api.tasks.TaskAction 11 | import ru.vyarus.gradle.plugin.mkdocs.util.TemplateUtils 12 | 13 | import javax.inject.Inject 14 | 15 | /** 16 | * Generate initial mkdocs site. Does not use "mkdocs new" command. Custom template is used instead in order 17 | * to pre-configure target site with the material theme and enable some extensions. 18 | * 19 | * @author Vyacheslav Rusakov 20 | * @since 13.11.2017 21 | */ 22 | @CompileStatic 23 | abstract class MkdocsInitTask extends DefaultTask { 24 | 25 | /** 26 | * Documentation sources folder (mkdocs sources root folder). 27 | */ 28 | @Input 29 | abstract Property getSourcesDir() 30 | 31 | protected Provider projectName = project.provider { project.name } 32 | protected Provider projectDesc = project.provider { project.description } 33 | 34 | @TaskAction 35 | void run() { 36 | String sourcesPath = sourcesDir.get() 37 | File dir = fs.file(sourcesPath) 38 | if (dir.exists() && dir.listFiles().length > 0) { 39 | throw new GradleException("Can't init new mkdocs site because target directory is not empty: $dir") 40 | } 41 | 42 | TemplateUtils.copy(fs, '/ru/vyarus/gradle/plugin/mkdocs/template/init/', dir, [ 43 | projectName: projectName.get(), 44 | projectDescription: projectDesc.orNull ?: '', 45 | docDir: sourcesPath, 46 | ]) 47 | logger.lifecycle("Mkdocs site initialized: $sourcesPath") 48 | } 49 | 50 | @Inject 51 | protected abstract FileOperations getFs() 52 | } 53 | -------------------------------------------------------------------------------- /src/main/groovy/ru/vyarus/gradle/plugin/mkdocs/task/MkdocsTask.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs.task 2 | 3 | import groovy.transform.CompileStatic 4 | import org.gradle.api.GradleException 5 | import org.gradle.api.internal.file.FileOperations 6 | import org.gradle.api.provider.MapProperty 7 | import org.gradle.api.provider.Property 8 | import org.gradle.api.tasks.Input 9 | import ru.vyarus.gradle.plugin.mkdocs.util.MkdocsConfig 10 | import ru.vyarus.gradle.plugin.python.task.PythonTask 11 | 12 | import javax.inject.Inject 13 | 14 | /** 15 | * General mkdocs task. 16 | *

17 | * Provides support for gradle-driven variables. When variables be declared in {@code mkdocs.extras} map, 18 | * task would generate special data file: {@code [mkdocs.yml location]/docs/_data/gradle.yml}. 19 | * Markdownextradata plugin must be activated in mkdocs.yml (exception will be thrown if not). Plugin searches 20 | * by default in @{code [mkdocs.yml location]/docs/_data/} dir for variable files (no magic behaviour). 21 | * In documentation variables may be used as

{{ gradle.var_name }}
. 22 | * 23 | * @author Vyacheslav Rusakov 24 | * @since 13.11.2017 25 | * @see markdownextradata plugin documentation 26 | */ 27 | @CompileStatic 28 | @SuppressWarnings(['AbstractClassWithoutAbstractMethod', 'AbstractClassWithPublicConstructor']) 29 | abstract class MkdocsTask extends PythonTask { 30 | 31 | MkdocsTask() { 32 | // restrict commands to mkdocs module 33 | module.set('mkdocs') 34 | } 35 | 36 | /** 37 | * Documentation sources folder (mkdocs sources root folder). 38 | */ 39 | @Input 40 | abstract Property getSourcesDir() 41 | 42 | /** 43 | * Extra gradle-provided variables to use in documentation. 44 | */ 45 | @Input 46 | abstract MapProperty getExtras() 47 | 48 | @Override 49 | @SuppressWarnings('UnnecessaryGetter') 50 | void run() { 51 | if (extras.get().isEmpty()) { 52 | // no vars - simple run 53 | super.run() 54 | } else { 55 | runWithVariables() 56 | } 57 | } 58 | 59 | @Inject 60 | protected abstract FileOperations getFs() 61 | 62 | private void runWithVariables() { 63 | File data = resolveDataDir() 64 | boolean removeDataDir = !data.exists() 65 | File gen = new File(data, 'gradle.yml') 66 | try { 67 | if (removeDataDir) { 68 | data.mkdirs() 69 | } 70 | // assuming this file owned by gradle exclusively and may remain only because of incorrect task shutdown 71 | if (gen.exists()) { 72 | gen.delete() 73 | } 74 | logger.lifecycle('Generating mkdocs data file: {}', getFilePath(gen)) 75 | String report = '' 76 | gen.withWriter { BufferedWriter writer -> 77 | extras.get().each { k, v -> 78 | // Object value used for deferred evaluation (GString may use lazy placeholders) 79 | String line = k.replaceAll('[ -]', '_') + ': ' + (v ?: '') 80 | writer.writeLine(line) 81 | report += "\t$line\n" 82 | } 83 | } 84 | logger.lifecycle(report) 85 | super.run() 86 | } finally { 87 | gen.delete() 88 | if (removeDataDir) { 89 | data.delete() 90 | } 91 | } 92 | } 93 | 94 | private File resolveDataDir() { 95 | MkdocsConfig config = new MkdocsConfig(fs, sourcesDir.get()) 96 | 97 | if (!config.contains('plugins.markdownextradata')) { 98 | throw new GradleException( 99 | 'Gradle-defined extra properties require \'markdownextradata\' plugin active in ' + 100 | 'your mkdocs.yml file, which is currently not the case. \nEither remove extra properties ' + 101 | 'declaration (in build.gradle) or declare plugin (in mkdocs.yml) like this: \n' + 102 | 'plugins:\n' + 103 | ' - search\n' + 104 | ' - markdownextradata') 105 | } 106 | 107 | // mkdocs.yml location 108 | File root = fs.file(sourcesDir.get()) 109 | 110 | // configuration may override default "docs" location 111 | String docsPath = config.find('docs_dir') ?: 'docs' 112 | File docs = new File(docsPath) 113 | // docs_dir config value may contain absolute path declaration 114 | if (!docs.absolute) { 115 | docs = new File(root, docs.path) 116 | } 117 | 118 | return new File(docs, '_data') 119 | } 120 | 121 | /** 122 | * Looks if file inside project and relative path would be reasonable, otherwise return absolute path. 123 | * 124 | * @param file file 125 | * @return relative or absolute file path 126 | */ 127 | private String getFilePath(File file) { 128 | if (file.path.startsWith(gradleEnv.get().rootDir.path)) { 129 | return fs.relativePath(file) 130 | } 131 | return file.absolutePath 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/main/groovy/ru/vyarus/gradle/plugin/mkdocs/task/publish/GitPublishCommit.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs.task.publish 2 | 3 | import groovy.transform.CompileStatic 4 | import org.ajoberstar.grgit.Configurable 5 | import org.ajoberstar.grgit.Grgit 6 | import org.ajoberstar.grgit.operation.AddOp 7 | import org.ajoberstar.grgit.operation.CommitOp 8 | import org.gradle.api.DefaultTask 9 | import org.gradle.api.Task 10 | import org.gradle.api.provider.Property 11 | import org.gradle.api.specs.Spec 12 | import org.gradle.api.tasks.* 13 | import ru.vyarus.gradle.plugin.mkdocs.service.GrgitService 14 | 15 | import java.util.stream.Collectors 16 | import java.util.stream.Stream 17 | 18 | /** 19 | * Git commit task. Based on https://github.com/ajoberstar/gradle-git-publish. 20 | * 21 | * @author Vyacheslav Rusakov 22 | * @since 08.04.2024 23 | */ 24 | @CompileStatic 25 | @SuppressWarnings('AbstractClassWithPublicConstructor') 26 | abstract class GitPublishCommit extends DefaultTask { 27 | 28 | /** 29 | * Commit message. 30 | */ 31 | @Input 32 | abstract Property getMessage() 33 | 34 | /** 35 | * Signing commits. Omit to use the default from your gitconfig. 36 | */ 37 | @Input 38 | @Optional 39 | abstract Property getSign() 40 | 41 | // grgit instance initiated under reset task 42 | @Internal 43 | abstract Property getGrgit() 44 | 45 | GitPublishCommit() { 46 | // always consider this task out of date 47 | this.outputs.upToDateWhen({ t -> false } as Spec) 48 | } 49 | 50 | @OutputDirectory 51 | File getRepoDirectory() { 52 | return grgit.get().grgit.repository.rootDir 53 | } 54 | 55 | @TaskAction 56 | void commit() { 57 | Grgit git = grgit.get().grgit 58 | git.add({ AddOp op -> 59 | op.patterns = Stream.of('.').collect(Collectors.toSet()) 60 | } as Configurable) 61 | 62 | // check if anything has changed 63 | if (git.status().clean) { 64 | didWork = false 65 | } else { 66 | git.commit({ CommitOp op -> 67 | op.message = message.get() 68 | if (sign.present) { 69 | op.sign = sign.get() 70 | } 71 | } as Configurable) 72 | didWork = true 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/groovy/ru/vyarus/gradle/plugin/mkdocs/task/publish/GitPublishPush.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs.task.publish 2 | 3 | import groovy.transform.CompileStatic 4 | import org.ajoberstar.grgit.BranchStatus 5 | import org.ajoberstar.grgit.Configurable 6 | import org.ajoberstar.grgit.Grgit 7 | import org.ajoberstar.grgit.operation.BranchChangeOp 8 | import org.ajoberstar.grgit.operation.BranchStatusOp 9 | import org.ajoberstar.grgit.operation.PushOp 10 | import org.gradle.api.DefaultTask 11 | import org.gradle.api.Task 12 | import org.gradle.api.provider.Property 13 | import org.gradle.api.specs.Spec 14 | import org.gradle.api.tasks.Input 15 | import org.gradle.api.tasks.Internal 16 | import org.gradle.api.tasks.OutputDirectory 17 | import org.gradle.api.tasks.TaskAction 18 | import ru.vyarus.gradle.plugin.mkdocs.service.GrgitService 19 | 20 | /** 21 | * Git push task. Based on https://github.com/ajoberstar/gradle-git-publish. 22 | * 23 | * @author Vyacheslav Rusakov 24 | * @since 08.04.2024 25 | */ 26 | @CompileStatic 27 | @SuppressWarnings('AbstractClassWithPublicConstructor') 28 | abstract class GitPublishPush extends DefaultTask { 29 | 30 | /** 31 | * Target branch (would be created if doesn't exists). 32 | */ 33 | @Input 34 | abstract Property getBranch() 35 | 36 | // grgit instance initiated under reset task 37 | @Internal 38 | abstract Property getGrgit() 39 | 40 | GitPublishPush() { 41 | // always consider this task out of date 42 | this.outputs.upToDateWhen({ t -> false } as Spec) 43 | // NOTE: onlyIf removed due to conflicts with configuration cache so task would never be up to date 44 | } 45 | 46 | @OutputDirectory 47 | File getRepoDirectory() { 48 | return grgit.get().grgit.repository.rootDir 49 | } 50 | 51 | @TaskAction 52 | void push() { 53 | Grgit git = grgit.get().grgit 54 | // moved from onlyIf to avoid calling git under configuration stage 55 | if (!isPushRequired(git)) { 56 | return 57 | } 58 | String pubBranch = branch.get() 59 | git.push({ PushOp op -> 60 | op.refsOrSpecs = Arrays.asList(String.format('refs/heads/%s:refs/heads/%s', pubBranch, pubBranch)) 61 | } as Configurable) 62 | // ensure tracking is set 63 | git.branch.change({ BranchChangeOp op -> 64 | op.name = pubBranch 65 | op.startPoint = 'origin/' + pubBranch 66 | op.mode = BranchChangeOp.Mode.TRACK 67 | } as Configurable) 68 | } 69 | 70 | private boolean isPushRequired(Grgit git) { 71 | try { 72 | BranchStatus status = git.branch.status({ BranchStatusOp op -> 73 | op.name = branch.get() 74 | } as Configurable) 75 | return status.aheadCount > 0 76 | } catch (IllegalStateException e) { 77 | // if we're not tracking anything yet (i.e. orphan) we need to push 78 | return true 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/groovy/ru/vyarus/gradle/plugin/mkdocs/util/MkdocsConfig.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs.util 2 | 3 | import groovy.transform.CompileStatic 4 | import org.gradle.api.GradleException 5 | import org.gradle.api.internal.file.FileOperations 6 | 7 | import java.util.regex.Matcher 8 | 9 | /** 10 | * Utility to work with mkdocs config (mkdocs.yml). 11 | * 12 | * @author Vyacheslav Rusakov 13 | * @since 07.12.2017 14 | */ 15 | @CompileStatic 16 | class MkdocsConfig { 17 | 18 | private final FileOperations fs 19 | private final String configLocation 20 | 21 | MkdocsConfig(FileOperations fs, String sourceDir) { 22 | this.fs = fs 23 | this.configLocation = (sourceDir ? "$sourceDir/" : '') + 'mkdocs.yml' 24 | } 25 | 26 | /** 27 | * @return mkdocs config file 28 | * @throws GradleException if config does not exist 29 | */ 30 | File getConfig() { 31 | File config = fs.file(configLocation) 32 | if (!config.exists()) { 33 | throw new GradleException("Mkdocs config file not found: ${fs.relativePath(config)}") 34 | } 35 | return config 36 | } 37 | 38 | /** 39 | * @param option config option to find 40 | * @return option value or null if option commented or not defined 41 | */ 42 | String find(String option) { 43 | String line = config.readLines().find { 44 | it.startsWith("$option:") 45 | } 46 | if (line) { 47 | int pos = line.indexOf(':') 48 | // special case: no value defined on property 49 | String res = pos < line.length() - 1 ? line[pos + 1..-1].trim() : '' 50 | // remove quotes 51 | return res.replaceAll(/^['"]/, '').replaceAll(/['"]$/, '') 52 | } 53 | return null 54 | } 55 | 56 | /** 57 | * Searches for specified property. Supports nesting: if property contains dots then it will search for 58 | * each property part sequentially (note that multiline list value also counted as property). 59 | *

60 | * Looks only not commented lines. Counts hierarchy. 61 | * 62 | * @param option option (maybe composite: separated with dots) name to find 63 | * @return true is string found, false otherwise 64 | */ 65 | boolean contains(String option) { 66 | String[] parts = option.split('\\.') 67 | int i = 0 68 | int whitespace = 0 69 | String line = config.readLines().find { 70 | // line must not be commented, contain enough whitespace and required option part 71 | // allowed: [ prop, prop:, - prop, -prop ] 72 | if (!it.trim().startsWith('#') && it.find( 73 | /${whitespace == 0 ? '^' : '\\s{' + whitespace + ',}'}(-\s{0,})?${parts[i]}(:|$|\s)/)) { 74 | if (whitespace == 0) { 75 | whitespace++ 76 | } else { 77 | // count starting whitespace (to correctly recognize structure) 78 | Matcher matcher = it =~ /^(\s+)/ 79 | if (!matcher.find()) { 80 | throw new IllegalStateException("Failed to recognize preceeding whitespace in '$it'") 81 | } 82 | whitespace = matcher.group(1).length() + 1 83 | } 84 | i++ 85 | } 86 | return i == parts.length 87 | } 88 | return line != null 89 | } 90 | 91 | /** 92 | * Replace option value in mkdocks config. 93 | * 94 | * @param option option name 95 | * @param value new option value 96 | */ 97 | void set(String option, String value) { 98 | config.text = config.text.replaceAll(/(?m)^$option:.*/, "$option: $value") 99 | } 100 | 101 | /** 102 | * Backup configuration file. 103 | * 104 | * @return configuration backup file 105 | */ 106 | File backup() { 107 | File backup = new File(config.parentFile, 'mkdocs.yml.bak') 108 | if (backup.exists()) { 109 | backup.delete() 110 | } 111 | backup << config.text 112 | return backup 113 | } 114 | 115 | /** 116 | * Replace current configuration file with provided backup. 117 | * 118 | * @param backup configuration backup 119 | * @throws IllegalStateException if backup file or config does not exists 120 | */ 121 | void restoreBackup(File backup) { 122 | if (!backup.exists()) { 123 | throw new IllegalStateException("No backup file found: ${fs.relativePath(backup)}") 124 | } 125 | File cfg = config 126 | cfg.delete() 127 | if (!backup.renameTo(cfg)) { 128 | throw new IllegalStateException("Failed to rename ${fs.relativePath(backup.absolutePath)} back " + 129 | "to ${fs.relativePath(cfg.absolutePath)}. Please rename manually to recover.") 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/groovy/ru/vyarus/gradle/plugin/mkdocs/util/TemplateUtils.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs.util 2 | 3 | import groovy.transform.CompileStatic 4 | import groovy.transform.TypeCheckingMode 5 | import org.apache.tools.ant.filters.ReplaceTokens 6 | import org.gradle.api.file.FileCopyDetails 7 | import org.gradle.api.file.FileTree 8 | import org.gradle.api.internal.file.FileOperations 9 | 10 | /** 11 | * Utility to extract templates from classpath (plugin jar) and copy to target location with placeholders processing. 12 | * 13 | * @author Vyacheslav Rusakov 14 | * @since 05.12.2017 15 | */ 16 | @CompileStatic 17 | class TemplateUtils { 18 | 19 | private static final String SLASH = '/' 20 | 21 | /** 22 | * Copies templates from classpath (inside the jar) with placeholders substitution. 23 | * 24 | * @param fs file operations 25 | * @param path path to folder on classpath to copy (path must start with '/') 26 | * @param to target location (string, File) 27 | * @param tokens substitution tokens 28 | */ 29 | @CompileStatic(TypeCheckingMode.SKIP) 30 | static void copy(FileOperations fs, String path, Object to, Map tokens) { 31 | URL folder = getUrl(path) 32 | FileTree tree 33 | boolean isJar = folder.toString().startsWith('jar:') 34 | if (isJar) { 35 | tree = fs.zipTree(getJarUrl(folder)) 36 | } else { 37 | tree = fs.fileTree(folder) 38 | } 39 | 40 | fs.copy { spec -> 41 | spec.from tree 42 | spec.into to 43 | if (isJar) { 44 | spec.include pathToWildcard(path) 45 | // cut off path 46 | spec.eachFile { FileCopyDetails f -> 47 | f.path = f.path.replaceFirst(pathToCutPrefix(path), '') 48 | } 49 | spec.includeEmptyDirs = false 50 | } 51 | spec.filter(ReplaceTokens, tokens: tokens) 52 | } 53 | } 54 | 55 | private static URL getUrl(String path) { 56 | if (!path.startsWith(SLASH)) { 57 | throw new IllegalArgumentException("Path must be absolute (start with '/'): $path") 58 | } 59 | URL folder = TemplateUtils.getResource(path) 60 | if (folder == null) { 61 | // workaround for tests 62 | folder = Thread.currentThread().contextClassLoader.getResource(path.replaceAll('^/', '')) 63 | } 64 | if (folder == null) { 65 | throw new IllegalArgumentException("No resources found on path: $path") 66 | } 67 | return folder 68 | } 69 | 70 | private static URL getJarUrl(URL fileUrl) { 71 | return ((JarURLConnection) fileUrl.openConnection()).jarFileURL 72 | } 73 | 74 | private static String pathToWildcard(String path) { 75 | return (path.endsWith(SLASH) ? path : path + SLASH) + '**' 76 | } 77 | 78 | private static String pathToCutPrefix(String path) { 79 | String res = path[1..-1] 80 | return res.endsWith(SLASH) ? res : res + SLASH 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/groovy/ru/vyarus/gradle/plugin/mkdocs/util/VersionsFileUtils.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs.util 2 | 3 | import groovy.json.JsonOutput 4 | import groovy.json.JsonSlurper 5 | import groovy.transform.CompileStatic 6 | 7 | /** 8 | * Versions file utilities. 9 | * 10 | * @author Vyacheslav Rusakov 11 | * @since 30.10.2022 12 | */ 13 | @CompileStatic 14 | class VersionsFileUtils { 15 | 16 | static final String VERSIONS_FILE = 'versions.json' 17 | static final String ALIASES = 'aliases' 18 | 19 | private static final Comparator VERSIONS_COMPARATOR = VersionsComparator.comparingVersions(false) 20 | 21 | /** 22 | * @param file versions file to parse 23 | * @return parsed versions or empty map 24 | */ 25 | static Map> parse(File file) { 26 | // self-sorted 27 | Map> res = 28 | new TreeMap>(VERSIONS_COMPARATOR.reversed()) 29 | 30 | if (file.exists()) { 31 | ((List>) new JsonSlurper().parse(file)) 32 | .each { ver -> res.put((String) ver['version'], ver) } 33 | } 34 | return res 35 | } 36 | 37 | /** 38 | * @param file versions structure 39 | * @param version version to add 40 | * @return true if version added, false if version already present 41 | */ 42 | @SuppressWarnings('SpaceAroundMapEntryColon') 43 | static boolean addVersion(Map> file, String version) { 44 | boolean added = false 45 | if (!file.containsKey(version)) { 46 | file.put(version, ['version': version, 47 | 'title' : version, 48 | (ALIASES): [],]) 49 | added = true 50 | } 51 | return added 52 | } 53 | 54 | /** 55 | * Updates version title and aliases (plus, removes used aliases from other versions). 56 | * 57 | * @param file versions structure 58 | * @param version taret version 59 | * @param title version title 60 | * @param aliases version aliases (may be null) 61 | */ 62 | static void updateVersion(Map> file, 63 | String version, String title, List aliases) { 64 | // remove current version aliases from all versions (avoid alias duplication) 65 | if (aliases) { 66 | file.values().each { 67 | List als = it[ALIASES] as List 68 | als.removeAll(aliases) 69 | } 70 | } 71 | // update custom title (to handle case when existing version re-generated) 72 | file.get(version).with { 73 | it.put('title', title) 74 | it.put(VersionsFileUtils.ALIASES, aliases as String[] ?: []) 75 | } 76 | } 77 | 78 | /** 79 | * @param buildDir mkdocs build dir 80 | * @return versions file in mkdocs build directory 81 | */ 82 | static File getTarget(File buildDir) { 83 | return new File(buildDir, VERSIONS_FILE) 84 | } 85 | 86 | /** 87 | * Writes versions structure into version file (overriding its content). 88 | * 89 | * @param file version structure 90 | * @param target target file 91 | */ 92 | static void write(Map> file, File target) { 93 | List> res = [] 94 | // map was sorted 95 | res.addAll(file.values()) 96 | 97 | String json = JsonOutput.toJson(res) 98 | // create parent dirs 99 | target.parentFile.mkdirs() 100 | target.newWriter().withWriter { w -> 101 | w << json 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/resources/ru/vyarus/gradle/plugin/mkdocs/template/init/docs/about/history.md: -------------------------------------------------------------------------------- 1 | ### 1.0.0 (2017.11.01) 2 | 3 | * Initial release -------------------------------------------------------------------------------- /src/main/resources/ru/vyarus/gradle/plugin/mkdocs/template/init/docs/guide/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | To install do... -------------------------------------------------------------------------------- /src/main/resources/ru/vyarus/gradle/plugin/mkdocs/template/init/docs/index.md: -------------------------------------------------------------------------------- 1 | # Welcome to MkDocs 2 | 3 | * [mkdocs documentation](http://mkdocs.org). 4 | * [mkdocs-material documentation](https://squidfunk.github.io/mkdocs-material/). 5 | 6 | ## Project layout 7 | 8 | mkdocs.yml # The configuration file. 9 | docs/ 10 | index.md # The documentation homepage. 11 | ... # Other markdown pages, images and other files. 12 | 13 | ## Gradle tasks 14 | 15 | * `mkdocsInit` - Create new mkdocs site (like this). 16 | * `mkdocsBuild` - Build the documentation site. 17 | * `mkdocsServe` - Start the live-reloading docs server. 18 | * `mkdocsPublish` - Publish generated site version to github pages. 19 | 20 | ## Mkdocs native Commands 21 | 22 | * `mkdocs new [dir-name]` - Create a new project. 23 | * `mkdocs serve` - Start the live-reloading docs server. 24 | * `mkdocs build` - Build the documentation site. 25 | * `mkdocs help` - Print this help message. -------------------------------------------------------------------------------- /src/main/resources/ru/vyarus/gradle/plugin/mkdocs/template/init/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: @projectName@ 2 | 3 | # Meta tags (placed in header) 4 | site_description: @projectDescription@ 5 | #site_author: Your Name 6 | site_url: # https://you.github.io/@projectName@ 7 | 8 | # Repository (add link to repository on each page) 9 | #repo_name: @projectName@ 10 | #repo_url: http://github.com/you/@projectName@ 11 | #edit_uri: edit/master/@docDir@/docs/ 12 | 13 | #Copyright (shown at the footer) 14 | #copyright: 'Copyright © 2017 Your Name' 15 | 16 | # Meterial theme 17 | theme: 18 | name: 'material' 19 | palette: 20 | - media: "(prefers-color-scheme: light)" 21 | scheme: default 22 | toggle: 23 | icon: material/toggle-switch-off-outline 24 | name: Switch to dark mode 25 | - media: "(prefers-color-scheme: dark)" 26 | scheme: slate 27 | toggle: 28 | icon: material/toggle-switch 29 | name: Switch to light mode 30 | features: 31 | #- navigation.tabs 32 | #- navigation.tabs.sticky 33 | #- navigation.instant 34 | - navigation.tracking 35 | - navigation.top 36 | 37 | #plugins: 38 | # - search 39 | # Required for variables support (https://github.com/rosscdh/mkdocs-markdownextradata-plugin) 40 | # - markdownextradata 41 | 42 | #extra: 43 | # palette: 44 | # primary: 'indigo' 45 | # accent: 'indigo' 46 | 47 | # version: 48 | # provider: mike 49 | 50 | # social: 51 | # - icon: fontawesome/brands/github 52 | # link: https://github.com/you 53 | # - icon: fontawesome/brands/twitter 54 | # link: https://twitter.com/you 55 | # 56 | # Google Analytics 57 | # analytics: 58 | # provider: google 59 | # property: UA-XXXXXXXX-X 60 | 61 | markdown_extensions: 62 | # Python Markdown 63 | - abbr 64 | - admonition 65 | - attr_list 66 | - def_list 67 | - footnotes 68 | - meta 69 | - md_in_html 70 | - toc: 71 | permalink: true 72 | 73 | # Python Markdown Extensions 74 | - pymdownx.arithmatex: 75 | generic: true 76 | - pymdownx.betterem: 77 | smart_enable: all 78 | - pymdownx.caret 79 | - pymdownx.details 80 | - pymdownx.emoji: 81 | emoji_index: !!python/name:material.extensions.emoji.twemoji 82 | emoji_generator: !!python/name:material.extensions.emoji.to_svg 83 | - pymdownx.highlight 84 | - pymdownx.inlinehilite 85 | - pymdownx.keys 86 | - pymdownx.mark 87 | - pymdownx.smartsymbols 88 | - pymdownx.superfences 89 | - pymdownx.tabbed: 90 | alternate_style: true 91 | - pymdownx.tasklist: 92 | custom_checkbox: true 93 | - pymdownx.tilde 94 | 95 | nav: 96 | - Home: index.md 97 | - User guide: 98 | - Installation: guide/installation.md 99 | - About: 100 | - Release notes: about/history.md -------------------------------------------------------------------------------- /src/main/resources/ru/vyarus/gradle/plugin/mkdocs/template/publish/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/AbstractKitTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs 2 | 3 | import org.apache.tools.ant.taskdefs.condition.Os 4 | import org.gradle.testkit.runner.BuildResult 5 | import org.gradle.testkit.runner.GradleRunner 6 | import spock.lang.Specification 7 | import spock.lang.TempDir 8 | 9 | /** 10 | * Base class for Gradle TestKit based tests. 11 | * Useful for full-cycle and files manipulation testing. 12 | * 13 | * @author Vyacheslav Rusakov 14 | * @since 29.10.2017 15 | */ 16 | abstract class AbstractKitTest extends Specification { 17 | 18 | boolean debug 19 | boolean isWin = Os.isFamily(Os.FAMILY_WINDOWS) 20 | 21 | @TempDir File testProjectDir 22 | File buildFile 23 | 24 | def setup() { 25 | buildFile = file('build.gradle') 26 | // jacoco coverage support 27 | fileFromClasspath('gradle.properties', 'testkit-gradle.properties') 28 | } 29 | 30 | def build(String file) { 31 | buildFile << file 32 | } 33 | 34 | File file(String path) { 35 | new File(testProjectDir, path) 36 | } 37 | 38 | File fileFromClasspath(String toFile, String source) { 39 | File target = file(toFile) 40 | target.parentFile.mkdirs() 41 | target.withOutputStream { 42 | it.write((getClass().getResourceAsStream(source) ?: getClass().classLoader.getResourceAsStream(source)).bytes) 43 | } 44 | target 45 | } 46 | 47 | /** 48 | * Enable it and run test with debugger (no manual attach required). Not always enabled to speed up tests during 49 | * normal execution. 50 | */ 51 | def debug() { 52 | debug = true 53 | } 54 | 55 | String projectName() { 56 | return testProjectDir.getName() 57 | } 58 | 59 | GradleRunner gradle(File root, String... commands) { 60 | GradleRunner.create() 61 | .withProjectDir(root) 62 | .withArguments((commands + ['--stacktrace']) as String[]) 63 | .withPluginClasspath() 64 | .withDebug(debug) 65 | .forwardOutput() 66 | } 67 | 68 | GradleRunner gradle(String... commands) { 69 | gradle(testProjectDir, commands) 70 | } 71 | 72 | BuildResult run(String... commands) { 73 | return gradle(commands).build() 74 | } 75 | 76 | BuildResult runFailed(String... commands) { 77 | return gradle(commands).buildAndFail() 78 | } 79 | 80 | BuildResult runVer(String gradleVersion, String... commands) { 81 | println 'Running with GRADLE ' + gradleVersion 82 | return gradle(commands).withGradleVersion(gradleVersion).build() 83 | } 84 | 85 | BuildResult runFailedVer(String gradleVersion, String... commands) { 86 | println 'Running with GRADLE ' + gradleVersion 87 | return gradle(commands).withGradleVersion(gradleVersion).buildAndFail() 88 | } 89 | 90 | protected String unifyString(String input) { 91 | return input 92 | // cleanup win line break for simpler comparisons 93 | .replace("\r", '') 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/AbstractTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs 2 | 3 | import org.apache.tools.ant.taskdefs.condition.Os 4 | import org.gradle.api.Project 5 | import org.gradle.testfixtures.ProjectBuilder 6 | import spock.lang.Specification 7 | import spock.lang.TempDir 8 | 9 | /** 10 | * Base class for plugin configuration tests. 11 | * 12 | * @author Vyacheslav Rusakov 13 | * @since 29.10.2017 14 | */ 15 | abstract class AbstractTest extends Specification{ 16 | 17 | boolean isWin = Os.isFamily(Os.FAMILY_WINDOWS) 18 | 19 | @TempDir File testProjectDir 20 | 21 | Project project(Closure config = null) { 22 | projectBuilder(config).build() 23 | } 24 | 25 | ExtendedProjectBuilder projectBuilder(Closure root = null) { 26 | new ExtendedProjectBuilder().root(testProjectDir, root) 27 | } 28 | 29 | File file(String path) { 30 | new File(testProjectDir, path) 31 | } 32 | 33 | File fileFromClasspath(String toFile, String source) { 34 | File target = file(toFile) 35 | target.parentFile.mkdirs() 36 | target << getClass().getResourceAsStream(source).text 37 | } 38 | 39 | static class ExtendedProjectBuilder { 40 | Project root 41 | 42 | ExtendedProjectBuilder root(File dir, Closure config = null) { 43 | assert root == null, "Root project already declared" 44 | Project project = ProjectBuilder.builder() 45 | .withProjectDir(dir).build() 46 | if (config) { 47 | project.configure(project, config) 48 | } 49 | root = project 50 | return this 51 | } 52 | 53 | /** 54 | * Direct child of parent project 55 | * 56 | * @param name child project name 57 | * @param config optional configuration closure 58 | * @return builder 59 | */ 60 | ExtendedProjectBuilder child(String name, Closure config = null) { 61 | return childOf(null, name, config) 62 | } 63 | 64 | /** 65 | * Direct child of any registered child project 66 | * 67 | * @param projectRef name of required parent module (gradle project reference format: `:some:deep:module`) 68 | * @param name child project name 69 | * @param config optional configuration closure 70 | * @return builder 71 | */ 72 | ExtendedProjectBuilder childOf(String projectRef, String name, Closure config = null) { 73 | assert root != null, "Root project not declared" 74 | Project parent = projectRef == null ? root : root.project(projectRef) 75 | File folder = parent.file(name) 76 | if (!folder.exists()) { 77 | folder.mkdir() 78 | } 79 | Project project = ProjectBuilder.builder() 80 | .withName(name) 81 | .withProjectDir(folder) 82 | .withParent(parent) 83 | .build() 84 | if (config) { 85 | project.configure(project, config) 86 | } 87 | return this 88 | } 89 | 90 | /** 91 | * Evaluate configuration. 92 | * 93 | * @return root project 94 | */ 95 | Project build() { 96 | if (root.subprojects) { 97 | linkSubprojectsEvaluation(root) 98 | } 99 | root.evaluate() 100 | return root 101 | } 102 | 103 | private void linkSubprojectsEvaluation(Project project) { 104 | project.evaluationDependsOnChildren() 105 | project.subprojects.each { linkSubprojectsEvaluation(it) } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/ConfigurationCacheSupportPushKitTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs 2 | 3 | import groovy.json.JsonSlurper 4 | import org.ajoberstar.grgit.Grgit 5 | import org.gradle.testkit.runner.BuildResult 6 | import org.gradle.testkit.runner.TaskOutcome 7 | import spock.lang.TempDir 8 | 9 | /** 10 | * @author Vyacheslav Rusakov 11 | * @since 10.04.2024 12 | */ 13 | class ConfigurationCacheSupportPushKitTest extends AbstractKitTest { 14 | 15 | @TempDir File repoDir 16 | 17 | Grgit repo 18 | 19 | @Override 20 | def setup() { 21 | // local repo used for push 22 | println 'init fake gh-pages repo' 23 | repo = Grgit.init(dir: repoDir, bare: true) 24 | assert repo.branch.list().size() == 0 25 | // connect with project folder 26 | println 'associate project with fake repo' 27 | Grgit prjRepo = Grgit.init(dir: testProjectDir) 28 | prjRepo.remote.add(name: 'origin', url: repoDir.canonicalPath, pushUrl: repoDir.canonicalPath) 29 | // init remote repo 30 | file('readme.txt') << 'sample' 31 | prjRepo.add(patterns: ['*']) 32 | prjRepo.commit(message: 'initial commit') 33 | prjRepo.push() 34 | prjRepo.close() 35 | 36 | assert repo.log().size() == 1 37 | assert repo.branch.list().size() == 1 38 | } 39 | 40 | void cleanup() { 41 | repo.close() 42 | } 43 | 44 | def "Check default publish"() { 45 | 46 | setup: 47 | build """ 48 | plugins { 49 | id 'ru.vyarus.mkdocs' 50 | } 51 | 52 | version = '1.0' 53 | 54 | python.scope = USER 55 | """ 56 | 57 | when: "run init" 58 | BuildResult result = run('--configuration-cache', '--configuration-cache-problems=warn', 'mkdocsInit') 59 | 60 | then: "no configuration cache incompatibilities" 61 | result.output.contains("1 problem was found storing the configuration cache") 62 | result.output.contains('Gradle runtime: support for using a Java agent with TestKit') 63 | result.output.contains('Calculating task graph as no cached configuration is available for tasks:') 64 | 65 | then: "docs created" 66 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 67 | file('src/doc/mkdocs.yml').exists() 68 | 69 | when: "publish" 70 | result = run('--configuration-cache', '--configuration-cache-problems=warn', 'mkdocsPublish') 71 | 72 | then: "no configuration cache incompatibilities" 73 | result.output.contains("1 problem was found storing the configuration cache") 74 | result.output.contains('Gradle runtime: support for using a Java agent with TestKit') 75 | result.output.contains('Calculating task graph as no cached configuration is available for tasks:') 76 | 77 | then: "published" 78 | result.task(':mkdocsPublish').outcome == TaskOutcome.SUCCESS 79 | repo.branch.list().size() == 2 80 | 81 | then: "content available" 82 | file('/.gradle/gh-pages/1.0/index.html').exists() 83 | file('/.gradle/gh-pages/index.html').exists() 84 | 85 | then: "versions file correct" 86 | result.output.contains("Versions file generated with 1 versions:") 87 | file('/.gradle/gh-pages/versions.json').exists() 88 | with(new JsonSlurper().parse(file('/.gradle/gh-pages/versions.json')) as List) { 89 | it.size() == 1 90 | it[0]['title'] == '1.0' 91 | } 92 | 93 | 94 | when: "publish another version" 95 | buildFile.delete() 96 | build """ 97 | plugins { 98 | id 'ru.vyarus.mkdocs' 99 | } 100 | 101 | version = '1.1' 102 | 103 | python.scope = USER 104 | """ 105 | result = run('--configuration-cache', '--configuration-cache-problems=warn', 'mkdocsPublish') 106 | 107 | then: "cache used" 108 | result.output.contains('Calculating task graph as configuration cache cannot be reused because file \'build.gradle\' has changed.') 109 | 110 | then: "version published" 111 | result.task(':mkdocsPublish').outcome == TaskOutcome.SUCCESS 112 | file('/.gradle/gh-pages/1.1/index.html').exists() 113 | file('/.gradle/gh-pages/1.0/index.html').exists() 114 | file('/.gradle/gh-pages/index.html').exists() 115 | file('/.gradle/gh-pages/index.html').text.contains('URL=\'1.1\'') 116 | 117 | then: "versions file correct" 118 | result.output.contains("Versions file generated with 2 versions:") 119 | file('/.gradle/gh-pages/versions.json').exists() 120 | with(new JsonSlurper().parse(file('/.gradle/gh-pages/versions.json')) as List) { 121 | it.size() == 2 122 | it[0]['title'] == '1.1' 123 | it[1]['title'] == '1.0' 124 | } 125 | 126 | 127 | 128 | when: "run from cache" 129 | println '\n\n------------------- FROM CACHE ----------------------------------------' 130 | result = run('--configuration-cache', '--configuration-cache-problems=warn', 'mkdocsPublish') 131 | 132 | then: "cache used" 133 | result.output.contains('Reusing configuration cache.') 134 | result.task(':mkdocsPublish').outcome == TaskOutcome.SUCCESS 135 | file('/.gradle/gh-pages/1.1/index.html').exists() 136 | file('/.gradle/gh-pages/1.0/index.html').exists() 137 | file('/.gradle/gh-pages/index.html').exists() 138 | file('/.gradle/gh-pages/index.html').text.contains('URL=\'1.1\'') 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/CustomThemeKitTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs 2 | 3 | import org.gradle.testkit.runner.BuildResult 4 | import org.gradle.testkit.runner.TaskOutcome 5 | 6 | /** 7 | * @author Vyacheslav Rusakov 8 | * @since 17.03.2021 9 | */ 10 | class CustomThemeKitTest extends AbstractKitTest { 11 | 12 | def "Check theme change"() { 13 | setup: 14 | build """ 15 | plugins { 16 | id 'ru.vyarus.mkdocs' 17 | } 18 | 19 | version = '1.0' 20 | 21 | python.pip 'mkdocs-ivory:0.4.6' 22 | 23 | mkdocs { 24 | sourcesDir 'doc' 25 | } 26 | """ 27 | 28 | file('doc').mkdir() 29 | file('doc/mkdocs.yml') << """ 30 | site_name: test 31 | 32 | theme: 33 | name: 'ivory' 34 | 35 | nav: 36 | - Home: index.md 37 | """ 38 | file('doc/docs').mkdir() 39 | file('doc/docs/index.md') << """ 40 | # Index page 41 | """ 42 | 43 | when: "run build" 44 | BuildResult result = run('mkdocsBuild') 45 | 46 | then: "build success" 47 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 48 | file('build/mkdocs/1.0/index.html').exists() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/DocsInModuleAndRootKitTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs 2 | 3 | import org.ajoberstar.grgit.Grgit 4 | import org.gradle.testkit.runner.BuildResult 5 | import org.gradle.testkit.runner.TaskOutcome 6 | import spock.lang.TempDir 7 | 8 | /** 9 | * @author Vyacheslav Rusakov 10 | * @since 04.08.2022 11 | */ 12 | class DocsInModuleAndRootKitTest extends AbstractKitTest { 13 | 14 | @TempDir File repoDir 15 | 16 | Grgit repo 17 | 18 | @Override 19 | def setup() { 20 | // local repo used for push 21 | println 'init fake gh-pages repo' 22 | repo = Grgit.init(dir: repoDir, bare: true) 23 | assert repo.branch.list().size() == 0 24 | // connect with project folder 25 | println 'associate project with fake repo' 26 | Grgit prjRepo = Grgit.init(dir: testProjectDir) 27 | prjRepo.remote.add(name: 'origin', url: repoDir.canonicalPath, pushUrl: repoDir.canonicalPath) 28 | // init remote repo 29 | file('readme.txt') << 'sample' 30 | prjRepo.add(patterns: ['*']) 31 | prjRepo.commit(message: 'initial commit') 32 | prjRepo.push() 33 | prjRepo.close() 34 | 35 | assert repo.log().size() == 1 36 | assert repo.branch.list().size() == 1 37 | } 38 | 39 | void cleanup() { 40 | repo.close() 41 | } 42 | 43 | def "Check docs in root and submodule"() { 44 | 45 | // both published into the same git, but with different naming scheme 46 | 47 | setup: 48 | file('settings.gradle') << ' include "doc"' 49 | file('doc').mkdir() 50 | build """ 51 | plugins { 52 | id 'ru.vyarus.mkdocs' 53 | } 54 | 55 | version = '1.0-SNAPSHOT' 56 | 57 | mkdocs { 58 | sourcesDir = 'docs' 59 | } 60 | 61 | project(':doc') { 62 | apply plugin: 'ru.vyarus.mkdocs' 63 | 64 | mkdocs { 65 | sourcesDir = 'src' 66 | 67 | publish { 68 | docPath = 'sub-\$version' 69 | rootRedirect = false 70 | } 71 | } 72 | } 73 | 74 | """ 75 | 76 | // root docs 77 | file('docs').mkdir() 78 | file('docs/mkdocs.yml') << """ 79 | site_name: root 80 | 81 | nav: 82 | - Home: index.md 83 | """ 84 | file('docs/docs').mkdir() 85 | file('docs/docs/index.md') << """ 86 | root index page 87 | """ 88 | 89 | // module docs 90 | file('doc').mkdir() 91 | file('doc/src').mkdir() 92 | file('doc/src/mkdocs.yml') << """ 93 | site_name: sub 94 | 95 | nav: 96 | - Home: index.md 97 | """ 98 | 99 | file('doc/src/docs').mkdir() 100 | file('doc/src/docs/index.md') << """ 101 | submodule index page 102 | """ 103 | 104 | when: "build site" 105 | BuildResult result = run('mkdocsPublish') 106 | 107 | then: "built" 108 | result.task(':mkdocsPublish').outcome == TaskOutcome.SUCCESS 109 | result.task(':doc:mkdocsPublish').outcome == TaskOutcome.SUCCESS 110 | file('build/mkdocs/1.0-SNAPSHOT/index.html').text.contains('root index page') 111 | file('doc/build/mkdocs/sub-1.0-SNAPSHOT/index.html').text.contains('submodule index page') 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/DocsInModuleKitTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs 2 | 3 | import org.gradle.testkit.runner.BuildResult 4 | import org.gradle.testkit.runner.TaskOutcome 5 | 6 | /** 7 | * @author Vyacheslav Rusakov 8 | * @since 14.10.2018 9 | */ 10 | class DocsInModuleKitTest extends AbstractKitTest { 11 | 12 | def "Check docs submodule workflow"() { 13 | setup: 14 | file('settings.gradle') << ' include "doc"' 15 | file('doc').mkdir() 16 | build """ 17 | plugins { 18 | id 'ru.vyarus.mkdocs' apply false 19 | } 20 | 21 | version = '1.0-SNAPSHOT' 22 | 23 | project(':doc') { 24 | apply plugin: 'ru.vyarus.mkdocs' 25 | 26 | mkdocs { 27 | sourcesDir = 'src' 28 | } 29 | } 30 | 31 | """ 32 | 33 | when: "run init" 34 | BuildResult result = run(':doc:mkdocsInit') 35 | 36 | then: "docs created" 37 | result.task(':doc:mkdocsInit').outcome == TaskOutcome.SUCCESS 38 | file('doc/src/mkdocs.yml').exists() 39 | 40 | when: "build site" 41 | result = run(':doc:mkdocsBuild') 42 | 43 | then: "built" 44 | result.task(':doc:mkdocsBuild').outcome == TaskOutcome.SUCCESS 45 | file('doc/build/mkdocs/1.0-SNAPSHOT/index.html').exists() 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/LegacyKitTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs 2 | 3 | import org.gradle.testkit.runner.BuildResult 4 | import org.gradle.testkit.runner.TaskOutcome 5 | import spock.lang.IgnoreIf 6 | 7 | /** 8 | * @author Vyacheslav Rusakov 9 | * @since 13.03.2020 10 | */ 11 | @IgnoreIf({jvm.java17Compatible}) // only gradle 7.3 supports java 17 12 | class LegacyKitTest extends AbstractKitTest { 13 | 14 | String GRADLE_VERSION = '7.0' 15 | 16 | def "Check workflow"() { 17 | setup: 18 | build """ 19 | plugins { 20 | id 'ru.vyarus.mkdocs' 21 | } 22 | 23 | version = '1.0-SNAPSHOT' 24 | python.scope = USER 25 | """ 26 | 27 | when: "run init" 28 | BuildResult result = runVer(GRADLE_VERSION, 'mkdocsInit') 29 | 30 | then: "docs created" 31 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 32 | file('src/doc/mkdocs.yml').exists() 33 | 34 | when: "build site" 35 | result = runVer(GRADLE_VERSION, 'mkdocsBuild') 36 | 37 | then: "built" 38 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 39 | file('build/mkdocs/1.0-SNAPSHOT/index.html').exists() 40 | 41 | } 42 | 43 | def "Check custom task"() { 44 | 45 | setup: 46 | build """ 47 | plugins { 48 | id 'ru.vyarus.mkdocs' 49 | } 50 | 51 | python.scope = USER 52 | 53 | task mkHelp(type: MkdocsTask) { 54 | command = '--help' 55 | } 56 | """ 57 | 58 | when: "run help" 59 | BuildResult result = runVer(GRADLE_VERSION, 'mkHelp') 60 | 61 | then: "executed" 62 | result.task(':mkHelp').outcome == TaskOutcome.SUCCESS 63 | result.output.contains('-V, --version Show the version and exit.') 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/MkdocsBuildKitTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs 2 | 3 | import org.gradle.testkit.runner.BuildResult 4 | import org.gradle.testkit.runner.TaskOutcome 5 | 6 | /** 7 | * @author Vyacheslav Rusakov 8 | * @since 28.10.2022 9 | */ 10 | class MkdocsBuildKitTest extends AbstractKitTest { 11 | 12 | def "Check workflow"() { 13 | setup: 14 | build """ 15 | plugins { 16 | id 'ru.vyarus.mkdocs-build' 17 | } 18 | 19 | version = '1.0-SNAPSHOT' 20 | python.scope = USER 21 | """ 22 | 23 | when: "run init" 24 | BuildResult result = run('mkdocsInit') 25 | 26 | then: "docs created" 27 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 28 | file('src/doc/mkdocs.yml').exists() 29 | 30 | when: "build site" 31 | result = run('mkdocsBuild') 32 | 33 | then: "built" 34 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 35 | file('build/mkdocs/1.0-SNAPSHOT/index.html').exists() 36 | 37 | } 38 | 39 | def "Check custom task"() { 40 | 41 | setup: 42 | build """ 43 | plugins { 44 | id 'ru.vyarus.mkdocs-build' 45 | } 46 | 47 | python.scope = USER 48 | 49 | task mkHelp(type: MkdocsTask) { 50 | command = '--help' 51 | } 52 | """ 53 | 54 | when: "run help" 55 | BuildResult result = run('mkHelp') 56 | 57 | then: "executed" 58 | result.task(':mkHelp').outcome == TaskOutcome.SUCCESS 59 | result.output.contains('-V, --version Show the version and exit.') 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/MkdocsBuildPluginTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs 2 | 3 | import org.gradle.api.Project 4 | import org.gradle.testfixtures.ProjectBuilder 5 | import ru.vyarus.gradle.plugin.python.PythonExtension 6 | 7 | /** 8 | * @author Vyacheslav Rusakov 9 | * @since 28.10.2022 10 | */ 11 | class MkdocsBuildPluginTest extends AbstractTest { 12 | 13 | def "Check extension registration"() { 14 | 15 | when: "plugin applied" 16 | Project project = ProjectBuilder.builder().build() 17 | project.plugins.apply "ru.vyarus.mkdocs-build" 18 | 19 | then: "extension registered" 20 | project.extensions.findByType(MkdocsExtension) 21 | 22 | then: "default modules registered" 23 | project.extensions.findByType(PythonExtension).modules == MkdocsExtension.DEFAULT_MODULES as List 24 | 25 | then: "mkdocs tasks registered" 26 | def task = { project.tasks.findByName(it) } 27 | task('mkdocsBuild') 28 | task('mkdocsServe') 29 | task('mkdocsInit') 30 | !task('mkdocsPublish') 31 | 32 | then: "publish extension not applied" 33 | !project.extensions.findByType(GitPublishExtension) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/MkdocsPluginKitTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs 2 | 3 | import org.gradle.testkit.runner.BuildResult 4 | import org.gradle.testkit.runner.TaskOutcome 5 | 6 | /** 7 | * @author Vyacheslav Rusakov 8 | * @since 29.10.2017 9 | */ 10 | class MkdocsPluginKitTest extends AbstractKitTest { 11 | 12 | def "Check workflow"() { 13 | setup: 14 | build """ 15 | plugins { 16 | id 'ru.vyarus.mkdocs' 17 | } 18 | 19 | version = '1.0-SNAPSHOT' 20 | python.scope = USER 21 | """ 22 | 23 | when: "run init" 24 | BuildResult result = run('mkdocsInit') 25 | 26 | then: "docs created" 27 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 28 | file('src/doc/mkdocs.yml').exists() 29 | 30 | when: "build site" 31 | result = run('mkdocsBuild') 32 | 33 | then: "built" 34 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 35 | file('build/mkdocs/1.0-SNAPSHOT/index.html').exists() 36 | 37 | } 38 | 39 | def "Check custom task"() { 40 | 41 | setup: 42 | build """ 43 | plugins { 44 | id 'ru.vyarus.mkdocs' 45 | } 46 | 47 | python.scope = USER 48 | 49 | task mkHelp(type: MkdocsTask) { 50 | command = '--help' 51 | } 52 | """ 53 | 54 | when: "run help" 55 | BuildResult result = run('mkHelp') 56 | 57 | then: "executed" 58 | result.task(':mkHelp').outcome == TaskOutcome.SUCCESS 59 | result.output.contains('-V, --version Show the version and exit.') 60 | } 61 | } -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/MkdocsPluginTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs 2 | 3 | import org.gradle.api.Project 4 | import org.gradle.api.tasks.TaskProvider 5 | import org.gradle.testfixtures.ProjectBuilder 6 | import ru.vyarus.gradle.plugin.mkdocs.task.publish.GitPublishPush 7 | import ru.vyarus.gradle.plugin.python.PythonExtension 8 | 9 | /** 10 | * @author Vyacheslav Rusakov 11 | * @since 29.10.2017 12 | */ 13 | class MkdocsPluginTest extends AbstractTest { 14 | 15 | def "Check extension registration"() { 16 | 17 | when: "plugin applied" 18 | Project project = ProjectBuilder.builder().build() 19 | project.plugins.apply "ru.vyarus.mkdocs" 20 | 21 | then: "extension registered" 22 | project.extensions.findByType(MkdocsExtension) 23 | 24 | then: "default modules registered" 25 | project.extensions.findByType(PythonExtension).modules == MkdocsExtension.DEFAULT_MODULES as List 26 | 27 | then: "mkdocs tasks registered" 28 | def task = { project.tasks.findByName(it) } 29 | task('mkdocsBuild') 30 | task('mkdocsServe') 31 | task('mkdocsInit') 32 | task('mkdocsPublish') 33 | 34 | then: "publish plugin applied" 35 | project.extensions.findByType(GitPublishExtension) 36 | 37 | then: "task graph valid" 38 | (task('mkdocsPublish').dependsOn[0] as TaskProvider).get() instanceof GitPublishPush 39 | task('gitPublishReset').dependsOn.contains('mkdocsBuild') 40 | } 41 | 42 | def "Check default resolution"() { 43 | 44 | when: "plugin applied" 45 | Project project = ProjectBuilder.builder().build() 46 | project.version = '1.0' 47 | project.plugins.apply "ru.vyarus.mkdocs" 48 | MkdocsExtension ext = project.extensions.findByType(MkdocsExtension) 49 | 50 | then: 'resolution correct' 51 | ext.resolveDocPath() == '1.0' 52 | ext.resolveComment() == 'Publish 1.0 documentation' 53 | 54 | } 55 | 56 | def "Check extra slashes resolution"() { 57 | 58 | when: "plugin applied" 59 | Project project = ProjectBuilder.builder().build() 60 | project.version = '1.0' 61 | project.plugins.apply "ru.vyarus.mkdocs" 62 | MkdocsExtension ext = project.extensions.findByType(MkdocsExtension) 63 | ext.publish.docPath = '/1.0/' 64 | 65 | then: 'resolution correct' 66 | ext.resolveDocPath() == '1.0' 67 | ext.resolveComment() == 'Publish 1.0 documentation' 68 | 69 | } 70 | 71 | def "Check complex path resolution"() { 72 | 73 | when: "plugin applied" 74 | Project project = ProjectBuilder.builder().build() 75 | project.version = '1.0' 76 | project.plugins.apply "ru.vyarus.mkdocs" 77 | MkdocsExtension ext = project.extensions.findByType(MkdocsExtension) 78 | ext.publish.docPath = '/en/$version/' 79 | 80 | then: 'resolution correct' 81 | ext.resolveDocPath() == 'en/1.0' 82 | ext.resolveComment() == 'Publish en/1.0 documentation' 83 | 84 | } 85 | 86 | def "Check no multi-version"() { 87 | 88 | when: "plugin applied" 89 | Project project = ProjectBuilder.builder().build() 90 | project.version = '1.0' 91 | project.plugins.apply "ru.vyarus.mkdocs" 92 | MkdocsExtension ext = project.extensions.findByType(MkdocsExtension) 93 | ext.publish.docPath = null 94 | 95 | then: 'resolution correct' 96 | ext.resolveDocPath() == MkdocsExtension.SINGLE_VERSION_PATH 97 | ext.resolveComment() == 'Publish documentation' 98 | 99 | } 100 | 101 | def "Check no multi-version 2"() { 102 | 103 | when: "plugin applied" 104 | Project project = ProjectBuilder.builder().build() 105 | project.version = '1.0' 106 | project.plugins.apply "ru.vyarus.mkdocs" 107 | MkdocsExtension ext = project.extensions.findByType(MkdocsExtension) 108 | ext.publish.docPath = '' 109 | 110 | then: 'resolution correct' 111 | ext.resolveDocPath() == MkdocsExtension.SINGLE_VERSION_PATH 112 | ext.resolveComment() == 'Publish documentation' 113 | 114 | } 115 | 116 | def "Check extra variables"() { 117 | 118 | when: "plugin applied" 119 | Project project = project { 120 | apply plugin: 'ru.vyarus.mkdocs' 121 | 122 | version = 1.0 123 | mkdocs { 124 | extras = [ 125 | 'foo': project.version, 126 | 'bar': "${-> project.version }", 127 | ] 128 | } 129 | 130 | version = 1.1 131 | } 132 | MkdocsExtension ext = project.extensions.findByType(MkdocsExtension) 133 | 134 | then: 'resolution correct' 135 | ext.extras.foo == 1.0 136 | ext.extras.bar == 1.1 137 | 138 | } 139 | 140 | def "Check version validation"() { 141 | 142 | when: "plugin applied" 143 | Project project = ProjectBuilder.builder().build() 144 | project.plugins.apply "ru.vyarus.mkdocs" 145 | MkdocsExtension ext = project.extensions.findByType(MkdocsExtension) 146 | 147 | then: 'failed' 148 | ext.resolveDocPath() == 'unspecified' 149 | 150 | } 151 | } -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/UpstreamKitTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs 2 | 3 | import org.gradle.testkit.runner.BuildResult 4 | import org.gradle.testkit.runner.TaskOutcome 5 | 6 | /** 7 | * @author Vyacheslav Rusakov 8 | * @since 13.03.2020 9 | */ 10 | class UpstreamKitTest extends AbstractKitTest { 11 | 12 | String GRADLE_VERSION = '8.7' 13 | 14 | def "Check workflow"() { 15 | setup: 16 | build """ 17 | plugins { 18 | id 'ru.vyarus.mkdocs' 19 | } 20 | 21 | version = '1.0-SNAPSHOT' 22 | python.scope = USER 23 | """ 24 | 25 | when: "run init" 26 | BuildResult result = runVer(GRADLE_VERSION, 'mkdocsInit', '--warning-mode', 'all') 27 | 28 | then: "docs created" 29 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 30 | file('src/doc/mkdocs.yml').exists() 31 | 32 | when: "build site" 33 | result = runVer(GRADLE_VERSION, 'mkdocsBuild', '--warning-mode', 'all') 34 | 35 | then: "built" 36 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 37 | file('build/mkdocs/1.0-SNAPSHOT/index.html').exists() 38 | 39 | } 40 | 41 | def "Check custom task"() { 42 | 43 | setup: 44 | build """ 45 | plugins { 46 | id 'ru.vyarus.mkdocs' 47 | } 48 | 49 | python.scope = USER 50 | 51 | task mkHelp(type: MkdocsTask) { 52 | command = '--help' 53 | } 54 | """ 55 | 56 | when: "run help" 57 | BuildResult result = runVer(GRADLE_VERSION, 'mkHelp', '--warning-mode', 'all') 58 | 59 | then: "executed" 60 | result.task(':mkHelp').outcome == TaskOutcome.SUCCESS 61 | result.output.contains('-V, --version Show the version and exit.') 62 | } 63 | 64 | def "Check extra props"() { 65 | 66 | setup: 67 | build """ 68 | plugins { 69 | id 'ru.vyarus.mkdocs' 70 | } 71 | 72 | python.scope = USER 73 | 74 | mkdocs { 75 | sourcesDir = 'doc' 76 | extras = [ 77 | 'version': "\${-> project.version}", 78 | ] 79 | } 80 | 81 | task mkHelp(type: MkdocsTask) { 82 | command = '--help' 83 | } 84 | """ 85 | 86 | file('doc').mkdir() 87 | file('doc/mkdocs.yml') << """ 88 | site_name: test 89 | 90 | plugins: 91 | - search 92 | - markdownextradata 93 | 94 | nav: 95 | - Home: index.md 96 | """ 97 | 98 | when: "run help" 99 | BuildResult result = runVer(GRADLE_VERSION, 'mkHelp', '--warning-mode', 'all') 100 | 101 | then: "executed" 102 | result.task(':mkHelp').outcome == TaskOutcome.SUCCESS 103 | result.output.contains('-V, --version Show the version and exit.') 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/UpstreamPublishKitTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs 2 | 3 | import org.ajoberstar.grgit.Grgit 4 | import org.gradle.testkit.runner.BuildResult 5 | import org.gradle.testkit.runner.TaskOutcome 6 | import spock.lang.TempDir 7 | 8 | /** 9 | * @author Vyacheslav Rusakov 10 | * @since 02.03.2021 11 | */ 12 | class UpstreamPublishKitTest extends AbstractKitTest { 13 | 14 | String GRADLE_VERSION = '8.7' 15 | 16 | @TempDir File repoDir 17 | 18 | Grgit repo 19 | 20 | @Override 21 | def setup() { 22 | // local repo used for push 23 | println 'init fake gh-pages repo' 24 | repo = Grgit.init(dir: repoDir, bare: true) 25 | assert repo.branch.list().size() == 0 26 | // connect with project folder 27 | println 'associate project with fake repo' 28 | Grgit prjRepo = Grgit.init(dir: testProjectDir) 29 | prjRepo.remote.add(name: 'origin', url: repoDir.canonicalPath, pushUrl: repoDir.canonicalPath) 30 | // init remote repo 31 | file('readme.txt') << 'sample' 32 | prjRepo.add(patterns: ['*']) 33 | prjRepo.commit(message: 'initial commit') 34 | prjRepo.push() 35 | prjRepo.close() 36 | 37 | assert repo.log().size() == 1 38 | assert repo.branch.list().size() == 1 39 | } 40 | 41 | void cleanup() { 42 | repo.close() 43 | } 44 | 45 | def "Check default publish"() { 46 | 47 | setup: 48 | build """ 49 | plugins { 50 | id 'ru.vyarus.mkdocs' 51 | } 52 | 53 | version = '1.0' 54 | 55 | python.scope = USER 56 | """ 57 | 58 | when: "run init" 59 | BuildResult result = runVer(GRADLE_VERSION, 'mkdocsInit', '--warning-mode', 'all') 60 | 61 | then: "docs created" 62 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 63 | file('src/doc/mkdocs.yml').exists() 64 | 65 | when: "publish" 66 | // debug() 67 | // println 'wait for debugger' 68 | result = runVer(GRADLE_VERSION, 'mkdocsPublish', '--warning-mode', 'all') 69 | 70 | then: "published" 71 | result.task(':mkdocsPublish').outcome == TaskOutcome.SUCCESS 72 | repo.branch.list().size() == 2 73 | 74 | then: "content available" 75 | file('/.gradle/gh-pages/1.0/index.html').exists() 76 | file('/.gradle/gh-pages/index.html').exists() 77 | 78 | 79 | when: "publish another version" 80 | buildFile.delete() 81 | build """ 82 | plugins { 83 | id 'ru.vyarus.mkdocs' 84 | } 85 | 86 | version = '1.1' 87 | 88 | python.scope = USER 89 | """ 90 | result = runVer(GRADLE_VERSION, 'mkdocsPublish', '--warning-mode', 'all') 91 | 92 | then: "version published" 93 | result.task(':mkdocsPublish').outcome == TaskOutcome.SUCCESS 94 | file('/.gradle/gh-pages/1.1/index.html').exists() 95 | file('/.gradle/gh-pages/1.0/index.html').exists() 96 | file('/.gradle/gh-pages/index.html').exists() 97 | file('/.gradle/gh-pages/index.html').text.contains('URL=\'1.1\'') 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/VersionsUpdateKitTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs 2 | 3 | import org.gradle.testkit.runner.BuildResult 4 | import org.gradle.testkit.runner.TaskOutcome 5 | 6 | /** 7 | * @author Vyacheslav Rusakov 8 | * @since 31.10.2022 9 | */ 10 | class VersionsUpdateKitTest extends AbstractKitTest { 11 | 12 | def "Check versions file creation with build"() { 13 | setup: 14 | build """ 15 | plugins { 16 | id 'ru.vyarus.mkdocs' 17 | } 18 | 19 | version = '1.0' 20 | 21 | mkdocs.publish.existingVersionsFile = 'prev-versions.json' 22 | 23 | python.scope = USER 24 | """ 25 | 26 | when: "run init" 27 | BuildResult result = run('mkdocsInit') 28 | 29 | then: "docs created" 30 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 31 | 32 | when: "build site" 33 | result = run('mkdocsBuild') 34 | File vers = file('build/mkdocs/versions.json') 35 | println vers.text 36 | 37 | then: "built" 38 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 39 | vers.exists() 40 | result.output.contains('WARNING: configured versions file \'prev-versions.json\' does not exist - creating new file instead') 41 | result.output.contains('New version added: 1.0') 42 | result.output.contains('Versions written to file: 1.0') 43 | 44 | } 45 | 46 | def "Check not existing versions file url"() { 47 | setup: 48 | build """ 49 | plugins { 50 | id 'ru.vyarus.mkdocs' 51 | } 52 | 53 | version = '1.0' 54 | 55 | mkdocs.publish.existingVersionsFile = 'https://xvik.github.io/gradle-use-python-plugin/versionssss.json' 56 | 57 | python.scope = USER 58 | """ 59 | 60 | when: "run init" 61 | BuildResult result = run('mkdocsInit') 62 | 63 | then: "docs created" 64 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 65 | 66 | when: "build site" 67 | result = run('mkdocsBuild') 68 | File vers = file('build/mkdocs/versions.json') 69 | println vers.text 70 | 71 | then: "built" 72 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 73 | vers.exists() 74 | result.output.contains('WARNING: configured versions file \'https://xvik.github.io/gradle-use-python-plugin/versionssss.json\' does not exist - creating new file instead') 75 | result.output.contains('New version added: 1.0') 76 | result.output.contains('Versions written to file: 1.0') 77 | } 78 | 79 | def "Check versions file update"() { 80 | setup: 81 | build """ 82 | plugins { 83 | id 'ru.vyarus.mkdocs' 84 | } 85 | 86 | version = '3.0' 87 | 88 | mkdocs.publish.existingVersionsFile = 'prev-versions.json' 89 | 90 | python.scope = USER 91 | """ 92 | file('prev-versions.json') << '[{"version":"2.0.0","title":"2.0.0","aliases":["latest"]},{"version":"1.0.0","title":"1.0.0","aliases":[]}]' 93 | 94 | when: "run init" 95 | BuildResult result = run('mkdocsInit') 96 | 97 | then: "docs created" 98 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 99 | 100 | when: "build site" 101 | result = run('mkdocsBuild') 102 | File vers = file('build/mkdocs/versions.json') 103 | println vers.text 104 | 105 | then: "built" 106 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 107 | vers.exists() 108 | result.output.contains('Existing versions file \'prev-versions.json\' loaded with 2 versions') 109 | result.output.contains('New version added: 3.0') 110 | result.output.contains('Versions written to file: 3.0, 2.0.0, 1.0.0') 111 | 112 | } 113 | 114 | def "Check aliases update"() { 115 | setup: 116 | build """ 117 | plugins { 118 | id 'ru.vyarus.mkdocs' 119 | } 120 | 121 | version = '3.0' 122 | 123 | mkdocs.publish { 124 | versionAliases = ['latest'] 125 | existingVersionsFile = 'prev-versions.json' 126 | } 127 | 128 | python.scope = USER 129 | """ 130 | file('prev-versions.json') << '[{"version":"2.0.0","title":"2.0.0","aliases":["latest"]},{"version":"1.0.0","title":"1.0.0","aliases":[]}]' 131 | 132 | when: "run init" 133 | BuildResult result = run('mkdocsInit') 134 | 135 | then: "docs created" 136 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 137 | 138 | when: "build site" 139 | result = run('mkdocsBuild') 140 | File vers = file('build/mkdocs/versions.json') 141 | println vers.text 142 | 143 | then: "built" 144 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 145 | vers.text == '[{"version":"3.0","title":"3.0","aliases":["latest"]},{"version":"2.0.0","title":"2.0.0","aliases":[]},{"version":"1.0.0","title":"1.0.0","aliases":[]}]' 146 | 147 | } 148 | 149 | def "Check version already declared"() { 150 | setup: 151 | build """ 152 | plugins { 153 | id 'ru.vyarus.mkdocs' 154 | } 155 | 156 | version = '3.0' 157 | 158 | mkdocs.publish { 159 | versionAliases = ['latest'] 160 | existingVersionsFile = 'prev-versions.json' 161 | } 162 | 163 | python.scope = USER 164 | """ 165 | file('prev-versions.json') << '[{"version":"3.0","title":"3.0","aliases":["latest"]},{"version":"2.0.0","title":"2.0.0","aliases":[]},{"version":"1.0.0","title":"1.0.0","aliases":[]}]' 166 | 167 | when: "run init" 168 | BuildResult result = run('mkdocsInit') 169 | 170 | then: "docs created" 171 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 172 | 173 | when: "build site" 174 | result = run('mkdocsBuild') 175 | File vers = file('build/mkdocs/versions.json') 176 | println vers.text 177 | 178 | then: "built" 179 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 180 | vers.text == '[{"version":"3.0","title":"3.0","aliases":["latest"]},{"version":"2.0.0","title":"2.0.0","aliases":[]},{"version":"1.0.0","title":"1.0.0","aliases":[]}]' 181 | 182 | } 183 | 184 | def "Check versions file from url update"() { 185 | setup: 186 | build """ 187 | plugins { 188 | id 'ru.vyarus.mkdocs' 189 | } 190 | 191 | version = '1.0' 192 | 193 | mkdocs.publish.existingVersionsFile = 'https://xvik.github.io/gradle-use-python-plugin/versions.json' 194 | 195 | python.scope = USER 196 | """ 197 | 198 | when: "run init" 199 | BuildResult result = run('mkdocsInit') 200 | 201 | then: "docs created" 202 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 203 | 204 | when: "build site" 205 | result = run('mkdocsBuild') 206 | File vers = file('build/mkdocs/versions.json') 207 | println vers.text 208 | 209 | then: "built" 210 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 211 | vers.exists() 212 | result.output.contains('Existing versions file \'https://xvik.github.io/gradle-use-python-plugin/versions.json\' loaded with') 213 | result.output.contains('New version added: 1.0') 214 | 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/docker/DockerKitTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs.docker 2 | 3 | import org.gradle.testkit.runner.BuildResult 4 | import org.gradle.testkit.runner.TaskOutcome 5 | import ru.vyarus.gradle.plugin.mkdocs.AbstractKitTest 6 | import spock.lang.IgnoreIf 7 | 8 | /** 9 | * @author Vyacheslav Rusakov 10 | * @since 13.10.2022 11 | */ 12 | // testcontainers doesn't work on windows server https://github.com/testcontainers/testcontainers-java/issues/2960 13 | @IgnoreIf({ System.getProperty("os.name").toLowerCase().contains("windows") }) 14 | class DockerKitTest extends AbstractKitTest { 15 | 16 | def "Check workflow"() { 17 | setup: 18 | build """ 19 | plugins { 20 | id 'ru.vyarus.mkdocs' 21 | } 22 | 23 | version = '1.0-SNAPSHOT' 24 | python.docker.use = true 25 | """ 26 | 27 | when: "run init" 28 | BuildResult result = run('mkdocsInit') 29 | 30 | then: "docs created" 31 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 32 | file('src/doc/mkdocs.yml').exists() 33 | 34 | when: "build site" 35 | result = run('mkdocsBuild') 36 | 37 | then: "built" 38 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 39 | file('build/mkdocs/1.0-SNAPSHOT/index.html').exists() 40 | 41 | } 42 | 43 | def "Check build"() { 44 | setup: 45 | build """ 46 | plugins { 47 | id 'ru.vyarus.mkdocs' 48 | } 49 | 50 | version = '1.0' 51 | 52 | python.docker.use = true 53 | """ 54 | 55 | when: "run init" 56 | BuildResult result = run('mkdocsInit') 57 | 58 | then: "docs created" 59 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 60 | 61 | when: "build site" 62 | File conf = file('src/doc/mkdocs.yml') 63 | conf.text = conf.text.replaceAll(/(?m)^site_url:.*/, "site_url: http://localhost") 64 | result = run('mkdocsBuild') 65 | 66 | then: "built" 67 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 68 | result.output =~ /python -m mkdocs build -c -d [^(-)]+ -s/ 69 | 70 | file('build/mkdocs/1.0/index.html').exists() 71 | // site_url wasn't modified 72 | file('build/mkdocs/1.0/sitemap.xml').text.contains('http://localhost/1.0/guide/installation/') 73 | file('build/mkdocs/index.html').exists() 74 | file('build/mkdocs/index.html').text.contains('URL=\'1.0\'') 75 | 76 | when: "up to date check" 77 | result = run('mkdocsBuild') 78 | 79 | then: "ok" 80 | result.task(':mkdocsBuild').outcome == TaskOutcome.UP_TO_DATE 81 | 82 | } 83 | 84 | def "Check serve"() { 85 | setup: 86 | build """ 87 | plugins { 88 | id 'ru.vyarus.mkdocs' 89 | } 90 | 91 | python.docker.use = true 92 | """ 93 | file('src/doc/').mkdirs() 94 | 95 | when: "serve site" 96 | BuildResult result = runFailed('mkdocsServe') 97 | 98 | then: "command correct" 99 | result.task(':mkdocsServe').outcome == TaskOutcome.FAILED 100 | result.output =~ /python -m mkdocs serve --dev-addr 0.0.0.0:3000/ 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/task/BuildTaskKitTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs.task 2 | 3 | import org.gradle.testkit.runner.BuildResult 4 | import org.gradle.testkit.runner.TaskOutcome 5 | import ru.vyarus.gradle.plugin.mkdocs.AbstractKitTest 6 | 7 | /** 8 | * @author Vyacheslav Rusakov 9 | * @since 29.11.2017 10 | */ 11 | class BuildTaskKitTest extends AbstractKitTest { 12 | 13 | def "Check build"() { 14 | setup: 15 | build """ 16 | plugins { 17 | id 'ru.vyarus.mkdocs' 18 | } 19 | 20 | version = '1.0' 21 | 22 | python.scope = USER 23 | """ 24 | 25 | when: "run init" 26 | BuildResult result = run('mkdocsInit') 27 | 28 | then: "docs created" 29 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 30 | 31 | when: "build site" 32 | File conf = file('src/doc/mkdocs.yml') 33 | conf.text = conf.text.replaceAll(/(?m)^site_url:.*/, "site_url: http://localhost") 34 | result = run('mkdocsBuild') 35 | 36 | then: "built" 37 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 38 | result.output =~ /\[python] python(3)? -m mkdocs build -c -d ${isWin ? '"[^"]+"' : '[^(-)]+'} -s/ 39 | 40 | file('build/mkdocs/1.0/index.html').exists() 41 | // site_url wasn't modified 42 | file('build/mkdocs/1.0/sitemap.xml').text.contains('http://localhost/1.0/guide/installation/') 43 | file('build/mkdocs/index.html').exists() 44 | file('build/mkdocs/index.html').text.contains('URL=\'1.0\'') 45 | 46 | when: "up to date check" 47 | result = run('mkdocsBuild') 48 | 49 | then: "ok" 50 | result.task(':mkdocsBuild').outcome == TaskOutcome.UP_TO_DATE 51 | 52 | } 53 | 54 | def "Check non strict build"() { 55 | setup: 56 | build """ 57 | plugins { 58 | id 'ru.vyarus.mkdocs' 59 | } 60 | 61 | version = '1.0' 62 | 63 | python.scope = USER 64 | 65 | mkdocs.strict = false 66 | """ 67 | 68 | when: "run init" 69 | BuildResult result = run('mkdocsInit') 70 | 71 | then: "docs created" 72 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 73 | 74 | when: "build site" 75 | File conf = file('src/doc/mkdocs.yml') 76 | conf.text = conf.text.replaceAll(/(?m)^site_url:.*/, "site_url: http://localhost") 77 | result = run('mkdocsBuild') 78 | 79 | then: "built" 80 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 81 | result.output =~ /\[python] python(3)? -m mkdocs build -c -d ${isWin ? '"[^"]+"' : '[^(-)]+'}/ 82 | 83 | file('build/mkdocs/1.0/index.html').exists() 84 | // site_url wasn't modified 85 | file('build/mkdocs/1.0/sitemap.xml').text.contains('http://localhost/1.0/guide/installation/') 86 | file('build/mkdocs/index.html').exists() 87 | file('build/mkdocs/index.html').text.contains('URL=\'1.0\'') 88 | 89 | when: "up to date check" 90 | result = run('mkdocsBuild') 91 | 92 | then: "ok" 93 | result.task(':mkdocsBuild').outcome == TaskOutcome.UP_TO_DATE 94 | 95 | } 96 | 97 | 98 | def "Check build path with space"() { 99 | setup: 100 | build """ 101 | plugins { 102 | id 'ru.vyarus.mkdocs' 103 | } 104 | 105 | version = 'v 1.0' 106 | 107 | python.scope = USER 108 | """ 109 | 110 | when: "run init" 111 | BuildResult result = run('mkdocsInit') 112 | 113 | then: "docs created" 114 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 115 | file('src/doc/mkdocs.yml').exists() 116 | 117 | when: "build site" 118 | result = run('mkdocsBuild') 119 | println(file('build/mkdocs/').list()) 120 | 121 | then: "built" 122 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 123 | result.output =~ /\[python] python(3)? -m mkdocs build -c -d ${isWin ? '"[^"]+"' : '[^(-)]+'} -s/ 124 | file('build/mkdocs/v 1.0/index.html').exists() 125 | } 126 | 127 | 128 | def "Check build not default doc"() { 129 | setup: 130 | build """ 131 | plugins { 132 | id 'ru.vyarus.mkdocs' 133 | } 134 | 135 | version = '1.0' 136 | 137 | python.scope = USER 138 | 139 | mkdocs.publish { 140 | // simulation case: updating docs for older version 141 | docPath = '0.9' 142 | rootRedirect = false 143 | } 144 | """ 145 | 146 | when: "run init" 147 | BuildResult result = run('mkdocsInit') 148 | 149 | then: "docs created" 150 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 151 | file('src/doc/mkdocs.yml').exists() 152 | 153 | when: "build site" 154 | result = run('mkdocsBuild') 155 | 156 | then: "built" 157 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 158 | file('build/mkdocs/0.9/index.html').exists() 159 | !file('build/mkdocs/index.html').exists() 160 | 161 | } 162 | 163 | def "Check non strict build"() { 164 | setup: 165 | build """ 166 | plugins { 167 | id 'ru.vyarus.mkdocs' 168 | } 169 | 170 | python.scope = USER 171 | 172 | mkdocs.strict = false 173 | """ 174 | file('src/doc/').mkdirs() 175 | 176 | when: "build site" 177 | BuildResult result = runFailed('mkdocsBuild') 178 | 179 | then: "command correct" 180 | result.task(':mkdocsBuild').outcome == TaskOutcome.FAILED 181 | !(result.output =~ /\[python] python(3)? -m mkdocs build -c -d ${isWin ? '"[^"]+"' : '[^(-)]+'} -s/) 182 | } 183 | 184 | def "Check different source folder"() { 185 | 186 | setup: 187 | build """ 188 | plugins { 189 | id 'ru.vyarus.mkdocs' 190 | } 191 | 192 | python.scope = USER 193 | 194 | mkdocs.sourcesDir = 'docs' 195 | """ 196 | file('docs/').mkdirs() 197 | 198 | when: "build site" 199 | BuildResult result = runFailed('mkdocsBuild') 200 | 201 | then: "correct source path used" 202 | result.task(':mkdocsBuild').outcome == TaskOutcome.FAILED 203 | result.output.contains("Mkdocs config file not found: docs${isWin ? '\\' : '/'}mkdocs.yml") 204 | } 205 | 206 | 207 | def "Check stale index.html remove"() { 208 | 209 | setup: 210 | build """ 211 | plugins { 212 | id 'ru.vyarus.mkdocs' 213 | } 214 | 215 | python.scope = USER 216 | """ 217 | file('docs/').mkdirs() 218 | 219 | when: "run init" 220 | BuildResult result = run('mkdocsInit') 221 | 222 | then: "docs created" 223 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 224 | file('src/doc/mkdocs.yml').exists() 225 | 226 | when: "build site" 227 | result = run('mkdocsBuild') 228 | 229 | then: "redirect index generated" 230 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 231 | file('build/mkdocs/index.html').exists() 232 | 233 | when: "building without redirect" 234 | buildFile.delete() 235 | build """ 236 | plugins { 237 | id 'ru.vyarus.mkdocs' 238 | } 239 | 240 | python.scope = USER 241 | 242 | mkdocs.publish.rootRedirect = false 243 | """ 244 | file('src/doc/docs/index.md') << 'overwrite file' 245 | result = run('mkdocsBuild') 246 | 247 | then: "index.html removed" 248 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 249 | !file('build/mkdocs/index.html').exists() 250 | } 251 | 252 | def "Check up to date"() { 253 | setup: 254 | build """ 255 | plugins { 256 | id 'ru.vyarus.mkdocs' 257 | } 258 | 259 | version = '1.0' 260 | 261 | python.scope = USER 262 | """ 263 | file('src/doc/').mkdirs() 264 | 265 | when: "run init" 266 | BuildResult result = run('mkdocsInit') 267 | 268 | then: "docs created" 269 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 270 | file('src/doc/mkdocs.yml').exists() 271 | 272 | when: "build site" 273 | result = run('mkdocsBuild') 274 | 275 | then: "built" 276 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 277 | 278 | when: "once again build" 279 | result = run('mkdocsBuild') 280 | 281 | then: "built" 282 | result.task(':mkdocsBuild').outcome == TaskOutcome.UP_TO_DATE 283 | 284 | } 285 | } 286 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/task/InitTaskKitTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs.task 2 | 3 | import org.gradle.testkit.runner.BuildResult 4 | import org.gradle.testkit.runner.TaskOutcome 5 | import ru.vyarus.gradle.plugin.mkdocs.AbstractKitTest 6 | 7 | /** 8 | * @author Vyacheslav Rusakov 9 | * @since 23.11.2017 10 | */ 11 | class InitTaskKitTest extends AbstractKitTest { 12 | 13 | def "Check site init"() { 14 | setup: 15 | build """ 16 | plugins { 17 | id 'ru.vyarus.mkdocs' 18 | } 19 | description = 'desc' 20 | 21 | python.scope = USER 22 | """ 23 | 24 | when: "run task" 25 | BuildResult result = run('mkdocsInit') 26 | 27 | then: "task successful" 28 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 29 | def yml = file('src/doc/mkdocs.yml') 30 | yml.exists() 31 | !yml.text.contains('@') 32 | 33 | then: "all dirs generated" 34 | file('src/doc/docs/index.md').exists() 35 | file('src/doc/docs/about/history.md').exists() 36 | file('src/doc/docs/guide/installation.md').exists() 37 | } 38 | 39 | def "Check site init into different dir"() { 40 | setup: 41 | build """ 42 | plugins { 43 | id 'ru.vyarus.mkdocs' 44 | } 45 | 46 | python.scope = USER 47 | 48 | mkdocs.sourcesDir = 'docs' 49 | """ 50 | file('docs/').mkdirs() 51 | 52 | when: "run task" 53 | BuildResult result = run('mkdocsInit') 54 | 55 | then: "task successful" 56 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 57 | result.output.contains('Mkdocs site initialized: docs') 58 | file('docs/mkdocs.yml').exists() 59 | 60 | then: "all dirs generated" 61 | file('docs/docs/index.md').exists() 62 | file('docs/docs/about/history.md').exists() 63 | file('docs/docs/guide/installation.md').exists() 64 | } 65 | 66 | def "Check init into existing docs dir"() { 67 | setup: 68 | build """ 69 | plugins { 70 | id 'ru.vyarus.mkdocs' 71 | } 72 | 73 | python.scope = USER 74 | """ 75 | 76 | when: "run task" 77 | BuildResult result = run('mkdocsInit') 78 | 79 | then: "task successful" 80 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 81 | def yml = file('src/doc/mkdocs.yml') 82 | yml.exists() 83 | 84 | when: "call init into already inited dir" 85 | result = runFailed('mkdocsInit') 86 | then: "error" 87 | result.output.contains('Can\'t init new mkdocs site because target directory is not empty:') 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/task/PublishJavadocKitTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs.task 2 | 3 | import org.ajoberstar.grgit.Grgit 4 | import org.gradle.testkit.runner.BuildResult 5 | import org.gradle.testkit.runner.TaskOutcome 6 | import ru.vyarus.gradle.plugin.mkdocs.AbstractKitTest 7 | import spock.lang.TempDir 8 | 9 | /** 10 | * @author Vyacheslav Rusakov 11 | * @since 01.12.2017 12 | */ 13 | class PublishJavadocKitTest extends AbstractKitTest { 14 | 15 | @TempDir File repoDir 16 | 17 | Grgit repo 18 | 19 | @Override 20 | def setup() { 21 | // local repo used for push 22 | println 'init fake gh-pages repo' 23 | repo = Grgit.init(dir: repoDir, bare: true) 24 | assert repo.branch.list().size() == 0 25 | // connect with project folder 26 | println 'associate project with fake repo' 27 | Grgit prjRepo = Grgit.init(dir: testProjectDir) 28 | prjRepo.remote.add(name: 'origin', url: repoDir.canonicalPath, pushUrl: repoDir.canonicalPath) 29 | // init remote repo 30 | file('readme.txt') << 'sample' 31 | prjRepo.add(patterns: ['*']) 32 | prjRepo.commit(message: 'initial commit') 33 | prjRepo.push() 34 | prjRepo.close() 35 | 36 | assert repo.log().size() == 1 37 | assert repo.branch.list().size() == 1 38 | } 39 | 40 | void cleanup() { 41 | repo.close() 42 | } 43 | 44 | def "Check additional resources publication"() { 45 | 46 | setup: 47 | build """ 48 | plugins { 49 | id 'java' 50 | id 'ru.vyarus.mkdocs' 51 | } 52 | 53 | version = '1.0' 54 | 55 | python.scope = USER 56 | 57 | gitPublish.contents { 58 | from(javadoc) { 59 | into "\${mkdocs.resolveDocPath()}/javadoc" 60 | } 61 | } 62 | 63 | // dependency will not be set automatically 64 | gitPublishReset.dependsOn javadoc 65 | 66 | """ 67 | file('src/main/java/').mkdirs() 68 | file('src/main/java/Sample.java') << """ 69 | /** 70 | * Sample class. 71 | */ 72 | public class Sample {} 73 | """ 74 | 75 | when: "run init" 76 | BuildResult result = run('mkdocsInit') 77 | 78 | then: "docs created" 79 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 80 | file('src/doc/mkdocs.yml').exists() 81 | 82 | when: "publish" 83 | // debug() 84 | // println 'wait for debugger' 85 | result = run('mkdocsPublish') 86 | 87 | then: "published with javadoc" 88 | result.task(':mkdocsPublish').outcome == TaskOutcome.SUCCESS 89 | 90 | then: "content available" 91 | file('/.gradle/gh-pages/1.0/index.html').exists() 92 | file('/.gradle/gh-pages/1.0/javadoc/index.html').exists() 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/task/ServeTaskKitTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs.task 2 | 3 | import org.gradle.testkit.runner.BuildResult 4 | import org.gradle.testkit.runner.TaskOutcome 5 | import ru.vyarus.gradle.plugin.mkdocs.AbstractKitTest 6 | 7 | /** 8 | * @author Vyacheslav Rusakov 9 | * @since 29.11.2017 10 | */ 11 | class ServeTaskKitTest extends AbstractKitTest { 12 | 13 | def "Check serve"() { 14 | setup: 15 | build """ 16 | plugins { 17 | id 'ru.vyarus.mkdocs' 18 | } 19 | 20 | python.scope = USER 21 | mkdocs.devPort = 3001 22 | """ 23 | file('src/doc/').mkdirs() 24 | 25 | when: "serve site" 26 | BuildResult result = runFailed('mkdocsServe') 27 | 28 | then: "command correct" 29 | result.task(':mkdocsServe').outcome == TaskOutcome.FAILED 30 | result.output =~ /\[python] python(3)? -m mkdocs serve -s --dev-addr 127.0.0.1:3001/ 31 | } 32 | 33 | def "Check non strict serve"() { 34 | setup: 35 | build """ 36 | plugins { 37 | id 'ru.vyarus.mkdocs' 38 | } 39 | 40 | python.scope = USER 41 | 42 | mkdocs.strict = false 43 | """ 44 | file('src/doc/').mkdirs() 45 | 46 | when: "serve site" 47 | BuildResult result = runFailed('mkdocsServe') 48 | 49 | then: "command correct" 50 | result.task(':mkdocsServe').outcome == TaskOutcome.FAILED 51 | result.output =~ /\[python] python(3)? -m mkdocs serve --dev-addr 127.0.0.1:3000/ 52 | } 53 | 54 | def "Check different source folder"() { 55 | 56 | setup: 57 | build """ 58 | plugins { 59 | id 'ru.vyarus.mkdocs' 60 | } 61 | 62 | python.scope = USER 63 | 64 | mkdocs.sourcesDir = 'docs' 65 | """ 66 | file('docs/').mkdirs() 67 | 68 | when: "serve site" 69 | BuildResult result = runFailed('mkdocsServe') 70 | 71 | then: "correct source path used" 72 | result.task(':mkdocsServe').outcome == TaskOutcome.FAILED 73 | result.output.contains("Config file 'mkdocs.yml' does not exist.") 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/task/UrlChangeKitTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs.task 2 | 3 | import org.gradle.testkit.runner.BuildResult 4 | import org.gradle.testkit.runner.TaskOutcome 5 | import ru.vyarus.gradle.plugin.mkdocs.AbstractKitTest 6 | 7 | /** 8 | * @author Vyacheslav Rusakov 9 | * @since 07.12.2017 10 | */ 11 | class UrlChangeKitTest extends AbstractKitTest { 12 | 13 | def "Check site url change"() { 14 | setup: 15 | build """ 16 | plugins { 17 | id 'ru.vyarus.mkdocs' 18 | } 19 | 20 | version = '1.0' 21 | 22 | python.scope = USER 23 | """ 24 | 25 | when: "run init" 26 | BuildResult result = run('mkdocsInit') 27 | 28 | then: "docs created" 29 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 30 | File conf = file('src/doc/mkdocs.yml') 31 | conf.exists() 32 | 33 | when: "build site" 34 | conf.text = conf.text.replaceAll(/(?m)^site_url:.*/, "site_url: http://some-url.com") 35 | result = run('mkdocsBuild') 36 | 37 | then: "built" 38 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 39 | result.output =~ /\[python] python(3)? -m mkdocs build -c -d ${isWin ? '"[^"]+"' : '[^(-)]+'} -s/ 40 | 41 | file('build/mkdocs/1.0/index.html').exists() 42 | // site_url modified 43 | file('build/mkdocs/1.0/sitemap.xml').text.contains('http://some-url.com/1.0/guide/installation/') 44 | file('build/mkdocs/index.html').exists() 45 | file('build/mkdocs/index.html').text.contains('URL=\'1.0\'') 46 | 47 | then: "config was reverted" 48 | !conf.text.contains('http://some-url.com/1.0') 49 | !file('src/doc/mkdocs.yml.bak').exists() 50 | } 51 | 52 | def "Check disabled site url change"() { 53 | setup: 54 | build """ 55 | plugins { 56 | id 'ru.vyarus.mkdocs' 57 | } 58 | 59 | version = '1.0' 60 | 61 | python.scope = USER 62 | 63 | mkdocs.updateSiteUrl = false 64 | """ 65 | 66 | when: "run init" 67 | BuildResult result = run('mkdocsInit') 68 | 69 | then: "docs created" 70 | result.task(':mkdocsInit').outcome == TaskOutcome.SUCCESS 71 | File conf = file('src/doc/mkdocs.yml') 72 | conf.exists() 73 | 74 | when: "build site" 75 | conf.text = conf.text.replaceAll(/(?m)^site_url:.*/, "site_url: http://some-url.com") 76 | result = run('mkdocsBuild') 77 | 78 | then: "built" 79 | result.task(':mkdocsBuild').outcome == TaskOutcome.SUCCESS 80 | result.output =~ /\[python] python(3)? -m mkdocs build -c -d ${isWin ? '"[^"]+"' : '[^(-)]+'} -s/ 81 | 82 | file('build/mkdocs/1.0/index.html').exists() 83 | // site_url wasn't modified 84 | file('build/mkdocs/1.0/sitemap.xml').text.contains('http://some-url.com/guide/installation/') 85 | file('build/mkdocs/index.html').exists() 86 | file('build/mkdocs/index.html').text.contains('URL=\'1.0\'') 87 | 88 | then: "config was reverted" 89 | !conf.text.contains('http://some-url.com/1.0') 90 | !file('src/doc/mkdocs.yml.bak').exists() 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/util/TemplateUtilsTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs.util 2 | 3 | import org.gradle.api.Project 4 | import org.gradle.api.internal.project.ProjectInternal 5 | import ru.vyarus.gradle.plugin.mkdocs.AbstractTest 6 | 7 | /** 8 | * @author Vyacheslav Rusakov 9 | * @since 05.12.2017 10 | */ 11 | class TemplateUtilsTest extends AbstractTest { 12 | 13 | def "Check direct access"() { 14 | 15 | when: "copy from classpath" 16 | Project project = project() 17 | TemplateUtils.copy((project as ProjectInternal).fileOperations, '/ru/vyarus/gradle/plugin/mkdocs/template/init/', 'tp', [:]) 18 | 19 | then: "copied" 20 | file('tp/mkdocs.yml').exists() 21 | file('tp/docs/index.md').exists() 22 | 23 | when: "no trailing slash" 24 | TemplateUtils.copy((project as ProjectInternal).fileOperations, '/ru/vyarus/gradle/plugin/mkdocs/template/init', 'tp2', [:]) 25 | 26 | then: "copied" 27 | file('tp2/mkdocs.yml').exists() 28 | file('tp2/docs/index.md').exists() 29 | 30 | when: "relative path" 31 | TemplateUtils.copy((project as ProjectInternal).fileOperations, 'relative/path', 'tp', [:]) 32 | then: "error" 33 | thrown(IllegalArgumentException) 34 | 35 | when: "not existing path" 36 | TemplateUtils.copy((project as ProjectInternal).fileOperations, '/not/existing', 'tp', [:]) 37 | then: "error" 38 | thrown(IllegalArgumentException) 39 | } 40 | 41 | def "Check zip access"() { 42 | 43 | when: "build jar" 44 | File templates = new File('src/main/resources/ru/vyarus/gradle/plugin/mkdocs/') 45 | Project project = project() 46 | project.ant.zip(destfile: 'test.jar') { 47 | fileset(dir: templates.absolutePath) { 48 | include(name: '**/*.md') 49 | include(name: '**/*.yml') 50 | include(name: '**/*.html') 51 | } 52 | } 53 | 54 | then: 'built' 55 | File jar = file('test.jar') 56 | jar.exists() 57 | 58 | when: "copy template from jar" 59 | // add to current classpath 60 | URLClassLoader extendedLoader = new URLClassLoader([jar.toURI().toURL()] as URL[], TemplateUtils.getClassLoader()) 61 | Thread.currentThread().setContextClassLoader(extendedLoader) 62 | 63 | TemplateUtils.copy((project as ProjectInternal).fileOperations, '/template/init/', 'tp', [:]) 64 | 65 | then: "copied" 66 | file('tp/mkdocs.yml').exists() 67 | file('tp/docs/index.md').exists() 68 | 69 | when: "no trailing slash" 70 | TemplateUtils.copy((project as ProjectInternal).fileOperations, '/template/init', 'tp2', [:]) 71 | 72 | then: "copied" 73 | file('tp2/mkdocs.yml').exists() 74 | file('tp2/docs/index.md').exists() 75 | } 76 | } -------------------------------------------------------------------------------- /src/test/groovy/ru/vyarus/gradle/plugin/mkdocs/util/VersionComparatorTest.groovy: -------------------------------------------------------------------------------- 1 | package ru.vyarus.gradle.plugin.mkdocs.util 2 | 3 | import spock.lang.Specification 4 | 5 | /** 6 | * @author Vyacheslav Rusakov 7 | * @since 07.12.2021 8 | */ 9 | class VersionComparatorTest extends Specification { 10 | 11 | def "Check strings sorting"() { 12 | 13 | when: "sorting alpha-numeric string, zero last" 14 | List ORDERED = ['1ab', '5ab', '10ab', 'a1b', 'a5b', 'a10b', 'ab1', 'ab5', 'ab10'] 15 | def list = new ArrayList(ORDERED) 16 | Collections.shuffle(list) 17 | Collections.sort(list, VersionsComparator.comparingVersions(false)) 18 | 19 | then: "order correct" 20 | list == ORDERED 21 | 22 | when: "sorting alpha-numeric string, zero first" 23 | list = new ArrayList(ORDERED) 24 | Collections.shuffle(list) 25 | Collections.sort(list, VersionsComparator.comparingVersions(true)) 26 | 27 | then: "order correct" 28 | list == ORDERED 29 | } 30 | 31 | def "Check reversed sorting"() { 32 | 33 | when: "sorting alpha-numeric string, zero last" 34 | List ORDERED = ['1ab', '5ab', '10ab', 'a1b', 'a5b', 'a10b', 'ab1', 'ab5', 'ab10'].reverse() 35 | def list = new ArrayList(ORDERED) 36 | Collections.shuffle(list) 37 | Collections.sort(list, VersionsComparator.comparingVersions(false).reversed()) 38 | 39 | then: "order correct" 40 | list == ORDERED 41 | 42 | when: "sorting alpha-numeric string, zero first" 43 | list = new ArrayList(ORDERED) 44 | Collections.shuffle(list) 45 | Collections.sort(list, VersionsComparator.comparingVersions(true).reversed()) 46 | 47 | then: "order correct" 48 | list == ORDERED 49 | } 50 | 51 | def "Check double reversed strings sorting"() { 52 | 53 | when: "sorting alpha-numeric string, zero last" 54 | List ORDERED = ['1ab', '5ab', '10ab', 'a1b', 'a5b', 'a10b', 'ab1', 'ab5', 'ab10'] 55 | def list = new ArrayList(ORDERED) 56 | Collections.shuffle(list) 57 | Collections.sort(list, VersionsComparator.comparingVersions(false).reversed().reversed()) 58 | 59 | then: "order correct" 60 | list == ORDERED 61 | 62 | when: "sorting alpha-numeric string, zero first" 63 | list = new ArrayList(ORDERED) 64 | Collections.shuffle(list) 65 | Collections.sort(list, VersionsComparator.comparingVersions(true).reversed().reversed()) 66 | 67 | then: "order correct" 68 | list == ORDERED 69 | } 70 | 71 | def "Check zeros sorting"() { 72 | 73 | when: "sorting alpha-numeric string, zero last" 74 | def list = ['abc 001', 'abc 1', 'abc 01', 'abc 01'] 75 | Collections.shuffle(list) 76 | Collections.sort(list, VersionsComparator.comparingVersions(false)) 77 | 78 | then: "order correct" 79 | list == ['abc 1', 'abc 01', 'abc 01', 'abc 001'] 80 | 81 | when: "sorting alpha-numeric string, zero first" 82 | list = ['abc 001', 'abc 1', 'abc 01', 'abc 01'] 83 | Collections.shuffle(list) 84 | Collections.sort(list, VersionsComparator.comparingVersions(true)) 85 | 86 | then: "order correct" 87 | list == ['abc 001', 'abc 01', 'abc 01', 'abc 1'] 88 | 89 | } 90 | 91 | def "Check versions sorting"() { 92 | 93 | List sorted = ['1.0', '1.3', '1.31', '2.0', '2.1', '2.1-rc1', '2.1-rc2', '2.1-rc12', '2.1.1', '2.1.2', '2.1.12'] 94 | 95 | when: "sorting versions" 96 | def list = new ArrayList(sorted) 97 | Collections.shuffle(list) 98 | Collections.sort(list, VersionsComparator.comparingVersions(false)) 99 | 100 | then: "sorted" 101 | list == sorted 102 | } 103 | } 104 | --------------------------------------------------------------------------------