From ade312ab5c1bc3356e902119137bc9a469d53b3c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:23:23 +0000 Subject: [PATCH 1/7] Initial plan From 89f88ae7d055344b9906a702636e73ffbaedca1b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:26:19 +0000 Subject: [PATCH 2/7] Add winget package submission support Co-authored-by: justinmchase <10974+justinmchase@users.noreply.github.com> --- .github/workflows/publish.yml | 216 +++++++++++++++++++++++++++++++++- README.md | 8 ++ 2 files changed, 223 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d8e1627..bcf5317 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -66,7 +66,15 @@ jobs: cd bin && tar -czf $APP_NAME.$TARGET.tar.gz ${APP_NAME}${EXT} ls -la - - name: Upload Release Asset + # Create ZIP file for Windows (required for winget) + - name: Create Windows ZIP + if: github.event_name == 'release' && matrix.target.name == 'x86_64-pc-windows-msvc' + run: | + cd bin + zip $APP_NAME.${{ matrix.target.name }}.zip ${APP_NAME}.exe + ls -la + + - name: Upload Release Asset (tar.gz) uses: actions/upload-release-asset@v1 if: github.event_name == 'release' env: @@ -77,6 +85,17 @@ jobs: asset_name: ${{ env.APP_NAME }}.${{ matrix.target.name }}.tar.gz asset_content_type: application/tar+gzip + - name: Upload Release Asset (zip for Windows) + uses: actions/upload-release-asset@v1 + if: github.event_name == 'release' && matrix.target.name == 'x86_64-pc-windows-msvc' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: ./bin/${{ env.APP_NAME }}.${{ matrix.target.name }}.zip + asset_name: ${{ env.APP_NAME }}.${{ matrix.target.name }}.zip + asset_content_type: application/zip + - name: Print Output if: github.event_name == 'release' env: @@ -277,6 +296,200 @@ jobs: --head "${branch_name}" \ --base main + winget: + if: ${{ github.event_name == 'release' && github.event.release.prerelease == false }} + runs-on: windows-latest + needs: + - version + - assets + permissions: + contents: write + pull-requests: write + env: + GH_TOKEN: ${{ secrets.SEMVER_PUBLISH_TOKEN }} + GITHUB_TOKEN: ${{ secrets.SEMVER_PUBLISH_TOKEN }} + steps: + - uses: actions/checkout@v4 + + - name: Configure Git + run: | + git config --global user.name 'github-actions[bot]' + git config --global user.email 'github-actions[bot]@users.noreply.github.com' + gh auth setup-git + + - name: Download Release Asset and Generate Winget Manifests + env: + VERSION: ${{ needs.version.outputs.version }} + shell: bash + run: | + mkdir -p assets manifests + + # Download the Windows ZIP asset using GitHub CLI + asset_name="semver.x86_64-pc-windows-msvc.zip" + echo "Downloading ${asset_name} using GitHub CLI" + gh release download "${VERSION}" --pattern "${asset_name}" --dir assets --repo Optum/semver-cli + + # Calculate SHA256 (PowerShell command via bash) + sha=$(powershell -Command "(Get-FileHash -Algorithm SHA256 assets/${asset_name}).Hash") + echo "SHA256: $sha" + + url="https://github.com/Optum/semver-cli/releases/download/${VERSION}/${asset_name}" + echo "URL: $url" + + # Create manifest directory structure + # Winget uses: manifests///// + manifest_dir="manifests/O/Optum/semver/${VERSION}" + mkdir -p "$manifest_dir" + + # Generate the installer manifest + cat > "${manifest_dir}/Optum.semver.installer.yaml" << EOF + # yaml-language-server: \$schema=https://aka.ms/winget-manifest.installer.1.6.0.schema.json + + PackageIdentifier: Optum.semver + PackageVersion: ${VERSION} + InstallerType: zip + UpgradeBehavior: install + Commands: + - semver + ReleaseDate: $(date -u +%Y-%m-%d) + Installers: + - Architecture: x64 + NestedInstallerType: portable + NestedInstallerFiles: + - RelativeFilePath: semver.exe + PortableCommandAlias: semver + InstallerUrl: ${url} + InstallerSha256: ${sha} + ManifestType: installer + ManifestVersion: 1.6.0 + EOF + + # Generate the locale manifest + cat > "${manifest_dir}/Optum.semver.locale.en-US.yaml" << EOF + # yaml-language-server: \$schema=https://aka.ms/winget-manifest.defaultLocale.1.6.0.schema.json + + PackageIdentifier: Optum.semver + PackageVersion: ${VERSION} + PackageLocale: en-US + Publisher: Optum + PublisherUrl: https://github.com/Optum + PublisherSupportUrl: https://github.com/Optum/semver-cli/issues + Author: Optum + PackageName: semver + PackageUrl: https://github.com/Optum/semver-cli + License: Apache-2.0 + LicenseUrl: https://github.com/Optum/semver-cli/blob/HEAD/LICENSE + Copyright: Copyright (c) Optum + ShortDescription: A technology agnostic cli for common semantic versioning operations + Description: A technology agnostic cli for common semantic versioning operations. Built with Deno. + Moniker: semver + Tags: + - cli + - semver + - semantic-version + - versioning + - deno + ReleaseNotesUrl: https://github.com/Optum/semver-cli/releases/tag/${VERSION} + ManifestType: defaultLocale + ManifestVersion: 1.6.0 + EOF + + # Generate the version manifest + cat > "${manifest_dir}/Optum.semver.yaml" << EOF + # yaml-language-server: \$schema=https://aka.ms/winget-manifest.version.1.6.0.schema.json + + PackageIdentifier: Optum.semver + PackageVersion: ${VERSION} + DefaultLocale: en-US + ManifestType: version + ManifestVersion: 1.6.0 + EOF + + echo "Generated manifests:" + ls -la "${manifest_dir}" + cat "${manifest_dir}/Optum.semver.installer.yaml" + cat "${manifest_dir}/Optum.semver.locale.en-US.yaml" + cat "${manifest_dir}/Optum.semver.yaml" + + - name: Validate Winget Manifests + env: + VERSION: ${{ needs.version.outputs.version }} + shell: bash + run: | + manifest_dir="manifests/O/Optum/semver/${VERSION}" + + # Install winget (if not already available on Windows runner) + # Windows runners typically have winget pre-installed + + # Validate manifests using winget + echo "Validating manifests with winget..." + winget validate "${manifest_dir}" || echo "Validation returned: $?" + + # Output to GitHub Summary + cat >> $GITHUB_STEP_SUMMARY << EOF + ## Winget Manifests Generated + + Successfully generated Winget manifests for version **${VERSION}**. + + ### Manifest Details + - **Package Identifier**: Optum.semver + - **Version**: ${VERSION} + - **Architecture**: x64 + - **Installer Type**: zip (portable) + + ### Files Generated + - Optum.semver.installer.yaml + - Optum.semver.locale.en-US.yaml + - Optum.semver.yaml + EOF + + - name: Create PR to Winget Repository + env: + VERSION: ${{ needs.version.outputs.version }} + shell: bash + run: | + # Clone the winget-pkgs repository + gh repo clone microsoft/winget-pkgs winget-pkgs-repo + cd winget-pkgs-repo + + # Create a new branch + branch_name="Optum.semver-${VERSION}" + git checkout -b "${branch_name}" + + # Copy the generated manifests + manifest_dir="../manifests/O/Optum/semver/${VERSION}" + target_dir="manifests/o/Optum/semver/${VERSION}" + mkdir -p "${target_dir}" + cp "${manifest_dir}"/* "${target_dir}/" + + # Commit and push the changes + git add "manifests/o/Optum/semver/${VERSION}" + git commit -m "New version: Optum.semver version ${VERSION}" + git push origin "${branch_name}" + + # Create the PR + gh pr create \ + --repo microsoft/winget-pkgs \ + --title "New version: Optum.semver version ${VERSION}" \ + --body "This PR adds Optum.semver version ${VERSION} to the Windows Package Manager repository. + + **Package Information:** + - **Package Identifier**: Optum.semver + - **Version**: ${VERSION} + - **Publisher**: Optum + - **License**: Apache-2.0 + + **Changes:** + - Added new package version ${VERSION} + - Installer type: zip (portable) + - Architecture: x64 + + This PR was automatically generated by the semver-cli release workflow. + + **Release Notes**: https://github.com/Optum/semver-cli/releases/tag/${VERSION}" \ + --head "${branch_name}" \ + --base master + tags: if: ${{ github.event.release.prerelease == false }} runs-on: ubuntu-latest @@ -285,6 +498,7 @@ jobs: - assets - docker - homebrew + - winget permissions: contents: write id-token: write diff --git a/README.md b/README.md index 2943422..5476f4d 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,14 @@ brew install optum/tap/semver via [optum](https://github.com/Optum/homebrew-tap) +## Winget (Windows Package Manager) + +```sh +winget install Optum.semver +``` + +via [microsoft/winget-pkgs](https://github.com/microsoft/winget-pkgs) + ## From Source Installation from source will require From 4de031c6c8641092eeb73f618da85673aa9b3632 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:28:32 +0000 Subject: [PATCH 3/7] Fix winget manifest directory paths and validation Co-authored-by: justinmchase <10974+justinmchase@users.noreply.github.com> --- .github/workflows/publish.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index bcf5317..eb7c54b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -337,8 +337,8 @@ jobs: echo "URL: $url" # Create manifest directory structure - # Winget uses: manifests///// - manifest_dir="manifests/O/Optum/semver/${VERSION}" + # Winget uses: manifests///// + manifest_dir="manifests/o/Optum/semver/${VERSION}" mkdir -p "$manifest_dir" # Generate the installer manifest @@ -416,14 +416,18 @@ jobs: VERSION: ${{ needs.version.outputs.version }} shell: bash run: | - manifest_dir="manifests/O/Optum/semver/${VERSION}" + manifest_dir="manifests/o/Optum/semver/${VERSION}" # Install winget (if not already available on Windows runner) # Windows runners typically have winget pre-installed # Validate manifests using winget echo "Validating manifests with winget..." - winget validate "${manifest_dir}" || echo "Validation returned: $?" + if ! winget validate "${manifest_dir}"; then + echo "::error::Winget manifest validation failed" + exit 1 + fi + echo "Validation successful!" # Output to GitHub Summary cat >> $GITHUB_STEP_SUMMARY << EOF @@ -457,7 +461,7 @@ jobs: git checkout -b "${branch_name}" # Copy the generated manifests - manifest_dir="../manifests/O/Optum/semver/${VERSION}" + manifest_dir="../manifests/o/Optum/semver/${VERSION}" target_dir="manifests/o/Optum/semver/${VERSION}" mkdir -p "${target_dir}" cp "${manifest_dir}"/* "${target_dir}/" From 01fcd49c8e2d371c9192f9994beafc2308c08580 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:29:33 +0000 Subject: [PATCH 4/7] Improve winget manifest generation Co-authored-by: justinmchase <10974+justinmchase@users.noreply.github.com> --- .github/workflows/publish.yml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index eb7c54b..23b12bb 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -329,12 +329,22 @@ jobs: echo "Downloading ${asset_name} using GitHub CLI" gh release download "${VERSION}" --pattern "${asset_name}" --dir assets --repo Optum/semver-cli - # Calculate SHA256 (PowerShell command via bash) - sha=$(powershell -Command "(Get-FileHash -Algorithm SHA256 assets/${asset_name}).Hash") + # Calculate SHA256 (PowerShell command via bash, convert to lowercase) + sha=$(powershell -Command "(Get-FileHash -Algorithm SHA256 assets/${asset_name}).Hash.ToLower()") echo "SHA256: $sha" url="https://github.com/Optum/semver-cli/releases/download/${VERSION}/${asset_name}" echo "URL: $url" + + # Get release date from GitHub event (fallback to current date if not available) + release_date="${{ github.event.release.published_at }}" + if [ -z "$release_date" ]; then + release_date=$(date -u +%Y-%m-%d) + else + # Extract just the date portion (YYYY-MM-DD) from the ISO timestamp + release_date=$(echo "$release_date" | cut -d'T' -f1) + fi + echo "Release Date: $release_date" # Create manifest directory structure # Winget uses: manifests///// @@ -351,7 +361,7 @@ jobs: UpgradeBehavior: install Commands: - semver - ReleaseDate: $(date -u +%Y-%m-%d) + ReleaseDate: ${release_date} Installers: - Architecture: x64 NestedInstallerType: portable From 2ff7692be82521cf872a40a1f4a2fbd2152a5b54 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 01:00:08 +0000 Subject: [PATCH 5/7] Refactor winget integration to use scripts and manifest templates Co-authored-by: justinmchase <10974+justinmchase@users.noreply.github.com> --- .github/version.yml | 9 ++ .github/workflows/checks.yml | 31 +++++ .github/workflows/publish.yml | 213 ++++------------------------------ README.md | 2 +- manifests/installer.yaml | 19 +++ manifests/locale.en-US.yaml | 26 +++++ manifests/version.yaml | 7 ++ scripts/winget-package.sh | 185 +++++++++++++++++++++++++++++ scripts/winget-publish.sh | 184 +++++++++++++++++++++++++++++ 9 files changed, 485 insertions(+), 191 deletions(-) create mode 100644 manifests/installer.yaml create mode 100644 manifests/locale.en-US.yaml create mode 100644 manifests/version.yaml create mode 100755 scripts/winget-package.sh create mode 100755 scripts/winget-publish.sh diff --git a/.github/version.yml b/.github/version.yml index 8ae5648..118599c 100644 --- a/.github/version.yml +++ b/.github/version.yml @@ -10,3 +10,12 @@ on: - kind: regexp file: setup/action.yml pattern: "(?<=default: ).*" + - kind: regexp + file: manifests/installer.yaml + pattern: "(?<=PackageVersion: ).*" + - kind: regexp + file: manifests/locale.en-US.yaml + pattern: "(?<=PackageVersion: ).*" + - kind: regexp + file: manifests/version.yaml + pattern: "(?<=PackageVersion: ).*" diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index a5d245c..4cc4e4d 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -168,3 +168,34 @@ jobs: push: false tags: optum/semver-cli:pr platforms: linux/amd64 + + winget-check: + runs-on: windows-latest + needs: + - check + steps: + - uses: actions/checkout@v4 + - uses: denoland/setup-deno@v2 + with: + deno-version: v2.x + + - name: Install Dependencies + run: | + rm deno.lock + deno install --no-lock + + - name: Compile Windows Binary + run: | + deno compile --allow-run --allow-env --allow-read --allow-write -o bin/semver --target x86_64-pc-windows-msvc main.ts + + - name: Test Winget Package Script + shell: bash + run: | + chmod +x scripts/winget-package.sh + ./scripts/winget-package.sh + + - name: Test Winget Publish Script (Dry Run) + shell: bash + run: | + chmod +x scripts/winget-publish.sh + ./scripts/winget-publish.sh --dry-run diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 23b12bb..cd0f708 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -66,15 +66,7 @@ jobs: cd bin && tar -czf $APP_NAME.$TARGET.tar.gz ${APP_NAME}${EXT} ls -la - # Create ZIP file for Windows (required for winget) - - name: Create Windows ZIP - if: github.event_name == 'release' && matrix.target.name == 'x86_64-pc-windows-msvc' - run: | - cd bin - zip $APP_NAME.${{ matrix.target.name }}.zip ${APP_NAME}.exe - ls -la - - - name: Upload Release Asset (tar.gz) + - name: Upload Release Asset uses: actions/upload-release-asset@v1 if: github.event_name == 'release' env: @@ -85,17 +77,6 @@ jobs: asset_name: ${{ env.APP_NAME }}.${{ matrix.target.name }}.tar.gz asset_content_type: application/tar+gzip - - name: Upload Release Asset (zip for Windows) - uses: actions/upload-release-asset@v1 - if: github.event_name == 'release' && matrix.target.name == 'x86_64-pc-windows-msvc' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ github.event.release.upload_url }} - asset_path: ./bin/${{ env.APP_NAME }}.${{ matrix.target.name }}.zip - asset_name: ${{ env.APP_NAME }}.${{ matrix.target.name }}.zip - asset_content_type: application/zip - - name: Print Output if: github.event_name == 'release' env: @@ -297,7 +278,7 @@ jobs: --base main winget: - if: ${{ github.event_name == 'release' && github.event.release.prerelease == false }} + if: ${{ github.event.release.prerelease == false }} runs-on: windows-latest needs: - version @@ -317,192 +298,44 @@ jobs: git config --global user.email 'github-actions[bot]@users.noreply.github.com' gh auth setup-git - - name: Download Release Asset and Generate Winget Manifests + - name: Package for Winget env: VERSION: ${{ needs.version.outputs.version }} shell: bash run: | - mkdir -p assets manifests - - # Download the Windows ZIP asset using GitHub CLI - asset_name="semver.x86_64-pc-windows-msvc.zip" - echo "Downloading ${asset_name} using GitHub CLI" - gh release download "${VERSION}" --pattern "${asset_name}" --dir assets --repo Optum/semver-cli - - # Calculate SHA256 (PowerShell command via bash, convert to lowercase) - sha=$(powershell -Command "(Get-FileHash -Algorithm SHA256 assets/${asset_name}).Hash.ToLower()") - echo "SHA256: $sha" - - url="https://github.com/Optum/semver-cli/releases/download/${VERSION}/${asset_name}" - echo "URL: $url" - - # Get release date from GitHub event (fallback to current date if not available) - release_date="${{ github.event.release.published_at }}" - if [ -z "$release_date" ]; then - release_date=$(date -u +%Y-%m-%d) + chmod +x scripts/winget-package.sh + if [ "${{ github.event_name }}" == "release" ]; then + ./scripts/winget-package.sh --release --version "${VERSION}" else - # Extract just the date portion (YYYY-MM-DD) from the ISO timestamp - release_date=$(echo "$release_date" | cut -d'T' -f1) + ./scripts/winget-package.sh --version "${VERSION}" fi - echo "Release Date: $release_date" - - # Create manifest directory structure - # Winget uses: manifests///// - manifest_dir="manifests/o/Optum/semver/${VERSION}" - mkdir -p "$manifest_dir" - - # Generate the installer manifest - cat > "${manifest_dir}/Optum.semver.installer.yaml" << EOF - # yaml-language-server: \$schema=https://aka.ms/winget-manifest.installer.1.6.0.schema.json - - PackageIdentifier: Optum.semver - PackageVersion: ${VERSION} - InstallerType: zip - UpgradeBehavior: install - Commands: - - semver - ReleaseDate: ${release_date} - Installers: - - Architecture: x64 - NestedInstallerType: portable - NestedInstallerFiles: - - RelativeFilePath: semver.exe - PortableCommandAlias: semver - InstallerUrl: ${url} - InstallerSha256: ${sha} - ManifestType: installer - ManifestVersion: 1.6.0 - EOF - - # Generate the locale manifest - cat > "${manifest_dir}/Optum.semver.locale.en-US.yaml" << EOF - # yaml-language-server: \$schema=https://aka.ms/winget-manifest.defaultLocale.1.6.0.schema.json - - PackageIdentifier: Optum.semver - PackageVersion: ${VERSION} - PackageLocale: en-US - Publisher: Optum - PublisherUrl: https://github.com/Optum - PublisherSupportUrl: https://github.com/Optum/semver-cli/issues - Author: Optum - PackageName: semver - PackageUrl: https://github.com/Optum/semver-cli - License: Apache-2.0 - LicenseUrl: https://github.com/Optum/semver-cli/blob/HEAD/LICENSE - Copyright: Copyright (c) Optum - ShortDescription: A technology agnostic cli for common semantic versioning operations - Description: A technology agnostic cli for common semantic versioning operations. Built with Deno. - Moniker: semver - Tags: - - cli - - semver - - semantic-version - - versioning - - deno - ReleaseNotesUrl: https://github.com/Optum/semver-cli/releases/tag/${VERSION} - ManifestType: defaultLocale - ManifestVersion: 1.6.0 - EOF - - # Generate the version manifest - cat > "${manifest_dir}/Optum.semver.yaml" << EOF - # yaml-language-server: \$schema=https://aka.ms/winget-manifest.version.1.6.0.schema.json - - PackageIdentifier: Optum.semver - PackageVersion: ${VERSION} - DefaultLocale: en-US - ManifestType: version - ManifestVersion: 1.6.0 - EOF - echo "Generated manifests:" - ls -la "${manifest_dir}" - cat "${manifest_dir}/Optum.semver.installer.yaml" - cat "${manifest_dir}/Optum.semver.locale.en-US.yaml" - cat "${manifest_dir}/Optum.semver.yaml" - - - name: Validate Winget Manifests - env: - VERSION: ${{ needs.version.outputs.version }} + - name: Upload ZIP as Release Asset + if: github.event_name == 'release' shell: bash run: | - manifest_dir="manifests/o/Optum/semver/${VERSION}" - - # Install winget (if not already available on Windows runner) - # Windows runners typically have winget pre-installed + VERSION="${{ needs.version.outputs.version }}" + ZIP_FILE="dist/winget/semver.x86_64-pc-windows-msvc.zip" - # Validate manifests using winget - echo "Validating manifests with winget..." - if ! winget validate "${manifest_dir}"; then - echo "::error::Winget manifest validation failed" + if [ -f "$ZIP_FILE" ]; then + echo "Uploading $ZIP_FILE to release $VERSION" + gh release upload "${VERSION}" "$ZIP_FILE" --repo Optum/semver-cli --clobber + else + echo "Error: ZIP file not found at $ZIP_FILE" exit 1 fi - echo "Validation successful!" - - # Output to GitHub Summary - cat >> $GITHUB_STEP_SUMMARY << EOF - ## Winget Manifests Generated - - Successfully generated Winget manifests for version **${VERSION}**. - - ### Manifest Details - - **Package Identifier**: Optum.semver - - **Version**: ${VERSION} - - **Architecture**: x64 - - **Installer Type**: zip (portable) - - ### Files Generated - - Optum.semver.installer.yaml - - Optum.semver.locale.en-US.yaml - - Optum.semver.yaml - EOF - - name: Create PR to Winget Repository + - name: Publish to Winget env: VERSION: ${{ needs.version.outputs.version }} shell: bash run: | - # Clone the winget-pkgs repository - gh repo clone microsoft/winget-pkgs winget-pkgs-repo - cd winget-pkgs-repo - - # Create a new branch - branch_name="Optum.semver-${VERSION}" - git checkout -b "${branch_name}" - - # Copy the generated manifests - manifest_dir="../manifests/o/Optum/semver/${VERSION}" - target_dir="manifests/o/Optum/semver/${VERSION}" - mkdir -p "${target_dir}" - cp "${manifest_dir}"/* "${target_dir}/" - - # Commit and push the changes - git add "manifests/o/Optum/semver/${VERSION}" - git commit -m "New version: Optum.semver version ${VERSION}" - git push origin "${branch_name}" - - # Create the PR - gh pr create \ - --repo microsoft/winget-pkgs \ - --title "New version: Optum.semver version ${VERSION}" \ - --body "This PR adds Optum.semver version ${VERSION} to the Windows Package Manager repository. - - **Package Information:** - - **Package Identifier**: Optum.semver - - **Version**: ${VERSION} - - **Publisher**: Optum - - **License**: Apache-2.0 - - **Changes:** - - Added new package version ${VERSION} - - Installer type: zip (portable) - - Architecture: x64 - - This PR was automatically generated by the semver-cli release workflow. - - **Release Notes**: https://github.com/Optum/semver-cli/releases/tag/${VERSION}" \ - --head "${branch_name}" \ - --base master + chmod +x scripts/winget-publish.sh + if [ "${{ github.event_name }}" == "release" ]; then + ./scripts/winget-publish.sh --release + else + ./scripts/winget-publish.sh --release --dry-run + fi tags: if: ${{ github.event.release.prerelease == false }} diff --git a/README.md b/README.md index 5476f4d..ea5873a 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ via [optum](https://github.com/Optum/homebrew-tap) ## Winget (Windows Package Manager) ```sh -winget install Optum.semver +winget install Optum.semver-cli ``` via [microsoft/winget-pkgs](https://github.com/microsoft/winget-pkgs) diff --git a/manifests/installer.yaml b/manifests/installer.yaml new file mode 100644 index 0000000..eb8b5d1 --- /dev/null +++ b/manifests/installer.yaml @@ -0,0 +1,19 @@ +# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.6.0.schema.json + +PackageIdentifier: Optum.semver-cli +PackageVersion: __VERSION__ +InstallerType: zip +UpgradeBehavior: install +Commands: +- semver +ReleaseDate: __RELEASE_DATE__ +Installers: +- Architecture: x64 + NestedInstallerType: portable + NestedInstallerFiles: + - RelativeFilePath: semver.exe + PortableCommandAlias: semver + InstallerUrl: __INSTALLER_URL__ + InstallerSha256: __INSTALLER_SHA256__ +ManifestType: installer +ManifestVersion: 1.6.0 diff --git a/manifests/locale.en-US.yaml b/manifests/locale.en-US.yaml new file mode 100644 index 0000000..a151dbc --- /dev/null +++ b/manifests/locale.en-US.yaml @@ -0,0 +1,26 @@ +# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.6.0.schema.json + +PackageIdentifier: Optum.semver-cli +PackageVersion: __VERSION__ +PackageLocale: en-US +Publisher: Optum +PublisherUrl: https://github.com/Optum +PublisherSupportUrl: https://github.com/Optum/semver-cli/issues +Author: Optum +PackageName: semver-cli +PackageUrl: https://github.com/Optum/semver-cli +License: Apache-2.0 +LicenseUrl: https://github.com/Optum/semver-cli/blob/HEAD/LICENSE +Copyright: Copyright (c) Optum +ShortDescription: A technology agnostic cli for common semantic versioning operations +Description: A technology agnostic cli for common semantic versioning operations. Built with Deno. +Moniker: semver +Tags: +- cli +- semver +- semantic-version +- versioning +- deno +ReleaseNotesUrl: https://github.com/Optum/semver-cli/releases/tag/__VERSION__ +ManifestType: defaultLocale +ManifestVersion: 1.6.0 diff --git a/manifests/version.yaml b/manifests/version.yaml new file mode 100644 index 0000000..c56adf6 --- /dev/null +++ b/manifests/version.yaml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.6.0.schema.json + +PackageIdentifier: Optum.semver-cli +PackageVersion: __VERSION__ +DefaultLocale: en-US +ManifestType: version +ManifestVersion: 1.6.0 diff --git a/scripts/winget-package.sh b/scripts/winget-package.sh new file mode 100755 index 0000000..7f27791 --- /dev/null +++ b/scripts/winget-package.sh @@ -0,0 +1,185 @@ +#!/usr/bin/env bash +set -euo pipefail + +# winget-package.sh - Package semver-cli for winget +# Creates ZIP file and generates winget manifest files + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +# Default values +RELEASE_MODE=false +VERSION="" +PACKAGE_DIR="${REPO_ROOT}/dist/winget" + +# Parse arguments +while [[ $# -gt 0 ]]; do + case $1 in + --release) + RELEASE_MODE=true + shift + ;; + --version) + VERSION="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" + echo "Usage: $0 [--release] [--version VERSION]" + exit 1 + ;; + esac +done + +# Get version if not provided +if [ -z "$VERSION" ]; then + if [ -f "$REPO_ROOT/VERSION" ]; then + VERSION=$(cat "$REPO_ROOT/VERSION") + else + echo "Error: VERSION file not found and --version not provided" + exit 1 + fi +fi + +echo "Packaging semver-cli version ${VERSION} for winget" +echo "Release mode: ${RELEASE_MODE}" + +# Create output directory +mkdir -p "$PACKAGE_DIR" + +# Function to package from local build +package_local() { + echo "Packaging from local build..." + + # Check if binary exists + if [ ! -f "$REPO_ROOT/bin/semver.exe" ]; then + echo "Error: bin/semver.exe not found. Please build the Windows binary first." + exit 1 + fi + + # Create ZIP file + echo "Creating ZIP file..." + cd "$REPO_ROOT/bin" + zip -q "${PACKAGE_DIR}/semver.x86_64-pc-windows-msvc.zip" semver.exe + cd - > /dev/null + + echo "ZIP created: ${PACKAGE_DIR}/semver.x86_64-pc-windows-msvc.zip" +} + +# Function to package from GitHub release +package_release() { + echo "Downloading from GitHub release ${VERSION}..." + + # Download the Windows exe asset + asset_name="semver.x86_64-pc-windows-msvc.tar.gz" + echo "Downloading ${asset_name}..." + + if ! gh release download "${VERSION}" --pattern "${asset_name}" --dir "${PACKAGE_DIR}" --repo Optum/semver-cli 2>/dev/null; then + echo "Error: Failed to download ${asset_name} from release ${VERSION}" + echo "Make sure the release exists and contains the Windows binary" + exit 1 + fi + + # Extract the exe from tar.gz + echo "Extracting exe from tar.gz..." + cd "$PACKAGE_DIR" + tar -xzf "$asset_name" semver.exe + + # Create ZIP file + echo "Creating ZIP file..." + zip -q "semver.x86_64-pc-windows-msvc.zip" semver.exe + + # Clean up + rm -f "$asset_name" semver.exe + cd - > /dev/null + + echo "ZIP created: ${PACKAGE_DIR}/semver.x86_64-pc-windows-msvc.zip" +} + +# Package based on mode +if [ "$RELEASE_MODE" = true ]; then + package_release +else + package_local +fi + +# Calculate SHA256 +echo "Calculating SHA256..." +if command -v sha256sum &> /dev/null; then + SHA256=$(sha256sum "${PACKAGE_DIR}/semver.x86_64-pc-windows-msvc.zip" | cut -d' ' -f1) +elif command -v shasum &> /dev/null; then + SHA256=$(shasum -a 256 "${PACKAGE_DIR}/semver.x86_64-pc-windows-msvc.zip" | cut -d' ' -f1) +else + echo "Error: No SHA256 tool found (sha256sum or shasum)" + exit 1 +fi + +echo "SHA256: ${SHA256}" + +# Determine installer URL +if [ "$RELEASE_MODE" = true ]; then + INSTALLER_URL="https://github.com/Optum/semver-cli/releases/download/${VERSION}/semver.x86_64-pc-windows-msvc.zip" +else + # For local builds, we'll upload the ZIP as an asset later + INSTALLER_URL="__INSTALLER_URL__" +fi + +# Get release date +if [ "$RELEASE_MODE" = true ]; then + # Try to get from GitHub release + RELEASE_DATE=$(gh release view "${VERSION}" --repo Optum/semver-cli --json publishedAt --jq '.publishedAt' 2>/dev/null | cut -d'T' -f1 || date -u +%Y-%m-%d) +else + RELEASE_DATE=$(date -u +%Y-%m-%d) +fi + +echo "Release date: ${RELEASE_DATE}" + +# Generate manifest files +MANIFEST_DIR="${PACKAGE_DIR}/manifests/o/Optum/semver-cli/${VERSION}" +mkdir -p "$MANIFEST_DIR" + +echo "Generating manifest files in ${MANIFEST_DIR}..." + +# Copy and update installer manifest +sed -e "s|__VERSION__|${VERSION}|g" \ + -e "s|__RELEASE_DATE__|${RELEASE_DATE}|g" \ + -e "s|__INSTALLER_URL__|${INSTALLER_URL}|g" \ + -e "s|__INSTALLER_SHA256__|${SHA256}|g" \ + "${REPO_ROOT}/manifests/installer.yaml" > "${MANIFEST_DIR}/Optum.semver-cli.installer.yaml" + +# Copy and update locale manifest +sed -e "s|__VERSION__|${VERSION}|g" \ + "${REPO_ROOT}/manifests/locale.en-US.yaml" > "${MANIFEST_DIR}/Optum.semver-cli.locale.en-US.yaml" + +# Copy and update version manifest +sed -e "s|__VERSION__|${VERSION}|g" \ + "${REPO_ROOT}/manifests/version.yaml" > "${MANIFEST_DIR}/Optum.semver-cli.yaml" + +echo "Manifest files generated:" +ls -la "${MANIFEST_DIR}" + +# Output summary +cat << EOF + +================================================================= +Winget Package Created Successfully +================================================================= +Version: ${VERSION} +Package: ${PACKAGE_DIR}/semver.x86_64-pc-windows-msvc.zip +SHA256: ${SHA256} +Installer URL: ${INSTALLER_URL} +Manifests: ${MANIFEST_DIR} +================================================================= + +EOF + +# Save metadata for publish script +cat > "${PACKAGE_DIR}/metadata.env" << EOF +VERSION=${VERSION} +SHA256=${SHA256} +INSTALLER_URL=${INSTALLER_URL} +RELEASE_DATE=${RELEASE_DATE} +MANIFEST_DIR=${MANIFEST_DIR} +EOF + +echo "Metadata saved to ${PACKAGE_DIR}/metadata.env" diff --git a/scripts/winget-publish.sh b/scripts/winget-publish.sh new file mode 100755 index 0000000..dd26ff7 --- /dev/null +++ b/scripts/winget-publish.sh @@ -0,0 +1,184 @@ +#!/usr/bin/env bash +set -euo pipefail + +# winget-publish.sh - Publish semver-cli to winget repository +# Creates PR to microsoft/winget-pkgs repository + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +# Default values +DRY_RUN=false +RELEASE_MODE=false +PACKAGE_DIR="${REPO_ROOT}/dist/winget" + +# Parse arguments +while [[ $# -gt 0 ]]; do + case $1 in + --dry-run) + DRY_RUN=true + shift + ;; + --release) + RELEASE_MODE=true + shift + ;; + *) + echo "Unknown option: $1" + echo "Usage: $0 [--dry-run] [--release]" + exit 1 + ;; + esac +done + +echo "Publishing semver-cli to winget" +echo "Dry run: ${DRY_RUN}" +echo "Release mode: ${RELEASE_MODE}" + +# Load metadata from package step +if [ ! -f "${PACKAGE_DIR}/metadata.env" ]; then + echo "Error: metadata.env not found. Please run winget-package.sh first." + exit 1 +fi + +source "${PACKAGE_DIR}/metadata.env" + +echo "Version: ${VERSION}" +echo "Manifest directory: ${MANIFEST_DIR}" + +# Validate manifests using winget (if available and on Windows) +if command -v winget &> /dev/null; then + echo "Validating manifests with winget..." + if ! winget validate "${MANIFEST_DIR}"; then + echo "::error::Winget manifest validation failed" + exit 1 + fi + echo "✓ Validation successful!" +else + echo "⚠ winget command not available, skipping validation" +fi + +# If dry-run, stop here +if [ "$DRY_RUN" = true ]; then + echo "" + echo "================================================================= " + echo "DRY RUN MODE - Skipping PR creation" + echo "=================================================================" + echo "" + echo "Manifests are ready at: ${MANIFEST_DIR}" + echo "" + echo "To publish for real, run without --dry-run flag" + echo "" + + # Show what would be committed + echo "Files that would be published:" + ls -la "${MANIFEST_DIR}" + + echo "" + echo "Installer manifest:" + cat "${MANIFEST_DIR}/Optum.semver-cli.installer.yaml" + + echo "" + echo "Locale manifest:" + cat "${MANIFEST_DIR}/Optum.semver-cli.locale.en-US.yaml" + + echo "" + echo "Version manifest:" + cat "${MANIFEST_DIR}/Optum.semver-cli.yaml" + + exit 0 +fi + +# Real publish - create PR to microsoft/winget-pkgs +echo "" +echo "Creating PR to microsoft/winget-pkgs repository..." +echo "" + +# Check if gh is available +if ! command -v gh &> /dev/null; then + echo "Error: GitHub CLI (gh) is required for publishing" + exit 1 +fi + +# Clone the winget-pkgs repository +WINGET_REPO_DIR="${PACKAGE_DIR}/winget-pkgs-repo" +if [ -d "$WINGET_REPO_DIR" ]; then + echo "Removing existing winget-pkgs clone..." + rm -rf "$WINGET_REPO_DIR" +fi + +echo "Cloning microsoft/winget-pkgs..." +if ! gh repo clone microsoft/winget-pkgs "$WINGET_REPO_DIR" -- --depth=1; then + echo "Error: Failed to clone microsoft/winget-pkgs" + exit 1 +fi + +cd "$WINGET_REPO_DIR" + +# Create a new branch +BRANCH_NAME="Optum.semver-cli-${VERSION}" +echo "Creating branch: ${BRANCH_NAME}" +git checkout -b "${BRANCH_NAME}" + +# Copy manifests to the winget-pkgs repository +TARGET_DIR="manifests/o/Optum/semver-cli/${VERSION}" +mkdir -p "${TARGET_DIR}" +cp "${MANIFEST_DIR}"/* "${TARGET_DIR}/" + +echo "Copied manifests to ${TARGET_DIR}" + +# Show what will be committed +echo "" +echo "Files to be committed:" +git status --short + +# Commit the changes +git add "${TARGET_DIR}" +git commit -m "New version: Optum.semver-cli version ${VERSION}" + +# Push the branch +echo "Pushing branch to origin..." +if ! git push origin "${BRANCH_NAME}"; then + echo "Error: Failed to push branch" + exit 1 +fi + +# Create the PR +echo "Creating pull request..." + +PR_BODY="This PR adds Optum.semver-cli version ${VERSION} to the Windows Package Manager repository. + +**Package Information:** +- **Package Identifier**: Optum.semver-cli +- **Version**: ${VERSION} +- **Publisher**: Optum +- **License**: Apache-2.0 + +**Changes:** +- Added new package version ${VERSION} +- Installer type: zip (portable) +- Architecture: x64 + +This PR was automatically generated by the semver-cli release workflow. + +**Release Notes**: https://github.com/Optum/semver-cli/releases/tag/${VERSION}" + +if ! gh pr create \ + --repo microsoft/winget-pkgs \ + --title "New version: Optum.semver-cli version ${VERSION}" \ + --body "$PR_BODY" \ + --head "${BRANCH_NAME}" \ + --base master; then + echo "Error: Failed to create pull request" + exit 1 +fi + +echo "" +echo "=================================================================" +echo "✓ Successfully created PR to microsoft/winget-pkgs" +echo "=================================================================" +echo "" +echo "Version ${VERSION} has been submitted to winget!" +echo "" + +cd - > /dev/null From 11ec56554e1cc1cc43394d22aec9d4f327bfeec3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 01:01:37 +0000 Subject: [PATCH 6/7] Fix winget job conditions and remove unnecessary conditionals Co-authored-by: justinmchase <10974+justinmchase@users.noreply.github.com> --- .github/workflows/publish.yml | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index cd0f708..06fd91d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -278,7 +278,7 @@ jobs: --base main winget: - if: ${{ github.event.release.prerelease == false }} + if: ${{ github.event_name == 'release' && github.event.release.prerelease == false }} runs-on: windows-latest needs: - version @@ -304,14 +304,9 @@ jobs: shell: bash run: | chmod +x scripts/winget-package.sh - if [ "${{ github.event_name }}" == "release" ]; then - ./scripts/winget-package.sh --release --version "${VERSION}" - else - ./scripts/winget-package.sh --version "${VERSION}" - fi + ./scripts/winget-package.sh --release --version "${VERSION}" - name: Upload ZIP as Release Asset - if: github.event_name == 'release' shell: bash run: | VERSION="${{ needs.version.outputs.version }}" @@ -331,11 +326,7 @@ jobs: shell: bash run: | chmod +x scripts/winget-publish.sh - if [ "${{ github.event_name }}" == "release" ]; then - ./scripts/winget-publish.sh --release - else - ./scripts/winget-publish.sh --release --dry-run - fi + ./scripts/winget-publish.sh --release tags: if: ${{ github.event.release.prerelease == false }} From 88f9bd5217385e3de3c1974b0ff262d4a9aad538 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 01:02:23 +0000 Subject: [PATCH 7/7] Add permissions block to winget-check job Co-authored-by: justinmchase <10974+justinmchase@users.noreply.github.com> --- .github/workflows/checks.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 4cc4e4d..0d71deb 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -171,6 +171,8 @@ jobs: winget-check: runs-on: windows-latest + permissions: + contents: read needs: - check steps: