From ef9570fd03addd116a1e1a71651b94adc3984973 Mon Sep 17 00:00:00 2001 From: Matt Edwards Date: Wed, 28 Aug 2024 12:21:39 -0400 Subject: [PATCH] Initial commit --- .github/dependabot.yml | 11 + .github/issue-branch.yml | 34 ++ .github/workflows/create-release.yml | 58 +++ .github/workflows/deploy-gh-pages.yml | 51 +++ .github/workflows/format.yml | 42 ++ .github/workflows/issue-branch.yml | 23 + .github/workflows/publish.yml | 83 ++++ .github/workflows/test-report.yml | 29 ++ .github/workflows/test.yml | 60 +++ .github/workflows/unlist-nuget.yml | 26 ++ .github/workflows/update-version.yml | 78 ++++ .gitignore | 398 ++++++++++++++++++ .vscode/settings.json | 3 + Directory.Build.props | 26 ++ Directory.Build.targets | 38 ++ LICENSE | 23 + README.md | 140 ++++++ assets/hyperbee.svg | 29 ++ assets/icon.png | Bin 0 -> 28103 bytes docs/_config.yml | 9 + docs/index.md | 5 + docs/todo.md | 3 + solution-helper.psm1 | 213 ++++++++++ src/Hyperbee.Project/hyperbee.project.txt | 0 .../hyperbee.project.test.txt | 0 25 files changed, 1382 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 .github/issue-branch.yml create mode 100644 .github/workflows/create-release.yml create mode 100644 .github/workflows/deploy-gh-pages.yml create mode 100644 .github/workflows/format.yml create mode 100644 .github/workflows/issue-branch.yml create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/test-report.yml create mode 100644 .github/workflows/test.yml create mode 100644 .github/workflows/unlist-nuget.yml create mode 100644 .github/workflows/update-version.yml create mode 100644 .gitignore create mode 100644 .vscode/settings.json create mode 100644 Directory.Build.props create mode 100644 Directory.Build.targets create mode 100644 LICENSE create mode 100644 README.md create mode 100644 assets/hyperbee.svg create mode 100644 assets/icon.png create mode 100644 docs/_config.yml create mode 100644 docs/index.md create mode 100644 docs/todo.md create mode 100644 solution-helper.psm1 create mode 100644 src/Hyperbee.Project/hyperbee.project.txt create mode 100644 test/Hyperbee.Project.Tests/hyperbee.project.test.txt diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..8ca517d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "nuget" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/issue-branch.yml b/.github/issue-branch.yml new file mode 100644 index 0000000..6c65fe3 --- /dev/null +++ b/.github/issue-branch.yml @@ -0,0 +1,34 @@ +defaultBranch: 'develop' +branchName: '${issue.number}:${issue.title,}' +mode: auto +gitSafeReplacementChar: '-' +branches: + - label : feature + prefix: feature/ + name: develop + prTarget: develop + skip: false + - label : bug + prefix: bugfix/ + name: develop + prTarget: develop + skip: false + - label : critical + prefix: hotfix/ + name: main + prTarget: main + skip: false + - label : documentation + prefix: doc/ + name: main + prTarget: main + - label : '*' + skip: true + + +prSkipCI: true +copyIssueDescriptionToPR: true +copyIssueLabelsToPR: true +copyIssueAssigneeToPR: true +openDraftPR: true +autoCloseIssue: true diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml new file mode 100644 index 0000000..74e64e6 --- /dev/null +++ b/.github/workflows/create-release.yml @@ -0,0 +1,58 @@ +name: Create Release + +on: + workflow_dispatch: + inputs: + is_prerelease: + description: 'Create a prerelease:' + type: boolean + required: true + default: false + is_draft: + description: 'Set as a draft:' + type: boolean + required: true + default: false + +env: + ALLOW_PRERELEASE: ${{ startsWith(github.ref, 'refs/heads/develop') || startsWith(github.ref, 'refs/heads/hotfix/') }} + +jobs: + create-release: + runs-on: ubuntu-latest + + steps: + - name: Check For Valid Prerelease + if: ${{ ( env.ALLOW_PRERELEASE == 'true' && github.event.inputs.is_prerelease == 'false' ) || ( github.ref == 'refs/heads/main' && github.event.inputs.is_prerelease == 'true' ) }} + run: | + echo "Prereleases should not be triggered on the main branch, please use development or hotfix" + exit 1 + + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Get Current Version + id: get_version + shell: pwsh + run: | + Import-Module ./solution-helper.psm1 -Force + $version = Get-Version + if ("${{ github.event.inputs.is_prerelease }}" -eq "true") { + $version_tag = "$version-develop.$(date +'%y%m%d%H%M%S')" + } else { + $version_tag = $version + } + echo "version_tag=$version_tag" | Out-File -FilePath $env:GITHUB_ENV -Append + + - name: Create Release + run: | + echo "🎁 Creating release ${{ env.version_tag }}" + gh release create ${{ env.version_tag }} \ + --target ${{ github.ref_name }} \ + --title ${{ env.version_tag }} \ + --generate-notes \ + $(if [[ "${{ github.event.inputs.is_draft }}" == "true" ]]; then echo "--draft"; fi) \ + $(if [[ "${{ github.event.inputs.is_prerelease }}" == "true" ]]; then echo "--prerelease"; fi) \ + $(if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then echo "--latest"; fi) + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/deploy-gh-pages.yml b/.github/workflows/deploy-gh-pages.yml new file mode 100644 index 0000000..909d330 --- /dev/null +++ b/.github/workflows/deploy-gh-pages.yml @@ -0,0 +1,51 @@ +# Sample workflow for building and deploying a Jekyll site to GitHub Pages +name: Deploy Jekyll with GitHub Pages dependencies preinstalled + +on: + # Runs on pushes targeting the default branch + push: + branches: ["main"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + # Build job + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Pages + uses: actions/configure-pages@v5 + - name: Build with Jekyll + uses: actions/jekyll-build-pages@v1 + with: + source: ./docs + destination: ./_site + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml new file mode 100644 index 0000000..74083f7 --- /dev/null +++ b/.github/workflows/format.yml @@ -0,0 +1,42 @@ +name: Format + +on: + push: + workflow_run: + workflows: + - Create Prerelease + - Create Release + types: [requested] + workflow_dispatch: + pull_request: + types: [opened, edited, synchronize, reopened] + branches: + - main + - develop + +env: + DOTNET_VERSION: "8.0.x" + +jobs: + format: + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Format + run: dotnet format + + - name: Update Styles + continue-on-error: true + run: | + git config --global user.name 'github-actions' + git config --global user.email 'github-actions@github.com' + git commit -am "Updated code formatting to match rules in .editorconfig" + git push diff --git a/.github/workflows/issue-branch.yml b/.github/workflows/issue-branch.yml new file mode 100644 index 0000000..4695151 --- /dev/null +++ b/.github/workflows/issue-branch.yml @@ -0,0 +1,23 @@ +name: Create Issue Branch + +on: + # The issue.opened event below is only needed for the "immediate" mode. + # The issue.assigned event below is only needed for the default ("auto") mode. + issues: + types: [ opened, assigned ] + # The issue_comment.created event below is only needed for the ChatOps mode. + issue_comment: + types: [ created ] + # The pull_request events below are only needed for pull-request related features. + pull_request: + types: [ opened, closed ] + +jobs: + create_issue_branch_job: + runs-on: ubuntu-latest + steps: + - name: Create Issue Branch + id: Create_Issue_Branch + uses: robvanderleek/create-issue-branch@main + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..2723bb2 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,83 @@ +name: Publish + +on: + workflow_dispatch: + release: + types: [published] + +env: + BRANCH_NAME: ${{ github.event.release.target_commitish }} + SOLUTION_NAME: ${{ vars.SOLUTION_NAME }} + DOTNET_VERSION: '8.0.x' + NUGET_SOURCE: 'https://api.nuget.org/v3/index.json' + BUILD_CONFIGURATION: '' + VERSION_SUFFIX: '' + +jobs: + build-publish: + runs-on: ubuntu-latest + + steps: + - name: Release Configuration + if: ${{ env.BRANCH_NAME == 'main' && (github.event.release.prerelease == false || github.event_name == 'workflow_dispatch') }} + run: | + echo "BUILD_CONFIGURATION=Release" >> $GITHUB_ENV + + - name: Debug Configuration + if: ${{ (github.event.release.prerelease || github.event_name == 'workflow_dispatch') }} + run: | + echo "BUILD_CONFIGURATION=Debug" >> $GITHUB_ENV + + - name: Check Build Configuration + if: ${{ env.BUILD_CONFIGURATION == '' }} + run: | + echo "Invalid Build Configuration" + exit 1 + + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Get Current Version + id: get_version + shell: pwsh + run: | + Import-Module ./solution-helper.psm1 -Force + $build_version = Get-Version + echo "build_version=$build_version" | Out-File -FilePath $env:GITHUB_ENV -Append + + - name: Get Version Suffix + id: get_version_suffix + shell: bash + run: | + # Fetch the list of releases + releases=$(gh release list --json createdAt,tagName --limit 100) + + # Filter the releases based on the starting version number, sort them by date, and extract the most recent one + latest_release=$(echo "$releases" | jq -r --arg build_version "$build_version" 'map(select(.tagName | startswith($build_version))) | sort_by(.createdAt) | reverse | .[0] | .tagName') + + version_suffix=${latest_release#*$build_version-} + + if [ "$version_suffix" == "$build_version" ]; then + version_suffix="" + fi + + echo "VERSION_SUFFIX=$version_suffix" >> $GITHUB_ENV + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Restore Dependencies + run: dotnet restore ${{ env.SOLUTION_NAME }} + + - name: Build + run: dotnet build --no-restore --configuration ${{ env.BUILD_CONFIGURATION }} ${{ env.SOLUTION_NAME }} + + - name: Test + run: dotnet test --no-build --verbosity normal --configuration ${{ env.BUILD_CONFIGURATION }} ${{ env.SOLUTION_NAME }} + + - name: Pack and Push + run: dotnet pack --no-build --configuration ${{ env.BUILD_CONFIGURATION }} -p:PackageOutputPath=../../output --version-suffix "${{ env.VERSION_SUFFIX }}" -p:PackageSource='${{ env.NUGET_SOURCE }}' -p:PushAfterPack=true -p:PackageApiKey='${{ secrets.NUGET_API_KEY }}' diff --git a/.github/workflows/test-report.yml b/.github/workflows/test-report.yml new file mode 100644 index 0000000..20dc477 --- /dev/null +++ b/.github/workflows/test-report.yml @@ -0,0 +1,29 @@ +name: Test Report +run-name: Generate Test Report for workflow ${{ github.event.workflow_run.name }} run ${{ github.event.workflow_run.run_number }} branch ${{ github.event.workflow_run.head_branch }} + +# https://github.com/dorny/test-reporter#recommended-setup-for-public-repositories +# This workflow is for test report + +on: + workflow_run: + workflows: [ "Test" ] + types: + - completed + +permissions: + contents: read + actions: read + checks: write + +jobs: + report: + runs-on: ubuntu-latest + steps: + - name: Test Report 🧪 + uses: dorny/test-reporter@v1 + with: + artifact: test-results + name: Unit Tests + path: "*.trx" + reporter: dotnet-trx + fail-on-error: false \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..3715983 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,60 @@ +name: Test + +on: + workflow_run: + workflows: + - Create Prerelease + - Create Release + # - Publish + types: [requested] + workflow_dispatch: + pull_request: + types: [opened, edited, synchronize, reopened] + branches: + - main + - develop + +env: + BRANCH_NAME: ${{ github.head_ref || github.ref_name }} + SOLUTION_NAME: ${{ vars.SOLUTION_NAME }} + DOTNET_VERSION: "8.0.x" + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Release Configuration + if: ${{ env.BRANCH_NAME == 'main' }} + run: | + echo "BUILD_CONFIGURATION=Release" >> $GITHUB_ENV + + - name: Debug Configuration + if: ${{ env.BRANCH_NAME != 'main' }} + run: | + echo "BUILD_CONFIGURATION=Debug" >> $GITHUB_ENV + + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Restore Dependencies + run: dotnet restore ${{ env.SOLUTION_NAME }} + + - name: Build + run: dotnet build --no-restore --configuration ${{ env.BUILD_CONFIGURATION }} ${{ env.SOLUTION_NAME }} + + - name: Tests + run: | + dotnet test --no-build --configuration ${{ env.BUILD_CONFIGURATION }} --logger:trx --results-directory:./TestResults ${{ env.SOLUTION_NAME }} + + - name: Upload Test Results + uses: actions/upload-artifact@v3 # upload test results + if: success() || failure() # run this step even if previous step failed + with: + name: test-results + path: ./TestResults/**/*.trx diff --git a/.github/workflows/unlist-nuget.yml b/.github/workflows/unlist-nuget.yml new file mode 100644 index 0000000..58c5254 --- /dev/null +++ b/.github/workflows/unlist-nuget.yml @@ -0,0 +1,26 @@ +name: Unlist NuGet + +on: + workflow_dispatch: + # release: + # types: [deleted] + +env: + BRANCH_NAME: ${{ github.event.release.target_commitish }} + PROJECT_NAME: ${{ vars.PROJECT_NAME }} + +jobs: + publish: + name: unlist on nuget + runs-on: windows-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + # Unlist + - name: Unlist Deleted Tag + uses: darenm/unlist-nuget@v1 + with: + NUGET_PACKAGE: ${{ env.PROJECT_NAME }} # Full Package ID + VERSION_REGEX: ${{ github.event.release.tag_name }} # Regex pattern to match version + NUGET_KEY: ${{ secrets.NUGET_API_KEY }} # nuget.org API key \ No newline at end of file diff --git a/.github/workflows/update-version.yml b/.github/workflows/update-version.yml new file mode 100644 index 0000000..c6758c9 --- /dev/null +++ b/.github/workflows/update-version.yml @@ -0,0 +1,78 @@ +name: Update Version + +on: + workflow_dispatch: + inputs: + version_type: + description: 'Update branch version by:' + type: choice + options: + - major + - minor + - patch + required: true + default: 'patch' + +env: + ALLOW_UPDATES: ${{ startsWith(github.ref, 'refs/heads/develop') || startsWith(github.ref, 'refs/heads/hotfix/') }} + +jobs: + update-version: + runs-on: ubuntu-latest + outputs: + version_tag: ${{ env.version_tag }} + previous_version_tag: ${{ env.previous_version_tag }} + + steps: + - name: Check For Valid Updates + if: env.ALLOW_UPDATES == false + run: | + echo "Version updates should only be done on development or hotfix" + exit 1 + + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Run Update Version + id: set_version + shell: pwsh + run: | + Import-Module ./solution-helper.psm1 -Force + $previousVersion, $newVersion = Update-Version -type ${{ github.event.inputs.version_type }} + echo "version_tag=$newVersion" | Out-File -FilePath $env:GITHUB_ENV -Append + echo "previous_version_tag=$previousVersion" | Out-File -FilePath $env:GITHUB_ENV -Append + + - name: Check for Existing Release + run: | + compare_versions() { + echo -e "$1\n$2" | sort -V | tail -n 1 + } + + # Fetch the list of releases + releases=$(gh release list --json createdAt,tagName --limit 100) + echo -e "$releases" + + # Sort the releases by date and extract the most recent one + latest_release=$(echo "$releases" | jq -r 'sort_by(.createdAt) | reverse | .[0] | .tagName') + echo -e "$latest_release" + + greater_version=$(compare_versions $latest_release $version_tag) + + if [ "$greater_version" = "$version_tag" ]; then + echo "✅ $version_tag is greater than $latest_release" + elif [ "$greater_version" = "$latest_release" ]; then + echo "⛔ $version_tag is less than $latest_release" + exit 1 + else + echo "⚠️ Versions are equal" + exit 1 + fi + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Update Version Number + run: | + git config --global user.name '${{ github.triggering_actor }}' + git config --global user.email '${{ github.triggering_actor }}@users.noreply.github.com' + git commit -am "Previous version was '${{ env.previous_version_tag }}'. Version now '${{ env.version_tag }}'." + git push \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8dd4607 --- /dev/null +++ b/.gitignore @@ -0,0 +1,398 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..3bd0bc0 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cSpell.words": ["Hyperbee"] +} diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..94bfb51 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,26 @@ + + + + 1 + 1 + 5 + + + + false + + + + + true + true + true + embedded + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + \ No newline at end of file diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 0000000..ab19c8b --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,38 @@ + + + + + + + + + + $(MajorVersion).$(MinorVersion).$(PatchVersion) + $(VersionPrefix) + $(VersionPrefix)-$(VersionSuffix) + + + + + + --source $(PackageSource) + + + + + + --api-key $(PackageApiKey) + + + + \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5487bc2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,23 @@ +## LICENSE + +MIT License + +Copyright (c) 2024 Stillpoint Software, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..44614ec --- /dev/null +++ b/README.md @@ -0,0 +1,140 @@ +# Inital Project Setup + +## Stucture + +### Source + +All projects should be in a folder with the same name as the project. + +### Tests + +All test should be in a project related to their project in the tests folder. + +### Solution Files + +- .github/worflow files include + +## Repo Settings + +Update the repository settings + +### Pull Request Labels + +Add the following labels. Label case is important for workflows. + +- feature + - description: Improvements or additions to documentation + - color: #0075ca +- critical + - description: Major Release Issue + - color: #B60205 + +### Variables + +Add the following variable to the repository so that the github action work correctly + +- SOLUTION_NAME = "Hyperbee.---.sln" + +### Issue Labels + +Default labels should line up with the settings in `issue-branch.yml` and any others that might be useful. + +## Dependabot + +- Enable and Group PRs +- dependabot.yml should be included with + +## Nuget Config + +### Project File + +The Project file should include the basic nuget information in sections like: + +```xml + + net8.0 + enable + true + Stillpoint Software, Inc. + README.md + {TAGS} + icon.png + https://github.com/Stillpoint-Software/Hyperbee.{PACKAGE}/ + https://github.com/Stillpoint-Software/Hyperbee.{PACKAGE}/releases/latest + net8.0 + LICENSE + Stillpoint Software, Inc. + Hyperbee {PACKAGE} + {PACKAGE INFO} + https://github.com/Stillpoint-Software/Hyperbee.{PACKAGE} + git + +``` + +And + +```xml + + + + True + \ + + + True + \ + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + +``` + +### Directory.Build.props + +Make sure the section is correctly set for initial release: + +```xml + + 1 + 0 + 0 + +``` + +### Status Area + +- Add the following paths for the **develop** and **main** Actions. Replace {project} with the hyperbee project name. + + - Develop: `[![Build status](https://github.com/Stillpoint-Software/Hyperbee.{projectName}/actions/workflows/publish.yml/badge.svg?branch=develop)](https://github.com/Stillpoint-Software/Hyperbee.{projectName}/actions/workflows/publish.yml)` + + - Main: `[![Build status](https://github.com/Stillpoint-Software/Hyperbee.{projectName}/actions/workflows/publish.yml/badge.svg)](https://github.com/Stillpoint-Software/Hyperbee.{projectName}/actions/workflows/publish.yml) ` + +- Add to bottom of status + +`[![Hyperbee.{projectName}](https://github.com/Stillpoint-Software/Hyperbee.{projectName}/blob/main/assets/hyperbee.jpg?raw=true)](https://github.com/Stillpoint-Software/Hyperbee.{projectName})` + +# -- SAMPLE TEMPATE README -- + +# Hyperbee. + +Classes for building awesome software + +## Usage + +```csharp +# Cool usage of the code! +``` + +# Status + +| Branch | Action | +| --------- | ------------ | +| `develop` | {links here} | +| `main` | {links here} | + +# Help + +See [Todo](https://github.com/Stillpoint-Software/Hyperbee.Project/blob/main/docs/todo.md) diff --git a/assets/hyperbee.svg b/assets/hyperbee.svg new file mode 100644 index 0000000..67b6ef3 --- /dev/null +++ b/assets/hyperbee.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icon.png b/assets/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..281d398d1b09da06f3f87875b0542de952a86a53 GIT binary patch literal 28103 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 literal 0 HcmV?d00001 diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000..d7f0218 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,9 @@ +title: Hyperbee.CookieCutter +description: Documentation for Hyperbee CookieCutter Projects. +remote_theme: pmarsceill/just-the-docs + +# Optional configuration +search_enabled: true +aux_links: + "GitHub Repository": + - "//github.com/Stillpoint-Software/hyperbee.cookiecutter" diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..0ff9720 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,5 @@ +# Welcome to Hyperbee.CookieCutter + +Hyperbee.CookieCutter is a template that initialize the default setting for a repository using the Hyperbee best practices. + +## Features diff --git a/docs/todo.md b/docs/todo.md new file mode 100644 index 0000000..304bc7c --- /dev/null +++ b/docs/todo.md @@ -0,0 +1,3 @@ +# Things TODO + +## Add work to be done \ No newline at end of file diff --git a/solution-helper.psm1 b/solution-helper.psm1 new file mode 100644 index 0000000..f59e729 --- /dev/null +++ b/solution-helper.psm1 @@ -0,0 +1,213 @@ +<# + .SYNOPSIS + Solution helpers. + + .DESCRIPTION + Commands for managing nugets. + These methods may be executed from the `Developer PowerShell` terminal window. + Import-Module ./solution-helper +#> + +function Publish-Packages() { + Param( + [Parameter(Position = 0)] + [Alias("c")] + [string] $Configuration = 'Debug', + + [Alias("t")] + [string] $Tag = 'local' + ) + + try { + $Tag = ($Tag -replace '\s+', '').ToLower() + Write-Host "Building and publishing packages for '$Configuration' with tag '$Tag'." + + $timestamp = [System.DateTime]::UtcNow.ToString( 'yyMMddHHmmss' ) + + if ( !$Tag ) { + Write-Error "Non-semver publication is not supported." + throw + } + + dotnet pack --no-build --configuration $Configuration --output ./output --version-suffix "$Tag.$timestamp" -p:PushAfterPack=true + } + catch { + Write-Error "Publish-Packages failed. Make sure you are executing from a `Developer PowerShell` session." + } +} + +function Resize-Feed() { + Param( + [string] $Name = '*', + [int] $Keep = 5, + [string] $Source = 'local' + ) + + Write-Host "Collecting package versions from $source ..." + + # get unique packages + $packages = Find-Package $Name -source $Source + + foreach( $package in $packages ) { + $packageName = $package.Name + + # get all versions for this package + + $sortExpr = { param($version) # convert '1.2.3-..' to '00001-00002-00003-..' + $parts = $version.Split('-') + $key = ( $parts[0].Split('.') | ForEach-Object { $_.PadLeft(5,'0') } ) -join '-' + $key,$parts[1] -join '-' + } + + $versions = Find-Package $packageName -source $source -allversions | Sort-Object { &$sortExpr -version $_.Version } -Descending + + Write-Host "Found '$packageName'. $($versions.Count) Packages." + + if ( $versions.Count -gt $Keep ) { + $removeCount = $versions.Count - $Keep + Write-Host "$removeCount Packages will be removed." + + foreach( $p in ($versions | Select-Object -Skip $Keep ) ) { + dotnet nuget delete $p.Name $p.Version --source $Source --non-interactive + } + } + } +} + +function Update-Version() { + Param( + [Parameter(Position = 0, Mandatory=$true)] + [ValidateSet('Major','Minor','Patch', IgnoreCase = $true)] + [string] $Type, + [string] $Path = 'Directory.Build.props', + [switch] $Commit + ) + + try { + if (!(Test-Path $Path)) { + Write-Error "The version file '$Path' was not found in the current directory." + throw + } + + $Type = (Get-Culture).TextInfo.ToTitleCase($Type) # e.g. convert 'major' to 'Major' + $propName = $Type + "Version" + + $xml = [xml](Get-Content $Path) + $ns = New-Object System.Xml.XmlNamespaceManager($xml.NameTable) + $ns.AddNamespace("ns", $xml.DocumentElement.NamespaceURI) + + $node = $xml.SelectSingleNode("//ns:Project/ns:PropertyGroup[ns:$propName]", $ns) + $version = $node.$propName -as [Int] + + $previousVersionString = "v$($node.MajorVersion).$($node.MinorVersion).$($node.PatchVersion)" + + $node.$propName = ($version + 1) -as [String] + + if ( $Type -eq 'major' ) { + $node.MinorVersion = '0' + $node.PatchVersion = '0' + } + + if ( $Type -eq 'minor' ) { + $node.PatchVersion = '0' + } + + $newVersionString = "v$($node.MajorVersion).$($node.MinorVersion).$($node.PatchVersion)" + Write-Host "Previous version was '$previousVersionString'. Version now '$newVersionString'." + + $xml.Save($Path) + + if ( $Commit ) { + git add $Path + git commit -m "bump $($Type.ToLower())" -q -o $Path + } + + return $previousVersionString, $newVersionString + } + catch { + Write-Error "Update-Version failed. Make sure you are executing from a `Developer PowerShell`." + } +} + +function Set-Version() { + Param( + [Parameter(Position = 0,Mandatory=$true)] + [string] $Version, + [string] $Path = 'Directory.Build.props', + [switch] $Commit + ) + + try { + if (!(Test-Path $Path)) { + Write-Error "The version file '$Path' was not found in the current directory." + throw + } + + # Remove any non-numeric characters from the version string + $Version = $Version -replace '[^0-9.]', '' + + # Split the version string into major, minor, and patch versions + $MajorVersion, $MinorVersion, $PatchVersion = $Version.Split('.') + + $xml = [xml](Get-Content $Path) + $ns = New-Object System.Xml.XmlNamespaceManager($xml.NameTable) + $ns.AddNamespace("ns", $xml.DocumentElement.NamespaceURI) + + $node = $xml.SelectSingleNode("//ns:Project/ns:PropertyGroup", $ns) + + $previousVersionString = "v$($node.MajorVersion).$($node.MinorVersion).$($node.PatchVersion)" + + # Update the version numbers + $node.MajorVersion = $MajorVersion + $node.MinorVersion = $MinorVersion + $node.PatchVersion = $PatchVersion + + $newVersionString = "v$($node.MajorVersion).$($node.MinorVersion).$($node.PatchVersion)" + Write-Host "Previous version was '$previousVersionString'. Version now '$newVersionString'." + + $xml.Save($Path) + + if ( $Commit ) { + git add $Path + git commit -m "bump $($Type.ToLower())" -q -o $Path + } + + return $previousVersionString, $newVersionString + } + catch { + Write-Error "Set-Version failed. Make sure you are executing from a `Developer PowerShell`." + } +} + +function Get-Version() { + Param( + [string] $Path = 'Directory.Build.props' + ) + + try { + if (!(Test-Path $Path)) { + Write-Error "The version file '$Path' was not found in the current directory." + throw + } + + $xml = [xml](Get-Content $Path) + $ns = New-Object System.Xml.XmlNamespaceManager($xml.NameTable) + $ns.AddNamespace("ns", $xml.DocumentElement.NamespaceURI) + + $node = $xml.SelectSingleNode("//ns:Project/ns:PropertyGroup", $ns) + + $versionString = "v$($node.MajorVersion).$($node.MinorVersion).$($node.PatchVersion)" + Write-Host "Current version is '$versionString'." + + return $versionString + } + catch { + Write-Error "Get-Version failed. Make sure you are executing from a `Developer PowerShell`." + } +} + +Export-ModuleMember -Function 'Publish-Packages' +Export-ModuleMember -Function 'Resize-Feed' +Export-ModuleMember -Function 'Update-Version' +Export-ModuleMember -Function 'Set-Version' +Export-ModuleMember -Function 'Get-Version' \ No newline at end of file diff --git a/src/Hyperbee.Project/hyperbee.project.txt b/src/Hyperbee.Project/hyperbee.project.txt new file mode 100644 index 0000000..e69de29 diff --git a/test/Hyperbee.Project.Tests/hyperbee.project.test.txt b/test/Hyperbee.Project.Tests/hyperbee.project.test.txt new file mode 100644 index 0000000..e69de29