@@ -29,6 +29,16 @@ internal abstract class PublishCommandBase : BaseCommand
2929 private readonly IFeatures _features ;
3030 private readonly ICliHostEnvironment _hostEnvironment ;
3131
32+ protected readonly Option < string ? > _logLevelOption = new ( "--log-level" )
33+ {
34+ Description = "Set the minimum log level for pipeline logging (trace, debug, information, warning, error, critical). The default is 'information'."
35+ } ;
36+
37+ protected readonly Option < string ? > _environmentOption = new ( "--environment" , "-e" )
38+ {
39+ Description = "The environment to use for the operation. The default is 'Production'."
40+ } ;
41+
3242 protected abstract string OperationCompletedPrefix { get ; }
3343 protected abstract string OperationFailedPrefix { get ; }
3444
@@ -70,6 +80,9 @@ protected PublishCommandBase(string name, string description, IDotNetCliRunner r
7080 } ;
7181 Options . Add ( outputPath ) ;
7282
83+ Options . Add ( _logLevelOption ) ;
84+ Options . Add ( _environmentOption ) ;
85+
7386 // In the publish and deploy commands we forward all unrecognized tokens
7487 // through to the underlying tooling when we launch the app host.
7588 TreatUnmatchedTokensAsErrors = false ;
@@ -278,6 +291,17 @@ protected override async Task<int> ExecuteAsync(ParseResult parseResult, Cancell
278291 }
279292 }
280293
294+ /// <summary>
295+ /// Conditionally converts markdown to Spectre markup based on the EnableMarkdown flag in the activity data.
296+ /// </summary>
297+ /// <param name="text">The text to convert.</param>
298+ /// <param name="activityData">The publishing activity data containing the EnableMarkdown flag.</param>
299+ /// <returns>The converted text if markdown is enabled, otherwise the original text.</returns>
300+ private static string ConvertTextWithMarkdownFlag ( string text , PublishingActivityData activityData )
301+ {
302+ return activityData . EnableMarkdown ? MarkdownToSpectreConverter . ConvertToSpectre ( text ) : text . EscapeMarkup ( ) ;
303+ }
304+
281305 public async Task < bool > ProcessPublishingActivitiesDebugAsync ( IAsyncEnumerable < PublishingActivity > publishingActivities , IAppHostBackchannel backchannel , CancellationToken cancellationToken )
282306 {
283307 var stepCounter = 1 ;
@@ -297,7 +321,7 @@ public async Task<bool> ProcessPublishingActivitiesDebugAsync(IAsyncEnumerable<P
297321 if ( ! steps . TryGetValue ( activity . Data . Id , out var stepStatus ) )
298322 {
299323 // New step - log it
300- var statusText = MarkdownToSpectreConverter . ConvertToSpectre ( activity . Data . StatusText ) ;
324+ var statusText = ConvertTextWithMarkdownFlag ( activity . Data . StatusText , activity . Data ) ;
301325 InteractionService . DisplaySubtleMessage ( $ "[[DEBUG]] Step { stepCounter ++ } : { statusText } ", escapeMarkup : false ) ;
302326 steps [ activity . Data . Id ] = activity . Data . CompletionState ;
303327 }
@@ -306,7 +330,7 @@ public async Task<bool> ProcessPublishingActivitiesDebugAsync(IAsyncEnumerable<P
306330 // Step completed - log completion
307331 var status = IsCompletionStateError ( activity . Data . CompletionState ) ? "FAILED" :
308332 IsCompletionStateWarning ( activity . Data . CompletionState ) ? "WARNING" : "COMPLETED" ;
309- var statusText = MarkdownToSpectreConverter . ConvertToSpectre ( activity . Data . StatusText ) ;
333+ var statusText = ConvertTextWithMarkdownFlag ( activity . Data . StatusText , activity . Data ) ;
310334 InteractionService . DisplaySubtleMessage ( $ "[[DEBUG]] Step { activity . Data . Id } : { status } - { statusText } ", escapeMarkup : false ) ;
311335 steps [ activity . Data . Id ] = activity . Data . CompletionState ;
312336 }
@@ -319,7 +343,7 @@ public async Task<bool> ProcessPublishingActivitiesDebugAsync(IAsyncEnumerable<P
319343 {
320344 // Log activity - display the log message
321345 var logLevel = activity . Data . LogLevel ?? "Information" ;
322- var message = MarkdownToSpectreConverter . ConvertToSpectre ( activity . Data . StatusText ) ;
346+ var message = ConvertTextWithMarkdownFlag ( activity . Data . StatusText , activity . Data ) ;
323347 var timestamp = activity . Data . Timestamp ? . ToString ( "HH:mm:ss" , CultureInfo . InvariantCulture ) ?? DateTimeOffset . UtcNow . ToString ( "HH:mm:ss" , CultureInfo . InvariantCulture ) ;
324348
325349 // Use 3-letter prefixes for log levels
@@ -337,9 +361,9 @@ public async Task<bool> ProcessPublishingActivitiesDebugAsync(IAsyncEnumerable<P
337361 // Make debug and trace logs more subtle
338362 var formattedMessage = logLevel . ToUpperInvariant ( ) switch
339363 {
340- "DEBUG" => $ "[{ timestamp } ] [dim][[{ logPrefix } ]] { message } [/]",
341- "TRACE" => $ "[{ timestamp } ] [dim][[{ logPrefix } ]] { message } [/]",
342- _ => $ "[{ timestamp } ] [[{ logPrefix } ]] { message } "
364+ "DEBUG" => $ "[[ { timestamp } ] ] [dim][[{ logPrefix } ]] { message } [/]",
365+ "TRACE" => $ "[[ { timestamp } ] ] [dim][[{ logPrefix } ]] { message } [/]",
366+ _ => $ "[[ { timestamp } ] ] [[{ logPrefix } ]] { message } "
343367 } ;
344368
345369 InteractionService . DisplaySubtleMessage ( formattedMessage , escapeMarkup : false ) ;
@@ -352,17 +376,17 @@ public async Task<bool> ProcessPublishingActivitiesDebugAsync(IAsyncEnumerable<P
352376 {
353377 var status = IsCompletionStateError ( activity . Data . CompletionState ) ? "FAILED" :
354378 IsCompletionStateWarning ( activity . Data . CompletionState ) ? "WARNING" : "COMPLETED" ;
355- var statusText = MarkdownToSpectreConverter . ConvertToSpectre ( activity . Data . StatusText ) ;
379+ var statusText = ConvertTextWithMarkdownFlag ( activity . Data . StatusText , activity . Data ) ;
356380 InteractionService . DisplaySubtleMessage ( $ "[[DEBUG]] Task { activity . Data . Id } ({ stepId } ): { status } - { statusText } ", escapeMarkup : false ) ;
357381 if ( ! string . IsNullOrEmpty ( activity . Data . CompletionMessage ) )
358382 {
359- var completionMessage = MarkdownToSpectreConverter . ConvertToSpectre ( activity . Data . CompletionMessage ) ;
383+ var completionMessage = ConvertTextWithMarkdownFlag ( activity . Data . CompletionMessage , activity . Data ) ;
360384 InteractionService . DisplaySubtleMessage ( $ "[[DEBUG]] { completionMessage } ", escapeMarkup : false ) ;
361385 }
362386 }
363387 else
364388 {
365- var statusText = MarkdownToSpectreConverter . ConvertToSpectre ( activity . Data . StatusText ) ;
389+ var statusText = ConvertTextWithMarkdownFlag ( activity . Data . StatusText , activity . Data ) ;
366390 InteractionService . DisplaySubtleMessage ( $ "[[DEBUG]] Task { activity . Data . Id } ({ stepId } ): { statusText } ", escapeMarkup : false ) ;
367391 }
368392 }
@@ -374,7 +398,7 @@ public async Task<bool> ProcessPublishingActivitiesDebugAsync(IAsyncEnumerable<P
374398 if ( publishingActivity is not null )
375399 {
376400 var status = hasErrors ? "FAILED" : hasWarnings ? "WARNING" : "COMPLETED" ;
377- var statusText = MarkdownToSpectreConverter . ConvertToSpectre ( publishingActivity . Data . StatusText ) ;
401+ var statusText = ConvertTextWithMarkdownFlag ( publishingActivity . Data . StatusText , publishingActivity . Data ) ;
378402 InteractionService . DisplaySubtleMessage ( $ "[[DEBUG]] { OperationCompletedPrefix } : { status } - { statusText } ", escapeMarkup : false ) ;
379403
380404 // Send visual bell notification when operation is complete
@@ -407,7 +431,7 @@ public async Task<bool> ProcessAndDisplayPublishingActivitiesAsync(IAsyncEnumera
407431 {
408432 if ( ! steps . TryGetValue ( activity . Data . Id , out var stepInfo ) )
409433 {
410- var title = MarkdownToSpectreConverter . ConvertToSpectre ( activity . Data . StatusText ) ;
434+ var title = ConvertTextWithMarkdownFlag ( activity . Data . StatusText , activity . Data ) ;
411435 stepInfo = new StepInfo
412436 {
413437 Id = activity . Data . Id ,
@@ -424,7 +448,7 @@ public async Task<bool> ProcessAndDisplayPublishingActivitiesAsync(IAsyncEnumera
424448 else if ( IsCompletionStateComplete ( activity . Data . CompletionState ) )
425449 {
426450 stepInfo . CompletionState = activity . Data . CompletionState ;
427- stepInfo . CompletionText = MarkdownToSpectreConverter . ConvertToSpectre ( activity . Data . StatusText ) ;
451+ stepInfo . CompletionText = ConvertTextWithMarkdownFlag ( activity . Data . StatusText , activity . Data ) ;
428452 stepInfo . EndTime = DateTime . UtcNow ;
429453 if ( IsCompletionStateError ( stepInfo . CompletionState ) )
430454 {
@@ -453,7 +477,7 @@ public async Task<bool> ProcessAndDisplayPublishingActivitiesAsync(IAsyncEnumera
453477 if ( stepId != null && steps . TryGetValue ( stepId , out var stepInfo ) )
454478 {
455479 var logLevel = activity . Data . LogLevel ?? "Information" ;
456- var message = MarkdownToSpectreConverter . ConvertToSpectre ( activity . Data . StatusText ) ;
480+ var message = ConvertTextWithMarkdownFlag ( activity . Data . StatusText , activity . Data ) ;
457481
458482 // Add 3-letter prefix to message for consistency
459483 var logPrefix = logLevel . ToUpperInvariant ( ) switch
@@ -508,7 +532,7 @@ public async Task<bool> ProcessAndDisplayPublishingActivitiesAsync(IAsyncEnumera
508532
509533 if ( ! tasks . TryGetValue ( activity . Data . Id , out var task ) )
510534 {
511- var statusText = MarkdownToSpectreConverter . ConvertToSpectre ( activity . Data . StatusText ) ;
535+ var statusText = ConvertTextWithMarkdownFlag ( activity . Data . StatusText , activity . Data ) ;
512536 task = new TaskInfo
513537 {
514538 Id = activity . Data . Id ,
@@ -521,13 +545,13 @@ public async Task<bool> ProcessAndDisplayPublishingActivitiesAsync(IAsyncEnumera
521545 logger . Progress ( stepInfo . Id , statusText ) ;
522546 }
523547
524- task . StatusText = MarkdownToSpectreConverter . ConvertToSpectre ( activity . Data . StatusText ) ;
548+ task . StatusText = ConvertTextWithMarkdownFlag ( activity . Data . StatusText , activity . Data ) ;
525549 task . CompletionState = activity . Data . CompletionState ;
526550
527551 if ( IsCompletionStateComplete ( activity . Data . CompletionState ) )
528552 {
529553 task . CompletionMessage = ! string . IsNullOrEmpty ( activity . Data . CompletionMessage )
530- ? MarkdownToSpectreConverter . ConvertToSpectre ( activity . Data . CompletionMessage )
554+ ? ConvertTextWithMarkdownFlag ( activity . Data . CompletionMessage , activity . Data )
531555 : null ;
532556
533557 var duration = DateTime . UtcNow - task . StartTime ;
@@ -617,12 +641,12 @@ var cs when IsCompletionStateWarning(cs) => ConsoleActivityLogger.ActivityState.
617641 }
618642 }
619643
620- private static string BuildPromptText ( PublishingPromptInput input , int inputCount , string statusText )
644+ private static string BuildPromptText ( PublishingPromptInput input , int inputCount , string statusText , PublishingActivityData activityData )
621645 {
622646 if ( inputCount > 1 )
623647 {
624648 // Multi-input: just show the label with markdown conversion
625- var labelText = MarkdownToSpectreConverter . ConvertToSpectre ( $ "{ input . Label } : ") ;
649+ var labelText = ConvertTextWithMarkdownFlag ( $ "{ input . Label } : ", activityData ) ;
626650 return labelText ;
627651 }
628652
@@ -633,12 +657,12 @@ private static string BuildPromptText(PublishingPromptInput input, int inputCoun
633657 // If StatusText equals Label (case-insensitive), show only the label once
634658 if ( header . Equals ( label , StringComparison . OrdinalIgnoreCase ) )
635659 {
636- return $ "[bold]{ MarkdownToSpectreConverter . ConvertToSpectre ( label ) } [/]";
660+ return $ "[bold]{ ConvertTextWithMarkdownFlag ( label , activityData ) } [/]";
637661 }
638662
639663 // Show StatusText as header (converted from markdown), then Label on new line
640- var convertedHeader = MarkdownToSpectreConverter . ConvertToSpectre ( header ) ;
641- var convertedLabel = MarkdownToSpectreConverter . ConvertToSpectre ( label ) ;
664+ var convertedHeader = ConvertTextWithMarkdownFlag ( header , activityData ) ;
665+ var convertedLabel = ConvertTextWithMarkdownFlag ( label , activityData ) ;
642666 return $ "[bold]{ convertedHeader } [/]\n { convertedLabel } : ";
643667 }
644668
@@ -663,7 +687,7 @@ private async Task HandlePromptActivityAsync(PublishingActivity activity, IAppHo
663687 // Don't display if there are validation errors. Validation errors means the header has already been displayed.
664688 if ( ! hasValidationErrors && inputs . Count > 1 )
665689 {
666- var headerText = MarkdownToSpectreConverter . ConvertToSpectre ( activity . Data . StatusText ) ;
690+ var headerText = ConvertTextWithMarkdownFlag ( activity . Data . StatusText , activity . Data ) ;
667691 AnsiConsole . MarkupLine ( $ "[bold]{ headerText } [/]") ;
668692 }
669693
@@ -680,7 +704,7 @@ private async Task HandlePromptActivityAsync(PublishingActivity activity, IAppHo
680704 if ( ! hasValidationErrors || input . ValidationErrors is { Count : > 0 } )
681705 {
682706 // Build the prompt text based on number of inputs
683- var promptText = BuildPromptText ( input , inputs . Count , activity . Data . StatusText ) ;
707+ var promptText = BuildPromptText ( input , inputs . Count , activity . Data . StatusText , activity . Data ) ;
684708
685709 result = await HandleSingleInputAsync ( input , promptText , cancellationToken ) ;
686710 }
0 commit comments