temp #92
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| push: | |
| branches: | |
| - main | |
| workflow_dispatch: | |
| inputs: | |
| release_type: | |
| description: 'Release type (major, minor, patch)' | |
| required: false | |
| type: choice | |
| options: | |
| - auto | |
| - major | |
| - minor | |
| - patch | |
| default: auto | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| security-events: write | |
| jobs: | |
| check-syntax-validation: | |
| name: Wait for Syntax Validation | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Wait for syntax validation to complete | |
| uses: lewagon/wait-on-check-action@v1.3.4 | |
| with: | |
| ref: ${{ github.sha }} | |
| check-name: 'PowerShell Syntax Validation' | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| wait-interval: 10 | |
| - name: Check syntax validation status | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const checks = await github.rest.checks.listForRef({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| ref: context.sha, | |
| check_name: 'PowerShell Syntax Validation' | |
| }); | |
| const syntaxCheck = checks.data.check_runs[0]; | |
| if (!syntaxCheck || syntaxCheck.conclusion !== 'success') { | |
| core.setFailed('Syntax validation must pass before releasing'); | |
| } | |
| check-integration-tests: | |
| name: Check Integration Tests Status | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check last integration test run | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const runs = await github.rest.actions.listWorkflowRuns({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| workflow_id: 'integration-tests.yml', | |
| per_page: 1, | |
| status: 'completed' | |
| }); | |
| if (runs.data.workflow_runs.length === 0) { | |
| core.setFailed('No completed integration test runs found. Run integration tests manually first.'); | |
| return; | |
| } | |
| const lastRun = runs.data.workflow_runs[0]; | |
| console.log(`Last integration test run: ${lastRun.html_url}`); | |
| console.log(`Status: ${lastRun.conclusion}`); | |
| console.log(`Completed: ${lastRun.updated_at}`); | |
| if (lastRun.conclusion !== 'success') { | |
| core.setFailed(`Last integration test run failed. Please fix and re-run integration tests before releasing.\nRun URL: ${lastRun.html_url}`); | |
| } else { | |
| console.log('✅ Integration tests passed'); | |
| } | |
| validate: | |
| name: Run Validation Checks | |
| needs: [check-syntax-validation, check-integration-tests] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install shellcheck | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y shellcheck | |
| - name: Validate bash scripts | |
| run: | | |
| find ./scripts/wsl -name "*.sh" -type f -exec bash -n {} \; | |
| find ./scripts/wsl -name "*.sh" -type f -exec shellcheck {} \; | |
| - name: Setup PowerShell | |
| shell: pwsh | |
| run: | | |
| Write-Host "PowerShell $($PSVersionTable.PSVersion)" | |
| - name: Validate PowerShell scripts | |
| shell: pwsh | |
| run: | | |
| $scripts = Get-ChildItem -Path ./scripts -Filter *.ps1 -Recurse | |
| $failed = $false | |
| $errors = @() | |
| foreach ($script in $scripts) { | |
| Write-Host "Validating $($script.Name)..." | |
| try { | |
| $parseErrors = $null | |
| $null = [System.Management.Automation.PSParser]::Tokenize( | |
| (Get-Content $script.FullName -Raw), | |
| [ref]$parseErrors | |
| ) | |
| if ($parseErrors.Count -gt 0) { | |
| $failed = $true | |
| $errors += "$($script.Name) has parse errors:" | |
| foreach ($err in $parseErrors) { | |
| $errors += " Line $($err.Token.StartLine): $($err.Message)" | |
| } | |
| } | |
| } catch { | |
| $failed = $true | |
| $errors += "$($script.Name) failed: $_" | |
| } | |
| } | |
| if ($failed) { | |
| $errors | ForEach-Object { Write-Host $_ } | |
| throw "PowerShell script validation failed" | |
| } | |
| Write-Host "✓ All scripts validated successfully" | |
| - name: Run Trivy security scan | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| scan-type: 'fs' | |
| scan-ref: '.' | |
| format: 'sarif' | |
| output: 'trivy-results.sarif' | |
| severity: 'CRITICAL,HIGH' | |
| - name: Upload Trivy results | |
| uses: github/codeql-action/upload-sarif@v3 | |
| with: | |
| sarif_file: 'trivy-results.sarif' | |
| release: | |
| name: Create Release | |
| needs: [validate] | |
| runs-on: windows-latest | |
| if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/main') | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Install semantic-release | |
| shell: pwsh | |
| run: | | |
| npm install -g semantic-release@23 ` | |
| @semantic-release/changelog@6 ` | |
| @semantic-release/git@10 ` | |
| @semantic-release/github@10 ` | |
| conventional-changelog-conventionalcommits@7 | |
| - name: Configure Git | |
| shell: pwsh | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| - name: Prepare release artifacts | |
| shell: pwsh | |
| run: | | |
| New-Item -ItemType Directory -Force -Path release-artifacts | |
| # Ensure we're using PowerShell 7+ with better ZIP support | |
| $PSVersionTable.PSVersion | |
| # Use generic naming - semantic-release will rename when uploading | |
| $version = "latest" | |
| # Create Windows scripts archive | |
| $windowsFiles = @( | |
| Get-ChildItem -Path "scripts/windows" -Filter "*.ps1" | |
| Get-Item -Path "setup-machine.ps1" | |
| Get-Item -Path "README.md" | |
| Get-Item -Path "LICENSE" | |
| ) | |
| Compress-Archive -LiteralPath $windowsFiles.FullName ` | |
| -DestinationPath "release-artifacts/devMachine-windows-scripts-$version.zip" ` | |
| -CompressionLevel Optimal -Force | |
| # Create WSL scripts archive | |
| $wslFiles = @( | |
| Get-ChildItem -Path "scripts/wsl" -Filter "*.sh" | |
| Get-Item -Path "README.md" | |
| Get-Item -Path "LICENSE" | |
| ) | |
| Compress-Archive -LiteralPath $wslFiles.FullName ` | |
| -DestinationPath "release-artifacts/devMachine-wsl-scripts-$version.zip" ` | |
| -CompressionLevel Optimal -Force | |
| # Create complete archive with proper structure | |
| $completeFiles = @( | |
| "scripts" | |
| "tests" | |
| "setup-machine.ps1" | |
| "README.md" | |
| "LICENSE" | |
| "SECURITY.md" | |
| "CONTRIBUTING.md" | |
| "CODE_OF_CONDUCT.md" | |
| "CHANGELOG.md" | |
| ) | |
| Compress-Archive -Path $completeFiles ` | |
| -DestinationPath "release-artifacts/devMachine-complete-$version.zip" ` | |
| -CompressionLevel Optimal -Force | |
| # Generate checksums | |
| Set-Location release-artifacts | |
| Get-ChildItem -Filter *.zip | ForEach-Object { | |
| $hash = (Get-FileHash $_.Name -Algorithm SHA256).Hash | |
| "$hash $($_.Name)" | Out-File -Append -Encoding utf8 "checksums-$version.txt" | |
| } | |
| - name: Run semantic-release | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| shell: pwsh | |
| run: npx semantic-release | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: release-artifacts | |
| path: release-artifacts/ | |
| retention-days: 90 |