@moon791017/neo-skills 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/GEMINI.md +115 -0
  2. package/README.md +155 -0
  3. package/bin/install-claude-skills.js +72 -0
  4. package/commands/neo/cd-app-service.toml +20 -0
  5. package/commands/neo/cd-iis.toml +20 -0
  6. package/commands/neo/ci-dotnet.toml +21 -0
  7. package/commands/neo/clarification.toml +48 -0
  8. package/commands/neo/code-review.toml +33 -0
  9. package/commands/neo/dotnet-gen-interface.toml +31 -0
  10. package/commands/neo/explain.toml +44 -0
  11. package/commands/neo/git-commit.toml +49 -0
  12. package/dist/hooks/secret-guard.js +2 -0
  13. package/dist/server.js +220 -0
  14. package/gemini-extension.json +15 -0
  15. package/package.json +39 -0
  16. package/skills/azure-pipelines/SKILL.md +45 -0
  17. package/skills/azure-pipelines/templates/build/build-dotnet.yml +92 -0
  18. package/skills/azure-pipelines/templates/deploy/deploy-app-service.yml +71 -0
  19. package/skills/azure-pipelines/templates/deploy/deploy-iis.yml +189 -0
  20. package/skills/azure-pipelines/templates/util/clean-artifact.yml +40 -0
  21. package/skills/azure-pipelines/templates/util/extract-artifact.yml +57 -0
  22. package/skills/azure-pipelines/templates/util/iis/iis-backup.yml +92 -0
  23. package/skills/azure-pipelines/templates/util/iis/iis-deploy-files.yml +112 -0
  24. package/skills/azure-pipelines/templates/util/iis/iis-manage-website.yml +112 -0
  25. package/skills/azure-pipelines/templates/util/iis/iis-rollback.yml +98 -0
  26. package/skills/azure-pipelines/templates/util/iis/iis-start-website.yml +89 -0
  27. package/skills/azure-pipelines/templates/util/iis/iis-stop-website.yml +80 -0
  28. package/skills/azure-pipelines/templates/util/iis/iis-task.yml +157 -0
  29. package/skills/azure-pipelines/templates/util/set-aspnetcore-env.yml +77 -0
  30. package/skills/clarification/SKILL.md +22 -0
  31. package/skills/code-review/SKILL.md +72 -0
  32. package/skills/csharp/SKILL.md +87 -0
  33. package/skills/csharp/reference/anti-patterns.md +142 -0
  34. package/skills/csharp/reference/coding-style.md +86 -0
  35. package/skills/csharp/reference/patterns.md +142 -0
  36. package/skills/csharp-interface-generator/SKILL.md +40 -0
  37. package/skills/dotnet/SKILL.md +41 -0
  38. package/skills/dotnet-ef-core/SKILL.md +78 -0
  39. package/skills/dotnet-ef-core/reference/anti-patterns.md +51 -0
  40. package/skills/dotnet-ef-core/reference/coding-style.md +42 -0
  41. package/skills/dotnet-ef-core/reference/patterns.md +53 -0
  42. package/skills/dotnet-minimal-apis/SKILL.md +78 -0
  43. package/skills/dotnet-minimal-apis/reference/anti-patterns.md +59 -0
  44. package/skills/dotnet-minimal-apis/reference/coding-style.md +54 -0
  45. package/skills/dotnet-minimal-apis/reference/patterns.md +68 -0
  46. package/skills/dotnet-mvc/SKILL.md +78 -0
  47. package/skills/dotnet-mvc/reference/anti-patterns.md +49 -0
  48. package/skills/dotnet-mvc/reference/coding-style.md +43 -0
  49. package/skills/dotnet-mvc/reference/patterns.md +56 -0
  50. package/skills/dotnet-webapi/SKILL.md +78 -0
  51. package/skills/dotnet-webapi/reference/anti-patterns.md +48 -0
  52. package/skills/dotnet-webapi/reference/coding-style.md +47 -0
  53. package/skills/dotnet-webapi/reference/patterns.md +52 -0
  54. package/skills/explain/SKILL.md +27 -0
  55. package/skills/git-commit/SKILL.md +84 -0
  56. package/skills/python/SKILL.md +61 -0
  57. package/skills/python/reference/anti-patterns.md +177 -0
  58. package/skills/python/reference/coding-style.md +92 -0
  59. package/skills/python/reference/patterns.md +112 -0
  60. package/skills/python-manager/SKILL.md +61 -0
  61. package/skills/start-plan/SKILL.md +29 -0
  62. package/skills/swift/SKILL.md +78 -0
  63. package/skills/swift/reference/anti-patterns.md +75 -0
  64. package/skills/swift/reference/coding-style.md +56 -0
  65. package/skills/swift/reference/patterns.md +94 -0
  66. package/skills/swift-ui/SKILL.md +76 -0
  67. package/skills/swift-ui/reference/anti-patterns.md +52 -0
  68. package/skills/swift-ui/reference/coding-style.md +46 -0
  69. package/skills/swift-ui/reference/patterns.md +87 -0
@@ -0,0 +1,112 @@
1
+ # ==============================================================================
2
+ # Template Name: Deploy Files (iis-deploy-files-robocopy.yml)
3
+ # Description:
4
+ # Copy files from source path to destination path.
5
+ # Supports "Clean Mode": Empty destination folder before copying.
6
+ # Uses PowerShell Copy-Item instead of Robocopy to simplify logic and ensure clean deployment.
7
+ # ==============================================================================
8
+
9
+ parameters:
10
+ # Source Path (e.g. Artifact download path)
11
+ - name: sourcePath
12
+ type: string
13
+
14
+ # Destination Path (e.g. Website physical path)
15
+ - name: destinationPath
16
+ type: string
17
+
18
+ # Whether to empty destination folder first
19
+ - name: cleanDestination
20
+ type: boolean
21
+ default: true
22
+
23
+ # Execution Condition
24
+ - name: runCondition
25
+ type: string
26
+ default: 'succeeded()'
27
+
28
+ steps:
29
+ # ----------------------------------------------------------------------------
30
+ # Execute PowerShell script for file deployment
31
+ # ----------------------------------------------------------------------------
32
+ - powershell: |
33
+ $sourceRaw = "${{ parameters.sourcePath }}"
34
+ $destRaw = "${{ parameters.destinationPath }}"
35
+ $clean = "${{ parameters.cleanDestination }}"
36
+
37
+ # Expand Environment Variables (e.g. convert %SystemDrive% to C:)
38
+ $source = [System.Environment]::ExpandEnvironmentVariables($sourceRaw)
39
+ $dest = [System.Environment]::ExpandEnvironmentVariables($destRaw)
40
+
41
+ # 1. Path Normalization (Remove trailing slash)
42
+ if ($source.EndsWith("\") -or $source.EndsWith("/")) { $source = $source.Substring(0, $source.Length - 1) }
43
+ if ($dest.EndsWith("\") -or $dest.EndsWith("/")) { $dest = $dest.Substring(0, $dest.Length - 1) }
44
+
45
+ Write-Host "Preparing to deploy files"
46
+ Write-Host "Source Path (Raw): $sourceRaw"
47
+ Write-Host "Source Path (Expanded): $source"
48
+ Write-Host "Destination Path (Raw): $destRaw"
49
+ Write-Host "Destination Path (Expanded): $dest"
50
+
51
+ if (-not (Test-Path $source)) {
52
+ Write-Error "Source path does not exist: $source"
53
+ exit 1
54
+ }
55
+
56
+ # 2. Handle Destination Directory (Create or Clean)
57
+ if (Test-Path $dest) {
58
+ if ($clean -eq 'true') {
59
+ Write-Host "Mode: Clean Destination"
60
+ Write-Host "Removing entire destination directory: $dest"
61
+ try {
62
+ # Force remove entire directory
63
+ Remove-Item -Path $dest -Recurse -Force -ErrorAction Stop
64
+ Write-Host "Directory removed."
65
+ } catch {
66
+ Write-Warning "Error removing directory (files might be locked): $_ "
67
+ # If remove fails, try clearing contents only as fallback
68
+ Get-ChildItem -Path $dest -Recurse | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
69
+ }
70
+ } else {
71
+ Write-Host "Mode: Overwrite/Merge (Keep existing files)"
72
+ }
73
+ }
74
+
75
+ # Ensure destination directory exists (Create if deleted or not exists)
76
+ if (-not (Test-Path $dest)) {
77
+ Write-Host "Destination directory does not exist, creating: $dest"
78
+ New-Item -ItemType Directory -Force -Path $dest | Out-Null
79
+ }
80
+
81
+ # 3. Execute Copy
82
+ Write-Host "Copying files..."
83
+
84
+ try {
85
+ # Debug Info: Check Source
86
+ # Use Recurse to list all levels, check for nested directory issues
87
+ $items = Get-ChildItem -Path $source -Recurse
88
+ Write-Host "Source directory ($source) contains $($items.Count) items (subdirs/files)."
89
+ if ($items.Count -gt 0) {
90
+ Write-Host "File list preview (first 10):"
91
+ $items | Select-Object -First 10 | ForEach-Object { Write-Host " - $($_.FullName)" }
92
+ }
93
+
94
+ # Debug Info: Check Destination
95
+ Write-Host "Destination Path: $dest"
96
+ Write-Host "Destination Exists: $(Test-Path $dest)"
97
+
98
+ if ($items.Count -gt 0) {
99
+ # Use basic Copy-Item syntax, add verbose log
100
+ # Note: If source contains subdirectories, -Recurse must be added
101
+ # Ensure Destination points to a folder path
102
+ Copy-Item -Path "$source\*" -Destination $dest -Recurse -Force -ErrorAction Stop -Verbose
103
+ Write-Host "File deployment successful."
104
+ } else {
105
+ Write-Warning "Source directory is empty, no files copied."
106
+ }
107
+ } catch {
108
+ Write-Error "File copy failed: $_ "
109
+ exit 1
110
+ }
111
+ displayName: 'Deploy Application Files (Copy-Item)'
112
+ condition: ${{ parameters.runCondition }}
@@ -0,0 +1,112 @@
1
+ # ==============================================================================
2
+ # Template Name: Manage IIS Website (iis-manage-website.yml)
3
+ # Description:
4
+ # This template is responsible for creating or updating IIS Website, Application Pool (AppPool), and setting Site Bindings.
5
+ # Implemented using PowerShell (WebAdministration module) to ensure settings meet expectations.
6
+ # ==============================================================================
7
+
8
+ parameters:
9
+ # Website Name (Display name in IIS)
10
+ - name: websiteName
11
+ type: string
12
+
13
+ # Website Physical Path (Absolute path on Server)
14
+ - name: websitePhysicalPath
15
+ type: string
16
+
17
+ # Application Pool Name
18
+ - name: appPoolName
19
+ type: string
20
+
21
+ # AppPool .NET CLR Version (For .NET Core/5+, 'No Managed Code' is recommended)
22
+ - name: appPoolDotNetVersion
23
+ type: string
24
+ default: 'No Managed Code'
25
+ values:
26
+ - 'No Managed Code'
27
+ - 'v4.0'
28
+ - 'v2.0'
29
+
30
+ # Site Binding Settings (JSON List)
31
+ # Format example: '[{"type":"http","port":80,"ip":"*","hostName":"sample.local"}]'
32
+ - name: bindings
33
+ type: string
34
+ default: '[]'
35
+
36
+ # Execution Condition
37
+ - name: runCondition
38
+ type: string
39
+ default: 'succeeded()'
40
+
41
+ steps:
42
+ # ----------------------------------------------------------------------------
43
+ # Execute PowerShell script to manage IIS Website
44
+ # Includes: Create/Config AppPool, Create/Config Website, Apply Bindings
45
+ # ----------------------------------------------------------------------------
46
+ - powershell: |
47
+ $websiteName = "${{ parameters.websiteName }}"
48
+ $physicalPath = "${{ parameters.websitePhysicalPath }}"
49
+ $appPoolName = "${{ parameters.appPoolName }}"
50
+ $appPoolDotNetVersion = "${{ parameters.appPoolDotNetVersion }}"
51
+ $bindingsJson = '${{ parameters.bindings }}'
52
+
53
+ Write-Host "Managing IIS Website: $websiteName"
54
+
55
+ # Ensure WebAdministration module is loaded
56
+ Import-Module WebAdministration
57
+
58
+ # --- 1. Configure Application Pool (AppPool) ---
59
+ if (!(Test-Path "IIS:\AppPools\$appPoolName")) {
60
+ Write-Host "Creating Application Pool: $appPoolName"
61
+ New-WebAppPool -Name $appPoolName
62
+ }
63
+
64
+ # Set .NET CLR Version
65
+ # If .NET Core/5+, usually set to 'No Managed Code' (Empty string)
66
+ $runtime = if ($appPoolDotNetVersion -eq 'No Managed Code') { "" } else { $appPoolDotNetVersion }
67
+ Set-ItemProperty "IIS:\AppPools\$appPoolName" -Name "managedRuntimeVersion" -Value $runtime
68
+ Write-Host "Application Pool '$appPoolName' managed runtime version set to: '$runtime'"
69
+
70
+ # --- 2. Configure Website ---
71
+ if (!(Test-Path "IIS:\Sites\$websiteName")) {
72
+ Write-Host "Creating new website: $websiteName"
73
+ # Assign a temporary Port 80 when creating, will be overwritten by Apply Bindings logic later
74
+ New-Website -Name $websiteName -PhysicalPath $physicalPath -ApplicationPool $appPoolName -Port 80 -Force
75
+ } else {
76
+ Write-Host "Updating website settings (Physical Path and Application Pool)"
77
+ Set-ItemProperty "IIS:\Sites\$websiteName" -Name "physicalPath" -Value $physicalPath
78
+ Set-ItemProperty "IIS:\Sites\$websiteName" -Name "applicationPool" -Value $appPoolName
79
+ }
80
+
81
+ # --- 3. Apply Bindings ---
82
+ # Sync Mode: Remove all existing bindings, keep only items in JSON settings
83
+ if (-not [string]::IsNullOrWhiteSpace($bindingsJson)) {
84
+ try {
85
+ $bindings = $bindingsJson | ConvertFrom-Json
86
+
87
+ if ($bindings.Count -gt 0) {
88
+ Write-Host "Applying binding settings..."
89
+
90
+ # Remove all existing Bindings
91
+ Get-WebBinding -Name $websiteName | Remove-WebBinding
92
+
93
+ # Add defined Bindings one by one
94
+ foreach ($b in $bindings) {
95
+ $protocol = if ($b.type) { $b.type } else { "http" }
96
+ $port = if ($b.port) { $b.port } else { 80 }
97
+ $ip = if ($b.ip) { $b.ip } else { "*" }
98
+ $hostName = if ($b.hostName) { $b.hostName } else { "" }
99
+
100
+ Write-Host "Adding Binding: ${protocol}://${ip}:${port}/${hostName}"
101
+ New-WebBinding -Name $websiteName -Protocol $protocol -Port $port -IPAddress $ip -HostHeader $hostName
102
+ }
103
+ } else {
104
+ Write-Host "Binding settings list is empty, skipping update."
105
+ }
106
+ } catch {
107
+ Write-Warning "Failed to parse Bindings JSON: $_"
108
+ Write-Warning "Original JSON Content: $bindingsJson"
109
+ }
110
+ }
111
+ displayName: 'Manage IIS Website (Create/Update) - PowerShell'
112
+ condition: ${{ parameters.runCondition }}
@@ -0,0 +1,98 @@
1
+ # ==============================================================================
2
+ # Template Name: IIS Rollback (iis-rollback.yml)
3
+ # Description:
4
+ # Restore action executed when deployment fails.
5
+ # 1. Check if there is a backup file generated by this deployment (Variable _GeneratedBackupPath).
6
+ # 2. If backup exists, restore files to website physical path.
7
+ # 3. Ensure IIS services (WAS, W3SVC) are running.
8
+ # 4. Restart IIS Website.
9
+ # ==============================================================================
10
+
11
+ parameters:
12
+ - name: websiteName
13
+ type: string
14
+ - name: websitePhysicalPath
15
+ type: string
16
+ - name: runCondition
17
+ type: string
18
+ default: 'failed()'
19
+
20
+ steps:
21
+ - powershell: |
22
+ $websiteName = "${{ parameters.websiteName }}"
23
+ $dest = "${{ parameters.websitePhysicalPath }}"
24
+ $backupZip = $env:_GeneratedBackupPath
25
+
26
+ Write-Host "Starting Rollback Process..."
27
+ Write-Host "Website Name: $websiteName"
28
+
29
+ # --- 1. Restore Files ---
30
+ if (-not [string]::IsNullOrWhiteSpace($backupZip) -and (Test-Path $backupZip)) {
31
+ Write-Host "Detected backup file: $backupZip"
32
+ Write-Host "Restoring to: $dest"
33
+
34
+ # Ensure destination directory exists
35
+ if (-not (Test-Path $dest)) {
36
+ New-Item -ItemType Directory -Force -Path $dest | Out-Null
37
+ }
38
+
39
+ # Extract and overwrite
40
+ try {
41
+ Expand-Archive -Path $backupZip -DestinationPath $dest -Force -ErrorAction Stop
42
+ Write-Host "Files restored successfully."
43
+ } catch {
44
+ Write-Error "Restore failed: $_"
45
+ # Continue attempting to start website even if restore fails
46
+ }
47
+ } else {
48
+ Write-Host "No backup file detected from this run (possibly failed before backup step), skipping file restore."
49
+ }
50
+
51
+ # --- 2. Start Website ---
52
+
53
+ function Ensure-Service-Running {
54
+ param($Name)
55
+ try {
56
+ $svc = Get-Service -Name $Name -ErrorAction Stop
57
+ if ($svc.Status -ne 'Running') {
58
+ Write-Warning "Service '$Name' is not running. Starting..."
59
+ Start-Service -Name $Name
60
+
61
+ # Wait for start
62
+ $timeout = 15
63
+ $timer = [System.Diagnostics.Stopwatch]::StartNew()
64
+ while ($svc.Status -ne 'Running' -and $timer.Elapsed.TotalSeconds -lt $timeout) {
65
+ Start-Sleep -Seconds 1
66
+ $svc.Refresh()
67
+ }
68
+ }
69
+ } catch {
70
+ Write-Warning "Check service '$Name' exception: $_"
71
+ }
72
+ }
73
+
74
+ function Start-Site-WithAppCmd {
75
+ param($Name)
76
+ $appCmd = "$env:systemroot\system32\inetsrv\appcmd.exe"
77
+ if (Test-Path $appCmd) {
78
+ Start-Process -FilePath $appCmd -ArgumentList "start site /site.name:`"$Name`"" -Wait -NoNewWindow
79
+ }
80
+ }
81
+
82
+ # Ensure Core Services
83
+ Ensure-Service-Running -Name "WAS"
84
+ Ensure-Service-Running -Name "W3SVC"
85
+
86
+ # Start Website
87
+ try {
88
+ Import-Module WebAdministration
89
+ Start-Website -Name $websiteName -ErrorAction Stop
90
+ Write-Host "Website '$websiteName' restarted."
91
+ } catch {
92
+ Write-Warning "PowerShell start failed, trying appcmd..."
93
+ Start-Site-WithAppCmd -Name $websiteName
94
+ }
95
+
96
+ displayName: 'Execute Rollback (Restore and Restart)'
97
+ # Execute only if previous steps failed AND deployment process was confirmed started (Variable _IISDeploymentStarted = true)
98
+ condition: ${{ parameters.runCondition }}
@@ -0,0 +1,89 @@
1
+ # ==============================================================================
2
+ # Template Name: Start IIS Website (iis-start-website.yml)
3
+ # Description:
4
+ # This template is responsible for safely starting the specified IIS website.
5
+ # Includes self-check and repair mechanism:
6
+ # 1. First check WAS and W3SVC service status, try to start if not running.
7
+ # 2. Prioritize using PowerShell to start the website.
8
+ # 3. If PowerShell fails (e.g. RPC error), automatically downgrade to use appcmd.exe to force start.
9
+ # ==============================================================================
10
+
11
+ parameters:
12
+ # Website Name (Display name in IIS)
13
+ - name: websiteName
14
+ type: string
15
+
16
+ # Execution Condition
17
+ - name: runCondition
18
+ type: string
19
+ default: 'always()'
20
+
21
+ steps:
22
+ # ----------------------------------------------------------------------------
23
+ # Execute PowerShell script to start IIS Website
24
+ # ----------------------------------------------------------------------------
25
+ - powershell: |
26
+ $websiteName = "${{ parameters.websiteName }}"
27
+ Write-Host "Attempting to start website: $websiteName"
28
+
29
+ function Ensure-Service-Running {
30
+ param($Name)
31
+ try {
32
+ $svc = Get-Service -Name $Name -ErrorAction Stop
33
+ if ($svc.Status -ne 'Running') {
34
+ Write-Warning "Service '$Name' is not running (Current Status: $($svc.Status)). Starting..."
35
+ Start-Service -Name $Name
36
+
37
+ # Wait for service start (Max 15 seconds)
38
+ $timeout = 15
39
+ $timer = [System.Diagnostics.Stopwatch]::StartNew()
40
+ while ($svc.Status -ne 'Running' -and $timer.Elapsed.TotalSeconds -lt $timeout) {
41
+ Start-Sleep -Seconds 1
42
+ $svc.Refresh()
43
+ }
44
+
45
+ if ($svc.Status -eq 'Running') {
46
+ Write-Host "Service '$Name' started successfully."
47
+ } else {
48
+ Write-Error "Unable to start service '$Name' (Timeout or Failed)."
49
+ }
50
+ }
51
+ } catch {
52
+ Write-Warning "Exception occurred while checking service '$Name': $_"
53
+ }
54
+ }
55
+
56
+ function Start-Site-WithAppCmd {
57
+ param($Name)
58
+ Write-Host "Attempting to start website using appcmd.exe..."
59
+ $appCmd = "$env:systemroot\system32\inetsrv\appcmd.exe"
60
+ if (Test-Path $appCmd) {
61
+ $p = Start-Process -FilePath $appCmd -ArgumentList "start site /site.name:`"$Name`"" -Wait -PassThru -NoNewWindow
62
+ if ($p.ExitCode -eq 0) {
63
+ Write-Host "appcmd: Website started."
64
+ } else {
65
+ Write-Error "appcmd failed to start website (Exit Code: $($p.ExitCode))."
66
+ exit 1
67
+ }
68
+ } else {
69
+ Write-Error "appcmd.exe not found."
70
+ exit 1
71
+ }
72
+ }
73
+
74
+ # 1. Ensure IIS Core Services (WAS, W3SVC) are functioning
75
+ # This is key to solving "RPC server is unavailable"
76
+ Ensure-Service-Running -Name "WAS"
77
+ Ensure-Service-Running -Name "W3SVC"
78
+
79
+ # 2. Attempt to start website
80
+ try {
81
+ Import-Module WebAdministration
82
+ Start-Website -Name $websiteName -ErrorAction Stop
83
+ Write-Host "Website '$websiteName' started successfully (PowerShell)."
84
+ } catch {
85
+ Write-Warning "Failed to start website using PowerShell: $_"
86
+ Start-Site-WithAppCmd -Name $websiteName
87
+ }
88
+ displayName: 'Start IIS Website'
89
+ condition: ${{ parameters.runCondition }}
@@ -0,0 +1,80 @@
1
+ # ==============================================================================
2
+ # Template Name: Stop IIS Website (iis-stop-website.yml)
3
+ # Description:
4
+ # This template is responsible for safely stopping the specified IIS website.
5
+ # Includes error handling mechanism: Prioritize using PowerShell, if fails (e.g. RPC error), automatically downgrade to use appcmd.exe to force stop.
6
+ # ==============================================================================
7
+
8
+ parameters:
9
+ # Website Name (Display name in IIS)
10
+ - name: websiteName
11
+ type: string
12
+
13
+ # Execution Condition
14
+ - name: runCondition
15
+ type: string
16
+ default: 'succeeded()'
17
+
18
+ steps:
19
+ # ----------------------------------------------------------------------------
20
+ # Execute PowerShell script to stop IIS Website
21
+ # ----------------------------------------------------------------------------
22
+ - powershell: |
23
+ $websiteName = "${{ parameters.websiteName }}"
24
+ Write-Host "Attempting to stop website: $websiteName"
25
+
26
+ if ([string]::IsNullOrWhiteSpace($websiteName)) {
27
+ Write-Error "Website name is empty."
28
+ exit 1
29
+ }
30
+
31
+ function Stop-Site-WithAppCmd {
32
+ param($Name)
33
+ Write-Host "Attempting to stop website using appcmd.exe..."
34
+ $appCmd = "$env:systemroot\system32\inetsrv\appcmd.exe"
35
+ if (Test-Path $appCmd) {
36
+ # Stop using appcmd, ignore possible errors (e.g. website already stopped)
37
+ $p = Start-Process -FilePath $appCmd -ArgumentList "stop site /site.name:`"$Name`"" -Wait -PassThru -NoNewWindow
38
+ if ($p.ExitCode -eq 0) {
39
+ Write-Host "appcmd: Website stopped."
40
+ } else {
41
+ Write-Warning "appcmd completed, Exit Code: $($p.ExitCode) (This is expected behavior if website was already stopped)."
42
+ }
43
+ } else {
44
+ Write-Error "appcmd.exe not found."
45
+ exit 1
46
+ }
47
+ }
48
+
49
+ try {
50
+ Import-Module WebAdministration
51
+ # Attempt to get website status
52
+ $site = Get-Website -Name $websiteName -ErrorAction Stop
53
+
54
+ if ($site) {
55
+ if ($site.State -eq "Stopped") {
56
+ Write-Host "Website '$websiteName' is already in stopped state."
57
+ } else {
58
+ Write-Host "Website current state: $($site.State). Stopping..."
59
+ Stop-Website -Name $websiteName -ErrorAction Stop
60
+ Write-Host "Website '$websiteName' stopped successfully."
61
+ }
62
+ } else {
63
+ Write-Host "Website '$websiteName' does not exist, skipping stop action."
64
+ }
65
+ } catch {
66
+ Write-Warning "Error occurred while managing website using PowerShell (Possible RPC service abnormality): $_"
67
+
68
+ # Check if error is caused by W3SVC service not running
69
+ $w3svc = Get-Service -Name "W3SVC" -ErrorAction SilentlyContinue
70
+ if ($w3svc -and $w3svc.Status -ne 'Running') {
71
+ Write-Host "Detected W3SVC (World Wide Web Publishing Service) is not running (Status: $($w3svc.Status))."
72
+ Write-Host "Website is naturally in stopped state as IIS service is not running. Skipping stop action."
73
+ exit 0
74
+ }
75
+
76
+ # Other errors occurred, try using appcmd
77
+ Stop-Site-WithAppCmd -Name $websiteName
78
+ }
79
+ displayName: 'Stop IIS Website'
80
+ condition: ${{ parameters.runCondition }}
@@ -0,0 +1,157 @@
1
+ # ==============================================================================
2
+ # Template Name: IIS Task Scheduler (iis-task.yml)
3
+ # Description:
4
+ # This is a unified interface (Facade) for calling various IIS related sub-tasks.
5
+ # Determines the specific action to execute by passing the `command` parameter.
6
+ #
7
+ # Supported Commands (command):
8
+ # - manage: Create or update website and AppPool (iis-manage-website.yml)
9
+ # - start: Start website (iis-start-website.yml)
10
+ # - stop: Stop website (iis-stop-website.yml)
11
+ # - backup: Backup website files (iis-backup.yml)
12
+ # - deploy: Deploy files (iis-deploy-files.yml)
13
+ # - rollback: Restore backup and restart (iis-rollback.yml)
14
+ # ==============================================================================
15
+
16
+ parameters:
17
+ # Specify the task command to execute
18
+ - name: command
19
+ type: string
20
+ values:
21
+ - manage
22
+ - start
23
+ - stop
24
+ - backup
25
+ - deploy
26
+ - rollback
27
+
28
+ # --- Common/Shared Parameters ---
29
+ # Website Name (Used by manage, start, stop, rollback)
30
+ - name: websiteName
31
+ type: string
32
+ default: ''
33
+
34
+ # Website Physical Path (Used by manage, backup, deploy, rollback)
35
+ - name: websitePhysicalPath
36
+ type: string
37
+ default: ''
38
+
39
+ # Execution Condition (Default is empty string, will be automatically filled based on default behavior of each command)
40
+ - name: runCondition
41
+ type: string
42
+ default: ''
43
+
44
+ # --- Manage Specific Parameters ---
45
+ # Application Pool Name
46
+ - name: appPoolName
47
+ type: string
48
+ default: ''
49
+
50
+ # AppPool .NET CLR Version
51
+ - name: appPoolDotNetVersion
52
+ type: string
53
+ default: 'No Managed Code'
54
+
55
+ # Site Binding Settings (JSON List)
56
+ - name: bindings
57
+ type: string
58
+ default: '[]'
59
+
60
+ # --- Backup Specific Parameters ---
61
+ # Backup Storage Path
62
+ - name: backupPath
63
+ type: string
64
+ default: ''
65
+
66
+ # Backup Retention Count
67
+ - name: backupRetentionCount
68
+ type: number
69
+ default: 5
70
+
71
+ # --- Deploy Specific Parameters ---
72
+ # Source Path (Artifact)
73
+ - name: sourcePath
74
+ type: string
75
+ default: ''
76
+
77
+ # Destination Path (If not specified, defaults to websitePhysicalPath)
78
+ - name: destinationPath
79
+ type: string
80
+ default: ''
81
+
82
+ # Whether to clean destination
83
+ - name: cleanDestination
84
+ type: boolean
85
+ default: true
86
+
87
+ steps:
88
+
89
+ # ----------------------------------------------------------------------------
90
+ # Command: manage
91
+ # ----------------------------------------------------------------------------
92
+ - ${{ if eq(parameters.command, 'manage') }}:
93
+ - template: iis-manage-website.yml
94
+ parameters:
95
+ websiteName: ${{ parameters.websiteName }}
96
+ websitePhysicalPath: ${{ parameters.websitePhysicalPath }}
97
+ appPoolName: ${{ parameters.appPoolName }}
98
+ appPoolDotNetVersion: ${{ parameters.appPoolDotNetVersion }}
99
+ bindings: ${{ parameters.bindings }}
100
+ # Default: succeeded()
101
+ runCondition: ${{ coalesce(parameters.runCondition, 'succeeded()') }}
102
+
103
+ # ----------------------------------------------------------------------------
104
+ # Command: start
105
+ # ----------------------------------------------------------------------------
106
+ - ${{ if eq(parameters.command, 'start') }}:
107
+ - template: iis-start-website.yml
108
+ parameters:
109
+ websiteName: ${{ parameters.websiteName }}
110
+ # Default: always() (Ensure restart attempt even if deployment failed, or adjust as needed)
111
+ runCondition: ${{ coalesce(parameters.runCondition, 'always()') }}
112
+
113
+ # ----------------------------------------------------------------------------
114
+ # Command: stop
115
+ # ----------------------------------------------------------------------------
116
+ - ${{ if eq(parameters.command, 'stop') }}:
117
+ - template: iis-stop-website.yml
118
+ parameters:
119
+ websiteName: ${{ parameters.websiteName }}
120
+ # Default: succeeded()
121
+ runCondition: ${{ coalesce(parameters.runCondition, 'succeeded()') }}
122
+
123
+ # ----------------------------------------------------------------------------
124
+ # Command: backup
125
+ # ----------------------------------------------------------------------------
126
+ - ${{ if eq(parameters.command, 'backup') }}:
127
+ - template: iis-backup.yml
128
+ parameters:
129
+ websitePhysicalPath: ${{ parameters.websitePhysicalPath }}
130
+ backupPath: ${{ parameters.backupPath }}
131
+ backupRetentionCount: ${{ parameters.backupRetentionCount }}
132
+ # Default: succeeded()
133
+ runCondition: ${{ coalesce(parameters.runCondition, 'succeeded()') }}
134
+
135
+ # ----------------------------------------------------------------------------
136
+ # Command: deploy
137
+ # ----------------------------------------------------------------------------
138
+ - ${{ if eq(parameters.command, 'deploy') }}:
139
+ - template: iis-deploy-files.yml
140
+ parameters:
141
+ sourcePath: ${{ parameters.sourcePath }}
142
+ # If destinationPath is empty, use websitePhysicalPath
143
+ destinationPath: ${{ coalesce(parameters.destinationPath, parameters.websitePhysicalPath) }}
144
+ cleanDestination: ${{ parameters.cleanDestination }}
145
+ # Default: succeeded()
146
+ runCondition: ${{ coalesce(parameters.runCondition, 'succeeded()') }}
147
+
148
+ # ----------------------------------------------------------------------------
149
+ # Command: rollback
150
+ # ----------------------------------------------------------------------------
151
+ - ${{ if eq(parameters.command, 'rollback') }}:
152
+ - template: iis-rollback.yml
153
+ parameters:
154
+ websiteName: ${{ parameters.websiteName }}
155
+ websitePhysicalPath: ${{ parameters.websitePhysicalPath }}
156
+ # Default: failed() (Execute only on failure)
157
+ runCondition: ${{ coalesce(parameters.runCondition, 'failed()') }}