@@ -41,109 +41,79 @@ class DocFxPlugin implements Plugin<Project> {
4141 task. group = " documentation"
4242 task. description = " Packages the generated DocFX documentation into a zip file"
4343 task. dependsOn(docsTask)
44+ task. archiveClassifier = " docfx"
45+ task. destinationDirectory = project. file(" ${ project.buildDir} /distributions" )
46+ }
47+
48+ // Configure the zip task in docFx task's doLast (after _site directory is created)
49+ // This is the correct place to configure the 'from' for the Zip task
50+ docsTask. doLast {
51+ // Get source from extension (after docFx has potentially updated it to point to docfx.json)
52+ def source = extension. source
53+ if ((source == null || source. trim(). isEmpty()) && docsTask. hasProperty(' source' )) {
54+ source = docsTask. source
55+ }
4456
45- // Use onlyIf to allow task to run even if source is not set yet
46- // (source might be set in another task's doLast, e.g., msbuild.doLast)
47- // Actual checks happen in doFirst after dependencies have run
48- task. onlyIf {
49- // Always allow the task to run - we'll check conditions in doFirst
50- // This handles the case where source is set in another task's doLast
51- return true
57+ if (source == null || source. trim(). isEmpty()) {
58+ project. logger. info(" docFxZip: source is not set, skipping zip configuration" )
59+ return
5260 }
5361
54- task. doFirst {
55- project. logger. quiet(" docFxZip: Starting zip task" )
56-
57- // Check source from extension first, then from docFx task (in case it was set on the task)
58- def source = extension. source
59- if ((source == null || source. trim(). isEmpty()) && docsTask. hasProperty(' source' )) {
60- source = docsTask. source
61- }
62-
63- project. logger. quiet(" docFxZip: checking conditions, extension.source=${ extension.source} , docFx.source=${ docsTask.hasProperty('source') ? docsTask.source : 'N/A'} , resolved source=${ source} " )
64-
65- if (source == null || source. trim(). isEmpty()) {
66- throw new org.gradle.api.tasks.StopExecutionException (" docFxZip SKIPPED: source is not set (null or empty) - docFx task may not have source configured. Make sure docFx.source is set before docFxZip runs." )
67- }
68-
69- // Determine the output directory from the docfx.json source
70- def sourceFile = project. file(source)
71- project. logger. quiet(" docFxZip: checking source file: ${ sourceFile.absolutePath} , exists=${ sourceFile.exists()} " )
72-
73- if (! sourceFile. exists()) {
74- throw new org.gradle.api.tasks.StopExecutionException (" docFxZip SKIPPED: source file does not exist: ${ sourceFile.absolutePath} " )
75- }
76-
77- def sourceDir = sourceFile. parentFile
78- def siteDir = new File (sourceDir, " _site" )
79- project. logger. quiet(" docFxZip: checking _site directory: ${ siteDir.absolutePath} , exists=${ siteDir.exists()} " )
80-
81- if (! siteDir. exists()) {
82- throw new org.gradle.api.tasks.StopExecutionException (" docFxZip SKIPPED: _site directory does not exist at ${ siteDir.absolutePath} (docFx task may not have run successfully)" )
83- }
84-
85- project. logger. quiet(" docFxZip: ALL CONDITIONS MET - zipping _site directory from ${ siteDir.absolutePath} " )
86- task. from(siteDir) {
87- into " /"
88- }
89- task. destinationDirectory = project. file(" ${ project.buildDir} /distributions" )
90- task. archiveClassifier = " docfx"
91-
92- // Set archive base name from source file name
93- def baseName = sourceFile. name
94- if (baseName. endsWith(' .json' )) {
95- baseName = baseName. substring(0 , baseName. length() - 5 )
96- }
97-
98- // Set archiveBaseName (works for both Gradle 8 and 9)
99- // In Gradle 8, archiveBaseName is a property
100- // In Gradle 9+, archiveBaseName is a Property<String>
101- try {
102- if (task. hasProperty(' archiveBaseName' )) {
103- def prop = task. archiveBaseName
104- if (prop instanceof org.gradle.api.provider.Property ) {
105- // Gradle 9+ - Property API
106- if (! prop. isPresent() || prop. get() == project. name) {
107- prop. set(baseName)
108- }
109- } else {
110- // Gradle 8 - direct property
111- if (prop == null || prop == project. name) {
112- task. archiveBaseName = baseName
113- }
62+ // Determine the output directory from the docfx.json source
63+ // After docFx runs, extension.source points to the docfx.json file
64+ def sourceFile = project. file(source)
65+ if (! sourceFile. exists()) {
66+ project. logger. info(" docFxZip: source file does not exist: ${ sourceFile.absolutePath} , skipping zip configuration" )
67+ return
68+ }
69+
70+ def sourceDir = sourceFile. parentFile
71+ def siteDir = new File (sourceDir, " _site" )
72+
73+ if (! siteDir. exists()) {
74+ project. logger. info(" docFxZip: _site directory does not exist at ${ siteDir.absolutePath} , skipping zip configuration" )
75+ return
76+ }
77+
78+ project. logger. quiet(" docFxZip: Configuring zip task from _site directory: ${ siteDir.absolutePath} " )
79+
80+ // Configure the zip task's from (this happens in docFx.doLast, which is the right time)
81+ zipTask. from(siteDir) {
82+ into " /"
83+ }
84+
85+ // Set archive base name from source file name
86+ def baseName = sourceFile. name
87+ if (baseName. endsWith(' .json' )) {
88+ baseName = baseName. substring(0 , baseName. length() - 5 )
89+ }
90+
91+ // Set archiveBaseName (works for both Gradle 8 and 9)
92+ try {
93+ if (zipTask. hasProperty(' archiveBaseName' )) {
94+ def prop = zipTask. archiveBaseName
95+ if (prop instanceof org.gradle.api.provider.Property ) {
96+ // Gradle 9+ - Property API
97+ if (! prop. isPresent() || prop. get() == project. name) {
98+ prop. set(baseName)
99+ }
100+ } else {
101+ // Gradle 8 - direct property
102+ if (prop == null || prop == project. name) {
103+ zipTask. archiveBaseName = baseName
114104 }
115105 }
116- } catch (Exception e) {
117- project. logger. debug(" Could not set archiveBaseName: ${ e.message} " )
118106 }
107+ } catch (Exception e) {
108+ project. logger. debug(" Could not set archiveBaseName: ${ e.message} " )
119109 }
120110
121- task . doLast {
122- project . logger . quiet( " docFxZip: Completed zip task " )
123- }
111+ // Configure inputs/outputs for up-to-date checking
112+ zipTask . inputs . dir(siteDir) . optional( )
113+ zipTask . outputs . file(zipTask . archiveFile)
124114 }
125115
126116 // Make docs task finalized by zip task
127117 docsTask. finalizedBy(zipTask)
128-
129- // After evaluation, find any custom Docs tasks and make docFxZip depend on them
130- // This allows build scripts to create custom Docs tasks and have them work with docFxZip
131- project. afterEvaluate {
132- project. tasks. withType(Docs ). each { docsTaskInstance ->
133- if (docsTaskInstance != docsTask && docsTaskInstance. name != DOCS_TASK ) {
134- // Found a custom Docs task - make docFxZip depend on it
135- zipTask. dependsOn(docsTaskInstance)
136- // Also make the custom task finalized by zip
137- docsTaskInstance. finalizedBy(zipTask)
138- }
139- }
140-
141- // Optionally hook into common publishing tasks
142- // Check for preparePublish task (common in build scripts)
143- def preparePublishTask = project. tasks. findByName(' preparePublish' )
144- if (preparePublishTask != null ) {
145- preparePublishTask. dependsOn(zipTask)
146- }
147- }
148118 }
149119}
0 commit comments