diff --git a/.github/workflows/Check-pull-request-source-branch.yml b/.github/workflows/Check-pull-request-source-branch.yml deleted file mode 100644 index 1d6bc9a1..00000000 --- a/.github/workflows/Check-pull-request-source-branch.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Check pull request source branch - -on: - pull_request_target: - types: - - opened - - reopened - - synchronize - - edited - -jobs: - check-branches: - runs-on: ubuntu-latest - steps: - - name: Check branches - run: | - if [ "${{ github.head_ref }}" != "develop" ] && [ "${{ github.base_ref }}" == "main" ]; then - echo "Error: Pull requests to the main branch are only allowed from the develop branch. Please submit your pull request to the develop branch." - exit 1 - fi \ No newline at end of file diff --git a/.github/workflows/CloseInactiveIssues.yml b/.github/workflows/GA_Close-Inactive-Issues.yml similarity index 100% rename from .github/workflows/CloseInactiveIssues.yml rename to .github/workflows/GA_Close-Inactive-Issues.yml diff --git a/.github/workflows/mega-linter.yml b/.github/workflows/GA_Mega-linter.yml similarity index 100% rename from .github/workflows/mega-linter.yml rename to .github/workflows/GA_Mega-linter.yml diff --git a/.github/workflows/GitFlow_Check-pull-request-source-branch.yml b/.github/workflows/GitFlow_Check-pull-request-source-branch.yml new file mode 100644 index 00000000..38a49704 --- /dev/null +++ b/.github/workflows/GitFlow_Check-pull-request-source-branch.yml @@ -0,0 +1,183 @@ +# This workflow enforces GitFlow branch patterns by: +# - Ensuring only hotfix/* branches can target main (release branches are handled automatically) +# - Adding labels and comments to non-compliant PRs +# - Automatically cleaning up when PRs are updated to comply + +name: GitFlow | Check PR Branch Pattern + +on: + pull_request_target: + types: + - opened + - reopened + - synchronize + - edited + +# Add explicit permissions +permissions: + pull-requests: write + issues: write + contents: read + +env: + MAIN_BRANCH: "main" + DEVELOP_BRANCH: "develop" + VALID_PATTERNS: "^(release|hotfix)/" + LABEL_NAME: "invalid-branch" + ERROR_MESSAGE_IDENTIFIER: "Invalid Branch Pattern for main Branch" + +jobs: + check_branch: + runs-on: ubuntu-latest + steps: + # Step 1: Use GitHub Script for branch pattern validation (safer than shell) + - name: Check branch pattern + id: branch_check + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + result-encoding: string + script: | + // Get branch information from context + const headRef = context.payload.pull_request.head.ref; + const baseRef = context.payload.pull_request.base.ref; + const mainBranch = process.env.MAIN_BRANCH; + const validPattern = new RegExp(process.env.VALID_PATTERNS); + + console.log(`Checking PR from '${headRef}' to '${baseRef}'`); + + // Perform the validation in JavaScript instead of shell + if (baseRef === mainBranch) { + if (!validPattern.test(headRef)) { + console.log(`::error::❌ Invalid branch! PRs to main must come from hotfix/* or release/* branches. Please target the develop branch instead.`); + return 'invalid'; + } else { + console.log(`::notice::✅ Branch pattern is valid: '${headRef}' → '${mainBranch}'`); + return 'valid'; + } + } else { + console.log(`::notice::✅ Not targeting main branch, no pattern restrictions apply.`); + return 'not-main'; + } + + # Step 2: If the branch pattern is invalid, add a label and comment to the PR + - name: Handle invalid branch (label + comment) + if: steps.branch_check.outputs.result == 'invalid' + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { owner, repo } = context.repo; + const issue_number = context.payload.pull_request.number; + const label = process.env.LABEL_NAME; + const messageIdentifier = process.env.ERROR_MESSAGE_IDENTIFIER; + + // Escape special characters in the message identifier for safer comparisons + const escapedMessageIdentifier = messageIdentifier.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + + const message = `❌ **${messageIdentifier}** + + According to our GitFlow workflow: + - Pull requests to the \`main\` branch are only allowed from \`hotfix/*\` branches + - Regular feature development and other changes should target the \`develop\` branch + + 📝 **Action required:** Please update your PR to target the \`develop\` branch instead. + + For more details about our contribution workflow, please refer to our [CONTRIBUTING.md](https://github.com/${owner}/${repo}/blob/main/CONTRIBUTING.md) guide.`; + + // First step: Always apply the label + console.log("Adding invalid-branch label to PR"); + try { + await github.rest.issues.addLabels({ + owner, + repo, + issue_number, + labels: [label] + }); + } catch (e) { + // In case label already exists or other error + console.log(`Note: Could not add label: ${e.message}`); + } + + // Second step: Add comment if it doesn't exist + const { data: comments } = await github.rest.issues.listComments({ + owner, + repo, + issue_number + }); + + // Use regex test instead of includes for safer comparison + const commentExists = comments.some(comment => + comment.body && new RegExp(escapedMessageIdentifier).test(comment.body) + ); + + if (!commentExists) { + console.log("Adding comment to PR"); + await github.rest.issues.createComment({ + owner, + repo, + issue_number, + body: message + }); + } else { + console.log("Comment already exists, skipping"); + } + + # Step 3: If the branch pattern is corrected, remove label and comment + - name: Clean up if branch is corrected + if: steps.branch_check.outputs.result == 'valid' || steps.branch_check.outputs.result == 'not-main' + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const { owner, repo } = context.repo; + const issue_number = context.payload.pull_request.number; + const label = process.env.LABEL_NAME; + const messageIdentifier = process.env.ERROR_MESSAGE_IDENTIFIER; + + // Escape special characters in the message identifier + const escapedMessageIdentifier = messageIdentifier.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const messageRegex = new RegExp(escapedMessageIdentifier); + + try { + // Check if the label is present and remove it + const { data: labels } = await github.rest.issues.listLabelsOnIssue({ + owner, + repo, + issue_number + }); + + if (labels.some(l => l.name === label)) { + console.log("Removing invalid-branch label from PR"); + await github.rest.issues.removeLabel({ + owner, + repo, + issue_number, + name: label + }); + } else { + console.log("No label to remove"); + } + + // Check existing comments and remove any invalid branch comments + const { data: comments } = await github.rest.issues.listComments({ + owner, + repo, + issue_number + }); + + // Find and delete any invalid branch comment + for (const comment of comments) { + // Use regex test instead of includes for safer comparison + if (comment.body && messageRegex.test(comment.body)) { + console.log(`Deleting comment ID: ${comment.id}`); + await github.rest.issues.deleteComment({ + owner, + repo, + comment_id: comment.id + }); + } + } + } catch (error) { + console.log(`Error in cleanup: ${error}`); + } \ No newline at end of file diff --git a/.github/workflows/GitFlow_Create-Release-Branch-and-PR.yaml b/.github/workflows/GitFlow_Create-Release-Branch-and-PR.yaml new file mode 100644 index 00000000..36ed1c39 --- /dev/null +++ b/.github/workflows/GitFlow_Create-Release-Branch-and-PR.yaml @@ -0,0 +1,71 @@ +# This workflow implements the GitFlow release creation process: +# - Creates a new release branch from develop +# - Increments version according to semantic versioning +# - Creates a pull request targeting main branch +# - This enables final testing before the actual release is created + +name: GitFlow | Create Release Branch and PR + +on: + # Manual trigger with version selection + workflow_dispatch: + inputs: + version: + type: choice + default: "Minor" + description: Select next release type + options: + - Patch # For bug fixes (x.y.Z) + - Minor # For new features (x.Y.z) + - Major # For breaking changes (X.y.z) + required: true + +jobs: + create-release: + runs-on: ubuntu-latest + steps: + # Step 1: Calculate the next version number based on the selected increment type + - name: Auto Increment Semver Action + uses: MCKanpolat/auto-semver-action@5003b8d37f4b03d95f15303ea10242cbf7c13141 # 2 + id: versioning + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + incrementPerCommit: false + releaseType: ${{ github.event.inputs.version }} + + # Step 2: Checkout the develop branch which contains all approved features + - name: Checkout code + uses: actions/checkout@v4.2.2 + with: + ref: develop # Always create releases from develop branch + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + # Step 3: Create a new release branch following GitFlow naming convention + - name: Create release branch + run: | + # Configure Git with GitHub Actions identity + git config --global user.name "GitHub Actions" + git config --global user.email "actions@github.com" + + # Create a new branch with the pattern release/X.Y.Z + git checkout -b release/${{ steps.versioning.outputs.version }} + + # Push the branch to remote repository + git push origin release/${{ steps.versioning.outputs.version }} + echo "Release Branch: release/${{ steps.versioning.outputs.version }}" + + # Step 4: Create a pull request from release branch to main + - name: Create Pull Request with GitHub CLI + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # Use GitHub CLI to create a properly formatted Pull Request + gh pr create \ + --base main \ + --head release/${{ steps.versioning.outputs.version }} \ + --title "Release ${{ steps.versioning.outputs.version }}" \ + --label "release" \ + --body "# Release ${{ steps.versioning.outputs.version }} + + This PR is automatically created to perform the final tests and validations before the release is created." \ No newline at end of file diff --git a/.github/workflows/GitFlow_Make-Release-and-Sync-to-Dev.yml b/.github/workflows/GitFlow_Make-Release-and-Sync-to-Dev.yml new file mode 100644 index 00000000..b14710c1 --- /dev/null +++ b/.github/workflows/GitFlow_Make-Release-and-Sync-to-Dev.yml @@ -0,0 +1,150 @@ +# This workflow completes the GitFlow release process: +# - Triggers automatically when a PR from release/* or hotfix/* to main is merged +# - Extracts version number from branch name +# - Builds stable release artifacts (not nightly builds) +# - Creates GitHub release with download stats +# - Synchronizes develop branch with main to maintain GitFlow integrity + +name: GitFlow | Make Release and resync to develop + +on: + # Trigger when PRs to main are closed (merged or not) + pull_request: + types: [closed] + branches: + - main + +permissions: + contents: write + pull-requests: read + +jobs: + build: + name: Create Release + # Run only when PR is merged (not just closed) and source branch is release/* or hotfix/* + if: github.event.pull_request.merged == true && (startsWith(github.event.pull_request.head.ref, 'release/') || startsWith(github.event.pull_request.head.ref, 'hotfix/')) + runs-on: windows-latest + steps: + # Step 1: Checkout the code from the main branch after merge + - name: Checkout code + uses: actions/checkout@v4.2.2 + with: + lfs: "true" + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + # Step 2: Extract version from branch name and calculate build number + - name: Get final Release Version + id: release_version + shell: bash + run: | + # Extract version from branch name if it's a release branch + if [[ "${{ github.event.pull_request.head.ref }}" =~ ^release/ ]]; then + VERSION=$(echo "${{ github.event.pull_request.head.ref }}" | sed -E 's/^release\///') + echo "Version extracted from release branch: $VERSION" + else + # Fetch the latest stable version for hotfix + LATEST_TAG=$(git tag -l --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -n 1) + echo "Latest stable version: $LATEST_TAG" + # Calculate the new hotfix version by incrementing patch number + IFS='.' read -r -a version_parts <<< "${LATEST_TAG/v/}" + PATCH=$((version_parts[2] + 1)) + VERSION="${version_parts[0]}.${version_parts[1]}.$PATCH" + echo "Version generated for hotfix: $VERSION" + fi + # Get the commit count and apply modulo 65535 (MSI version component limit) + commit_count=$(git rev-list --count HEAD) + commit_count_mod=$((commit_count % 65535)) + NEW_VERSION="$VERSION.$commit_count_mod" + echo "Final version: $NEW_VERSION" + echo "newversion=$NEW_VERSION" >> $GITHUB_OUTPUT + echo "version=$VERSION" >> $GITHUB_OUTPUT + + # Step 3: Build all project artifacts for the stable release + - name: Build project + id: build_project + shell: powershell + run: | + # Download and install Microsoft Deployment Toolkit + echo "### Get MDT from Microsoft ###" + wget https://download.microsoft.com/download/3/3/9/339BE62D-B4B8-4956-B58D-73C4685FC492/MicrosoftDeploymentToolkit_x64.msi -UseBasicParsing -OutFile .\MicrosoftDeploymentToolkit_x64.msi + Start-Process .\MicrosoftDeploymentToolkit_x64.msi -ArgumentList "/quiet /norestart" -Wait + + # Extract ServiceUI for elevated notifications + echo "### Copy ServiceUI.exe x64 to 'Sources\Winget-AutoUpdate' folder ###" + Copy-Item -Path "C:\Program Files\Microsoft Deployment Toolkit\Templates\Distribution\Tools\x64\ServiceUI.exe" -Destination ".\Sources\Winget-AutoUpdate\ServiceUI.exe" -Force + Get-Item .\Sources\Winget-AutoUpdate\* + + # Install WiX tools for MSI creation + echo "### Install WiX ###" + dotnet new console + dotnet tool install --global wix --version 5.0.1 + wix extension add WixToolset.UI.wixext/5.0.1 -g + wix extension add WixToolset.Util.wixext/5.0.1 -g + + # Build MSI package with STABLE flag + echo "### Create WAU msi ###" + cd .\Sources\Wix\ + wix build -src build.wxs -ext WixToolset.Util.wixext -ext WixToolset.UI.wixext -out ..\..\WAU.msi -arch x64 -d Version=${{ steps.release_version.outputs.newversion }} -d NextSemVer=${{ steps.release_version.outputs.newversion }} -d Comment="STABLE" -d PreRelease=0 + cd ..\.. + Get-Item .\WAU.msi + + # Calculate MSI file hash for verification + echo "### Get MSI file SHA ###" + $MsiSHA = (Get-FileHash .\WAU.msi).hash + echo " - WAU.msi SHA256: $MsiSHA" + echo "msi_sha=$MsiSHA" >> $env:GITHUB_OUTPUT + + # Package ADMX policy templates + echo "### Zip ADMX ###" + Compress-Archive -Path .\Sources\Policies\ADMX -DestinationPath .\WAU_ADMX.zip -Force + Get-Item .\*.zip + + # Calculate ADMX package hash for verification + echo "### Get ADMX zip SHA ###" + $ADMXSHA = (Get-FileHash .\WAU_ADMX.zip).hash + echo " - WAU_ADMX.zip SHA256: $ADMXSHA" + echo "admx_sha=$ADMXSHA" >> $env:GITHUB_OUTPUT + + # Create installation counter file for tracking installs + echo "### Create install counter file ###" + echo "Install counter file." > WAU_InstallCounter + + # Step 4: Create stable GitHub release with all artifacts + - name: Create release + uses: ncipollo/release-action@440c8c1cb0ed28b9f43e4d1d670870f059653174 # v1.16.0 + with: + tag: v${{ steps.release_version.outputs.version }} + prerelease: false # This is a stable release + generateReleaseNotes: true + name: WAU ${{ steps.release_version.outputs.version }} + artifacts: "WAU.msi,WAU_ADMX.zip,WAU_InstallCounter" + body: | + ## Files + |Files|Hash (SHA256)|Downloads| + |---|---|---| + |[WAU.msi](https://github.com/Romanitho/Winget-AutoUpdate/releases/download/v${{ steps.release_version.outputs.version }}/WAU.msi) (x64)|`${{ steps.build_project.outputs.msi_sha }}`|![WAU.msi](https://img.shields.io/github/downloads/Romanitho/Winget-AutoUpdate/v${{ steps.release_version.outputs.version }}/WAU.msi?style=flat-square&label=&color=blue)| + |[WAU_ADMX.zip](https://github.com/Romanitho/Winget-AutoUpdate/releases/download/v${{ steps.release_version.outputs.version }}/WAU_ADMX.zip)|`${{ steps.build_project.outputs.admx_sha }}`|![WAU_ADMX.zip](https://img.shields.io/github/downloads/Romanitho/Winget-AutoUpdate/v${{ steps.release_version.outputs.version }}/WAU_ADMX.zip?style=flat-square&label=&color=blue)| + + ![Install counter](https://img.shields.io/github/downloads/Romanitho/Winget-AutoUpdate/v${{ steps.release_version.outputs.version }}/WAU_InstallCounter?style=flat-square&label=Total%20reported%20installations%20for%20this%20release&color=blue) + + # Step 5: Configure Git for merge back to develop + - name: Configure Git + shell: bash + run: | + git config --global user.name "GitHub Actions" + git config --global user.email "actions@github.com" + + # Step 6: Sync develop with main to ensure all release changes are in the develop branch + - name: Sync develop with main + shell: bash + run: | + # Checkout develop branch + git checkout develop + git pull origin develop + + # Merge main into develop with no fast-forward to preserve history + git merge --no-ff origin/main -m "Merge main into develop after the creation of release v${{ steps.release_version.outputs.version }}" + + # Push changes to develop branch + git push origin develop \ No newline at end of file diff --git a/.github/workflows/GitFlow_Nightly-builds.yml b/.github/workflows/GitFlow_Nightly-builds.yml new file mode 100644 index 00000000..1ed439a7 --- /dev/null +++ b/.github/workflows/GitFlow_Nightly-builds.yml @@ -0,0 +1,174 @@ +# This workflow creates nightly builds from the develop branch: +# - Checks for merged PRs since the last tag +# - Creates a pre-release version if changes are detected +# - Builds and packages the software +# - Creates GitHub release with artifacts and download counters + +name: GitFlow | Nightly Builds + +on: + # Automated nightly builds at midnight + schedule: + - cron: "0 0 * * *" + # Allow manual triggering for testing + workflow_dispatch: + +permissions: + contents: write + +jobs: + build: + name: Create Nightly Build + runs-on: windows-latest + steps: + # Step 1: Checkout the develop branch for nightly builds + - name: Checkout code + uses: actions/checkout@v4 + with: + lfs: "true" + fetch-depth: 0 + # Always checkout develop for nightly builds + ref: develop + + # Step 2: Verify if a new build is required by checking for merged PRs since last tag + - name: Check for merged PRs since last tag + id: check_prs + shell: powershell + run: | + # Find the latest tag of any type + $LATEST_TAG = git tag --sort=-v:refname | Select-Object -First 1 + Write-Host "Latest tag: $LATEST_TAG" + + # Get merged PRs since last tag using Git directly + $MERGED_PRS = git log --merges --grep="Merge pull request" --oneline "$LATEST_TAG..develop" + + # If merged PRs exist, set BUILD_NEEDED and determine release type + if ($MERGED_PRS) { + Write-Host "Found PRs merged to develop since latest tag:" + Write-Host $MERGED_PRS + echo "BUILD_NEEDED=true" >> $env:GITHUB_OUTPUT + + # If latest tag is already a pre-release, create another pre-release + # Otherwise create a pre-minor release + if ($LATEST_TAG -like "*-*") { + echo "RELEASE_TYPE=prerelease" >> $env:GITHUB_OUTPUT + } + else { + echo "RELEASE_TYPE=preminor" >> $env:GITHUB_OUTPUT + } + Write-Host "Next release: $($LATEST_TAG -like "*-*" ? "prerelease" : "preminor")" + } else { + # If no merged PRs, skip building + Write-Host "No PRs merged to develop since latest tag. Skipping build." + echo "BUILD_NEEDED=false" >> $env:GITHUB_OUTPUT + } + + # Step 3: Generate new semantic version number + - name: Auto Increment Semver Action + uses: MCKanpolat/auto-semver-action@5003b8d37f4b03d95f15303ea10242cbf7c13141 # 2 + if: steps.check_prs.outputs.BUILD_NEEDED == 'true' + id: versioning + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + incrementPerCommit: false + releaseType: ${{ steps.check_prs.outputs.RELEASE_TYPE }} + + # Step 4: Format version numbers for different purposes (SemVer, MSI version) + - name: Format Semver (and MSI version) + if: steps.check_prs.outputs.BUILD_NEEDED == 'true' + id: format_version + shell: powershell + run: | + # Get version from previous step + $NextSemver = "${{ steps.versioning.outputs.version }}" + + # Create MSI-compatible version (x.y.z.build) + $commit_count = (git rev-list --count HEAD) + $commit_count_mod = $commit_count % 65535 # MSI has a version limit + $MsiBase = $NextSemver.Split("-")[0] # Remove prerelease segment + $MsiVersion = "$MsiBase.$commit_count_mod" + + # Format the release name + $ReleaseName = "WAU $NextSemver [Nightly Build]" + + # Output all version information + echo "MSI version: $MsiVersion" + echo "Semver created: $NextSemver" + echo "Release name: $ReleaseName" + echo "MsiVersion=$MsiVersion" >> $env:GITHUB_OUTPUT + echo "NextSemVer=$NextSemver" >> $env:GITHUB_OUTPUT + echo "ReleaseName=$ReleaseName" >> $env:GITHUB_OUTPUT + + # Step 5: Build the project and generate artifacts + - name: Build project + if: steps.check_prs.outputs.BUILD_NEEDED == 'true' + id: build_project + shell: powershell + run: | + # Download and install Microsoft Deployment Toolkit + echo "### Get MDT from Microsoft ###" + wget https://download.microsoft.com/download/3/3/9/339BE62D-B4B8-4956-B58D-73C4685FC492/MicrosoftDeploymentToolkit_x64.msi -UseBasicParsing -OutFile .\MicrosoftDeploymentToolkit_x64.msi + Start-Process .\MicrosoftDeploymentToolkit_x64.msi -ArgumentList "/quiet /norestart" -Wait + + # Extract ServiceUI for elevated notifications + echo "### Copy ServiceUI.exe x64 to 'Sources\Winget-AutoUpdate' folder ###" + Copy-Item -Path "C:\Program Files\Microsoft Deployment Toolkit\Templates\Distribution\Tools\x64\ServiceUI.exe" -Destination ".\Sources\Winget-AutoUpdate\ServiceUI.exe" -Force + Get-Item .\Sources\Winget-AutoUpdate\* + + # Install WiX tools for MSI creation + echo "### Install WiX ###" + dotnet new console + dotnet tool install --global wix --version 5.0.1 + wix extension add WixToolset.UI.wixext/5.0.1 -g + wix extension add WixToolset.Util.wixext/5.0.1 -g + + # Build MSI package with version information + echo "### Create WAU MSI ###" + cd .\Sources\Wix\ + wix build -src build.wxs -ext WixToolset.Util.wixext -ext WixToolset.UI.wixext -out ..\..\WAU.msi -arch x64 -d Version=${{ steps.format_version.outputs.MsiVersion }} -d NextSemVer=${{ steps.format_version.outputs.NextSemVer }} -d Comment="${{ steps.format_version.outputs.ReleaseName }}" -d PreRelease=1 + cd ..\.. + Get-Item .\WAU.msi + + # Calculate MSI file hash for verification + echo "### Get MSI file SHA ###" + $MsiSHA = (Get-FileHash .\WAU.msi).hash + echo " - WAU.msi SHA256: $MsiSHA" + echo "msi_sha=$MsiSHA" >> $env:GITHUB_OUTPUT + + # Package ADMX policy templates + echo "### Zip ADMX ###" + Compress-Archive -Path .\Sources\Policies\ADMX -DestinationPath .\WAU_ADMX.zip -Force + Get-Item .\*.zip + + # Calculate ADMX package hash for verification + echo "### Get ADMX zip SHA ###" + $ADMXSHA = (Get-FileHash .\WAU_ADMX.zip).hash + echo " - WAU_ADMX.zip SHA256: $ADMXSHA" + echo "admx_sha=$ADMXSHA" >> $env:GITHUB_OUTPUT + + # Create installation counter file for tracking installs + echo "### Create install counter file ###" + echo "Install counter file." > WAU_InstallCounter + + # Step 6: Create GitHub release with all artifacts + - name: Create release + uses: ncipollo/release-action@440c8c1cb0ed28b9f43e4d1d670870f059653174 # v1.16.0 + if: steps.check_prs.outputs.BUILD_NEEDED == 'true' + with: + tag: v${{ steps.format_version.outputs.NextSemVer }} + prerelease: true + generateReleaseNotes: true + name: ${{ steps.format_version.outputs.ReleaseName }} + artifacts: "WAU.msi,WAU_ADMX.zip,WAU_InstallCounter" + body: | + This is an **automated nightly build** created from the latest changes in the develop branch. + + ⚠️ **Warning**: This build may contain unstable features and is intended for testing purposes only. + + ## Files + |Files|Hash (SHA256)|Downloads| + |---|---|---| + |[WAU.msi](https://github.com/Romanitho/Winget-AutoUpdate/releases/download/v${{ steps.format_version.outputs.NextSemVer }}/WAU.msi) (x64)|`${{ steps.build_project.outputs.msi_sha }}`|![WAU.msi](https://img.shields.io/github/downloads/Romanitho/Winget-AutoUpdate/v${{ steps.format_version.outputs.NextSemVer }}/WAU.msi?style=flat-square&label=&color=blue)| + |[WAU_ADMX.zip](https://github.com/Romanitho/Winget-AutoUpdate/releases/download/v${{ steps.format_version.outputs.NextSemVer }}/WAU_ADMX.zip)|`${{ steps.build_project.outputs.admx_sha }}`|![WAU_ADMX.zip](https://img.shields.io/github/downloads/Romanitho/Winget-AutoUpdate/v${{ steps.format_version.outputs.NextSemVer }}/WAU_ADMX.zip?style=flat-square&label=&color=blue)| + + ![Install counter](https://img.shields.io/github/downloads/Romanitho/Winget-AutoUpdate/v${{ steps.format_version.outputs.NextSemVer }}/WAU_InstallCounter?style=flat-square&label=Total%20reported%20installations%20for%20this%20release&color=blue) \ No newline at end of file diff --git a/.github/workflows/WAU-ReleaseBuilder.yml b/.github/workflows/WAU-ReleaseBuilder.yml deleted file mode 100644 index 09a37b1c..00000000 --- a/.github/workflows/WAU-ReleaseBuilder.yml +++ /dev/null @@ -1,162 +0,0 @@ ---- -name: WAU - Release builder - -on: - # To trigger nightly release (Auto) - schedule: - - cron: "0 0 * * *" - # To trigger stable release - workflow_dispatch: - inputs: - version: - type: choice - default: "Minor" - description: Select next release type - options: - - Patch - - Minor - - Major - required: true - pre-release: - type: boolean - description: Set as Pre-release version - -permissions: - contents: write - -jobs: - build: - name: Create Release - runs-on: windows-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - lfs: "true" - fetch-depth: 0 - # Checkout develop for scheduled builds, main for manual releases - ref: ${{ github.event_name == 'schedule' && 'develop' || 'main' }} - - - name: Manually OR Scheduled. If Scheduled, check if release is necessary - run: | - if ("${{ github.event_name }}" -eq "schedule") { - echo "Latest tag:" - git log --tags --pretty="%ci - %h - %s %d" -n 1 - $LATEST_TAG_DATE = git log --tags -n 1 --pretty="%ct" - echo $LATEST_TAG_DATE - - echo "Latest merge:" - git log --merges --pretty="%ci - %h - %s %d" -n 1 - $LATEST_MERGE_DATE = git log --merges -n 1 --pretty="%ct" - echo $LATEST_MERGE_DATE - - if ( $LATEST_MERGE_DATE -gt $LATEST_TAG_DATE ) { - echo "Scheduled request. Latest tag is older than latest merge. Nightly prerelease will be created." - echo "ReleaseType=Prerelease" >> $env:GITHUB_ENV - } - else { - echo "Scheduled request. Latest tag is not older than latest merge. No new Nightly release needed." - echo "ReleaseType=No" >> $env:GITHUB_ENV - } - } - else { - echo "Manual request. Release will be created." - echo "ReleaseType=Release" >> $env:GITHUB_ENV - } - - - name: Auto Increment Semver Action - uses: MCKanpolat/auto-semver-action@5003b8d37f4b03d95f15303ea10242cbf7c13141 # 2 - if: env.ReleaseType != 'No' - id: versioning - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - incrementPerCommit: false - releaseType: Pre${{ github.event.inputs.version || 'patch'}} # Using Prepatch by default - - - name: Format Semver (and msi version) - if: env.ReleaseType != 'No' - # Remove "-0" for stable release and replace by "-n" for Nightlies - run: | - $NextAutoSemver = "${{ steps.versioning.outputs.version }}" - if ("${{ env.ReleaseType }}" -eq "Release") { - $MsiVersion = $NextAutoSemver.Split("-")[0] - $NextSemver = $NextAutoSemver.Split("-")[0] - $ReleaseName = "WAU " + $NextSemver - $Prerelease = 0 - } - else { - $MsiVersion = $NextAutoSemver.Split("-")[0] - $NextSemver = $NextAutoSemver.Replace("-0","-n") - $ReleaseName = "WAU " + $NextSemver + " [Nightly Build]" - $Prerelease = 1 - } - echo "MSI version: $MsiVersion" - echo "Semver created: $NextSemver" - echo "Prerelease: $Prerelease" - echo "Release name: $ReleaseName" - echo "MsiVersion=$MsiVersion" >> $env:GITHUB_ENV - echo "NextSemVer=$NextSemVer" >> $env:GITHUB_ENV - echo "Prerelease=$Prerelease" >> $env:GITHUB_ENV - echo "ReleaseName=$ReleaseName" >> $env:GITHUB_ENV - - - name: Build project - if: env.ReleaseType != 'No' - shell: powershell - run: | - echo "### Get MDT from Microsoft ###" - wget https://download.microsoft.com/download/3/3/9/339BE62D-B4B8-4956-B58D-73C4685FC492/MicrosoftDeploymentToolkit_x64.msi -UseBasicParsing -OutFile .\MicrosoftDeploymentToolkit_x64.msi - Start-Process .\MicrosoftDeploymentToolkit_x64.msi -ArgumentList "/quiet /norestart" -Wait - - echo "### Copy ServiceUI.exe x64 to 'Sources\Winget-AutoUpdate' folder ###" - Copy-Item -Path "C:\Program Files\Microsoft Deployment Toolkit\Templates\Distribution\Tools\x64\ServiceUI.exe" -Destination ".\Sources\Winget-AutoUpdate\ServiceUI.exe" -Force - Get-Item .\Sources\Winget-AutoUpdate\* - - echo "### Install WiX ###" - dotnet new console - dotnet tool install --global wix --version 5.0.1 - wix extension add WixToolset.UI.wixext/5.0.1 -g - wix extension add WixToolset.Util.wixext/5.0.1 -g - - echo "### Create WAU msi ###" - cd .\Sources\Wix\ - wix build -src build.wxs -ext WixToolset.Util.wixext -ext WixToolset.UI.wixext -out ..\..\WAU.msi -arch x64 -d Version=${{ env.MsiVersion }} -d NextSemVer=${{ env.NextSemVer }} -d Comment="${{ env.ReleaseName }}" -d PreRelease=${{ env.PreRelease }} - cd ..\.. - Get-Item .\WAU.msi - - echo "### Get MSI file SHA ###" - $MsiSHA = (Get-FileHash .\WAU.msi).hash - echo " - WAU.msi SHA256: $MsiSHA" - echo "MSI_SHA=$MsiSHA" >> $env:GITHUB_ENV - - echo "### Zip ADMX ###" - Compress-Archive -Path .\Sources\Policies\ADMX -DestinationPath .\WAU_ADMX.zip -Force - Get-Item .\*.zip - - echo "### Get ADMX zip SHA ###" - $ADMXSHA = (Get-FileHash .\WAU_ADMX.zip).hash - echo " - WAU_ADMX.zip SHA256: $ADMXSHA" - echo "ADMX_SHA=$ADMXSHA" >> $env:GITHUB_ENV - - echo "### Create install counter file ###" - echo "Install counter file." > WAU_InstallCounter - - echo "### Download the latest v1 WAU.zip (as v2 updater)" - wget https://github.com/Romanitho/Winget-AutoUpdate/releases/download/v1.21.13/WAU.zip -UseBasicParsing -OutFile .\WAU.zip - - - name: Create release - uses: ncipollo/release-action@440c8c1cb0ed28b9f43e4d1d670870f059653174 # v1.16.0 - if: env.ReleaseType != 'No' - with: - tag: v${{ env.NextSemVer }} - prerelease: ${{ github.event.inputs.pre-release || true }} - generateReleaseNotes: true - name: ${{ env.ReleaseName }} - artifacts: "WAU.msi,WAU_ADMX.zip,WAU.zip,WAU_InstallCounter" - body: | - ## Files - |Files|Hash (SHA256)|Downloads| - |---|---|---| - |[WAU.msi](https://github.com/Romanitho/Winget-AutoUpdate/releases/download/v${{ env.NextSemVer }}/WAU.msi) (x64)|`${{ env.MSI_SHA }}`|![WAU.msi](https://img.shields.io/github/downloads/Romanitho/Winget-AutoUpdate/v${{ env.NextSemVer }}/WAU.msi?style=flat-square&label=&color=blue)| - |[WAU_ADMX.zip](https://github.com/Romanitho/Winget-AutoUpdate/releases/download/v${{ env.NextSemVer }}/WAU_ADMX.zip)|`${{ env.ADMX_SHA }}`|![WAU_ADMX.zip](https://img.shields.io/github/downloads/Romanitho/Winget-AutoUpdate/v${{ env.NextSemVer }}/WAU_ADMX.zip?style=flat-square&label=&color=blue)| - - ![Install counter](https://img.shields.io/github/downloads/Romanitho/Winget-AutoUpdate/v${{ env.NextSemVer }}/WAU_InstallCounter?style=flat-square&label=Total%20reported%20installations%20for%20this%20release&color=blue) diff --git a/.github/workflows/automerge-dependabot.yml b/.github/workflows/automerge-dependabot.yml deleted file mode 100644 index cf7bcfc7..00000000 --- a/.github/workflows/automerge-dependabot.yml +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: "Dependabot Automerge - Action" - -on: - pull_request: - -permissions: - contents: write - pull-requests: write - -jobs: - auto-merge: - name: DependabotMerge - runs-on: ubuntu-latest - if: ${{ github.actor == 'dependabot[bot]' && github.event_name == 'pull_request'}} # Detect that the PR author is dependabot - steps: - - name: Enable auto-merge for Dependabot PRs - run: gh pr merge --auto --merge "$PR_URL" # Use Github CLI to merge automatically the PR - env: - PR_URL: ${{github.event.pull_request.html_url}} - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7006c23c..005f94bb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,24 +1,45 @@ # Contribution Guide -Thank you for your interest in contributing to this project! Here are some guidelines and best practices to help you get started. +Thank you for your interest in contributing to this project! ## Branches -- **`main`**: Contains the production code and is locked for direct modifications. +- **`main`**: Contains the production code and is locked for direct commits. - **`develop`**: Contains the code under development for the next release. - **`feature/`**: Used to develop new features. -- **`bugfix/`**: Used to fix bugs. +- **`hotfix/`**: Used to fix bugs. ## Protection of the `main` Branch -To ensure the quality and stability of the production code, the `main` branch is protected and locked to prevent direct modifications. All changes must go through a pull request to the `develop` branch. +To ensure the quality and stability of the production code, contributors should follow these steps: +- Create a new branch from `develop` for their feature, +- Once the work is complete, open a pull request +- Ensure that the pull request has a clear title +- The pull request must pass all tests and receive approval from reviewers -Contributors should follow these steps: -- Create a new branch from `develop` for their feature or bugfix. -- Once the work is complete, open a pull request to merge their branch into `develop`. -- Ensure that the pull request has a clear title and description. -- The pull request must pass all tests and receive a code review before being merged. +This workflow ensures that the `main` branch remains stable and production-ready. -This workflow ensures that the `main` branch remains stable and that all changes are properly reviewed and tested before being released. +## Use Gitflow as much as possible -Thank you for your contribution! +![Hotfix_branches](https://github.com/user-attachments/assets/d1b2efe3-3c2e-47c1-8e39-66bf93c34efa) + +### GitFlow Process + +1. **Main Branches**: + - `main`: The primary branch containing the official release history. + - `develop`: The branch where the latest development changes accumulate. + +2. **Branch Types in our Workflow**: + - `feature/`: For contributors to develop new features. + - `hotfix/`: For contributors to fix critical bugs. + - `release/`: Automatically created by GitHub Actions for preparing new production releases (not created directly by contributors). + +3. **Pull Request Process for Contributors**: + - Each new feature should be developed in a `feature` branch. + - A PR should be requested to merge the `feature` branch into `develop`. + +4. **Release Creation**: + - Once a new release needs to be created, a GitHub Action is manually triggered to create a release branch from the develop branch. + - A Pull Request is automatically issued to merge the release branch into the main branch. + - Final reviews and validations are performed at this stage. + - Merging the release branch into the main branch automatically creates a new release via another GitHub Action. diff --git a/Sources/Winget-AutoUpdate/Winget-Upgrade.ps1 b/Sources/Winget-AutoUpdate/Winget-Upgrade.ps1 index 0f43d2a8..64a5d0bd 100644 --- a/Sources/Winget-AutoUpdate/Winget-Upgrade.ps1 +++ b/Sources/Winget-AutoUpdate/Winget-Upgrade.ps1 @@ -23,8 +23,7 @@ $Script:ProgressPreference = [System.Management.Automation.ActionPreference]::Si Write-ToLog "Reading WAUConfig"; $Script:WAUConfig = Get-WAUConfig; -if ($WAUConfig.WAU_ActivateGPOManagement -eq 1) -{ +if ($WAUConfig.WAU_ActivateGPOManagement -eq 1) { Write-ToLog "WAU Policies management Enabled."; } #endregion Get settings and Domain/Local Policies (GPO) if activated. @@ -37,10 +36,8 @@ if ($WAUConfig.WAU_ActivateGPOManagement -eq 1) [string]$Script:WingetSourceCustom = $DefaultWingetRepoName; # Defining custom repository for winget tool (only if GPO management is active) -if ($Script:WAUConfig.WAU_ActivateGPOManagement) -{ - if ($null -ne $Script:WAUConfig.WAU_WingetSourceCustom) - { +if ($Script:WAUConfig.WAU_ActivateGPOManagement) { + if ($null -ne $Script:WAUConfig.WAU_WingetSourceCustom) { $Script:WingetSourceCustom = $Script:WAUConfig.WAU_WingetSourceCustom.Trim(); Write-ToLog "Selecting winget repository named '$($Script:WingetSourceCustom)'"; } @@ -50,18 +47,16 @@ if ($Script:WAUConfig.WAU_ActivateGPOManagement) #region Checking execution context # Check if running account is system or interactive logon System(default) otherwise User [bool]$Script:IsSystem = [System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem; - + # Check for current session ID (O = system without ServiceUI) [Int32]$Script:SessionID = [System.Diagnostics.Process]::GetCurrentProcess().SessionId; #endregion # Preparation to run in current context -if ($true -eq $IsSystem) -{ +if ($true -eq $IsSystem) { #If log file doesn't exist, force create it - if (!(Test-Path -Path $LogFile)) - { + if (!(Test-Path -Path $LogFile)) { Write-ToLog "New log file created"; } @@ -72,19 +67,16 @@ if ($true -eq $IsSystem) [string]$fp2 = [System.IO.Path]::Combine($IntuneLogsDir, 'WAU-install.log'); # Check if Intune Management Extension Logs folder exists - if (Test-Path -Path $IntuneLogsDir -PathType Container -ErrorAction SilentlyContinue) - { + if (Test-Path -Path $IntuneLogsDir -PathType Container -ErrorAction SilentlyContinue) { # Check if symlink WAU-updates.log exists, make symlink (doesn't work under ServiceUI) - if (!(Test-Path -Path $fp0 -ErrorAction SilentlyContinue)) - { + if (!(Test-Path -Path $fp0 -ErrorAction SilentlyContinue)) { New-Item -Path $fp0 -ItemType SymbolicLink -Value $LogFile -Force -ErrorAction SilentlyContinue | Out-Null; Write-ToLog "SymLink for 'update' log file created in in $($IntuneLogsDir) folder"; } # Check if install.log and symlink WAU-install.log exists, make symlink (doesn't work under ServiceUI) - if ( (Test-Path -Path $fp1 -ErrorAction SilentlyContinue) -and !(Test-Path -Path $fp2 -ErrorAction SilentlyContinue) ) - { + if ( (Test-Path -Path $fp1 -ErrorAction SilentlyContinue) -and !(Test-Path -Path $fp2 -ErrorAction SilentlyContinue) ) { New-Item -Path $fp2 -ItemType SymbolicLink -Value $fp1 -Force -Confirm:$False -ErrorAction SilentlyContinue | Out-Null; Write-ToLog "SymLink for 'install' log file created in $($IntuneLogsDir) folder" } @@ -93,40 +85,34 @@ if ($true -eq $IsSystem) $UserDirs = Get-ChildItem -Path "C:\Users" -Directory | Where-Object { ($_ -notmatch "Default") -and ($_ -notmatch "Public") -and ($_ -notmatch "All Users") -and ($_ -notmatch "Default User") } - foreach ($UserDir in $UserDirs) - { + foreach ($UserDir in $UserDirs) { # Define user-specific log path and log file $UserLogPath = "$($UserDir.FullName)\AppData\Roaming\Winget-AutoUpdate\Logs" $UserLogFile = "$UserLogPath\install_$($UserDir.Name).log" - + # Check if the user's log file exists - if (Test-Path -Path $UserLogFile -ErrorAction SilentlyContinue) - { + if (Test-Path -Path $UserLogFile -ErrorAction SilentlyContinue) { # Define the Symlink target $UserLogLink = "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-user_$($UserDir.Name).log" - + # Create Symlink if it doesn't already exist - if (!(Test-Path -Path $UserLogLink -ErrorAction SilentlyContinue)) - { + if (!(Test-Path -Path $UserLogLink -ErrorAction SilentlyContinue)) { New-Item -Path $UserLogLink -ItemType SymbolicLink -Value $UserLogFile -Force -ErrorAction SilentlyContinue | Out-Null Write-ToLog "Created Symlink for user log: $UserLogLink -> $UserLogFile" } } } } - + #Check if running with session ID 0 - if ($SessionID -eq 0) - { + if ($SessionID -eq 0) { #Check if ServiceUI exists [string]$fp3 = [System.IO.Path]::Combine($Script:WorkingDir, 'ServiceUI.exe'); [bool]$ServiceUI = Test-Path $fp3 -PathType Leaf; - if ($true -eq $ServiceUI) - { + if ($true -eq $ServiceUI) { #Check if any connected user $explorerprocesses = @(Get-CimInstance -Query "SELECT * FROM Win32_Process WHERE Name='explorer.exe'" -ErrorAction SilentlyContinue); - if ($explorerprocesses.Count -gt 0) - { + if ($explorerprocesses.Count -gt 0) { Write-ToLog "Rerun WAU in system context with ServiceUI"; Start-Process ` -FilePath $fp3 ` @@ -135,64 +121,53 @@ if ($true -eq $IsSystem) Wait-Process "ServiceUI" -ErrorAction SilentlyContinue; Exit 0; } - else - { + else { Write-ToLog -LogMsg "CHECK FOR APP UPDATES (System context)" -IsHeader } } - else - { + else { Write-ToLog -LogMsg "CHECK FOR APP UPDATES (System context - No ServiceUI)" -IsHeader } } - else - { + else { Write-ToLog -LogMsg "CHECK FOR APP UPDATES (System context - Connected user)" -IsHeader } } -else -{ +else { Write-ToLog -LogMsg "CHECK FOR APP UPDATES (User context)" -IsHeader } #region Log running context -if ($true -eq $IsSystem) -{ +if ($true -eq $IsSystem) { # Maximum number of log files to keep. Default is 3. Setting MaxLogFiles to 0 will keep all log files. $MaxLogFiles = $WAUConfig.WAU_MaxLogFiles - if ($null -eq $MaxLogFiles) - { + if ($null -eq $MaxLogFiles) { [int32]$MaxLogFiles = 3; } - else - { + else { [int32]$MaxLogFiles = $MaxLogFiles; } # Maximum size of log file. $MaxLogSize = $WAUConfig.WAU_MaxLogSize; - if (!$MaxLogSize) - { + if (!$MaxLogSize) { [int64]$MaxLogSize = [int64]1MB; # in bytes, default is 1 MB = 1048576 } - else - { + else { [int64]$MaxLogSize = $MaxLogSize; } #LogRotation if System [bool]$LogRotate = Invoke-LogRotation $LogFile $MaxLogFiles $MaxLogSize; - if ($false -eq $LogRotate) - { + if ($false -eq $LogRotate) { Write-ToLog "An Exception occurred during Log Rotation..." } } #endregion Log running context #region Run Scope Machine function if run as System -if ($true -eq $IsSystem) -{ +if ($true -eq $IsSystem) { Add-ScopeMachine; } #endregion Run Scope Machine function if run as System @@ -200,15 +175,13 @@ if ($true -eq $IsSystem) #region Get Notif Locale function [string]$LocaleDisplayName = Get-NotifLocale; Write-ToLog "Notification Level: $($WAUConfig.WAU_NotificationLevel). Notification Language: $LocaleDisplayName" "Cyan"; -#endregion +#endregion #Check network connectivity -if (Test-Network) -{ +if (Test-Network) { #Check prerequisites - if ($true -eq $IsSystem) - { + if ($true -eq $IsSystem) { Install-Prerequisites; } @@ -216,11 +189,9 @@ if (Test-Network) [string]$Script:Winget = Get-WingetCmd; Write-ToLog "Selected winget instance: $($Script:Winget)"; - if ($Script:Winget) - { + if ($Script:Winget) { - if ($true -eq $IsSystem) - { + if ($true -eq $IsSystem) { #Get Current Version $WAUCurrentVersion = $WAUConfig.ProductVersion; @@ -229,86 +200,67 @@ if (Test-Network) #Check if WAU update feature is enabled or not if run as System $WAUDisableAutoUpdate = $WAUConfig.WAU_DisableAutoUpdate; #If yes then check WAU update if run as System - if ($WAUDisableAutoUpdate -eq 1) - { + if ($WAUDisableAutoUpdate -eq 1) { Write-ToLog "WAU AutoUpdate is Disabled." "Gray"; } - else - { + else { Write-ToLog "WAU AutoUpdate is Enabled." "Green"; #Get Available Version $Script:WAUAvailableVersion = Get-WAUAvailableVersion; #Compare - if ([version]$WAUAvailableVersion.replace("-n", "") -gt [version]$WAUCurrentVersion.replace("-n", "")) - { + if ([version]$WAUAvailableVersion.replace("-n", "") -gt [version]$WAUCurrentVersion.replace("-n", "")) { #If new version is available, update it Write-ToLog "WAU Available version: $WAUAvailableVersion" "Yellow"; Update-WAU; } - else - { + else { Write-ToLog "WAU is up to date." "Green"; } } #Delete previous list_/winget_error (if they exist) if run as System [string]$fp4 = [System.IO.Path]::Combine($Script:WorkingDir, 'logs', 'error.txt'); - if (Test-Path $fp4) - { + if (Test-Path $fp4) { Remove-Item $fp4 -Force; } #Get External ListPath if run as System - if ($WAUConfig.WAU_ListPath) - { + if ($WAUConfig.WAU_ListPath) { $ListPathClean = $($WAUConfig.WAU_ListPath.TrimEnd(" ", "\", "/")) Write-ToLog "WAU uses External Lists from: $ListPathClean" - if ($ListPathClean -ne "GPO") - { + if ($ListPathClean -ne "GPO") { $NewList = Test-ListPath $ListPathClean $WAUConfig.WAU_UseWhiteList $WAUConfig.InstallLocation.TrimEnd(" ", "\") - if ($ReachNoPath) - { + if ($ReachNoPath) { Write-ToLog "Couldn't reach/find/compare/copy from $ListPathClean..." "Red" - if ($ListPathClean -notlike "http*") - { - if (Test-Path -Path "$ListPathClean" -PathType Leaf) - { + if ($ListPathClean -notlike "http*") { + if (Test-Path -Path "$ListPathClean" -PathType Leaf) { Write-ToLog "PATH must end with a Directory, not a File..." "Red" } } - else - { - if ($ListPathClean -match "_apps.txt") - { + else { + if ($ListPathClean -match "_apps.txt") { Write-ToLog "PATH must end with a Directory, not a File..." "Red" } } $Script:ReachNoPath = $False } - if ($NewList) - { - if ($AlwaysDownloaded) - { + if ($NewList) { + if ($AlwaysDownloaded) { Write-ToLog "List downloaded/copied to local path: $($WAUConfig.InstallLocation.TrimEnd(" ", "\"))" "Yellow" } - else - { + else { Write-ToLog "Newer List downloaded/copied to local path: $($WAUConfig.InstallLocation.TrimEnd(" ", "\"))" "Yellow" } $Script:AlwaysDownloaded = $False } - else - { - if ($WAUConfig.WAU_UseWhiteList -and (Test-Path "$WorkingDir\included_apps.txt")) - { + else { + if ($WAUConfig.WAU_UseWhiteList -and (Test-Path "$WorkingDir\included_apps.txt")) { Write-ToLog "List (white) is up to date." "Green" } - elseif (!$WAUConfig.WAU_UseWhiteList -and (Test-Path "$WorkingDir\excluded_apps.txt")) - { + elseif (!$WAUConfig.WAU_UseWhiteList -and (Test-Path "$WorkingDir\excluded_apps.txt")) { Write-ToLog "List (black) is up to date." "Green" } - else - { + else { Write-ToLog "Critical: White/Black List doesn't exist, exiting..." "Red" New-Item "$WorkingDir\logs\error.txt" -Value "White/Black List doesn't exist" -Force Exit 1 @@ -318,54 +270,43 @@ if (Test-Network) } #Get External ModsPath if run as System - if ($WAUConfig.WAU_ModsPath) - { + if ($WAUConfig.WAU_ModsPath) { $ModsPathClean = $($WAUConfig.WAU_ModsPath.TrimEnd(" ", "\", "/")) Write-ToLog "WAU uses External Mods from: $ModsPathClean" - if ($WAUConfig.WAU_AzureBlobSASURL) - { + if ($WAUConfig.WAU_AzureBlobSASURL) { $NewMods, $DeletedMods = Test-ModsPath $ModsPathClean $WAUConfig.InstallLocation.TrimEnd(" ", "\") $WAUConfig.WAU_AzureBlobSASURL.TrimEnd(" ") } - else - { + else { $NewMods, $DeletedMods = Test-ModsPath $ModsPathClean $WAUConfig.InstallLocation.TrimEnd(" ", "\") } - if ($ReachNoPath) - { + if ($ReachNoPath) { Write-ToLog "Couldn't reach/find/compare/copy from $ModsPathClean..." "Red" $Script:ReachNoPath = $False } - if ($NewMods -gt 0) - { + if ($NewMods -gt 0) { Write-ToLog "$NewMods newer Mods downloaded/copied to local path: $($WAUConfig.InstallLocation.TrimEnd(" ", "\"))\mods" "Yellow" } - else - { - if (Test-Path "$WorkingDir\mods\*.ps1") - { + else { + if (Test-Path "$WorkingDir\mods\*.ps1") { Write-ToLog "Mods are up to date." "Green" } - else - { + else { Write-ToLog "No Mods are implemented..." "Yellow" } } - if ($DeletedMods -gt 0) - { + if ($DeletedMods -gt 0) { Write-ToLog "$DeletedMods Mods deleted (not externally managed) from local path: $($WAUConfig.InstallLocation.TrimEnd(" ", "\"))\mods" "Red" } } #Test if _WAU-mods.ps1 exist: Mods for WAU (if Network is active/any Winget is installed/running as SYSTEM) $Mods = "$WorkingDir\mods" - if (Test-Path "$Mods\_WAU-mods.ps1") - { + if (Test-Path "$Mods\_WAU-mods.ps1") { Write-ToLog "Running Mods for WAU..." "Yellow" & "$Mods\_WAU-mods.ps1" $ModsExitCode = $LASTEXITCODE #If _WAU-mods.ps1 has ExitCode 1 - Re-run WAU - if ($ModsExitCode -eq 1) - { + if ($ModsExitCode -eq 1) { Write-ToLog "Re-run WAU" Start-Process powershell -ArgumentList "-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -Command `"$WorkingDir\winget-upgrade.ps1`"" Exit @@ -374,41 +315,33 @@ if (Test-Network) } - if ($($WAUConfig.WAU_ListPath) -eq "GPO") - { + if ($($WAUConfig.WAU_ListPath) -eq "GPO") { $Script:GPOList = $True } #Get White or Black list - if ($WAUConfig.WAU_UseWhiteList -eq 1) - { + if ($WAUConfig.WAU_UseWhiteList -eq 1) { Write-ToLog "WAU uses White List config" $toUpdate = Get-IncludedApps $UseWhiteList = $true } - else - { + else { Write-ToLog "WAU uses Black List config" $toSkip = Get-ExcludedApps } #Fix and count the array if GPO List as ERROR handling! - if ($GPOList) - { - if ($UseWhiteList) - { - if (-not $toUpdate) - { + if ($GPOList) { + if ($UseWhiteList) { + if (-not $toUpdate) { Write-ToLog "Critical: Whitelist doesn't exist in GPO, exiting..." "Red" New-Item "$WorkingDir\logs\error.txt" -Value "Whitelist doesn't exist in GPO" -Force Exit 1 } foreach ($app in $toUpdate) { Write-ToLog "Include app ${app}" } } - else - { - if (-not $toSkip) - { + else { + if (-not $toSkip) { Write-ToLog "Critical: Blacklist doesn't exist in GPO, exiting..." "Red" New-Item "$WorkingDir\logs\error.txt" -Value "Blacklist doesn't exist in GPO" -Force Exit 1 @@ -422,16 +355,13 @@ if (Test-Network) $outdated = Get-WingetOutdatedApps -src $Script:WingetSourceCustom; #If something unusual happened or no update found - if ($outdated -like "No update found.*") - { + if ($outdated -like "No update found.*") { Write-ToLog "$outdated" "cyan" } #Run only if $outdated is populated! - else - { + else { #Log list of app to update - foreach ($app in $outdated) - { + foreach ($app in $outdated) { #List available updates $Log = "-> Available update : $($app.Name). Current version : $($app.Version). Available version : $($app.AvailableVersion)." $Log | Write-Host @@ -442,79 +372,64 @@ if (Test-Network) $Script:InstallOK = 0 #Trick under user context when -BypassListForUsers is used - if ($IsSystem -eq $false -and $WAUConfig.WAU_BypassListForUsers -eq 1) - { + if ($IsSystem -eq $false -and $WAUConfig.WAU_BypassListForUsers -eq 1) { Write-ToLog "Bypass system list in user context is Enabled." $UseWhiteList = $false $toSkip = $null } #If White List - if ($UseWhiteList) - { + if ($UseWhiteList) { #For each app, notify and update - foreach ($app in $outdated) - { + foreach ($app in $outdated) { #if current app version is unknown, skip it - if ($($app.Version) -eq "Unknown") - { + if ($($app.Version) -eq "Unknown") { Write-ToLog "$($app.Name) : Skipped upgrade because current version is 'Unknown'" "Gray" } #if app is in "include list", update it - elseif ($toUpdate -contains $app.Id) - { + elseif ($toUpdate -contains $app.Id) { Update-App $app } #if app with wildcard is in "include list", update it - elseif ($toUpdate | Where-Object { $app.Id -like $_ }) - { + elseif ($toUpdate | Where-Object { $app.Id -like $_ }) { Write-ToLog "$($app.Name) is wildcard in the include list." Update-App $app } #else, skip it - else - { + else { Write-ToLog "$($app.Name) : Skipped upgrade because it is not in the included app list" "Gray" } } } #If Black List or default - else - { + else { #For each app, notify and update - foreach ($app in $outdated) - { + foreach ($app in $outdated) { #if current app version is unknown, skip it - if ($($app.Version) -eq "Unknown") - { + if ($($app.Version) -eq "Unknown") { Write-ToLog "$($app.Name) : Skipped upgrade because current version is 'Unknown'" "Gray" } #if app is in "excluded list", skip it - elseif ($toSkip -contains $app.Id) - { + elseif ($toSkip -contains $app.Id) { Write-ToLog "$($app.Name) : Skipped upgrade because it is in the excluded app list" "Gray" } #if app with wildcard is in "excluded list", skip it - elseif ($toSkip | Where-Object { $app.Id -like $_ }) - { + elseif ($toSkip | Where-Object { $app.Id -like $_ }) { Write-ToLog "$($app.Name) : Skipped upgrade because it is *wildcard* in the excluded app list" "Gray" } # else, update it - else - { + else { Update-App $app } } } - if ($InstallOK -gt 0) - { + if ($InstallOK -gt 0) { Write-ToLog "$InstallOK apps updated ! No more update." "Green" } } - if ($InstallOK -eq 0 -or !$InstallOK) - { + if ($InstallOK -eq 0 -or !$InstallOK) { Write-ToLog "No new update." "Green" } @@ -527,18 +442,15 @@ if (Test-Network) } #Check if user context is activated during system run - if ($IsSystem -and ($WAUConfig.WAU_UserContext -eq 1)) - { + if ($IsSystem -and ($WAUConfig.WAU_UserContext -eq 1)) { $UserContextTask = Get-ScheduledTask -TaskName 'Winget-AutoUpdate-UserContext' -ErrorAction SilentlyContinue $explorerprocesses = @(Get-CimInstance -Query "SELECT * FROM Win32_Process WHERE Name='explorer.exe'" -ErrorAction SilentlyContinue) - If ($explorerprocesses.Count -eq 0) - { + If ($explorerprocesses.Count -eq 0) { Write-ToLog "No explorer process found / Nobody interactively logged on..." } - Else - { + Else { #Get Winget system apps to escape them before running user context Write-ToLog "User logged on, get a list of installed Winget apps in System context..." Get-WingetSystemApps -src $Script:WingetSourceCustom; @@ -550,8 +462,7 @@ if (Test-Network) } } } - else - { + else { Write-ToLog "Critical: Winget not installed or detected, exiting..." "red" New-Item "$WorkingDir\logs\error.txt" -Value "Winget not installed or detected" -Force Write-ToLog "End of process!" "Cyan"