├── .csharpierrc ├── .editorconfig ├── .gitattributes ├── .github ├── CODEOWNERS ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── issue-report.md ├── PULL_REQUEST_TEMPLATE.md ├── actions │ ├── action.yml │ ├── build-check │ │ └── action.yml │ ├── build-tools │ │ └── action.yml │ ├── build-version │ │ └── action.yml │ ├── build │ │ └── action.yml │ ├── cloudformation-deploy │ │ └── action.yml │ ├── database-deploy │ │ └── action.yml │ ├── dispatch-deploy │ │ └── action.yml │ ├── docker-build-to-registry │ │ └── action.yml │ ├── docker-image-test │ │ └── action.yml │ ├── docker-setup │ │ └── action.yml │ ├── dotnet-publish │ │ └── action.yml │ ├── dotnet-tool │ │ └── action.yml │ ├── dotnet │ │ └── action.yml │ ├── npm │ │ └── action.yml │ ├── nuget-push-integrated-symbol-feed │ │ ├── action.yml │ │ └── actions.yml │ ├── nuget-push-separate-symbol-feed │ │ ├── action.yml │ │ └── actions.yml │ ├── nuget │ │ └── action.yml │ ├── sarif │ │ └── action.yml │ ├── save-secret-as-file │ │ └── action.yml │ ├── sbom │ │ └── action.yml │ ├── sleet │ │ └── action.yml │ └── sql │ │ └── action.yml ├── dependabot.yml ├── labeler.yml ├── labels.yml ├── linters │ ├── .eslintrc.yml │ ├── .hadolint.yaml │ ├── .markdown-lint.yml │ ├── .python-black │ ├── .python-lint │ ├── .yaml-lint.yml │ ├── actionlint.yaml │ ├── syft.yml │ └── tslint.json ├── pr-lint.yml └── workflows │ ├── approve-dependabot.yml │ ├── build-and-publish-pre-release.yml │ ├── build-and-publish-release.yml │ ├── create-prs-for-stale-branches.yml │ ├── dependabot.yml │ ├── deploy.yml │ ├── dotnet-version.yml │ ├── merge-dependabot.yml │ ├── missing-releases.yml │ ├── on-pr-closed.yml │ ├── on_new_pr.yml │ ├── oss-scorecared.yml │ ├── pr-lint.yml │ ├── pr-update.yml │ ├── pull-request.yml │ ├── reformat-sql.yml │ ├── reformat-yaml.yml │ ├── todos.yml │ └── update-labels.yml ├── .gitignore ├── .gitleaks.toml ├── .tsqllintrc ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md └── src ├── .idea └── .idea.Credfeto.Enumeration.Source.Generation │ └── .idea │ ├── .gitignore │ ├── .name │ ├── encodings.xml │ ├── indexLayout.xml │ └── vcs.xml ├── CodeAnalysis.ruleset ├── Credfeto.Enumeration.Source.Generation.Attributes ├── Credfeto.Enumeration.Source.Generation.Attributes.csproj └── EnumTextAttribute.cs ├── Credfeto.Enumeration.Source.Generation.Benchmarks ├── BenchBase.cs ├── Credfeto.Enumeration.Source.Generation.Benchmarks.csproj ├── EnumBench.cs ├── EnumWrappers.cs └── Program.cs ├── Credfeto.Enumeration.Source.Generation.Generics ├── Credfeto.Enumeration.Source.Generation.Generics.csproj └── EnumHelpers.cs ├── Credfeto.Enumeration.Source.Generation.Models.Tests ├── Credfeto.Enumeration.Source.Generation.Models.Tests.csproj ├── EnumGetDescriptionTests.cs └── EnumGetNameTests.cs ├── Credfeto.Enumeration.Source.Generation.Models ├── .gitignore ├── Credfeto.Enumeration.Source.Generation.Models.csproj ├── EnumExtensions.cs └── ExampleEnumValues.cs ├── Credfeto.Enumeration.Source.Generation.sln ├── Credfeto.Enumeration.Source.Generation.sln.DotSettings ├── Credfeto.Enumeration.Source.Generation ├── Builders │ └── CodeBuilder.cs ├── Credfeto.Enumeration.Source.Generation.csproj ├── EnumGenerator.cs ├── EnumSourceGenerator.cs ├── Extensions │ ├── EnumerableExtensions.cs │ ├── SymbolExtensions.cs │ ├── TypeDeclarationSyntaxExtensions.cs │ └── TypeInfoExtensions.cs ├── Helpers │ ├── LiteralString.cs │ ├── RuleHelpers.cs │ └── SupportedDiagnosticsList.cs ├── IaHelper.cs ├── Models │ ├── AccessType.cs │ ├── ClassEnumGeneration.cs │ ├── EnumGeneration.cs │ ├── ErrorInfo.cs │ └── GenerationOptions.cs ├── ProhibitEnumToStringsDiagnosticsAnalyzer.cs ├── Receivers │ └── SyntaxExtractor.cs └── tools │ ├── install.ps1 │ └── uninstall.ps1 ├── Directory.Build.props ├── KeepGeneratedFiles.props ├── SourceGenerator.props └── global.json /.csharpierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "useTabs": false, 4 | "tabWidth": 4, 5 | "endOfLine": "auto" 6 | } 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | 5 | #note left to system settings 6 | * text=auto 7 | 8 | ############################################################################### 9 | # Scripts 10 | ############################################################################### 11 | 12 | # We dont want CRLF for bash shell scripts 13 | *.sh text eol=lf 14 | 15 | 16 | ############################################################################### 17 | # DFINITY/Motoko 18 | ############################################################################### 19 | 20 | *.mo text eol=lf 21 | 22 | ############################################################################### 23 | # Yaml 24 | ############################################################################### 25 | 26 | 27 | *.yml text eol=lf 28 | *.yaml text eol=lf 29 | 30 | ############################################################################### 31 | # C# 32 | ############################################################################### 33 | 34 | *.cs text=auto diff=csharp 35 | 36 | ############################################################################### 37 | # Explicitly binary - should be handled automatically anyway 38 | ############################################################################### 39 | *.jpg binary 40 | *.jpeg binary 41 | *.png binary 42 | *.gif binary 43 | *.ico binary 44 | *.woff binary 45 | *.wof binary 46 | *.eot binary 47 | *.ttf binary 48 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @credfeto 2 | * @funfair-tech/Server 3 | db/* @funfair-tech/ServerDatabase 4 | Tools/* @funfair-tech/ServerDatabase -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: credfeto 2 | buy_me_a_coffee: mark.ridgwell 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: 'T: Feature' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 15 | 16 | **Is your feature request related to a problem? Please describe.** 17 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 18 | 19 | **Describe the solution you'd like** 20 | A clear and concise description of what you want to happen. 21 | 22 | **Describe alternatives you've considered** 23 | A clear and concise description of any alternative solutions or features you've considered. 24 | 25 | **Additional context** 26 | Add any other context or screenshots about the feature request here. 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Issue report 3 | about: Report a problem 4 | title: '' 5 | labels: 'T: Bug' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 16 | 17 | **Describe the problem**: 18 | [A clear and concise description of what the bug is.] 19 | 20 | **To Reproduce**: 21 | [Steps to reproduce the behavior] 22 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Description 4 | 5 | 6 | # Related Issue\Feature 7 | 8 | 9 | # How Has This Been Tested 10 | - [ ] All unit tests pass. 11 | - [ ] All integration tests pass. 12 | - [ ] Manual Testing: 13 | 14 | 15 | 16 | 17 | # Types of changes 18 | 19 | 20 | - [ ] Docs change 21 | - [ ] Refactoring 22 | - [ ] Dependency upgrade 23 | - [ ] Additional Unit Tests\Integration Tests 24 | - [ ] Bug fix (non-breaking change which fixes an issue) 25 | - [ ] New feature (non-breaking change which adds functionality) 26 | - [ ] Breaking change (fix or feature that would cause existing functionality to change) 27 | - [ ] Removed no-longer used code 28 | 29 | ## Deployment Configuration Changes 30 | - [ ] Requires deployment configuration changes as specified below and in CHANGELOG.md 31 | 32 | 33 | # Checklist 34 | 35 | 36 | - [ ] There are no Resharper\static code analysis errors anywhere in the solution. 37 | - [ ] I have ONLY run a code clean-up on any files I have modified to make sure they are in the correct format and no others. 38 | - [ ] I have added tests to cover my changes. 39 | - [ ] I have run the code and quickly verified it all works to my satisfaction. 40 | - [ ] All new/modified code has sufficient logging to be able to diagnose what is wrong. 41 | - [ ] All new and existing tests passed. 42 | - [ ] All new/modified public interfaces/classes have are documented with xmldoc comments. 43 | - [ ] Unreleased section of CHANGELOG.md has been updated with details of this PR. 44 | -------------------------------------------------------------------------------- /.github/actions/build-check/action.yml: -------------------------------------------------------------------------------- 1 | --- # Define build version properties 2 | name: 'Define Build Version' 3 | description: 'Defines the build version properties' 4 | inputs: 5 | # GENERAL 6 | GITHUB_TOKEN: 7 | description: 'Github Token' 8 | required: true 9 | 10 | runs: 11 | using: "composite" 12 | steps: 13 | - name: "Dotnet: Run build check (Pre-Release)" 14 | if: env.Release == 'false' 15 | working-directory: ${{github.workspace}}/src 16 | shell: bash 17 | run: dotnet tool run buildcheck -Solution "$(find . -type f -iname "*.sln" | head -1)" -WarningAsErrors true -PreReleaseBuild false 18 | env: 19 | DOTNET_ROOT: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 20 | DOTNET_INSTALL_DIR: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 21 | DOTNET_MULTILEVEL_LOOKUP: "false" 22 | DOTNET_NOLOGO: "true" 23 | DOTNET_PRINT_TELEMETRY_MESSAGE: "false" 24 | DOTNET_JitCollect64BitCounts: "1" 25 | DOTNET_ReadyToRun: "0" 26 | DOTNET_TC_QuickJitForLoops: "1" 27 | DOTNET_TC_CallCountingDelayMs: "0" 28 | DOTNET_TieredPGO: "1" 29 | MSBUILDTERMINALLOGGER: "auto" 30 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages 31 | 32 | - name: "Dotnet: Run build check (Release)" 33 | if: env.Release == 'true' 34 | working-directory: ${{github.workspace}}/src 35 | shell: bash 36 | run: dotnet tool run buildcheck -Solution "$(find . -type f -iname "*.sln" | head -1)" -WarningAsErrors true -PreReleaseBuild false 37 | env: 38 | DOTNET_ROOT: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 39 | DOTNET_INSTALL_DIR: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 40 | DOTNET_MULTILEVEL_LOOKUP: "false" 41 | DOTNET_NOLOGO: "true" 42 | DOTNET_PRINT_TELEMETRY_MESSAGE: "false" 43 | DOTNET_JitCollect64BitCounts: "1" 44 | DOTNET_ReadyToRun: "0" 45 | DOTNET_TC_QuickJitForLoops: "1" 46 | DOTNET_TC_CallCountingDelayMs: "0" 47 | DOTNET_TieredPGO: "1" 48 | MSBUILDTERMINALLOGGER: "auto" 49 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages 50 | -------------------------------------------------------------------------------- /.github/actions/build-tools/action.yml: -------------------------------------------------------------------------------- 1 | --- # Build and deploy packages 2 | name: 'Install dotnet and build tools' 3 | description: 'Install dotnet and build tools' 4 | inputs: 5 | # GENERAL 6 | GITHUB_TOKEN: 7 | description: 'Github Token' 8 | required: true 9 | 10 | # NUGET 11 | NUGET_PUBLIC_RESTORE_FEED_CACHE: 12 | description: 'Local cache of public nuget feed' 13 | required: false 14 | NUGET_PUBLIC_RESTORE_FEED: 15 | description: 'public nuget feed' 16 | required: false 17 | NUGET_ADDITIONAL_RESTORE_FEED_RELEASE_CACHE: 18 | description: 'Any additional nuget feed to download packages from' 19 | required: false 20 | NUGET_ADDITIONAL_RESTORE_FEED_PRERELEASE_CACHE: 21 | description: 'Any additional nuget feed to download packages from' 22 | required: false 23 | NUGET_ADDITIONAL_RESTORE_FEED_RELEASE: 24 | description: 'Any additional nuget feed to download packages from' 25 | required: false 26 | NUGET_ADDITIONAL_RESTORE_FEED_PRERELEASE: 27 | description: 'Any additional nuget feed to download packages from' 28 | required: false 29 | 30 | runs: 31 | using: "composite" 32 | steps: 33 | 34 | # Workaround for https://github.com/dotnet/sdk/issues/11432 35 | - name: "Explicitly kill any existing dotnet" 36 | shell: bash 37 | working-directory: ${{ github.workspace }} 38 | run: | 39 | [ -d "$HOME/.dotnet" ] && rm -fr "$HOME/.dotnet" 40 | mkdir "$HOME/.dotnet" 41 | 42 | # Workaround for https://github.com/dotnet/sdk/issues/11432 43 | - name: "Re-map users nuget package feed to temp folder" 44 | shell: bash 45 | working-directory: ${{ github.workspace }} 46 | run: | 47 | echo "Ensure ~/.nuget folder exists" 48 | [ -d "$HOME/.nuget" ] || mkdir -p "$HOME/.nuget" 49 | echo "Ensure NUGET_PACKAGES folder exists at ${{env.NUGET_PACKAGES}}" 50 | [ -d "${{env.NUGET_PACKAGES}}" ] || mkdir -p "${{env.NUGET_PACKAGES}}" 51 | echo "Ensure ~/.nuget/packages doesn't exist" 52 | rm -fr "$HOME/.nuget/packages" 53 | echo "Link ~/.nuget/packages to ${{env.NUGET_PACKAGES}}" 54 | ln -sf "${{env.NUGET_PACKAGES}}" "$HOME/.nuget/packages" 55 | echo "Check ~/.nuget/packages" 56 | ls -la "$HOME/.nuget/packages" 57 | env: 58 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages 59 | 60 | - name: "Determine dotnet version" 61 | uses: credfeto/action-dotnet-version-detect@v1.3.0 62 | with: 63 | file: src/global.json 64 | fallback: 7.0.* 65 | 66 | - name: "Explicitly kill any existing dotnet" 67 | run: rm -fr "${{github.workspace}}/.dotnet" 68 | shell: bash 69 | 70 | - name: "Install dotnet" 71 | uses: actions/setup-dotnet@v4.2.0 72 | env: 73 | GITHUB_TOKEN: ${{inputs.GITHUB_TOKEN}} 74 | DOTNET_ROOT: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 75 | DOTNET_INSTALL_DIR: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 76 | DOTNET_MULTILEVEL_LOOKUP: "false" 77 | DOTNET_NOLOGO: "true" 78 | DOTNET_PRINT_TELEMETRY_MESSAGE: "false" 79 | DOTNET_JitCollect64BitCounts: "1" 80 | DOTNET_ReadyToRun: "0" 81 | DOTNET_TC_QuickJitForLoops: "1" 82 | DOTNET_TC_CallCountingDelayMs: "0" 83 | DOTNET_TieredPGO: "1" 84 | MSBUILDTERMINALLOGGER: "auto" 85 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages 86 | with: 87 | dotnet-version: | 88 | 8.0.* 89 | 9.0.* 90 | ${{env.DOTNET_VERSION}} 91 | 92 | - name: "Configure nuget feeds" 93 | uses: ./.github/actions/nuget 94 | with: 95 | NUGET_PUBLIC_RESTORE_FEED_CACHE: ${{inputs.NUGET_PUBLIC_RESTORE_FEED_CACHE}} 96 | NUGET_PUBLIC_RESTORE_FEED: ${{inputs.NUGET_PUBLIC_RESTORE_FEED}} 97 | NUGET_ADDITIONAL_RESTORE_FEED_RELEASE_CACHE: ${{inputs.NUGET_ADDITIONAL_RESTORE_FEED_RELEASE_CACHE}} 98 | NUGET_ADDITIONAL_RESTORE_FEED_PRERELEASE_CACHE: ${{inputs.NUGET_ADDITIONAL_RESTORE_FEED_PRERELEASE_CACHE}} 99 | NUGET_ADDITIONAL_RESTORE_FEED_RELEASE: ${{inputs.NUGET_ADDITIONAL_RESTORE_FEED_RELEASE}} 100 | NUGET_ADDITIONAL_RESTORE_FEED_PRERELEASE: ${{inputs.NUGET_ADDITIONAL_RESTORE_FEED_PRERELEASE}} 101 | 102 | - name: "Enable dotnet tools" 103 | shell: bash 104 | working-directory: ${{ github.workspace }} 105 | run: | 106 | [ ! -f .config/dotnet-tools.json ] && dotnet new tool-manifest 107 | dotnet tool restore || true 108 | env: 109 | DOTNET_ROOT: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 110 | DOTNET_INSTALL_DIR: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 111 | DOTNET_MULTILEVEL_LOOKUP: "false" 112 | DOTNET_NOLOGO: "true" 113 | DOTNET_PRINT_TELEMETRY_MESSAGE: "false" 114 | DOTNET_JitCollect64BitCounts: "1" 115 | DOTNET_ReadyToRun: "0" 116 | DOTNET_TC_QuickJitForLoops: "1" 117 | DOTNET_TC_CallCountingDelayMs: "0" 118 | DOTNET_TieredPGO: "1" 119 | MSBUILDTERMINALLOGGER: "auto" 120 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages 121 | 122 | - name: "Install Sleet package management tool" 123 | uses: ./.github/actions/dotnet-tool 124 | with: 125 | TOOL_NAME: sleet 126 | TOOL_VERSION: latest 127 | 128 | - name: "Install Build Version Tool" 129 | uses: ./.github/actions/dotnet-tool 130 | with: 131 | TOOL_NAME: FunFair.BuildVersion 132 | TOOL_VERSION: latest 133 | 134 | - name: "Install Changelog Tool" 135 | uses: ./.github/actions/dotnet-tool 136 | with: 137 | TOOL_NAME: Credfeto.Changelog.Cmd 138 | TOOL_VERSION: latest 139 | -------------------------------------------------------------------------------- /.github/actions/build-version/action.yml: -------------------------------------------------------------------------------- 1 | --- # Define build version properties 2 | name: 'Define Build Version' 3 | description: 'Defines the build version properties' 4 | inputs: 5 | # GENERAL 6 | GITHUB_TOKEN: 7 | description: 'Github Token' 8 | required: true 9 | 10 | runs: 11 | using: "composite" 12 | steps: 13 | - name: "Define Build Version" 14 | shell: bash 15 | working-directory: ${{ github.workspace }} 16 | run: dotnet tool run buildversion --GithubToken "${{inputs.GITHUB_TOKEN}}" --TagPrefix "github" 17 | env: 18 | DOTNET_ROOT: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 19 | DOTNET_INSTALL_DIR: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 20 | DOTNET_MULTILEVEL_LOOKUP: "false" 21 | DOTNET_NOLOGO: "true" 22 | DOTNET_PRINT_TELEMETRY_MESSAGE: "false" 23 | DOTNET_JitCollect64BitCounts: "1" 24 | DOTNET_ReadyToRun: "0" 25 | DOTNET_TC_QuickJitForLoops: "1" 26 | DOTNET_TC_CallCountingDelayMs: "0" 27 | DOTNET_TieredPGO: "1" 28 | MSBUILDTERMINALLOGGER: "auto" 29 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages 30 | 31 | - name: "Log build version" 32 | shell: bash 33 | run: | 34 | echo "****************************************************************" 35 | echo "* Current Build: ${{env.BUILD_VERSION}}" 36 | echo "****************************************************************" 37 | -------------------------------------------------------------------------------- /.github/actions/cloudformation-deploy/action.yml: -------------------------------------------------------------------------------- 1 | --- # Deploy docker image using cloudformation template to aws 2 | name: 'Deploy to Cloudformation template' 3 | description: 'Deploy docker image using cloudformation template to aws' 4 | inputs: 5 | CLOUD_FORMATION_STACK: 6 | description: 'The Cloud Formation stack to deploy as' 7 | required: true 8 | CLOUDFORMATION_SNS_ARN: 9 | description: 'SSN Notification ARN' 10 | required: false 11 | CLOUD_FORMATION_TEMPLATE_FILE: 12 | description: 'The Cloud Formation file to deploy' 13 | required: true 14 | DOCKER_APP_OWNER: 15 | description: 'docker app owner' 16 | required: true 17 | DOCKER_APP_NAME: 18 | description: 'docker app name' 19 | required: true 20 | API_HOST: 21 | description: 'Api Host' 22 | required: true 23 | API_PREFIX: 24 | description: 'API Prefix' 25 | required: false 26 | AWS_LOAD_BALANCER_HOSTNAME: 27 | description: "AWS Load Balancer match hostname" 28 | required: true 29 | AWS_LOAD_BALANCER_PRIORITY: 30 | description: "AWS Load Balancer match priority" 31 | required: true 32 | AWS_CONTAINER_REGISTRY: 33 | description: "AWS container registry to retrieve package from" 34 | required: true 35 | BUILD_VERSION: 36 | description: "Build Version" 37 | required: true 38 | 39 | runs: 40 | using: "composite" 41 | steps: 42 | 43 | - name: "Build TemplateParameters file" 44 | shell: bash 45 | run: | 46 | FIRST=1 47 | { 48 | echo "[" 49 | jq '.Parameters' "${{inputs.CLOUD_FORMATION_TEMPLATE_FILE}}" | \ 50 | grep ': {' | \ 51 | grep -oEi '([a-z]|_|[1-9])+' | \ 52 | sort | \ 53 | uniq | while read -r key; do 54 | 55 | value="${!key}" 56 | 57 | # only output the keys which have values 58 | if [ -n "$value" ]; then 59 | 60 | [ "$FIRST" -eq 0 ] && echo " ," 61 | FIRST=0 62 | 63 | # TODO: need a better way to do this that allows for escaping of 64 | # characters that need to in json. 65 | echo " {\"ParameterKey\":\"$key\",\"ParameterValue\":\"$value\"}" 66 | 67 | fi 68 | 69 | done 70 | echo "]" 71 | } > "${{github.workspace}}/TemplateParameters.json" 72 | env: 73 | ApplicationName: ${{inputs.CLOUD_FORMATION_STACK}} 74 | ApplicationContainer: ${{inputs.DOCKER_APP_NAME}} 75 | ApplicationVersion: ${{inputs.BUILD_VERSION}} 76 | ApiPrefix: /${{inputs.DOCKER_APP_NAME}} 77 | ApiHost: ${{inputs.API_HOST}} 78 | LoadBalancerHostName: ${{inputs.AWS_LOAD_BALANCER_HOSTNAME}} 79 | LoadBalancerPriority: ${{inputs.AWS_LOAD_BALANCER_PRIORITY}} 80 | AwsContainerRegistry: ${{inputs.AWS_CONTAINER_REGISTRY}} 81 | 82 | - name: "show Validated TemplateParameters" 83 | shell: bash 84 | run: | 85 | echo "SNS ARN: ${{inputs.CLOUDFORMATION_SNS_ARN}}" 86 | echo "Validated parameters:" 87 | jq . "${{github.workspace}}/TemplateParameters.json" 88 | 89 | - if: inputs.CLOUDFORMATION_SNS_ARN != '' 90 | name: "AWS Cloudformation Deploy (With Notifications)" 91 | shell: bash 92 | run: | 93 | /usr/local/aws-cli/v2/current/bin/aws \ 94 | cloudformation deploy \ 95 | --template-file \ 96 | "${{inputs.CLOUD_FORMATION_TEMPLATE_FILE}}" \ 97 | --stack-name \ 98 | "${{inputs.CLOUD_FORMATION_STACK}}" \ 99 | --parameter-overrides \ 100 | file://TemplateParameters.json \ 101 | --notification-arns \ 102 | "${{inputs.CLOUDFORMATION_SNS_ARN}}" \ 103 | --tags \ 104 | "App=${{inputs.CLOUD_FORMATION_STACK}}" \ 105 | "Version=${{inputs.BUILD_VERSION}}" 106 | 107 | - if: inputs.CLOUDFORMATION_SNS_ARN == '' 108 | name: "AWS Cloudformation Deploy (No Notifications)" 109 | shell: bash 110 | run: | 111 | /usr/local/aws-cli/v2/current/bin/aws \ 112 | cloudformation deploy \ 113 | --template-file \ 114 | "${{inputs.CLOUD_FORMATION_TEMPLATE_FILE}}" \ 115 | --stack-name \ 116 | "${{inputs.CLOUD_FORMATION_STACK}}" \ 117 | --parameter-overrides \ 118 | file://TemplateParameters.json \ 119 | --tags \ 120 | "App=${{inputs.CLOUD_FORMATION_STACK}}" \ 121 | "Version=${{inputs.BUILD_VERSION}}" 122 | 123 | - name: "AWS Enable Stack termination protection" 124 | shell: bash 125 | run: | 126 | /usr/local/aws-cli/v2/current/bin/aws \ 127 | cloudformation update-termination-protection \ 128 | --enable-termination-protection \ 129 | --stack-name "${{inputs.CLOUD_FORMATION_STACK}}" 130 | -------------------------------------------------------------------------------- /.github/actions/database-deploy/action.yml: -------------------------------------------------------------------------------- 1 | --- # Build and deploy packages 2 | name: 'Build and deploy' 3 | description: 'Builds and deploys the source' 4 | inputs: 5 | BUILD_VERSION: 6 | description: "Build Version" 7 | required: true 8 | SQL_SERVER: 9 | description: 'SQL Server to connect to' 10 | required: true 11 | SQL_DB: 12 | description: 'Database to deploy to' 13 | required: true 14 | SQL_USER: 15 | description: 'User to connect to the database as' 16 | required: true 17 | SQL_PASSWORD: 18 | description: 'Password for SQL_USER' 19 | required: true 20 | DB_FOLDER: 21 | description: 'Folder where SQL Files live' 22 | required: true 23 | REDGATE_EMAIL: 24 | description: 'Redgate authentication email' 25 | required: true 26 | REDGATE_PAT: 27 | description: 'Redgate authentication Personal Access Token' 28 | required: true 29 | SQLCOMPARE_VERSION: 30 | description: 'Version of SQL Compare to use' 31 | required: true 32 | 33 | runs: 34 | using: "composite" 35 | steps: 36 | 37 | - name: "Get SQL Compare" 38 | shell: bash 39 | run: docker pull redgate/sqlcompare:${{inputs.SQLCOMPARE_VERSION}} 40 | 41 | # Need to get these to work 42 | - name: "Build SQL Diff change" 43 | shell: bash 44 | run: | 45 | docker run \ 46 | "-v$GITHUB_WORKSPACE:$GITHUB_WORKSPACE" \ 47 | --net=host \ 48 | --rm \ 49 | "redgate/sqlcompare:${{inputs.SQLCOMPARE_VERSION}}" \ 50 | /email:"${{inputs.REDGATE_EMAIL}}" \ 51 | /token:"${{inputs.REDGATE_PAT}}" \ 52 | /IAgreeToTheEULA \ 53 | /filter:"$DB_FILTER" \ 54 | /options:CaseSensitiveObjectDefinition,ConsiderNextFilegroupInPartitionSchemes,DecryptPost2kEncryptedObjects,DoNotOutputCommentHeader,ForceColumnOrder,IgnoreCertificatesAndCryptoKeys,IgnoreDatabaseAndServerName,IgnoreUserProperties,IgnoreUsersPermissionsAndRoleMemberships,IgnoreWhiteSpace,IgnoreWithElementOrder,IncludeDependencies,NoDeploymentLogging,ThrowOnFileParseFailed,UseCompatibilityLevel \ 55 | /transactionIsolationLevel:SERIALIZABLE \ 56 | /include:staticData \ 57 | /Include:Identical \ 58 | /scriptFile:"$DB_OUTPUT" \ 59 | /scripts1:"$DB_SOURCE" \ 60 | /showWarnings \ 61 | /include:Identical \ 62 | /report:"$DB_REPORT" \ 63 | /reportType:Xml \ 64 | /force \ 65 | /OutputWidth:1024 \ 66 | "/server2:$SQL_SERVER" \ 67 | "/database2:$SQL_DB" \ 68 | "/username2:$SQL_USER" \ 69 | "/password2:$SQL_PASSWORD" \ 70 | /verbose 71 | env: 72 | DB_SOURCE: ${{inputs.DB_FOLDER}} 73 | DB_OUTPUT: ${{github.workspace}}/update.sql 74 | DB_LOG: ${{github.workspace}}/update.log 75 | DB_REPORT: ${{github.workspace}}/update.xml 76 | DB_FILTER: ${{inputs.DB_FOLDER}}/Filter.scpf 77 | DOCKER_CONTENT_TRUST: 0 78 | SQL_SERVER: "${{inputs.SQL_SERVER}}" 79 | SQL_DB: "${{inputs.SQL_DB}}" 80 | SQL_USER: "${{inputs.SQL_USER}}" 81 | SQL_PASSWORD: "${{inputs.SQL_PASSWORD}}" 82 | 83 | - name: "Check SQL Diff Output status" 84 | id: sql 85 | shell: bash 86 | run: | 87 | { 88 | [ -f "$DB_LOG" ] && echo "log=true" || echo "log=false" 89 | [ -f "$DB_OUTPUT" ] && echo "script=true" || echo "script=false" 90 | } >> "$GITHUB_OUTPUT" 91 | env: 92 | DB_OUTPUT: ${{github.workspace}}/update.sql 93 | DB_LOG: ${{github.workspace}}/update.log 94 | 95 | - name: "Log Script" 96 | if: ${{steps.sql.outputs.script == 'true'}} 97 | shell: bash 98 | run: cat "$DB_OUTPUT" 99 | env: 100 | DB_OUTPUT: ${{github.workspace}}/update.sql 101 | 102 | - name: "Log Output" 103 | if: ${{steps.sql.outputs.log == 'true'}} 104 | shell: bash 105 | run: cat "DB_LOG" 106 | env: 107 | DB_LOG: ${{github.workspace}}/update.log 108 | 109 | - name: "Deploy schema" 110 | if: ${{steps.sql.outputs.script == 'true'}} 111 | uses: azure/sql-action@v2.3 112 | with: 113 | connection-string: "Server=${{inputs.SQL_SERVER}};Database=${{inputs.SQL_DB}};User Id=${{inputs.SQL_USER}};Password=${{inputs.SQL_PASSWORD}};Connection Timeout=60;TrustServerCertificate=true;Application Name=Deploy Schema ${{inputs.BUILD_VERSION}}" 114 | path: ${{github.workspace}}/update.sql 115 | arguments: -e -b 116 | -------------------------------------------------------------------------------- /.github/actions/dispatch-deploy/action.yml: -------------------------------------------------------------------------------- 1 | --- # Dispatch to deploy workflow for deployment. 2 | name: 'Dispatch to deploy workflow' 3 | description: 'Dispatches deployment to a separate workflow' 4 | inputs: 5 | CLOUD_FORMATION_STACK: 6 | description: 'The Cloud Formation stack to deploy as' 7 | required: true 8 | CLOUD_FORMATION_TEMPLATE_FILE: 9 | description: 'The Cloud Formation file to deploy' 10 | required: true 11 | DOCKER_APP_OWNER: 12 | description: 'docker app owner' 13 | required: true 14 | DOCKER_APP_NAME: 15 | description: 'docker app name' 16 | required: true 17 | API_HOST: 18 | description: 'Api Host' 19 | required: false 20 | API_PREFIX: 21 | description: 'API Prefix' 22 | required: false 23 | AWS_LOAD_BALANCER_HOSTNAME: 24 | description: "AWS Load Balancer match hostname" 25 | required: false 26 | AWS_LOAD_BALANCER_PRIORITY: 27 | description: "AWS Load Balancer match priority" 28 | required: true 29 | AWS_CONTAINER_REGISTRY: 30 | description: "AWS container registry to retrieve package from" 31 | required: true 32 | BUILD_VERSION: 33 | description: "Build Version" 34 | required: true 35 | GITHUB_TOKEN: 36 | description: 'github token for accessing github' 37 | required: true 38 | default: ${{github.token}} 39 | 40 | runs: 41 | using: "composite" 42 | steps: 43 | - name: "Log parameters" 44 | shell: bash 45 | run: | 46 | echo "CLOUD_FORMATION_STACK: ${{inputs.CLOUD_FORMATION_STACK}}" 47 | echo "CLOUD_FORMATION_TEMPLATE_FILE: ${{inputs.CLOUD_FORMATION_TEMPLATE_FILE}}" 48 | echo "DOCKER_APP_OWNER: ${{inputs.DOCKER_APP_OWNER}}" 49 | echo "DOCKER_APP_NAME: ${{inputs.DOCKER_APP_NAME}}" 50 | echo "BUILD_VERSION: ${{inputs.BUILD_VERSION}}" 51 | echo "API_HOST: ${{inputs.API_HOST}}" 52 | echo "API_PREFIX: ${{inputs.API_PREFIX}}" 53 | echo "AWS_LOAD_BALANCER_HOSTNAME: ${{inputs.AWS_LOAD_BALANCER_HOSTNAME}}" 54 | echo "AWS_CONTAINER_REGISTRY: ${{inputs.AWS_CONTAINER_REGISTRY}}" 55 | echo "AWS_LOAD_BALANCER_PRIORITY: ${{inputs.AWS_LOAD_BALANCER_PRIORITY}}" 56 | 57 | - name: "Trigger Deployment Workflow" 58 | uses: actions/github-script@v6 59 | with: 60 | github-token: ${{ inputs.GITHUB_TOKEN }} 61 | script: | 62 | github.rest.actions.createWorkflowDispatch({ 63 | owner: context.repo.owner, 64 | repo: context.repo.repo, 65 | workflow_id: 'deploy.yml', 66 | ref: 'main', 67 | inputs: { 68 | CLOUD_FORMATION_STACK: "${{inputs.CLOUD_FORMATION_STACK}}", 69 | CLOUD_FORMATION_TEMPLATE_FILE: "${{inputs.CLOUD_FORMATION_TEMPLATE_FILE}}", 70 | DOCKER_APP_OWNER: "${{inputs.DOCKER_APP_OWNER}}", 71 | DOCKER_APP_NAME: "${{inputs.DOCKER_APP_NAME}}", 72 | BUILD_VERSION: "${{inputs.BUILD_VERSION}}", 73 | API_HOST: "${{inputs.API_HOST}}", 74 | API_PREFIX: "${{inputs.API_PREFIX}}", 75 | AWS_LOAD_BALANCER_HOSTNAME: "${{inputs.AWS_LOAD_BALANCER_HOSTNAME}}", 76 | AWS_CONTAINER_REGISTRY: "${{inputs.AWS_CONTAINER_REGISTRY}}", 77 | AWS_LOAD_BALANCER_PRIORITY: "${{inputs.AWS_LOAD_BALANCER_PRIORITY}}", 78 | } 79 | }) 80 | -------------------------------------------------------------------------------- /.github/actions/docker-build-to-registry/action.yml: -------------------------------------------------------------------------------- 1 | --- # Build Docker container and optionally deploy to ACR 2 | name: 'Build Docker container and optionally deploy to ACR' 3 | description: 'Builds a docker image and optionally pushes it to AWS ECR' 4 | inputs: 5 | DEPLOY: 6 | description: 'Whether to deploy' 7 | required: true 8 | GITHUB_TOKEN: 9 | description: 'github token for accessing github' 10 | required: true 11 | default: ${{github.token}} 12 | BUILD_VERSION: 13 | description: 'Build version' 14 | required: true 15 | APP_OWNER: 16 | description: 'docker app owner' 17 | required: true 18 | APP_NAME: 19 | description: 'docker app name' 20 | required: true 21 | AWS_CONTAINER_REGISTRY: 22 | description: 'AWS Elastic Container Registry' 23 | required: true 24 | default: '117769150821.dkr.ecr.eu-west-1.amazonaws.com' 25 | CONTAINER_SOURCE: 26 | description: 'Location of app container source' 27 | required: true 28 | CONTAINER_PLATFORM: 29 | description: 'Container platform' 30 | required: true 31 | 32 | runs: 33 | using: "composite" 34 | steps: 35 | - name: "Docker Trust Enable" 36 | shell: bash 37 | run: | 38 | echo "DOCKER_CONTENT_TRUST_ORIGINAL=${{env.DOCKER_CONTENT_TRUST}}" >> "$GITHUB_ENV" 39 | echo "DOCKER_CONTENT_TRUST=1" >> "$GITHUB_ENV" 40 | 41 | - name: "Build and export docker container" 42 | uses: docker/build-push-action@v6.15.0 43 | with: 44 | context: ${{inputs.CONTAINER_SOURCE}} 45 | load: true 46 | tags: ${{inputs.APP_OWNER}}/${{inputs.APP_NAME}}:test 47 | # cache-from: type=gha 48 | # cache-to: type=gha,mode=max 49 | 50 | ## Run docker image tests 51 | - name: "Run docker image tests" 52 | uses: ./.github/actions/docker-image-test 53 | with: 54 | APP_OWNER: ${{inputs.APP_OWNER}} 55 | APP_NAME: ${{inputs.APP_NAME}}c 56 | GITHUB_TOKEN: ${{inputs.GITHUB_TOKEN}} 57 | 58 | - name: "Docker: Build with tags" 59 | uses: docker/build-push-action@v6.15.0 60 | with: 61 | context: ${{inputs.CONTAINER_SOURCE}} 62 | platforms: ${{inputs.CONTAINER_PLATFORM}} 63 | push: ${{inputs.DEPLOY}} 64 | tags: | 65 | ${{inputs.AWS_CONTAINER_REGISTRY}}/${{inputs.APP_OWNER}}/${{inputs.APP_NAME}}:latest 66 | ${{inputs.AWS_CONTAINER_REGISTRY}}/${{inputs.APP_OWNER}}/${{inputs.APP_NAME}}:${{inputs.BUILD_VERSION}} 67 | # cache-from: type=gha 68 | # cache-to: type=gha,mode=max 69 | provenance: false 70 | 71 | - name: "Docker Trust Restore" 72 | shell: bash 73 | run: echo "DOCKER_CONTENT_TRUST=${{env.DOCKER_CONTENT_TRUST_ORIGINAL}}" >> "$GITHUB_ENV" 74 | -------------------------------------------------------------------------------- /.github/actions/docker-image-test/action.yml: -------------------------------------------------------------------------------- 1 | --- # Run docker image tests 2 | name: 'Run docker image tests' 3 | description: 'Docker image tests' 4 | inputs: 5 | APP_OWNER: 6 | description: 'docker app owner' 7 | required: true 8 | APP_NAME: 9 | description: 'docker app name' 10 | required: true 11 | GITHUB_TOKEN: 12 | description: 'github token for accessing github' 13 | required: true 14 | default: ${{github.token}} 15 | 16 | runs: 17 | using: "composite" 18 | steps: 19 | - name: "Wouldn't it be nice if all these things worked" 20 | shell: bash 21 | run: echo "Urrgh" 22 | 23 | # - name: "Create SBOM" 24 | # uses: anchore/sbom-action@v0.18.0 25 | # with: 26 | # github-token: ${{inputs.GITHUB_TOKEN}} 27 | # format: spdx-json 28 | # output-file: "${{ github.event.repository.name }}-sbom.spdx.json" 29 | # config: "${{ github.workspace }}.github/linters/syft.yml" 30 | # 31 | # - name: "Scan SBOM" 32 | # uses: anchore/scan-action@v6.1.0 33 | # with: 34 | # sbom: "${{ github.event.repository.name }}-sbom.spdx.json" 35 | # fail-build: false 36 | # output-format: table 37 | # severity-cutoff: medium 38 | # only-fixed: true 39 | # add-cpes-if-none: false 40 | # by-cve: false 41 | # 42 | # - name: "Run Grype vulnerability scanner" 43 | # if: always() 44 | # uses: anchore/scan-action@v6.1.0 45 | # with: 46 | # image: "${{inputs.APP_OWNER}}/${{inputs.APP_NAME}}:test" 47 | # fail-build: true 48 | # output-format: table 49 | # severity-cutoff: medium 50 | # only-fixed: true 51 | # add-cpes-if-none: false 52 | # by-cve: false 53 | 54 | # - name: "Run Dockle vulnerability scanner" 55 | # if: always() 56 | # uses: erzz/dockle-action@v1.4.0 57 | # with: 58 | # image: "${{inputs.APP_OWNER}}/${{inputs.APP_NAME}}:test" 59 | # report-format: json 60 | # report-name: dockle-report 61 | # failure-threshold: warn 62 | # exit-code: 1 63 | # dockle-version: latest 64 | # accept-extensions: pem 65 | # token: ${{inputs.GITHUB_TOKEN}} 66 | 67 | # - name: "Upload dockle Report" 68 | # uses: actions/upload-artifact@v3.1.3 69 | # if: always() 70 | # with: 71 | # name: Dockle Report 72 | # path: dockle-report.json 73 | 74 | # NOT SURE WHY THIS DOESN'T WORK 75 | # -- Tries to write to /github! 76 | # 77 | # - name: "Run Trivy vulnerability scanner" 78 | # if: always() 79 | # uses: aquasecurity/trivy-action@0.16.1 80 | # with: 81 | # image-ref: "${{inputs.APP_OWNER}}/${{inputs.APP_NAME}}:test" 82 | # format: 'table' 83 | # exit-code: '1' 84 | # ignore-unfixed: true 85 | # vuln-type: 'os,library' 86 | # severity: 'CRITICAL,HIGH' 87 | -------------------------------------------------------------------------------- /.github/actions/docker-setup/action.yml: -------------------------------------------------------------------------------- 1 | --- # Setup Docker 2 | name: 'Setup Docker' 3 | description: 'Setup docker' 4 | inputs: 5 | AWS_ACCESS_KEY_ID: 6 | description: 'AWS Access key' 7 | required: true 8 | AWS_SECRET_ACCESS_KEY: 9 | description: 'AWS Secret key' 10 | required: true 11 | AWS_REGION: 12 | description: 'AWS region' 13 | required: true 14 | AWS_CONTAINER_REGISTRY: 15 | description: 'AWS Elastic Container Registry' 16 | required: true 17 | DOCKER_USERNAME: 18 | description: 'Docker username' 19 | required: true 20 | DOCKER_ACCESS_TOKEN: 21 | description: 'Docker access token' 22 | required: true 23 | 24 | runs: 25 | using: "composite" 26 | steps: 27 | - name: "Set up Docker Buildx" 28 | uses: docker/setup-buildx-action@v3.0.0 29 | 30 | - name: "Configure AWS Credentials" 31 | if: inputs.AWS_ACCESS_KEY_ID != '' 32 | uses: aws-actions/configure-aws-credentials@v4.0.2 33 | with: 34 | aws-access-key-id: ${{inputs.AWS_ACCESS_KEY_ID}} 35 | aws-secret-access-key: ${{inputs.AWS_SECRET_ACCESS_KEY}} 36 | aws-region: ${{inputs.AWS_REGION}} 37 | 38 | - name: "Docker: Login to Docker Hub" 39 | if: inputs.DOCKER_ACCESS_TOKEN != '' 40 | uses: docker/login-action@v3.0.0 41 | with: 42 | username: ${{inputs.DOCKER_USERNAME}} 43 | password: ${{inputs.DOCKER_ACCESS_TOKEN}} 44 | ecr: false 45 | 46 | - name: "Docker: Login to AWS ECR" 47 | if: inputs.AWS_ACCESS_KEY_ID != '' 48 | uses: docker/login-action@v3.0.0 49 | with: 50 | registry: ${{inputs.AWS_CONTAINER_REGISTRY}} 51 | ecr: true 52 | -------------------------------------------------------------------------------- /.github/actions/dotnet-publish/action.yml: -------------------------------------------------------------------------------- 1 | --- # Publishes a Dotnet app to an executable 2 | name: 'Publishes a Dotnet app to an executable' 3 | description: 'Publishes a Dotnet app to an executable' 4 | inputs: 5 | # General 6 | PRODUCTION_BUILD: 7 | description: 'Whether to build a production build' 8 | required: true 9 | 10 | BUILD_VERSION: 11 | description: 'Build version' 12 | required: true 13 | 14 | RELEASE_NOTES: 15 | description: 'Release notes' 16 | required: false 17 | 18 | PLATFORM: 19 | description: 'Platform to build' 20 | required: true 21 | 22 | PROJECT_TO_PUBLISH: 23 | description: 'Package (root) to deploy' 24 | required: false 25 | 26 | runs: 27 | using: "composite" 28 | steps: 29 | - name: "Dotnet: Check Variables" 30 | shell: bash 31 | run: | 32 | echo "Platform: $PLATFORM" 33 | if [ -z "$PLATFORM" ]; then 34 | echo "Missing Platform"; 35 | exit 1 36 | fi 37 | env: 38 | PLATFORM: ${{inputs.PLATFORM}} 39 | 40 | # TODO: Investigate changing the settings for these to be project settings like with "-p:PublishTrimmed=False" so can 41 | # optimise the projects that better suit the settings. 42 | # 43 | # -p:PublishAot=false 44 | # -p:PublishReadyToRun=False 45 | ## Notes: NETSDK1094 can't use --no-restore 46 | - name: "Dotnet: Publish" 47 | working-directory: ${{github.workspace}}/src/${{inputs.PROJECT_TO_PUBLISH}} 48 | shell: bash 49 | run: | 50 | dotnet publish \ 51 | -warnaserror \ 52 | --configuration:Release \ 53 | "-r:${{inputs.PLATFORM}}" \ 54 | --self-contained \ 55 | --ignore-failed-sources \ 56 | -nodeReuse:False \ 57 | "-p:Deterministic=True" \ 58 | "-p:DisableSwagger=${{env.RELEASE}}" \ 59 | "-p:FFPublishing=True" \ 60 | "-p:IncludeNativeLibrariesForSelfExtract=True" \ 61 | "-p:IsProduction=${{inputs.PRODUCTION_BUILD}}" \ 62 | "-p:NoWarn=NETSDK1179" \ 63 | "-p:Optimize=true" \ 64 | "-p:PublishAot=false" \ 65 | "-p:PublishReadyToRun=True" \ 66 | "-p:PublishReadyToRunShowWarnings=True" \ 67 | "-p:PublishSingleFile=true" \ 68 | "-p:SolutionDir=..\\" \ 69 | "-p:SuppressNETCoreSdkPreviewMessage=true" \ 70 | "-p:TreatWarningsAsErrors=True" \ 71 | "-p:Version=${{inputs.BUILD_VERSION}}" \ 72 | --output ${{github.workspace}}/server-dist/${{inputs.PLATFORM}} \ 73 | ${{env.DOTNET_RELEASE_DEFINES}} 74 | env: 75 | ReleaseNotes: ${{inputs.RELEASE_NOTES}} 76 | DOTNET_ROOT: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 77 | DOTNET_INSTALL_DIR: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 78 | DOTNET_MULTILEVEL_LOOKUP: "false" 79 | DOTNET_NOLOGO: "true" 80 | DOTNET_PRINT_TELEMETRY_MESSAGE: "false" 81 | DOTNET_JitCollect64BitCounts: "1" 82 | DOTNET_ReadyToRun: "0" 83 | DOTNET_TC_QuickJitForLoops: "1" 84 | DOTNET_TC_CallCountingDelayMs: "0" 85 | DOTNET_TieredPGO: "1" 86 | MSBUILDTERMINALLOGGER: "auto" 87 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages 88 | -------------------------------------------------------------------------------- /.github/actions/dotnet-tool/action.yml: -------------------------------------------------------------------------------- 1 | --- # Install dotnet tool 2 | name: 'Install dotnet tool' 3 | description: 'Install dotnet tool' 4 | inputs: 5 | TOOL_NAME: 6 | description: 'Tool to install' 7 | required: true 8 | TOOL_VERSION: 9 | description: 'Tool version to install' 10 | required: false 11 | default: 'latest' 12 | 13 | runs: 14 | using: "composite" 15 | steps: 16 | 17 | - name: "Install dotnet tool (Latest)" 18 | if: inputs.TOOL_VERSION == 'latest' 19 | shell: bash 20 | working-directory: ${{ github.workspace }} 21 | run: (r=3;while ! dotnet tool install --local ${{inputs.TOOL_NAME}} ; do ((--r))||exit 1;sleep 30;done) 22 | env: 23 | DOTNET_ROOT: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 24 | DOTNET_INSTALL_DIR: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 25 | DOTNET_MULTILEVEL_LOOKUP: "false" 26 | DOTNET_NOLOGO: "true" 27 | DOTNET_PRINT_TELEMETRY_MESSAGE: "false" 28 | DOTNET_JitCollect64BitCounts: "1" 29 | DOTNET_ReadyToRun: "0" 30 | DOTNET_TC_QuickJitForLoops: "1" 31 | DOTNET_TC_CallCountingDelayMs: "0" 32 | DOTNET_TieredPGO: "1" 33 | MSBUILDTERMINALLOGGER: "auto" 34 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages 35 | 36 | - name: "Install dotnet tool (Specific Version)" 37 | if: inputs.TOOL_VERSION != 'latest' 38 | shell: bash 39 | working-directory: ${{ github.workspace }} 40 | run: (r=3;while ! dotnet tool install --local ${{inputs.TOOL_NAME}} --version ${{inputs.TOOL_VERSION}} ; do ((--r))||exit 1;sleep 30;done) 41 | env: 42 | DOTNET_ROOT: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 43 | DOTNET_INSTALL_DIR: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 44 | DOTNET_MULTILEVEL_LOOKUP: "false" 45 | DOTNET_NOLOGO: "true" 46 | DOTNET_PRINT_TELEMETRY_MESSAGE: "false" 47 | DOTNET_JitCollect64BitCounts: "1" 48 | DOTNET_ReadyToRun: "0" 49 | DOTNET_TC_QuickJitForLoops: "1" 50 | DOTNET_TC_CallCountingDelayMs: "0" 51 | DOTNET_TieredPGO: "1" 52 | MSBUILDTERMINALLOGGER: "auto" 53 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages 54 | -------------------------------------------------------------------------------- /.github/actions/nuget-push-integrated-symbol-feed/action.yml: -------------------------------------------------------------------------------- 1 | --- # Build and deploy packages 2 | name: 'Publish to nuget using multi-push (With integrated symbol feed)' 3 | description: 'Publishes Nuget packages with multi-push (With integrated symbol feed)' 4 | inputs: 5 | NUGET_FEED: 6 | description: 'Nuget feed to push packages to' 7 | required: false 8 | NUGET_API_KEY: 9 | description: 'API key to authenticate when pushing packages' 10 | required: false 11 | 12 | runs: 13 | using: "composite" 14 | steps: 15 | 16 | - name: "NuGet Push with Symbols" 17 | if: always() 18 | shell: bash 19 | working-directory: ${{ github.workspace }} 20 | run: dotnet tool run pushpackages --folder dist --api-key "${{inputs.NUGET_API_KEY}}" --source ${{inputs.NUGET_FEED}} 21 | env: 22 | DOTNET_ROOT: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 23 | DOTNET_INSTALL_DIR: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 24 | DOTNET_MULTILEVEL_LOOKUP: "false" 25 | DOTNET_NOLOGO: "true" 26 | DOTNET_PRINT_TELEMETRY_MESSAGE: "false" 27 | DOTNET_JitCollect64BitCounts: "1" 28 | DOTNET_ReadyToRun: "0" 29 | DOTNET_TC_QuickJitForLoops: "1" 30 | DOTNET_TC_CallCountingDelayMs: "0" 31 | DOTNET_TieredPGO: "1" 32 | MSBUILDTERMINALLOGGER: "auto" 33 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages 34 | -------------------------------------------------------------------------------- /.github/actions/nuget-push-integrated-symbol-feed/actions.yml: -------------------------------------------------------------------------------- 1 | --- # Build and deploy packages 2 | name: 'Publish to nuget using multi-push (With integrated symbol feed)' 3 | description: 'Publishes Nuget packages with multi-push (With integrated symbol feed)' 4 | inputs: 5 | NUGET_FEED: 6 | description: 'Nuget feed to push packages to' 7 | required: false 8 | NUGET_API_KEY: 9 | description: 'API key to authenticate when pushing packages' 10 | required: false 11 | 12 | runs: 13 | using: "composite" 14 | steps: 15 | 16 | - name: "NuGet Push with Symbols" 17 | if: always() 18 | shell: bash 19 | working-directory: ${{ github.workspace }} 20 | run: dotnet tool run pushpackages --folder dist --api-key "${{inputs.NUGET_API_KEY}}" --source ${{inputs.NUGET_FEED}} 21 | env: 22 | DOTNET_ROOT: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 23 | DOTNET_INSTALL_DIR: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 24 | DOTNET_MULTILEVEL_LOOKUP: "false" 25 | DOTNET_NOLOGO: "true" 26 | DOTNET_PRINT_TELEMETRY_MESSAGE: "false" 27 | DOTNET_JitCollect64BitCounts: "1" 28 | DOTNET_ReadyToRun: "0" 29 | DOTNET_TC_QuickJitForLoops: "1" 30 | DOTNET_TC_CallCountingDelayMs: "0" 31 | DOTNET_TieredPGO: "1" 32 | MSBUILDTERMINALLOGGER: "auto" 33 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages 34 | -------------------------------------------------------------------------------- /.github/actions/nuget-push-separate-symbol-feed/action.yml: -------------------------------------------------------------------------------- 1 | --- # Build and deploy packages 2 | name: 'Publish to nuget using multi-push (wit symbols)' 3 | description: 'Publishes Nuget packages with multi-push (wit symbols)' 4 | inputs: 5 | NUGET_FEED: 6 | description: 'Nuget feed to push packages to' 7 | required: false 8 | NUGET_SYMBOL_FEED: 9 | description: 'Nuget feed to push packages symbols to' 10 | required: false 11 | NUGET_API_KEY: 12 | description: 'API key to authenticate when pushing packages' 13 | required: false 14 | 15 | runs: 16 | using: "composite" 17 | steps: 18 | 19 | - name: "NuGet Push without Symbols" 20 | if: always() 21 | shell: bash 22 | working-directory: ${{ github.workspace }} 23 | run: dotnet tool run pushpackages --folder dist --api-key "${{inputs.NUGET_API_KEY}}" --source ${{inputs.NUGET_FEED}} --symbol-source ${{inputs.NUGET_SYMBOL_FEED}} 24 | env: 25 | DOTNET_ROOT: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 26 | DOTNET_INSTALL_DIR: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 27 | DOTNET_MULTILEVEL_LOOKUP: "false" 28 | DOTNET_NOLOGO: "true" 29 | DOTNET_PRINT_TELEMETRY_MESSAGE: "false" 30 | DOTNET_JitCollect64BitCounts: "1" 31 | DOTNET_ReadyToRun: "0" 32 | DOTNET_TC_QuickJitForLoops: "1" 33 | DOTNET_TC_CallCountingDelayMs: "0" 34 | DOTNET_TieredPGO: "1" 35 | MSBUILDTERMINALLOGGER: "auto" 36 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages 37 | -------------------------------------------------------------------------------- /.github/actions/nuget-push-separate-symbol-feed/actions.yml: -------------------------------------------------------------------------------- 1 | --- # Build and deploy packages 2 | name: 'Publish to nuget using multi-push (wit symbols)' 3 | description: 'Publishes Nuget packages with multi-push (wit symbols)' 4 | inputs: 5 | NUGET_FEED: 6 | description: 'Nuget feed to push packages to' 7 | required: false 8 | NUGET_SYMBOL_FEED: 9 | description: 'Nuget feed to push packages symbols to' 10 | required: false 11 | NUGET_API_KEY: 12 | description: 'API key to authenticate when pushing packages' 13 | required: false 14 | 15 | runs: 16 | using: "composite" 17 | steps: 18 | 19 | - name: "NuGet Push without Symbols" 20 | if: always() 21 | shell: bash 22 | working-directory: ${{ github.workspace }} 23 | run: dotnet tool run pushpackages --folder dist --api-key "${{inputs.NUGET_API_KEY}}" --source ${{inputs.NUGET_FEED}} --symbol-source ${{inputs.NUGET_SYMBOL_FEED}} 24 | env: 25 | DOTNET_ROOT: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 26 | DOTNET_INSTALL_DIR: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 27 | DOTNET_MULTILEVEL_LOOKUP: "false" 28 | DOTNET_NOLOGO: "true" 29 | DOTNET_PRINT_TELEMETRY_MESSAGE: "false" 30 | DOTNET_JitCollect64BitCounts: "1" 31 | DOTNET_ReadyToRun: "0" 32 | DOTNET_TC_QuickJitForLoops: "1" 33 | DOTNET_TC_CallCountingDelayMs: "0" 34 | DOTNET_TieredPGO: "1" 35 | MSBUILDTERMINALLOGGER: "auto" 36 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages 37 | -------------------------------------------------------------------------------- /.github/actions/sarif/action.yml: -------------------------------------------------------------------------------- 1 | --- # Build and deploy packages 2 | name: 'Upload sarif files' 3 | description: 'Builds and deploys the source' 4 | inputs: 5 | # GENERAL 6 | GITHUB_TOKEN: 7 | description: 'Github Token' 8 | required: true 9 | REPO_VISIBILITY: 10 | description: 'Visibility of the repo' 11 | required: true 12 | 13 | runs: 14 | using: "composite" 15 | steps: 16 | - name: "Sarif Files to upload" 17 | shell: bash 18 | working-directory: ${{github.workspace}}/results 19 | run: | 20 | ls -la 21 | rm -rf *.Tests.sarif 22 | echo "Hash: ${{ hashfiles('**/*.sarif') }}" 23 | echo "SARIF_HASH=${{ hashfiles('**/*.sarif') }}" >> $GITHUB_ENV 24 | 25 | - if: inputs.REPO_VISIBILITY == 'public' && env.SARIF_HASH != '' 26 | name: "Upload SARIF file for diagnostics" 27 | id: sarif 28 | uses: github/codeql-action/upload-sarif@v3.27.0 29 | continue-on-error: true 30 | with: 31 | sarif_file: ${{github.workspace}}/results 32 | token: ${{github.token}} 33 | wait-for-processing: true 34 | 35 | - if: inputs.REPO_VISIBILITY == 'public' && env.SARIF_HASH != '' 36 | name: "Sarif Upload Summary" 37 | uses: actions/github-script@v7.0.1 38 | continue-on-error: true 39 | with: 40 | script: | 41 | core.info('Sarif Upload Completed'); 42 | core.notice('sarifId: ${{steps.sarif.outputs.sarif-id}}'); 43 | -------------------------------------------------------------------------------- /.github/actions/save-secret-as-file/action.yml: -------------------------------------------------------------------------------- 1 | --- # Save a secret to file 2 | name: 'Save Secret To File' 3 | description: 'Saves a secret to a file' 4 | inputs: 5 | secret: 6 | description: 'Secret value to write' 7 | required: true 8 | outputs: 9 | file: 10 | description: "The file the secret was written to" 11 | value: ${{ steps.generate-filename.outputs.file }} 12 | 13 | runs: 14 | using: "composite" 15 | steps: 16 | - name: "Write secret to file" 17 | shell: bash 18 | id: generate-filename 19 | run: | 20 | echo "file=$WORKSPACE/$(openssl rand -base64 40 | tr '/+' '_-' | tr -d '=').tmp" >> "${GITHUB_OUTPUT}" 21 | env: 22 | WORKSPACE: ${{github.workspace}} 23 | 24 | - name: "Write secret to file" 25 | shell: bash 26 | id: write-file 27 | run: | 28 | echo "$VALUE" > "${FILE}" 29 | env: 30 | FILE: "${{steps.generate-filename.outputs.file}}" 31 | VALUE: "${{ inputs.SECRET }}" 32 | 33 | -------------------------------------------------------------------------------- /.github/actions/sbom/action.yml: -------------------------------------------------------------------------------- 1 | --- # Software Bill of Materials (SBOM) Action 2 | name: 'Run Software Bill of Materials' 3 | description: 'Software Bill of materials' 4 | inputs: 5 | # GENERAL 6 | GITHUB_TOKEN: 7 | description: 'Github Token' 8 | required: true 9 | REPO_VISIBILITY: 10 | description: 'Visibility of the repo' 11 | required: true 12 | 13 | runs: 14 | using: "composite" 15 | steps: 16 | - name: "Create SBOM" 17 | shell: bash 18 | run: echo "Create SBOM..." 19 | 20 | # - name: "Create SBOM" 21 | # uses: anchore/sbom-action@v0.15.10 22 | # with: 23 | # github-token: ${{inputs.GITHUB_TOKEN}} 24 | # format: spdx-json 25 | # output-file: "${{ github.event.repository.name }}-sbom.spdx.json" 26 | # config: "${{ github.workspace }}.github/linters/syft.yml" 27 | # 28 | # - name: "Log SBOM filename" 29 | # shell: bash 30 | # run: | 31 | # echo "Output ${{ github.event.repository.name }}-sbom.spdx.json" 32 | # ls "${{ github.event.repository.name }}-sbom.spdx.json" 33 | # 34 | # - name: "Scan SBOM (public Repo)" 35 | # if: inputs.REPO_VISIBILITY == 'public' 36 | # uses: anchore/scan-action@v3.6.4 37 | # id: sbom 38 | # with: 39 | # sbom: "${{ github.event.repository.name }}-sbom.spdx.json" 40 | # fail-build: false 41 | # output-format: sarif 42 | # only-fixed: true 43 | # add-cpes-if-none: false 44 | # by-cve: false 45 | # 46 | # - name: "Copy SBOM to sarif (public Repo)" 47 | # if: |- 48 | # inputs.REPO_VISIBILITY == 'public' && 49 | # steps.sbom.outputs.sarif != '' 50 | # shell: bash 51 | # run: | 52 | # echo "SBOM: ${{ steps.sbom.outputs.sarif }}" 53 | # cp "${{ steps.sbom.outputs.sarif }}" "${{ github.workspace }}/results/${{ github.event.repository.name }}-sbom.sarif" 54 | # cat "${{ steps.sbom.outputs.sarif }}" 55 | # 56 | # - name: "Scan SBOM (private repo)" 57 | # uses: anchore/scan-action@v3.6.4 58 | # if: inputs.REPO_VISIBILITY == 'private' 59 | # with: 60 | # sbom: "${{ github.event.repository.name }}-sbom.spdx.json" 61 | # fail-build: false 62 | # output-format: table 63 | # only-fixed: true 64 | # add-cpes-if-none: false 65 | # by-cve: false 66 | -------------------------------------------------------------------------------- /.github/actions/sleet/action.yml: -------------------------------------------------------------------------------- 1 | --- # Build and deploy packages 2 | name: 'Publish to Sleet' 3 | description: 'Publishes Nuget packages with sleet' 4 | inputs: 5 | SLEET_CONFIG: 6 | description: 'Sleet config file' 7 | required: false 8 | SLEET_FEED: 9 | description: 'Sleet feed to push packages to' 10 | required: false 11 | 12 | runs: 13 | using: "composite" 14 | steps: 15 | 16 | - name: "Sleet: Generate Sleet Config" 17 | uses: joutvhu/write-file@v1 18 | with: 19 | path: sleet.json 20 | contents: ${{ inputs.SLEET_CONFIG }} 21 | write_mode: overwrite 22 | 23 | - name: "Sleet: Publish Packages to Nuget (Using Sleet)" 24 | if: always() 25 | shell: bash 26 | working-directory: ${{ github.workspace }} 27 | run: dotnet tool run sleet push "${{github.workspace}}/dist" --config sleet.json --source ${{inputs.SLEET_FEED}} 28 | env: 29 | DOTNET_ROOT: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 30 | DOTNET_INSTALL_DIR: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 31 | DOTNET_MULTILEVEL_LOOKUP: "false" 32 | DOTNET_NOLOGO: "true" 33 | DOTNET_PRINT_TELEMETRY_MESSAGE: "false" 34 | DOTNET_JitCollect64BitCounts: "1" 35 | DOTNET_ReadyToRun: "0" 36 | DOTNET_TC_QuickJitForLoops: "1" 37 | DOTNET_TC_CallCountingDelayMs: "0" 38 | DOTNET_TieredPGO: "1" 39 | MSBUILDTERMINALLOGGER: "auto" 40 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages 41 | -------------------------------------------------------------------------------- /.github/actions/sql/action.yml: -------------------------------------------------------------------------------- 1 | --- # Build SQL 2 | name: 'Build SQL' 3 | description: 'Builds SQL Package' 4 | inputs: 5 | # General 6 | BUILD_VERSION: 7 | description: 'Build version' 8 | required: true 9 | 10 | DB_FOLDER: 11 | description: 'Folder where SQL Files live' 12 | required: true 13 | 14 | REDGATE_EMAIL: 15 | description: 'Redgate authentication email' 16 | required: true 17 | REDGATE_PAT: 18 | description: 'Redgate authentication Personal Access Token' 19 | required: true 20 | SQLCOMPARE_VERSION: 21 | description: 'Version of SQL Compare to use' 22 | required: true 23 | 24 | runs: 25 | using: "composite" 26 | steps: 27 | 28 | - name: "SQL: Install TSQLLint" 29 | uses: ./.github/actions/dotnet-tool 30 | with: 31 | TOOL_NAME: TSQLLint 32 | TOOL_VERSION: latest 33 | 34 | - name: "SQL: Lint SQL Files" 35 | shell: bash 36 | working-directory: ${{ github.workspace }} 37 | run: dotnet tool run tsqllint "${{inputs.DB_FOLDER}}" 38 | env: 39 | DOTNET_ROOT: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 40 | DOTNET_INSTALL_DIR: "${{github.workspace}}/.dotnet/${{github.sha}}-${{github.run_id}}-${{github.run_number}}-${{github.run_attempt}}" 41 | DOTNET_MULTILEVEL_LOOKUP: "false" 42 | DOTNET_NOLOGO: "true" 43 | DOTNET_PRINT_TELEMETRY_MESSAGE: "false" 44 | DOTNET_JitCollect64BitCounts: "1" 45 | DOTNET_ReadyToRun: "0" 46 | DOTNET_TC_QuickJitForLoops: "1" 47 | DOTNET_TC_CallCountingDelayMs: "0" 48 | DOTNET_TieredPGO: "1" 49 | MSBUILDTERMINALLOGGER: "auto" 50 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages 51 | 52 | - name: "SQL: Get SQL Compare" 53 | shell: bash 54 | run: docker pull "redgate/sqlcompare:${{inputs.SQLCOMPARE_VERSION}}" 55 | 56 | # Need to get these to work 57 | # /email:"${{inputs.REDGATE_EMAIL}}" \ 58 | # /token:"${{inputs.REDGATE_PAT}}" \ 59 | - name: "Build SQL change" 60 | shell: bash 61 | run: | 62 | docker run \ 63 | "-v$GITHUB_WORKSPACE:$GITHUB_WORKSPACE" \ 64 | --net=host \ 65 | --rm \ 66 | "redgate/sqlcompare:${{inputs.SQLCOMPARE_VERSION}}" \ 67 | /email:"${{inputs.REDGATE_EMAIL}}" \ 68 | /token:"${{inputs.REDGATE_PAT}}" \ 69 | /IAgreeToTheEULA \ 70 | /filter:"$DB_FILTER" \ 71 | /options:CaseSensitiveObjectDefinition,ConsiderNextFilegroupInPartitionSchemes,DecryptPost2kEncryptedObjects,DoNotOutputCommentHeader,ForceColumnOrder,IgnoreCertificatesAndCryptoKeys,IgnoreDatabaseAndServerName,IgnoreUserProperties,IgnoreUsersPermissionsAndRoleMemberships,IgnoreWhiteSpace,IgnoreWithElementOrder,IncludeDependencies,NoDeploymentLogging,ThrowOnFileParseFailed,UseCompatibilityLevel \ 72 | /transactionIsolationLevel:SERIALIZABLE \ 73 | /include:staticData \ 74 | /scriptFile:"$DB_OUTPUT" \ 75 | /scripts1:"$DB_SOURCE" \ 76 | /showWarnings \ 77 | /include:Identical \ 78 | /report:"$DB_REPORT" \ 79 | /reportType:Xml \ 80 | /force \ 81 | /OutputWidth:1024 \ 82 | /empty2 \ 83 | /verbose 84 | env: 85 | DB_SOURCE: ${{inputs.DB_FOLDER}} 86 | DB_OUTPUT: ${{github.workspace}}/update.test.sql 87 | DB_LOG: ${{github.workspace}}/update.log 88 | DB_REPORT: ${{github.workspace}}/update.xml 89 | DB_FILTER: ${{inputs.DB_FOLDER}}/Filter.scpf 90 | DOCKER_CONTENT_TRUST: 0 91 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | ".NET update": 2 | - any: [ 'src/global.json' ] 3 | "C#": 4 | - any: [ './**/*.cs', './**/*.csproj' ] 5 | "C# Project": 6 | - any: [ './**/*.csproj' ] 7 | "C# Solution": 8 | - any: [ './**/*.sln' ] 9 | "Change Log": 10 | - any: [ 'CHANGELOG.md' ] 11 | "Config Change": 12 | - any: [ 'src/**/*.json', '!src/global.json' ] 13 | "credfeto-enumeration-source-generation": 14 | - any: [ 'src/$Credfeto.Enumeration.Source.Generation/**/*' ] 15 | "credfeto-enumeration-source-generation-attributes": 16 | - any: [ 'src/$Credfeto.Enumeration.Source.Generation.Attributes/**/*' ] 17 | "credfeto-enumeration-source-generation-benchmarks": 18 | - any: [ 'src/$Credfeto.Enumeration.Source.Generation.Benchmarks/**/*' ] 19 | "credfeto-enumeration-source-generation-generics": 20 | - any: [ 'src/$Credfeto.Enumeration.Source.Generation.Generics/**/*' ] 21 | "credfeto-enumeration-source-generation-models": 22 | - any: [ 'src/$Credfeto.Enumeration.Source.Generation.Models/**/*' ] 23 | "credfeto-enumeration-source-generation-models-tests": 24 | - any: [ 'src/$Credfeto.Enumeration.Source.Generation.Models.Tests/**/*' ] 25 | "github-actions": 26 | - any: [ '.github/workflows/*.yml' ] 27 | "Legal Text": 28 | - any: [ 'tools/LegalText/**/*' ] 29 | "Markdown": 30 | - any: [ './**/*.md' ] 31 | "Migration Script": 32 | - any: [ 'tools/MigrationScripts/**/*' ] 33 | "Powershell": 34 | - any: [ './**/*.ps1', './**/*.psm1' ] 35 | "Read Me": 36 | - any: [ 'README.md' ] 37 | "Setup": 38 | - any: [ 'SETUP.md' ] 39 | "Solidity": 40 | - any: [ './**/*.sol' ] 41 | "SQL": 42 | - any: [ './**/*.sql', 'db/**/*' ] 43 | "Static Code Analysis Rules": 44 | - any: [ 'src/CodeAnalysis.ruleset' ] 45 | "unit-tests": 46 | - any: [ 'src/*.Tests.*/**/*', 'src/*.Tests.Integration.*/**/*', 'src/*.Tests.Integration/**/*', 'src/*.Tests/**/*' ] 47 | -------------------------------------------------------------------------------- /.github/labels.yml: -------------------------------------------------------------------------------- 1 | - name: "!!! WAITING FOR CLIENT PR" 2 | color: "ffff00" 3 | description: "Pull request needs a client pull request to be merged at the same time" 4 | 5 | - name: "!!! WAITING FOR ETHEREUM PR" 6 | color: "ffff00" 7 | description: "Pull request needs a server ethereum pull request to be merged at the same time" 8 | 9 | - name: "!!! WAITING FOR QA SIGNOFF" 10 | color: "ffff00" 11 | description: "Pull request needs a QA Signoff before it can be merged" 12 | 13 | - name: "!!! WAITING FOR SERVER PR" 14 | color: "ffff00" 15 | description: "Pull request needs a server pull request to be merged at the same time" 16 | 17 | - name: "!!! WAITING FOR WALLET PR" 18 | color: "ffff00" 19 | description: "Pull request needs a wallet pull request to be merged at the same time" 20 | 21 | - name: ".NET update" 22 | color: "a870c9" 23 | description: "Update to .net global.json" 24 | 25 | - name: "auto-pr" 26 | color: "0000aa" 27 | description: "Pull request created automatically" 28 | 29 | - name: "C#" 30 | color: "db6baa" 31 | description: "C# Source Files" 32 | 33 | - name: "C# Project" 34 | color: "db6baa" 35 | description: "C# Project Files" 36 | 37 | - name: "C# Solution" 38 | color: "db6baa" 39 | description: "C# Solutions" 40 | 41 | - name: "Change Log" 42 | color: "53fcd4" 43 | description: "Changelog tracking file" 44 | 45 | - name: "Config Change" 46 | color: "d8bb50" 47 | description: "Configuration files changes" 48 | 49 | - name: "credfeto-enumeration-source-generation" 50 | color: "96f7d2" 51 | description: "Changes in $Credfeto.Enumeration.Source.Generation project" 52 | 53 | - name: "credfeto-enumeration-source-generation-attributes" 54 | color: "96f7d2" 55 | description: "Changes in $Credfeto.Enumeration.Source.Generation.Attributes project" 56 | 57 | - name: "credfeto-enumeration-source-generation-benchmarks" 58 | color: "96f7d2" 59 | description: "Changes in $Credfeto.Enumeration.Source.Generation.Benchmarks project" 60 | 61 | - name: "credfeto-enumeration-source-generation-generics" 62 | color: "96f7d2" 63 | description: "Changes in $Credfeto.Enumeration.Source.Generation.Generics project" 64 | 65 | - name: "credfeto-enumeration-source-generation-models" 66 | color: "96f7d2" 67 | description: "Changes in $Credfeto.Enumeration.Source.Generation.Models project" 68 | 69 | - name: "credfeto-enumeration-source-generation-models-tests" 70 | color: "0e8a16" 71 | description: "Changes in $Credfeto.Enumeration.Source.Generation.Models.Tests project" 72 | 73 | - name: "dependencies" 74 | color: "0366d6" 75 | description: "Updates to dependencies" 76 | 77 | - name: "DO NOT MERGE" 78 | color: "ff0000" 79 | description: "This pull request should not be merged yet" 80 | 81 | - name: "dotnet" 82 | color: "db6baa" 83 | description: "Dotnet package updates" 84 | 85 | - name: "github-actions" 86 | color: "e09cf4" 87 | description: "Github actions workflow files" 88 | 89 | - name: "Legal Text" 90 | color: "facef0" 91 | description: "Legal text files" 92 | 93 | - name: "Markdown" 94 | color: "5319e7" 95 | description: "Markdown files" 96 | 97 | - name: "Migration Script" 98 | color: "b680e5" 99 | description: "SQL Migration scripts" 100 | 101 | - name: "no-pr-activity" 102 | color: "ffff00" 103 | description: "Pull Request has had no activity for a long time" 104 | 105 | - name: "npm" 106 | color: "e99695" 107 | description: "npm package update" 108 | 109 | - name: "Powershell" 110 | color: "23bc12" 111 | description: "Powershell Source Files" 112 | 113 | - name: "Read Me" 114 | color: "5319e7" 115 | description: "Repository readme file" 116 | 117 | - name: "Setup" 118 | color: "5319e7" 119 | description: "Setup instructions" 120 | 121 | - name: "Solidity" 122 | color: "413cd1" 123 | description: "Solidity Source Files" 124 | 125 | - name: "SQL" 126 | color: "413cd1" 127 | description: "SQL Source Files" 128 | 129 | - name: "Static Code Analysis Rules" 130 | color: "00dead" 131 | description: "Ruleset for static code analysis files" 132 | 133 | - name: "Tech Debt" 134 | color: "30027a" 135 | description: "Technical debt" 136 | 137 | - name: "unit-tests" 138 | color: "0e8a16" 139 | description: "Unit test and integration test projects" 140 | 141 | -------------------------------------------------------------------------------- /.github/linters/.eslintrc.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ############################# 4 | ############################# 5 | ## JavaScript Linter rules ## 6 | ############################# 7 | ############################# 8 | 9 | ############ 10 | # Env Vars # 11 | ############ 12 | env: 13 | browser: true 14 | es6: true 15 | jest: true 16 | 17 | ############### 18 | # Global Vars # 19 | ############### 20 | globals: 21 | Atomics: readonly 22 | SharedArrayBuffer: readonly 23 | 24 | ############### 25 | # Parser vars # 26 | ############### 27 | parser: '@typescript-eslint/parser' 28 | parserOptions: 29 | ecmaVersion: 2018 30 | sourceType: module 31 | 32 | ########### 33 | # Plugins # 34 | ########### 35 | plugins: 36 | - '@typescript-eslint' 37 | 38 | ######### 39 | # Rules # 40 | ######### 41 | rules: {} -------------------------------------------------------------------------------- /.github/linters/.hadolint.yaml: -------------------------------------------------------------------------------- 1 | ignored: 2 | - DL3008 3 | - DL3009 4 | - DL3018 5 | -------------------------------------------------------------------------------- /.github/linters/.markdown-lint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ########################### 3 | ########################### 4 | ## Markdown Linter rules ## 5 | ########################### 6 | ########################### 7 | 8 | # Linter rules doc: 9 | # - https://github.com/DavidAnson/markdownlint 10 | # 11 | # Note: 12 | # To comment out a single error: 13 | # 14 | # any violations you want 15 | # 16 | # 17 | 18 | ############### 19 | # Rules by id # 20 | ############### 21 | MD004: false # Unordered list style 22 | MD007: 23 | indent: 2 # Unordered list indentation 24 | MD013: 25 | line_length: 808 # Line length 26 | MD024: false # Duplicate headings (e.g. in changelog) 27 | MD026: 28 | punctuation: ".,;:!。,;:" # List of not allowed 29 | MD029: false # Ordered list item prefix 30 | MD033: false # Allow inline HTML 31 | MD034: false # Allow Naked Links 32 | MD036: false # Emphasis used instead of a heading 33 | 34 | ################# 35 | # Rules by tags # 36 | ################# 37 | blank_lines: false # Error on blank lines -------------------------------------------------------------------------------- /.github/linters/.python-black: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/credfeto/credfeto-enum-source-generation/f49c86e99e6b4830604b07e5a40e95153764f530/.github/linters/.python-black -------------------------------------------------------------------------------- /.github/linters/.yaml-lint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ########################################### 3 | # These are the rules used for # 4 | # linting all the yaml files in the stack # 5 | # NOTE: # 6 | # You can disable line with: # 7 | # # yamllint disable-line # 8 | ########################################### 9 | rules: 10 | braces: 11 | level: warning 12 | min-spaces-inside: 0 13 | max-spaces-inside: 0 14 | min-spaces-inside-empty: 1 15 | max-spaces-inside-empty: 5 16 | brackets: 17 | level: warning 18 | min-spaces-inside: 0 19 | max-spaces-inside: 0 20 | min-spaces-inside-empty: 1 21 | max-spaces-inside-empty: 5 22 | colons: 23 | level: warning 24 | max-spaces-before: 0 25 | max-spaces-after: 1 26 | commas: 27 | level: warning 28 | max-spaces-before: 0 29 | min-spaces-after: 1 30 | max-spaces-after: 1 31 | comments: disable 32 | comments-indentation: disable 33 | document-end: disable 34 | document-start: disable 35 | empty-lines: 36 | level: warning 37 | max: 2 38 | max-start: 0 39 | max-end: 0 40 | hyphens: 41 | level: warning 42 | max-spaces-after: 1 43 | indentation: 44 | level: warning 45 | spaces: consistent 46 | indent-sequences: true 47 | check-multi-line-strings: false 48 | key-duplicates: enable 49 | line-length: 50 | level: warning 51 | max: 160 52 | allow-non-breakable-words: true 53 | allow-non-breakable-inline-mappings: true 54 | new-line-at-end-of-file: disable 55 | new-lines: 56 | type: unix 57 | trailing-spaces: disable -------------------------------------------------------------------------------- /.github/linters/actionlint.yaml: -------------------------------------------------------------------------------- 1 | self-hosted-runner: 2 | # Labels of self-hosted runner in array of string 3 | labels: 4 | - build 5 | - deploy -------------------------------------------------------------------------------- /.github/linters/syft.yml: -------------------------------------------------------------------------------- 1 | # suppress all output (except for the SBOM report) 2 | # SYFT_QUIET env var / -q flag 3 | quiet: false 4 | 5 | # maximum number of workers used to process the list of package catalogers in parallel 6 | parallelism: 1 7 | 8 | log: 9 | # use structured logging 10 | # SYFT_LOG_STRUCTURED env var 11 | structured: false 12 | 13 | # the log level; note: detailed logging suppress the ETUI 14 | # SYFT_LOG_LEVEL env var 15 | level: "error" 16 | 17 | # location to write the log file (default is not to have a log file) 18 | # SYFT_LOG_FILE env var 19 | file: "" 20 | -------------------------------------------------------------------------------- /.github/linters/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["rxjs-tslint-rules"], 3 | "linterOptions": { 4 | "exclude": [ 5 | "node_modules/**", 6 | "**/*.json", 7 | "**/*.spec.ts", 8 | "**/*.mock.ts", 9 | "./src/ABI/**/*" 10 | ] 11 | }, 12 | "rulesDirectory": ["node_modules/codelyzer"], 13 | "rules": { 14 | "rxjs-prefer-observer": { 15 | "options": [ 16 | { 17 | "allowNext": true 18 | } 19 | ], 20 | "severity": "error" 21 | }, 22 | "arrow-return-shorthand": true, 23 | "callable-types": true, 24 | "class-name": true, 25 | "comment-format": [true, "check-space"], 26 | "curly": true, 27 | "deprecation": { 28 | "severity": "warn" 29 | }, 30 | "eofline": true, 31 | "forin": true, 32 | "import-blacklist": [true, "rxjs/Rx"], 33 | "import-spacing": true, 34 | "indent": [true, "spaces"], 35 | "interface-over-type-literal": true, 36 | "label-position": true, 37 | "max-line-length": [true, 140], 38 | "member-access": true, 39 | "member-ordering": [ 40 | true, 41 | { 42 | "order": [ 43 | "static-field", 44 | "instance-field", 45 | "static-method", 46 | "instance-method" 47 | ] 48 | } 49 | ], 50 | "no-arg": true, 51 | "no-any": true, 52 | "no-bitwise": false, 53 | "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], 54 | "no-construct": true, 55 | "no-debugger": true, 56 | "no-duplicate-super": true, 57 | "no-empty": false, 58 | "no-empty-interface": true, 59 | "no-eval": true, 60 | "no-inferrable-types": [true, "ignore-params"], 61 | "no-misused-new": true, 62 | "no-redundant-jsdoc": true, 63 | "no-shadowed-variable": true, 64 | "no-string-literal": false, 65 | "no-string-throw": true, 66 | "no-switch-case-fall-through": true, 67 | "no-trailing-whitespace": true, 68 | "no-unnecessary-initializer": true, 69 | "no-unused-expression": true, 70 | "no-use-before-declare": true, 71 | "no-var-keyword": true, 72 | "object-literal-sort-keys": false, 73 | "one-line": [ 74 | true, 75 | "check-open-brace", 76 | "check-catch", 77 | "check-else", 78 | "check-whitespace" 79 | ], 80 | "prefer-const": true, 81 | "quotemark": [true, "single"], 82 | "radix": true, 83 | "semicolon": [true, "always"], 84 | "triple-equals": [true, "allow-null-check"], 85 | "typedef": [ 86 | true, 87 | "call-signature", 88 | "property-declaration", 89 | "parameter", 90 | "object-destructuring", 91 | "array-destructuring" 92 | ], 93 | "typedef-whitespace": [ 94 | true, 95 | { 96 | "call-signature": "nospace", 97 | "index-signature": "nospace", 98 | "parameter": "nospace", 99 | "property-declaration": "nospace", 100 | "variable-declaration": "nospace" 101 | } 102 | ], 103 | "unified-signatures": true, 104 | "variable-name": false, 105 | "whitespace": [ 106 | true, 107 | "check-branch", 108 | "check-decl", 109 | "check-operator", 110 | "check-separator", 111 | "check-type" 112 | ], 113 | "no-output-on-prefix": true, 114 | "no-inputs-metadata-property": true, 115 | "no-outputs-metadata-property": true, 116 | "no-host-metadata-property": true, 117 | "no-input-rename": false, 118 | "no-output-rename": false, 119 | "use-lifecycle-interface": true, 120 | "use-pipe-transform-interface": true, 121 | "component-class-suffix": true, 122 | "directive-class-suffix": true 123 | } 124 | } -------------------------------------------------------------------------------- /.github/pr-lint.yml: -------------------------------------------------------------------------------- 1 | projects: ['FF'] 2 | check_title: true 3 | check_branch: false 4 | check_commits: false 5 | ignore_case: true 6 | -------------------------------------------------------------------------------- /.github/workflows/approve-dependabot.yml: -------------------------------------------------------------------------------- 1 | name: "Dependabot: Approve updates" 2 | on: 3 | # https://securitylab.github.com/research/github-actions-preventing-pwn-requests 4 | # could and should work, at least for public repos; 5 | # tracking issue for this action's issue: 6 | # https://github.com/ahmadnassri/action-dependabot-auto-merge/issues/60 7 | pull_request_target: 8 | types: 9 | - opened 10 | - edited 11 | - reopened 12 | - synchronize 13 | - ready_for_review 14 | branches: 15 | - main 16 | 17 | permissions: 18 | contents: read 19 | 20 | 21 | jobs: 22 | enable-auto-merge-github-actions: 23 | if: |- 24 | vars.DEPENDABOT_AUTOMERGE == 'true' && 25 | startsWith(github.head_ref, 'dependabot/github_actions/') 26 | runs-on: ubuntu-latest 27 | 28 | permissions: 29 | contents: write 30 | pull-requests: write 31 | 32 | 33 | # Specifically check that dependabot (or another trusted party) created this pull-request, and that it has been labelled correctly. 34 | 35 | steps: 36 | 37 | - name: "Initialise Workspace" 38 | if: startsWith(runner.name, 'buildagent-') 39 | shell: bash 40 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 41 | 42 | - name: "Set Active Environment" 43 | shell: bash 44 | run: | 45 | { 46 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 47 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 48 | echo "ACTIVE_USER=$USER" 49 | } >> "$GITHUB_ENV" 50 | 51 | - name: "Check Repo Owner" 52 | uses: actions/github-script@v7.0.1 53 | with: 54 | script: | 55 | core.info('Owner: ${{github.repository_owner}}'); 56 | 57 | - name: "Auto Merge" 58 | uses: alexwilson/enable-github-automerge-action@2.0.0 59 | with: 60 | github-token: ${{secrets.SOURCE_PUSH_TOKEN}} 61 | merge-method: "MERGE" 62 | 63 | enable-auto-merge-npm: 64 | if: |- 65 | vars.DEPENDABOT_AUTOMERGE == 'true' && 66 | startsWith(github.head_ref, 'dependabot/npm_and_yarn/') 67 | runs-on: ubuntu-latest 68 | 69 | permissions: 70 | contents: write 71 | pull-requests: write 72 | 73 | # Specifically check that dependabot (or another trusted party) created this pull-request, and that it has been labelled correctly. 74 | 75 | steps: 76 | - name: "Initialise Workspace" 77 | if: startsWith(runner.name, 'buildagent-') 78 | shell: bash 79 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 80 | 81 | - name: "Set Active Environment" 82 | shell: bash 83 | run: | 84 | { 85 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 86 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 87 | echo "ACTIVE_USER=$USER" 88 | } >> "$GITHUB_ENV" 89 | 90 | - name: "Check Repo Owner" 91 | uses: actions/github-script@v7.0.1 92 | with: 93 | script: | 94 | core.info('Owner: ${{github.repository_owner}}'); 95 | 96 | - name: "Auto Merge" 97 | uses: alexwilson/enable-github-automerge-action@2.0.0 98 | with: 99 | github-token: ${{secrets.SOURCE_PUSH_TOKEN}} 100 | merge-method: "MERGE" 101 | 102 | auto-approve-dependabot-gitub-actions: 103 | if: |- 104 | vars.DEPENDABOT_AUTOMERGE == 'true' && 105 | startsWith(github.head_ref, 'dependabot/github_actions/') 106 | runs-on: ubuntu-latest 107 | 108 | permissions: 109 | contents: write 110 | pull-requests: write 111 | 112 | steps: 113 | - name: "Initialise Workspace" 114 | if: startsWith(runner.name, 'buildagent-') 115 | shell: bash 116 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 117 | 118 | - name: "Set Active Environment" 119 | shell: bash 120 | run: | 121 | { 122 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 123 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 124 | echo "ACTIVE_USER=$USER" 125 | } >> "$GITHUB_ENV" 126 | 127 | - name: "Check Repo Owner" 128 | uses: actions/github-script@v7.0.1 129 | with: 130 | script: | 131 | core.info('Owner: ${{github.repository_owner}}'); 132 | 133 | - name: "Approve" 134 | uses: hmarr/auto-approve-action@v4 135 | with: 136 | github-token: ${{secrets.SOURCE_PUSH_TOKEN}} 137 | 138 | auto-approve-dependabot-npm: 139 | if: |- 140 | vars.DEPENDABOT_AUTOMERGE == 'true' && 141 | startsWith(github.head_ref, 'dependabot/npm_and_yarn/') 142 | runs-on: ubuntu-latest 143 | 144 | permissions: 145 | contents: write 146 | pull-requests: write 147 | 148 | steps: 149 | - name: "Initialise Workspace" 150 | if: startsWith(runner.name, 'buildagent-') 151 | shell: bash 152 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 153 | 154 | - name: "Set Active Environment" 155 | shell: bash 156 | run: | 157 | { 158 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 159 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 160 | echo "ACTIVE_USER=$USER" 161 | } >> "$GITHUB_ENV" 162 | 163 | - name: "Check Repo Owner" 164 | uses: actions/github-script@v7.0.1 165 | with: 166 | script: | 167 | core.info('Owner: ${{github.repository_owner}}'); 168 | 169 | - name: "Approve" 170 | uses: hmarr/auto-approve-action@v4 171 | with: 172 | github-token: ${{secrets.SOURCE_PUSH_TOKEN}} 173 | -------------------------------------------------------------------------------- /.github/workflows/build-and-publish-pre-release.yml: -------------------------------------------------------------------------------- 1 | name: "Build: Pre-Release" 2 | 3 | on: 4 | push: 5 | paths: 6 | - 'cloudformation.json' 7 | - 'Dockerfile' 8 | - 'healthcheck' 9 | - 'db/**/*' 10 | - 'src/**/*' 11 | - '.editorconfig' 12 | - '.github/actions/**/*' 13 | - '.github/workflows/*' 14 | branches-ignore: 15 | - 'release/*' 16 | - 'hotfix/*' 17 | 18 | # Don't cancel anything in progress 19 | concurrency: 20 | group: ${{github.workflow}}-${{github.ref}}-pre-release 21 | cancel-in-progress: false 22 | 23 | permissions: 24 | contents: write 25 | security-events: write 26 | 27 | jobs: 28 | build-pre-release: 29 | 30 | runs-on: ubuntu-latest 31 | 32 | env: 33 | # Optimisation for repo visibility check 34 | REPO_STATUS: ${{vars.REPO_VISIBILITY}} 35 | # SQL Compare 36 | SQLCOMPARE_VERSION: latest 37 | # Which NPM Registry to use 38 | NPM_REGISTRY: ${{vars.NPM_REGISTRY}} 39 | NPM_CACHE_CERT: ${{vars.NPM_CACHE_CERT}} 40 | # Nuget caching 41 | USE_NUGET_CACHE: ${{vars.USE_NUGET_CACHE}} 42 | NUGET_BAGET_CACHE: '' 43 | PRERELEASE_BAGET_CACHE: '' 44 | RELEASE_BAGET_CACHE: '' 45 | 46 | steps: 47 | - name: "Initialise Workspace" 48 | if: startsWith(runner.name, 'buildagent-') 49 | shell: bash 50 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 51 | 52 | - name: "Set Active Environment" 53 | shell: bash 54 | run: | 55 | { 56 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 57 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 58 | echo "ACTIVE_USER=$USER" 59 | echo "TEMP=${{runner.temp}}" 60 | echo "TMP=${{runner.temp}}" 61 | } >> "$GITHUB_ENV" 62 | 63 | - name: "Checkout Source" 64 | uses: actions/checkout@v4.2.2 65 | with: 66 | fetch-depth: 0 67 | fetch-tags: true 68 | 69 | - if: env.USE_NUGET_CACHE == '' 70 | name: "Setup Nuget Cache (Cache disabled)" 71 | shell: bash 72 | run: echo "USE_NUGET_CACHE=false" >> "$GITHUB_ENV" 73 | 74 | - if: startsWith(runner.name, 'buildagent-') != true 75 | name: "Ensure on github agents nuget cache is disabled" 76 | shell: bash 77 | run: echo "USE_NUGET_CACHE=false" >> "$GITHUB_ENV" 78 | 79 | - if: env.REPO_STATUS == '' 80 | name: "Check Repo Visibility" 81 | uses: credfeto/action-repo-visibility@v1.2.0 82 | id: visibility 83 | with: 84 | repository: ${{github.repository}} 85 | token: ${{secrets.SOURCE_PUSH_TOKEN}} 86 | 87 | - name: "Check Runner details" 88 | uses: actions/github-script@v7.0.1 89 | with: 90 | script: | 91 | core.info('Name: ${{runner.name}}'); 92 | core.info('OS: ${{runner.os}}'); 93 | 94 | - name: "Enable Local nuget/npm feeds if caching" 95 | if: env.USE_NUGET_CACHE == 'true' 96 | shell: bash 97 | run: | 98 | { 99 | echo "NUGET_BAGET_CACHE=${{vars.NUGET_BAGET_CACHE}}" 100 | echo "PRERELEASE_BAGET_CACHE=${{vars.PRERELEASE_BAGET_CACHE}}" 101 | echo "RELEASE_BAGET_CACHE=${{vars.RELEASE_BAGET_CACHE}}" 102 | [[ -n "${{vars.NPM_CACHE}}" ]] \ 103 | && echo "NPM_REGISTRY=${{vars.NPM_CACHE}}" 104 | }>> "$GITHUB_ENV" 105 | 106 | - name: "Build and deploy" 107 | uses: ./.github/actions/build 108 | with: 109 | PRODUCTION_BUILD: False 110 | NPM_PRODUCTION_PACKAGER_VERSION: ${{vars.PRODUCTION_PACKAGER_VERSION}} 111 | NPM_CONTENT_PACKAGE_WALLET_PASSWORD: ${{secrets.CONTENT_PACKAGE_WALLET_PASSWORD}} 112 | NPM_PACKAGE_STORE_SIGNING_WALLET: ${{secrets.PACKAGE_STORE_SIGNING_WALLET}} 113 | NPM_PACKAGE_STORE_SIGNING_WALLET_PASSWORD: ${{secrets.PACKAGE_STORE_SIGNING_WALLET_PASSWORD}} 114 | NPM_REGISTRY: ${{env.NPM_REGISTRY}} 115 | NPM_CACHE_CERT: ${{env.NPM_CACHE_CERT}} 116 | NUGET_PUBLIC_RESTORE_FEED_CACHE: ${{env.NUGET_BAGET_CACHE}} 117 | NUGET_PUBLIC_RESTORE_FEED: ${{vars.NUGET_PUBLIC_RESTORE_FEED}} 118 | NUGET_ADDITIONAL_RESTORE_FEED_RELEASE_CACHE: ${{env.RELEASE_BAGET_CACHE}} 119 | NUGET_ADDITIONAL_RESTORE_FEED_PRERELEASE_CACHE: ${{env.PRERELEASE_BAGET_CACHE}} 120 | NUGET_ADDITIONAL_RESTORE_FEED_RELEASE: ${{vars.NUGET_ADDITIONAL_RESTORE_FEED_RELEASE}} 121 | NUGET_ADDITIONAL_RESTORE_FEED_PRERELEASE: ${{vars.NUGET_ADDITIONAL_RESTORE_FEED_PRERELEASE}} 122 | NUGET_PACK: ${{vars.NUGET_PACK}} 123 | NUGET_FEED: ${{secrets.NUGET_FEED}} 124 | NUGET_SYMBOL_FEED: ${{secrets.NUGET_SYMBOL_FEED}} 125 | NUGET_API_KEY: ${{secrets.NUGET_API_KEY}} 126 | SLEET_CONFIG: ${{secrets.SLEET_CONFIG}} 127 | SLEET_FEED: ${{vars.PRE_RELEASE_SLEET_FEED}} 128 | PROJECT_TO_PUBLISH: ${{vars.PROJECT_TO_PUBLISH}} 129 | DOCKER_APP_OWNER: ${{vars.DOCKER_APP_OWNER}} 130 | DOCKER_APP_NAME: ${{vars.DOCKER_APP_NAME}} 131 | CLOUD_FORMATION_DEPLOY: ${{vars.CLOUD_FORMATION_DEPLOY}} 132 | CLOUD_FORMATION_STACK: ${{vars.CLOUD_FORMATION_STACK}} 133 | GITHUB_TOKEN: ${{secrets.SOURCE_PUSH_TOKEN}} 134 | REPO_VISIBILITY: ${{env.REPO_STATUS}} 135 | AWS_ACCESS_KEY_ID: ${{secrets.AWS_DOCKER_CONTAINER_REGISTRY_ACCESS_KEY_ID}} 136 | AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_DOCKER_CONTAINER_REGISTRY_SECRET_ACCESS_KEY}} 137 | AWS_REGION: ${{vars.AWS_REGION}} 138 | AWS_CONTAINER_REGISTRY: ${{vars.AWS_CONTAINER_REGISTRY}} 139 | AWS_LOAD_BALANCER_HOSTNAME: ${{vars.AWS_LOAD_BALANCER_HOSTNAME_DEV}} 140 | AWS_LOAD_BALANCER_PRIORITY: ${{vars.AWS_LOAD_BALANCER_PRIORITY_DEV}} 141 | API_HOST: ${{vars.AWS_LOAD_BALANCER_HOSTNAME_DEV}} 142 | API_PREFIX: ${{vars.API_PREFIX}} 143 | DOCKER_USERNAME: ${{secrets.DOCKER_USERNAME}} 144 | DOCKER_ACCESS_TOKEN: ${{secrets.DOCKER_ACCESS_TOKEN}} 145 | DOTNET_DOCKER_PLATFORM: ${{vars.DOTNET_DOCKER_PLATFORM}} 146 | DOTNET_CONTAINER_PLATFORM: ${{vars.DOTNET_CONTAINER_PLATFORM}} 147 | SQL_SERVER: ${{vars.SQL_SERVER}} 148 | SQL_DB: ${{vars.SQL_DB}} 149 | SQL_USER: ${{vars.SQL_USER}} 150 | SQL_PASSWORD: ${{secrets.SQL_PASSWORD}} 151 | REDGATE_EMAIL: ${{secrets.REDGATE_EMAIL}} 152 | REDGATE_PAT: ${{secrets.REDGATE_PAT}} 153 | SQLCOMPARE_VERSION: ${{env.SQLCOMPARE_VERSION}} 154 | CREATE_RELEASE: false 155 | 156 | - name: "Build Version" 157 | uses: actions/github-script@v7.0.1 158 | with: 159 | script: | 160 | core.info('Version: \u001b[38;5;6m${{env.BUILD_VERSION}}'); 161 | core.notice('Version: ${{env.BUILD_VERSION}}'); 162 | -------------------------------------------------------------------------------- /.github/workflows/build-and-publish-release.yml: -------------------------------------------------------------------------------- 1 | name: "Build: Release" 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'release/*' 7 | - 'hotfix/*' 8 | 9 | # Don't cancel anything in progress 10 | concurrency: 11 | group: ${{github.workflow}}-${{github.ref}}-release 12 | cancel-in-progress: false 13 | 14 | permissions: 15 | contents: write 16 | security-events: write 17 | 18 | jobs: 19 | build-release: 20 | 21 | runs-on: ubuntu-latest 22 | 23 | env: 24 | # Optimisation for repo visibility check 25 | REPO_STATUS: ${{vars.REPO_VISIBILITY}} 26 | # SQL Compare 27 | SQLCOMPARE_VERSION: latest 28 | # Which NPM Registry to use 29 | NPM_REGISTRY: ${{vars.NPM_REGISTRY}} 30 | NPM_CACHE_CERT: ${{vars.NPM_CACHE_CERT}} 31 | # Nuget caching 32 | USE_NUGET_CACHE: ${{vars.USE_NUGET_CACHE}} 33 | NUGET_BAGET_CACHE: '' 34 | PRERELEASE_BAGET_CACHE: '' 35 | RELEASE_BAGET_CACHE: '' 36 | 37 | steps: 38 | - name: "Initialise Workspace" 39 | if: startsWith(runner.name, 'buildagent-') 40 | shell: bash 41 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 42 | 43 | - name: "Set Active Environment" 44 | shell: bash 45 | run: | 46 | { 47 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 48 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 49 | echo "ACTIVE_USER=$USER" 50 | echo "TEMP=${{runner.temp}}" 51 | echo "TMP=${{runner.temp}}" 52 | } >> "$GITHUB_ENV" 53 | 54 | - name: "Checkout Source" 55 | uses: actions/checkout@v4.2.2 56 | with: 57 | fetch-depth: 0 58 | fetch-tags: true 59 | 60 | - if: env.USE_NUGET_CACHE == '' 61 | name: "Setup Nuget Cache (Cache disabled)" 62 | shell: bash 63 | run: echo "USE_NUGET_CACHE=false" >> "$GITHUB_ENV" 64 | 65 | - if: startsWith(runner.name, 'buildagent-') != true 66 | name: "Ensure on github agents nuget cache is disabled" 67 | shell: bash 68 | run: echo "USE_NUGET_CACHE=false" >> "$GITHUB_ENV" 69 | 70 | - if: env.REPO_STATUS == '' 71 | name: "Check Repo Visibility" 72 | uses: credfeto/action-repo-visibility@v1.2.0 73 | id: visibility 74 | with: 75 | repository: ${{github.repository}} 76 | token: ${{secrets.SOURCE_PUSH_TOKEN}} 77 | 78 | - name: "Check Runner details" 79 | uses: actions/github-script@v7.0.1 80 | with: 81 | script: | 82 | core.info('Name: ${{runner.name}}'); 83 | core.info('OS: ${{runner.os}}'); 84 | 85 | - name: "Enable Local nuget/npm feeds if caching" 86 | if: env.USE_NUGET_CACHE == 'true' 87 | shell: bash 88 | run: | 89 | { 90 | echo "NUGET_BAGET_CACHE=${{vars.NUGET_BAGET_CACHE}}" 91 | echo "PRERELEASE_BAGET_CACHE=${{vars.PRERELEASE_BAGET_CACHE}}" 92 | echo "RELEASE_BAGET_CACHE=${{vars.RELEASE_BAGET_CACHE}}" 93 | [[ -n "${{vars.NPM_CACHE}}" ]] \ 94 | && echo "NPM_REGISTRY=${{vars.NPM_CACHE}}" 95 | }>> "$GITHUB_ENV" 96 | 97 | - name: "Build and deploy" 98 | uses: ./.github/actions/build 99 | with: 100 | PRODUCTION_BUILD: True 101 | NPM_PRODUCTION_PACKAGER_VERSION: ${{vars.PRODUCTION_PACKAGER_VERSION}} 102 | NPM_CONTENT_PACKAGE_WALLET_PASSWORD: ${{secrets.CONTENT_PACKAGE_WALLET_PASSWORD}} 103 | NPM_PACKAGE_STORE_SIGNING_WALLET: ${{secrets.PACKAGE_STORE_SIGNING_WALLET}} 104 | NPM_PACKAGE_STORE_SIGNING_WALLET_PASSWORD: ${{secrets.PACKAGE_STORE_SIGNING_WALLET_PASSWORD}} 105 | NPM_REGISTRY: ${{env.NPM_REGISTRY}} 106 | NPM_CACHE_CERT: ${{env.NPM_CACHE_CERT}} 107 | NUGET_PUBLIC_RESTORE_FEED_CACHE: ${{env.NUGET_BAGET_CACHE}} 108 | NUGET_PUBLIC_RESTORE_FEED: ${{vars.NUGET_PUBLIC_RESTORE_FEED}} 109 | NUGET_ADDITIONAL_RESTORE_FEED_RELEASE_CACHE: ${{env.RELEASE_BAGET_CACHE}} 110 | NUGET_ADDITIONAL_RESTORE_FEED_PRERELEASE_CACHE: "" 111 | NUGET_ADDITIONAL_RESTORE_FEED_RELEASE: ${{vars.NUGET_ADDITIONAL_RESTORE_FEED_RELEASE}} 112 | NUGET_ADDITIONAL_RESTORE_FEED_PRERELEASE: "" 113 | NUGET_PACK: ${{vars.NUGET_PACK}} 114 | NUGET_FEED: ${{secrets.NUGET_FEED}} 115 | NUGET_SYMBOL_FEED: ${{secrets.NUGET_SYMBOL_FEED}} 116 | NUGET_API_KEY: ${{secrets.NUGET_API_KEY}} 117 | SLEET_CONFIG: ${{secrets.SLEET_CONFIG}} 118 | SLEET_FEED: "dotnet-release" 119 | PROJECT_TO_PUBLISH: ${{vars.PROJECT_TO_PUBLISH}} 120 | DOCKER_APP_OWNER: ${{vars.DOCKER_APP_OWNER}} 121 | DOCKER_APP_NAME: ${{vars.DOCKER_APP_NAME}} 122 | CLOUD_FORMATION_DEPLOY: ${{vars.CLOUD_FORMATION_DEPLOY}} 123 | CLOUD_FORMATION_STACK: ${{vars.CLOUD_FORMATION_STACK}} 124 | GITHUB_TOKEN: ${{secrets.SOURCE_PUSH_TOKEN}} 125 | REPO_VISIBILITY: ${{env.REPO_STATUS}} 126 | AWS_ACCESS_KEY_ID: ${{secrets.AWS_DOCKER_CONTAINER_REGISTRY_ACCESS_KEY_ID}} 127 | AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_DOCKER_CONTAINER_REGISTRY_SECRET_ACCESS_KEY}} 128 | AWS_REGION: ${{vars.AWS_REGION}} 129 | AWS_CONTAINER_REGISTRY: ${{vars.AWS_CONTAINER_REGISTRY}} 130 | AWS_LOAD_BALANCER_HOSTNAME: ${{vars.AWS_LOAD_BALANCER_HOSTNAME_PROD}} 131 | AWS_LOAD_BALANCER_PRIORITY: ${{vars.AWS_LOAD_BALANCER_PRIORITY_PROD}} 132 | API_HOST: ${{vars.AWS_LOAD_BALANCER_HOSTNAME_DEV}} 133 | API_PREFIX: ${{vars.API_PREFIX}} 134 | DOCKER_USERNAME: ${{secrets.DOCKER_USERNAME}} 135 | DOCKER_ACCESS_TOKEN: ${{secrets.DOCKER_ACCESS_TOKEN}} 136 | DOTNET_DOCKER_PLATFORM: ${{vars.DOTNET_DOCKER_PLATFORM}} 137 | DOTNET_CONTAINER_PLATFORM: ${{vars.DOTNET_CONTAINER_PLATFORM}} 138 | SQL_SERVER: ${{vars.SQL_SERVER}} 139 | SQL_DB: ${{vars.SQL_DB}} 140 | SQL_USER: ${{vars.SQL_USER}} 141 | SQL_PASSWORD: ${{secrets.SQL_PASSWORD}} 142 | REDGATE_EMAIL: ${{secrets.REDGATE_EMAIL}} 143 | REDGATE_PAT: ${{secrets.REDGATE_PAT}} 144 | SQLCOMPARE_VERSION: ${{env.SQLCOMPARE_VERSION}} 145 | CREATE_RELEASE: true 146 | 147 | - name: "Build Version" 148 | uses: actions/github-script@v7.0.1 149 | with: 150 | script: | 151 | core.info('Version: \u001b[38;5;6m${{env.BUILD_VERSION}}'); 152 | core.notice('Version: ${{env.BUILD_VERSION}}'); 153 | -------------------------------------------------------------------------------- /.github/workflows/dependabot.yml: -------------------------------------------------------------------------------- 1 | name: "Dependabot: Rebase" 2 | on: 3 | push: 4 | branches: 5 | - main 6 | release: 7 | types: [published] 8 | 9 | concurrency: 10 | group: ${{github.workflow}}-${{github.ref}} 11 | cancel-in-progress: true 12 | 13 | 14 | jobs: 15 | auto-rebase: 16 | runs-on: ubuntu-latest 17 | 18 | if: github.ref == 'refs/heads/main' || github.event_name == 'release' 19 | timeout-minutes: 5 20 | steps: 21 | - name: "Initialise Workspace" 22 | if: startsWith(runner.name, 'buildagent-') 23 | shell: bash 24 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 25 | 26 | - name: "Set Active Environment" 27 | shell: bash 28 | run: | 29 | { 30 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 31 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 32 | echo "ACTIVE_USER=$USER" 33 | } >> "$GITHUB_ENV" 34 | 35 | - name: "Rebase" 36 | uses: bbeesley/gha-auto-dependabot-rebase@v1.5.145 37 | env: 38 | GITHUB_TOKEN: ${{secrets.SOURCE_PUSH_TOKEN}} 39 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: "!!Deploy: Using Cloudformation" 2 | on: 3 | workflow_dispatch: 4 | # note MAX inputs = 10 5 | inputs: 6 | CLOUD_FORMATION_STACK: 7 | description: '1. The Cloud Formation stack to deploy as' 8 | required: true 9 | CLOUD_FORMATION_TEMPLATE_FILE: 10 | description: '2. The Cloud Formation file to deploy' 11 | required: true 12 | DOCKER_APP_OWNER: 13 | description: '3. docker app owner' 14 | required: true 15 | DOCKER_APP_NAME: 16 | description: '4. docker app name' 17 | required: true 18 | API_HOST: 19 | description: '5. Api Host' 20 | required: false 21 | API_PREFIX: 22 | description: '6. API Prefix' 23 | required: false 24 | AWS_LOAD_BALANCER_HOSTNAME: 25 | description: "7. AWS Load Balancer match hostname" 26 | required: false 27 | AWS_LOAD_BALANCER_PRIORITY: 28 | description: "8. AWS Load Balancer match priority" 29 | required: true 30 | AWS_CONTAINER_REGISTRY: 31 | description: "9. AWS container registry to retrieve package from" 32 | required: true 33 | BUILD_VERSION: 34 | description: "10. Build Version" 35 | required: true 36 | 37 | # Don't cancel anything in progress 38 | concurrency: 39 | group: ${{github.workflow}}-${{inputs.CLOUD_FORMATION_STACK}}-${{inputs.BUILD_VERSION}} 40 | cancel-in-progress: false 41 | 42 | permissions: 43 | contents: write 44 | security-events: write 45 | 46 | jobs: 47 | deploy: 48 | runs-on: ubuntu-latest 49 | 50 | steps: 51 | - name: "Correct ownership" 52 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 53 | 54 | - name: "Set Active Environment" 55 | shell: bash 56 | run: | 57 | { 58 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 59 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 60 | echo "ACTIVE_USER=$USER" 61 | } >> "$GITHUB_ENV" 62 | 63 | - name: "Checkout" 64 | uses: actions/checkout@v4.2.2 65 | with: 66 | fetch-depth: 0 67 | fetch-tags: true 68 | 69 | - name: "Log parameters" 70 | shell: bash 71 | run: | 72 | echo "CLOUD_FORMATION_STACK: ${{inputs.CLOUD_FORMATION_STACK}}" 73 | echo "CLOUD_FORMATION_TEMPLATE_FILE: ${{inputs.CLOUD_FORMATION_TEMPLATE_FILE}}" 74 | echo "DOCKER_APP_OWNER: ${{inputs.DOCKER_APP_OWNER}}" 75 | echo "DOCKER_APP_NAME: ${{inputs.DOCKER_APP_NAME}}" 76 | echo "BUILD_VERSION: ${{inputs.BUILD_VERSION}}" 77 | echo "API_HOST: ${{inputs.API_HOST}}" 78 | echo "API_PREFIX: ${{inputs.API_PREFIX}}" 79 | echo "AWS_LOAD_BALANCER_HOSTNAME: ${{inputs.AWS_LOAD_BALANCER_HOSTNAME}}" 80 | echo "AWS_CONTAINER_REGISTRY: ${{inputs.AWS_CONTAINER_REGISTRY}}" 81 | echo "AWS_LOAD_BALANCER_PRIORITY: ${{inputs.AWS_LOAD_BALANCER_PRIORITY}}" 82 | 83 | - name: "Configure AWS Credentials" 84 | uses: aws-actions/configure-aws-credentials@v4.2.1 85 | with: 86 | aws-access-key-id: ${{secrets.AWS_DOCKER_CONTAINER_REGISTRY_ACCESS_KEY_ID}} 87 | aws-secret-access-key: ${{secrets.AWS_DOCKER_CONTAINER_REGISTRY_SECRET_ACCESS_KEY}} 88 | aws-region: ${{vars.AWS_REGION}} 89 | 90 | - name: "Cloudformation Deploy" 91 | uses: ./.github/actions/cloudformation-deploy 92 | with: 93 | CLOUD_FORMATION_STACK: ${{inputs.CLOUD_FORMATION_STACK}} 94 | CLOUDFORMATION_SNS_ARN: ${{vars.CLOUDFORMATION_SNS_ARN}} 95 | CLOUD_FORMATION_TEMPLATE_FILE: "${{github.workspace}}/${{inputs.CLOUD_FORMATION_TEMPLATE_FILE}}" 96 | DOCKER_APP_OWNER: ${{inputs.DOCKER_APP_OWNER}} 97 | DOCKER_APP_NAME: ${{inputs.DOCKER_APP_NAME}} 98 | BUILD_VERSION: ${{inputs.BUILD_VERSION}} 99 | API_HOST: ${{inputs.API_HOST}} 100 | API_PREFIX: ${{inputs.API_PREFIX}} 101 | AWS_LOAD_BALANCER_HOSTNAME: ${{inputs.AWS_LOAD_BALANCER_HOSTNAME}} 102 | AWS_LOAD_BALANCER_PRIORITY: ${{inputs.AWS_LOAD_BALANCER_PRIORITY}} 103 | AWS_CONTAINER_REGISTRY: ${{inputs.AWS_CONTAINER_REGISTRY}} 104 | 105 | - name: "Log Build Version" 106 | uses: actions/github-script@v7.0.1 107 | with: 108 | script: | 109 | core.info('Application: \u001b[38;5;6m${{inputs.DOCKER_APP_OWNER}}\\${{inputs.DOCKER_APP_NAME}}'); 110 | core.info('Version: \u001b[38;5;6m${{inputs.BUILD_VERSION}}'); 111 | core.info('Stack: \u001b[38;5;6m${{inputs.CLOUD_FORMATION_STACK}}'); 112 | core.notice('Application: ${{inputs.DOCKER_APP_OWNER}}\\${{inputs.DOCKER_APP_NAME}}'); 113 | core.notice('Version: ${{inputs.BUILD_VERSION}}'); 114 | core.notice('Stack: ${{inputs.CLOUD_FORMATION_STACK}}'); 115 | -------------------------------------------------------------------------------- /.github/workflows/dotnet-version.yml: -------------------------------------------------------------------------------- 1 | --- # Create a new branch for the latest (released) dotnet version if there's an update 2 | name: "Repo: Update Dotnet Version to latest released version" 3 | on: 4 | push: 5 | branches: 6 | - "main" 7 | paths: 8 | - ".github/workflows/dotnet-version.yml" 9 | schedule: 10 | - cron: "0 1 * * *" 11 | 12 | concurrency: 13 | group: ${{github.workflow}}-${{github.ref}} 14 | cancel-in-progress: false 15 | 16 | permissions: 17 | contents: write 18 | 19 | 20 | jobs: 21 | bump-dotnet-sdk-version: 22 | if: endsWith(github.repository, 'funfair-server-template') 23 | runs-on: ubuntu-latest 24 | 25 | steps: 26 | - name: "Initialise Workspace" 27 | if: startsWith(runner.name, 'buildagent-') 28 | shell: bash 29 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 30 | 31 | - name: "Set Active Environment" 32 | shell: bash 33 | run: | 34 | { 35 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 36 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 37 | echo "ACTIVE_USER=$USER" 38 | } >> "$GITHUB_ENV" 39 | 40 | - name: "Checkout Source" 41 | uses: actions/checkout@v4.2.2 42 | with: 43 | fetch-depth: 0 44 | fetch-tags: true 45 | token: ${{secrets.SOURCE_PUSH_TOKEN}} 46 | 47 | - name: "Install Build tools" 48 | if: startsWith(runner.name, 'buildagent-') 49 | uses: ./.github/actions/build-tools 50 | with: 51 | GITHUB_TOKEN: ${{secrets.SOURCE_PUSH_TOKEN}} 52 | NUGET_PUBLIC_RESTORE_FEED_CACHE: ${{vars.NUGET_BAGET_CACHE}} 53 | NUGET_PUBLIC_RESTORE_FEED: ${{vars.NUGET_PUBLIC_RESTORE_FEED}} 54 | NUGET_ADDITIONAL_RESTORE_FEED_RELEASE_CACHE: ${{vars.RELEASE_BAGET_CACHE}} 55 | NUGET_ADDITIONAL_RESTORE_FEED_PRERELEASE_CACHE: ${{vars.PRERELEASE_BAGET_CACHE}} 56 | NUGET_ADDITIONAL_RESTORE_FEED_RELEASE: ${{vars.NUGET_ADDITIONAL_RESTORE_FEED_RELEASE}} 57 | NUGET_ADDITIONAL_RESTORE_FEED_PRERELEASE: ${{vars.NUGET_ADDITIONAL_RESTORE_FEED_PRERELEASE}} 58 | 59 | - name: "Install Build tools" 60 | if: startsWith(runner.name, 'buildagent-') != true 61 | uses: ./.github/actions/build-tools 62 | with: 63 | GITHUB_TOKEN: ${{secrets.SOURCE_PUSH_TOKEN}} 64 | NUGET_PUBLIC_RESTORE_FEED_CACHE: "" 65 | NUGET_PUBLIC_RESTORE_FEED: ${{vars.NUGET_PUBLIC_RESTORE_FEED}} 66 | NUGET_ADDITIONAL_RESTORE_FEED_RELEASE_CACHE: "" 67 | NUGET_ADDITIONAL_RESTORE_FEED_PRERELEASE_CACHE: "" 68 | NUGET_ADDITIONAL_RESTORE_FEED_RELEASE: ${{vars.NUGET_ADDITIONAL_RESTORE_FEED_RELEASE}} 69 | NUGET_ADDITIONAL_RESTORE_FEED_PRERELEASE: ${{vars.NUGET_ADDITIONAL_RESTORE_FEED_PRERELEASE}} 70 | 71 | - name: "Get latest installed dotnet version" 72 | id: latest-dotnet-version 73 | run: | 74 | echo "LATEST_RELEASE_VERSION=$(dotnet --list-sdks | cut -f 1 -d " " | grep "^[0-9]*\.[0-9]*\.[0-9]*$" | sort | tail -1)" >> "$GITHUB_OUTPUT" 75 | 76 | - name: "Display latest installed dotnet version" 77 | run: | 78 | echo "Latest installed dotnet version: ${{steps.latest-dotnet-version.outputs.LATEST_RELEASE_VERSION}}" 79 | echo "Requested dotnet version: ${{env.DOTNET_VERSION}}" 80 | 81 | - name: "Switch to version branch" 82 | if: ${{env.DOTNET_VERSION < steps.latest-dotnet-version.outputs.LATEST_RELEASE_VERSION}} 83 | shell: bash 84 | run: | 85 | git checkout "depends/dotnet/${{env.NEW_DOTNET_VERSION}}" || git checkout -b "depends/dotnet/${{env.NEW_DOTNET_VERSION}}" 86 | env: 87 | NEW_DOTNET_VERSION: ${{steps.latest-dotnet-version.outputs.LATEST_RELEASE_VERSION}} 88 | 89 | - name: "Update global.json to latest version" 90 | if: ${{env.DOTNET_VERSION < steps.latest-dotnet-version.outputs.LATEST_RELEASE_VERSION}} 91 | shell: bash 92 | working-directory: src 93 | run: | 94 | echo "Should update to ${{steps.latest-dotnet-version.outputs.LATEST_RELEASE_VERSION}}" 95 | mv "global.json" "global.json.tmp"; 96 | jq --arg v "$NEW_DOTNET_VERSION" '.sdk.version = $v' < "global.json.tmp" > "global.json"; 97 | [ -f "global.json.tmp" ] && rm -f "global.json.tmp" 98 | cat "global.json" 99 | env: 100 | NEW_DOTNET_VERSION: ${{steps.latest-dotnet-version.outputs.LATEST_RELEASE_VERSION}} 101 | 102 | - name: "Commit changes to new branch" 103 | if: ${{env.DOTNET_VERSION < steps.latest-dotnet-version.outputs.LATEST_RELEASE_VERSION}} 104 | uses: stefanzweifel/git-auto-commit-action@v5.2.0 105 | with: 106 | commit_message: "SDK - Update DotNet SDK to ${{steps.latest-dotnet-version.outputs.LATEST_RELEASE_VERSION}}" 107 | branch: "depends/dotnet/${{steps.latest-dotnet-version.outputs.LATEST_RELEASE_VERSION}}" 108 | file_pattern: src/global.json 109 | commit_user_name: "fun-version[bot]" 110 | commit_user_email: "credfeto@users.noreply.github.com" 111 | commit_author: "fun-version[bot] " 112 | skip_dirty_check: false 113 | -------------------------------------------------------------------------------- /.github/workflows/merge-dependabot.yml: -------------------------------------------------------------------------------- 1 | name: "Dependabot: Merge updates" 2 | on: 3 | # https://securitylab.github.com/research/github-actions-preventing-pwn-requests 4 | # could and should work, at least for public repos; 5 | # tracking issue for this action's issue: 6 | # https://github.com/ahmadnassri/action-dependabot-auto-merge/issues/60 7 | pull_request: 8 | types: 9 | - labeled 10 | - unlabeled 11 | - synchronize 12 | - opened 13 | - edited 14 | - ready_for_review 15 | - reopened 16 | - unlocked 17 | pull_request_review: 18 | types: 19 | - submitted 20 | check_suite: 21 | types: 22 | - completed 23 | status: { } 24 | 25 | permissions: 26 | contents: read 27 | 28 | jobs: 29 | auto-merge-dependabot-github-actions: 30 | 31 | if: |- 32 | vars.DEPENDABOT_AUTOMERGE == 'true' && 33 | startsWith(github.head_ref, 'dependabot/github_actions/') 34 | runs-on: ubuntu-latest 35 | 36 | permissions: 37 | contents: write 38 | pull-requests: write 39 | 40 | # Specifically check that dependabot (or another trusted party) created this pull-request, and that it has been labelled correctly. 41 | 42 | steps: 43 | - name: "Initialise Workspace" 44 | if: startsWith(runner.name, 'buildagent-') 45 | shell: bash 46 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 47 | 48 | - name: "Set Active Environment" 49 | shell: bash 50 | run: | 51 | { 52 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 53 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 54 | echo "ACTIVE_USER=$USER" 55 | } >> "$GITHUB_ENV" 56 | 57 | - name: "Check Owner" 58 | uses: actions/github-script@v7.0.1 59 | with: 60 | script: | 61 | core.info('Owner: ${{github.repository_owner}}'); 62 | 63 | - name: "Auto-Merge" 64 | if: github.repository_owner == 'funfair-tech' 65 | uses: pascalgn/automerge-action@v0.16.4 66 | env: 67 | GITHUB_TOKEN: ${{secrets.SOURCE_PUSH_TOKEN}} 68 | MERGE_METHOD: merge 69 | MERGE_COMMIT_MESSAGE: pull-request-title-and-description 70 | MERGE_REQUIRED_APPROVALS: 1 71 | MERGE_DELETE_BRANCH: true 72 | MERGE_FORKS: false 73 | MERGE_LABELS: github-actions 74 | UPDATE_RETRIES: 10 75 | -------------------------------------------------------------------------------- /.github/workflows/missing-releases.yml: -------------------------------------------------------------------------------- 1 | --- # Create a new branch for anything that has a changelog entry, but no branch 2 | name: "Repo: Create missing releases" 3 | on: 4 | push: 5 | branches: 6 | - "main" 7 | paths: 8 | - ".github/workflows/missing-releases.yml" 9 | - "CHANGELOG.md" 10 | schedule: 11 | - cron: "0 1 * * *" 12 | 13 | concurrency: 14 | group: ${{github.workflow}}-${{github.ref}} 15 | cancel-in-progress: false 16 | 17 | permissions: 18 | contents: write 19 | 20 | jobs: 21 | missing-releases: 22 | runs-on: ubuntu-latest 23 | 24 | steps: 25 | - name: "Initialise Workspace" 26 | if: startsWith(runner.name, 'buildagent-') 27 | shell: bash 28 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 29 | 30 | - name: "Set Active Environment" 31 | shell: bash 32 | run: | 33 | { 34 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 35 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 36 | echo "ACTIVE_USER=$USER" 37 | } >> "$GITHUB_ENV" 38 | 39 | - name: "Checkout Source" 40 | uses: actions/checkout@v4.2.2 41 | with: 42 | fetch-depth: 0 43 | fetch-tags: true 44 | token: ${{secrets.SOURCE_PUSH_TOKEN}} 45 | 46 | - name: "Check for missing releases" 47 | shell: bash 48 | run: | 49 | REGEX_CHANGELOG="^([0-9a-zA-Z]*)\s.*Changelog\sfor\s([0-9]*\.[0-9]*\.[0-9]*)$" 50 | matchingBranch() { 51 | CHANGE_RELEASE=$1 52 | SEARCH_BRANCH="origin/release/$CHANGE_RELEASE" 53 | git branch --remote | while read -r BRANCH; do 54 | #echo "SRC: $BRANCH" 55 | if [[ "$BRANCH" = "$SEARCH_BRANCH" ]]; then 56 | echo "Y" 57 | break 58 | fi 59 | done 60 | } 61 | 62 | git log --oneline | while read -r CHANGE; do 63 | if [[ $CHANGE =~ $REGEX_CHANGELOG ]]; then 64 | CHANGE_HASH="${BASH_REMATCH[1]}" 65 | CHANGE_RELEASE="${BASH_REMATCH[2]}" 66 | 67 | # Check to see if branch exists 68 | FOUND=$(matchingBranch "$CHANGE_RELEASE") 69 | if [ "$FOUND" = "Y" ]; then 70 | echo "* Found Release $CHANGE_RELEASE at in release/$CHANGE_RELEASE at $CHANGE_HASH" 71 | else 72 | echo "- Missing Release $CHANGE_RELEASE in $CHANGE_HASH" 73 | git checkout "$CHANGE_HASH" 74 | git checkout -b "release/$CHANGE_RELEASE" 75 | git push --set-upstream origin "release/$CHANGE_RELEASE" 76 | git switch main || echo "Switching to Main" 77 | echo "+++ Created branch release/$CHANGE_RELEASE" 78 | fi 79 | fi 80 | done && echo "OK" || echo "Failed" 81 | 82 | -------------------------------------------------------------------------------- /.github/workflows/on-pr-closed.yml: -------------------------------------------------------------------------------- 1 | --- # Cleanup on PR Close 2 | name: "PR: Closed" 3 | on: 4 | pull_request: 5 | types: 6 | - closed 7 | 8 | jobs: 9 | cleanup-cache: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: "Initialise Workspace" 13 | if: startsWith(runner.name, 'buildagent-') 14 | shell: bash 15 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 16 | 17 | - name: "Set Active Environment" 18 | shell: bash 19 | run: | 20 | { 21 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 22 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 23 | echo "ACTIVE_USER=$USER" 24 | } >> "$GITHUB_ENV" 25 | 26 | - name: "Install extensions" 27 | run: gh extension install actions/gh-actions-cache 28 | env: 29 | GH_TOKEN: ${{ secrets.SOURCE_PUSH_TOKEN }} 30 | 31 | - name: "Cleanup" 32 | run: | 33 | echo "Fetching list of cache key" 34 | cacheKeysForPR=$(gh actions-cache list -R "$REPO" -B "$BRANCH" -L 100 | cut -f 1 ) 35 | 36 | ## Setting this to not fail the workflow while deleting cache keys. 37 | set +e 38 | echo "Deleting caches..." 39 | for cacheKey in $cacheKeysForPR 40 | do 41 | echo "Deleting cache key: $cacheKey" 42 | gh actions-cache delete "$cacheKey" -R "$REPO" -B "$BRANCH" --confirm 43 | done 44 | echo "Done" 45 | env: 46 | GH_TOKEN: ${{ secrets.SOURCE_PUSH_TOKEN }} 47 | REPO: ${{ github.repository }} 48 | BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge 49 | -------------------------------------------------------------------------------- /.github/workflows/on_new_pr.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request 2 | on: 3 | # https://securitylab.github.com/research/github-actions-preventing-pwn-requests 4 | # could and should work, at least for public repos; 5 | # tracking issue for this action's issue: 6 | # https://github.com/ahmadnassri/action-dependabot-auto-merge/issues/60 7 | pull_request_target: 8 | types: 9 | - opened 10 | - edited 11 | - reopened 12 | - synchronize 13 | - ready_for_review 14 | 15 | permissions: 16 | contents: read 17 | 18 | jobs: 19 | enable-auto-merge: 20 | runs-on: ubuntu-latest 21 | 22 | permissions: 23 | contents: write 24 | pull-requests: write 25 | 26 | # Specifically check that dependabot (or another trusted party) created this pull-request, and that it has been labelled correctly. 27 | if: contains(github.event.pull_request.labels.*.name, 'dependencies') 28 | steps: 29 | - uses: alexwilson/enable-github-automerge-action@2.0.0 30 | with: 31 | github-token: ${{secrets.SOURCE_PUSH_TOKEN}} 32 | merge-method: "MERGE" 33 | 34 | auto_approve_dependabot: 35 | runs-on: ubuntu-latest 36 | 37 | permissions: 38 | contents: write 39 | pull-requests: write 40 | 41 | if: contains(github.event.pull_request.labels.*.name, 'dependencies') 42 | steps: 43 | - uses: hmarr/auto-approve-action@v4 44 | with: 45 | github-token: ${{secrets.SOURCE_PUSH_TOKEN}} 46 | -------------------------------------------------------------------------------- /.github/workflows/oss-scorecared.yml: -------------------------------------------------------------------------------- 1 | name: "Security: Scorecard analysis" 2 | on: 3 | # Only the default branch is supported. 4 | branch_protection_rule: 5 | schedule: 6 | # Weekly on Saturdays. 7 | - cron: '30 1 * * 6' 8 | push: 9 | branches: [ main, master ] 10 | 11 | # Declare default permissions as read only. 12 | permissions: read-all 13 | 14 | jobs: 15 | analysis: 16 | name: "Scorecard analysis" 17 | runs-on: ubuntu-latest 18 | permissions: 19 | # Needed if using Code scanning alerts 20 | security-events: write 21 | # Needed for GitHub OIDC token if publish_results is true 22 | id-token: write 23 | 24 | steps: 25 | - name: "Harden Security" 26 | uses: step-security/harden-runner@v2.12.0 27 | with: 28 | egress-policy: block 29 | disable-sudo: true 30 | allowed-endpoints: > 31 | api.deps.dev:443 32 | api.github.com:443 33 | api.osv.dev:443 34 | api.scorecard.dev:443 35 | api.securityscorecards.dev:443 36 | auth.docker.io:443 37 | codeload.github.com:443 38 | fulcio.sigstore.dev:443 39 | github.com:443 40 | index.docker.io:443 41 | oss-fuzz-build-logs.storage.googleapis.com:443 42 | rekor.sigstore.dev:443 43 | tuf-repo-cdn.sigstore.dev:443 44 | www.bestpractices.dev:443 45 | 46 | - name: "Checkout code" 47 | uses: actions/checkout@v4.1.1 48 | with: 49 | fetch-depth: 0 50 | fetch-tags: true 51 | persist-credentials: false 52 | 53 | - name: "Run analysis" 54 | uses: ossf/scorecard-action@v2.4.2 55 | with: 56 | results_file: results.sarif 57 | results_format: sarif 58 | # (Optional) fine-grained personal access token. Uncomment the `repo_token` line below if: 59 | # - you want to enable the Branch-Protection check on a *public* repository, or 60 | # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-fine-grained-pat-optional. 61 | repo_token: ${{ secrets.SOURCE_PUSH_TOKEN }} 62 | 63 | # Publish the results for public repositories to enable scorecard badges. For more details, see 64 | # https://github.com/ossf/scorecard-action#publishing-results. 65 | # For private repositories, `publish_results` will automatically be set to `false`, regardless 66 | # of the value entered here. 67 | publish_results: true 68 | 69 | # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF 70 | # format to the repository Actions tab. 71 | - name: "Upload artifact" 72 | uses: actions/upload-artifact@v4.6.2 73 | with: 74 | name: SARIF file 75 | path: results.sarif 76 | retention-days: 5 77 | 78 | # required for Code scanning alerts 79 | - name: "Upload SARIF results to code scanning" 80 | uses: github/codeql-action/upload-sarif@v3.28.19 81 | with: 82 | sarif_file: results.sarif 83 | -------------------------------------------------------------------------------- /.github/workflows/pr-update.yml: -------------------------------------------------------------------------------- 1 | name: "PR: Update" 2 | on: 3 | pull_request: 4 | types: 5 | - opened 6 | - reopened 7 | - synchronize 8 | branches: 9 | - main 10 | 11 | concurrency: 12 | group: ${{github.workflow}}-${{github.ref}} 13 | cancel-in-progress: false 14 | 15 | env: 16 | HEAD_REF: ${{github.head_ref}} 17 | BASE_REF: ${{github.base_ref}} 18 | 19 | jobs: 20 | info: 21 | if: endsWith(github.repository , '-template') 22 | runs-on: ubuntu-latest 23 | steps: 24 | - name: "Initialise Workspace" 25 | if: startsWith(runner.name, 'buildagent-') 26 | shell: bash 27 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 28 | 29 | - name: "Set Active Environment" 30 | shell: bash 31 | run: | 32 | { 33 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 34 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 35 | echo "ACTIVE_USER=$USER" 36 | } >> "$GITHUB_ENV" 37 | 38 | - name: "Info" 39 | uses: actions/github-script@v7.0.1 40 | with: 41 | script: | 42 | core.info('Branch: ${{env.HEAD_REF}}'); 43 | core.info('Base Branch: ${{env.BASE_REF}}'); 44 | core.info('Repo: ${{github.repository}}'); 45 | core.info('Owner: ${{github.repository_owner}}'); 46 | core.info('Assigned: ${{github.event.pull_request.assignee.login}}'); 47 | core.info('Assigned: ${{github.event.pull_request.assignees[0].login}}'); 48 | core.info('Last Modified By: ${{github.event.pull_request.head.user.login}}'); 49 | core.info('PR Creator: ${{github.event.pull_request.creator.login}}'); 50 | core.info('PR Owner: ${{github.event.pull_request.owner}}'); 51 | core.info('Actor: ${{github.actor}}'); 52 | 53 | add-pr-label: 54 | if: ${{github.actor != 'dependabot[bot]'}} 55 | runs-on: ubuntu-latest 56 | steps: 57 | - name: "Initialise Workspace" 58 | if: startsWith(runner.name, 'buildagent-') 59 | shell: bash 60 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 61 | 62 | - name: "Set Active Environment" 63 | shell: bash 64 | run: | 65 | { 66 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 67 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 68 | echo "ACTIVE_USER=$USER" 69 | } >> "$GITHUB_ENV" 70 | 71 | - name: "Add Labels" 72 | uses: actions/labeler@v5 73 | with: 74 | repo-token: ${{secrets.SOURCE_PUSH_TOKEN}} 75 | configuration-path: .github/labeler.yml 76 | sync-labels: true 77 | 78 | assign-to-creator: 79 | if: |- 80 | ${{!github.event.pull_request.assignee.login 81 | && github.event_name == 'pull_request' 82 | && ( github.event.action == 'opened' || github.event.action == 'reopened') 83 | && github.actor != 'dependabot[bot]'}} 84 | runs-on: ubuntu-latest 85 | steps: 86 | - name: "Initialise Workspace" 87 | if: startsWith(runner.name, 'buildagent-') 88 | shell: bash 89 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 90 | 91 | - name: "Set Active Environment" 92 | shell: bash 93 | run: | 94 | { 95 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 96 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 97 | echo "ACTIVE_USER=$USER" 98 | } >> "$GITHUB_ENV" 99 | 100 | - name: "Assign PR to the creator" 101 | uses: thomaseizinger/assign-pr-creator-action@v1.0.0 102 | with: 103 | repo-token: ${{secrets.SOURCE_PUSH_TOKEN}} 104 | -------------------------------------------------------------------------------- /.github/workflows/pull-request.yml: -------------------------------------------------------------------------------- 1 | name: "PR: Create" 2 | on: 3 | push: 4 | branches-ignore: 5 | - master 6 | - main 7 | - "release/**" 8 | - "hotfix/**" 9 | - "feature/**" 10 | 11 | permissions: 12 | contents: read 13 | pull-requests: write 14 | 15 | concurrency: 16 | group: ${{github.workflow}}-${{github.ref}} 17 | cancel-in-progress: true 18 | 19 | env: 20 | HEAD_REF: ${{github.head_ref}} 21 | BASE_REF: ${{github.base_ref}} 22 | REPO: ${{github.repository}} 23 | REPO_OWNER: ${{github.repository_owner}} 24 | 25 | jobs: 26 | info: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: "Initialise Workspace" 30 | if: startsWith(runner.name, 'buildagent-') 31 | shell: bash 32 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 33 | 34 | - name: "Set Active Environment" 35 | shell: bash 36 | run: | 37 | { 38 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 39 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 40 | echo "ACTIVE_USER=$USER" 41 | } >> "$GITHUB_ENV" 42 | 43 | - name: "Info" 44 | uses: actions/github-script@v7.0.1 45 | with: 46 | script: | 47 | core.info('Branch: ${{env.HEAD_REF}}'); 48 | core.info('Base Branch: ${{env.BASE_REF}}'); 49 | core.info('Repo: ${{env.REPO}}'); 50 | core.info('Owner: ${{env.REPO_OWNER}}'); 51 | 52 | pull-request: 53 | runs-on: ubuntu-latest 54 | 55 | env: 56 | CREATE_DRAFT: true 57 | REPO_STATUS: private 58 | 59 | steps: 60 | - name: "Initialise Workspace" 61 | if: startsWith(runner.name, 'buildagent-') 62 | shell: bash 63 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 64 | 65 | - name: "Set Active Environment" 66 | shell: bash 67 | run: | 68 | { 69 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 70 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 71 | echo "ACTIVE_USER=$USER" 72 | } >> "$GITHUB_ENV" 73 | 74 | - name: "Checkout source" 75 | uses: actions/checkout@v4.2.2 76 | with: 77 | fetch-depth: 1 78 | fetch-tags: true 79 | 80 | - name: "Find PR For branch" 81 | uses: juliangruber/find-pull-request-action@v1.9.0 82 | id: findPr 83 | with: 84 | branch: ${{github.ref_name}} 85 | 86 | - name: "Existing PR Information" 87 | if: steps.findPr.outputs.number != '' 88 | uses: actions/github-script@v7.0.1 89 | with: 90 | script: | 91 | core.info('Pull request already exists with id: ${{steps.findPr.outputs.number}}'); 92 | core.info('URL: https://github.com/${{env.REPO}}/pull/${{steps.findPr.outputs.number}}'); 93 | 94 | - name: "Read PR Template" 95 | if: steps.findPr.outputs.number == '' 96 | id: pr-template 97 | uses: juliangruber/read-file-action@v1.1.7 98 | with: 99 | path: ./.github/PULL_REQUEST_TEMPLATE.md 100 | 101 | - name: "Get last commit info" 102 | if: steps.findPr.outputs.number == '' 103 | shell: bash 104 | run: echo "COMMIT_MSG=$(git log -1 --pretty=%B)" >> "$GITHUB_ENV" 105 | 106 | - name: "Check Repo Visibility" 107 | if: env.REPO_STATUS == '' &&steps.findPr.outputs.number == '' 108 | uses: credfeto/action-repo-visibility@v1.2.0 109 | id: visibility 110 | with: 111 | repository: ${{env.REPO}} 112 | token: ${{secrets.SOURCE_PUSH_TOKEN}} 113 | 114 | - name: "Override DRAFT Flag" 115 | if: |- 116 | steps.findPr.outputs.number == '' 117 | && env.REPO_OWNER != 'funfair-tech' 118 | && env.REPO_STATUS == 'private' 119 | shell: bash 120 | run: echo "CREATE_DRAFT=false" >> "$GITHUB_ENV" 121 | 122 | - name: "Status" 123 | uses: actions/github-script@v7.0.1 124 | with: 125 | script: | 126 | core.info('Repo: ${{env.REPO}}'); 127 | core.info('Owner: ${{env.REPO_OWNER}}'); 128 | core.info('Repo Status: ${{env.REPO_STATUS}}'); 129 | core.info('PR OK: ${{steps.findPr.outputs.number == ''}}'); 130 | core.info('Owner OK: ${{env.REPO_OWNER != 'funfair-tech'}}'); 131 | core.info('Status OK: ${{env.REPO_STATUS == 'private'}}'); 132 | 133 | - name: "Create Pull Request" 134 | if: steps.findPr.outputs.number == '' 135 | id: open-pr 136 | uses: repo-sync/pull-request@v2.12 137 | with: 138 | source_branch: "" # If blank, default: triggered branch 139 | destination_branch: "main" # If blank, default: master 140 | pr_assignee: ${{github.actor}} # Comma-separated list (no spaces) 141 | pr_label: "auto-pr" # Comma-separated list (no spaces) 142 | pr_draft: ${{env.CREATE_DRAFT}} # Creates pull request as draft 143 | pr_title: ${{env.COMMIT_MSG}} 144 | pr_body: ${{steps.pr-template.outputs.content}} 145 | github_token: ${{github.token}} 146 | 147 | - name: "New PR Details" 148 | if: steps.findPr.outputs.number == '' 149 | uses: actions/github-script@v7.0.1 150 | with: 151 | script: | 152 | core.info('URL: ${{steps.open-pr.outputs.pr_url}}'); 153 | core.info('PR: ${{steps.open-pr.outputs.pr_number}}'); 154 | core.info('CF: ${{steps.open-pr.outputs.has_changed_files}}'); 155 | 156 | - name: "Sync Labels" 157 | if: steps.findPr.outputs.number == '' 158 | uses: actions/labeler@v5 159 | with: 160 | repo-token: ${{secrets.SOURCE_PUSH_TOKEN}} 161 | configuration-path: .github/labeler.yml 162 | sync-labels: true 163 | pr-number: ${{steps.open-pr.outputs.pr_number}} 164 | -------------------------------------------------------------------------------- /.github/workflows/reformat-sql.yml: -------------------------------------------------------------------------------- 1 | --- # Reformatting MSSQL 2 | name: "Standardise: MSSQL Format" 3 | 4 | on: 5 | push: 6 | branches-ignore: 7 | - "release/*" 8 | - "hotfix/*" 9 | paths: 10 | - '**.sql' 11 | - '.github/workflows/reformat-sql.yml' 12 | 13 | concurrency: 14 | group: ${{github.workflow}}-${{github.ref}} 15 | cancel-in-progress: true 16 | 17 | permissions: 18 | contents: write 19 | 20 | jobs: 21 | standardise-tsql-files: 22 | 23 | if: |- 24 | github.event.pull_request.draft == false 25 | && ( !startsWith(github.head_ref, 'release/') 26 | && !startsWith(github.head_ref, 'hotfix/') ) 27 | && github.actor != 'dependabot[bot]' 28 | runs-on: ubuntu-latest 29 | 30 | steps: 31 | - name: "Initialise Workspace" 32 | if: startsWith(runner.name, 'buildagent-') 33 | shell: bash 34 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 35 | 36 | - name: "Set Active Environment" 37 | shell: bash 38 | run: | 39 | { 40 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 41 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 42 | echo "ACTIVE_USER=$USER" 43 | } >> "$GITHUB_ENV" 44 | 45 | - name: "Checkout Source" 46 | uses: actions/checkout@v4.2.2 47 | with: 48 | fetch-depth: 0 49 | fetch-tags: true 50 | token: ${{secrets.SOURCE_PUSH_TOKEN}} 51 | 52 | - name: "Reformat" 53 | uses: credfeto/action-sql-format@v1.5.1 54 | 55 | - name: "Commit Changes" 56 | uses: stefanzweifel/git-auto-commit-action@v5.2.0 57 | with: 58 | commit_message: "[Reformat] SQL Files to common format" 59 | file_pattern: "*.sql" 60 | commit_user_name: "fun-sqlfmt[bot]" 61 | commit_user_email: "credfeto@users.noreply.github.com" 62 | commit_author: "fun-sqlfmt[bot] " 63 | skip_dirty_check: false 64 | -------------------------------------------------------------------------------- /.github/workflows/reformat-yaml.yml: -------------------------------------------------------------------------------- 1 | --- # Reformatting Yaml 2 | name: "Standardise: YAML format" 3 | 4 | on: 5 | push: 6 | branches-ignore: 7 | - "release/*" 8 | - "hotfix/*" 9 | paths: 10 | - '**.yml' 11 | - '**.yaml' 12 | - '.github/workflows/reformat-yaml.yml' 13 | 14 | concurrency: 15 | group: ${{github.workflow}}-${{github.ref}} 16 | cancel-in-progress: true 17 | 18 | permissions: 19 | contents: write 20 | 21 | jobs: 22 | standardise-yaml-files: 23 | 24 | if: |- 25 | github.event.pull_request.draft == false 26 | && ( !startsWith(github.head_ref, 'release/') 27 | && !startsWith(github.head_ref, 'hotfix/') ) 28 | && github.actor != 'dependabot[bot]' 29 | runs-on: ubuntu-latest 30 | 31 | steps: 32 | - name: "Initialise Workspace" 33 | if: startsWith(runner.name, 'buildagent-') 34 | shell: bash 35 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 36 | 37 | - name: "Set Active Environment" 38 | shell: bash 39 | run: | 40 | { 41 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 42 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 43 | echo "ACTIVE_USER=$USER" 44 | } >> "$GITHUB_ENV" 45 | 46 | - name: "Checkout Source" 47 | uses: actions/checkout@v4.2.2 48 | with: 49 | fetch-depth: 0 50 | fetch-tags: true 51 | token: ${{secrets.SOURCE_PUSH_TOKEN}} 52 | 53 | - name: "Reformat" 54 | uses: credfeto/action-yaml-format@v1.3.2 55 | 56 | - name: "Commit Changes" 57 | uses: stefanzweifel/git-auto-commit-action@v5.2.0 58 | with: 59 | commit_message: "[Reformat] YAML Files to common format" 60 | file_pattern: "*.yml" 61 | commit_user_name: "fun-ymlfmt[bot]" 62 | commit_user_email: "credfeto@users.noreply.github.com" 63 | commit_author: "fun-ymlfmt[bot] " 64 | skip_dirty_check: false 65 | -------------------------------------------------------------------------------- /.github/workflows/todos.yml: -------------------------------------------------------------------------------- 1 | name: "Analysis: TODO" 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | concurrency: 9 | group: ${{github.workflow}}-${{github.ref}} 10 | cancel-in-progress: true 11 | 12 | permissions: 13 | issues: write 14 | repository-projects: read 15 | contents: read 16 | 17 | jobs: 18 | todos: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: "Harden Security" 23 | uses: step-security/harden-runner@v2.12.0 24 | with: 25 | egress-policy: block 26 | disable-sudo: true 27 | allowed-endpoints: > 28 | api.github.com:443 29 | api.osv.dev:443 30 | api.securityscorecards.dev:443 31 | codeload.github.com:443 32 | fulcio.sigstore.dev:443 33 | github.com:443 34 | oss-fuzz-build-logs.storage.googleapis.com:443 35 | rekor.sigstore.dev:443 36 | tuf-repo-cdn.sigstore.dev:443 37 | www.bestpractices.dev:443 38 | 39 | - name: "Checkout code" 40 | uses: actions/checkout@v4.1.1 41 | with: 42 | fetch-depth: 0 43 | fetch-tags: true 44 | persist-credentials: false 45 | 46 | - name: "Seach for TODOS" 47 | uses: derjuulsn/todo-issue@main 48 | with: 49 | excludePattern: '(node_modules/)' 50 | autoAssign: 'true' 51 | keywords: 'TODO' 52 | blobLines: 7 53 | blobLinesBefore: 2 54 | caseSensitive: false 55 | label: true 56 | reopenClosed: true 57 | 58 | env: 59 | GITHUB_TOKEN: ${{secrets.SOURCE_PUSH_TOKEN}} 60 | -------------------------------------------------------------------------------- /.github/workflows/update-labels.yml: -------------------------------------------------------------------------------- 1 | name: "Repo: Update Labels" 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - '.github/labels.yml' 9 | - '.github/workflows/update-labels.yml' 10 | 11 | concurrency: 12 | group: ${{github.workflow}}-${{github.ref}} 13 | cancel-in-progress: true 14 | 15 | permissions: 16 | contents: read 17 | 18 | 19 | jobs: 20 | 21 | update-labels-config: 22 | 23 | runs-on: ubuntu-latest 24 | 25 | permissions: 26 | issues: write # for crazy-max/ghaction-github-labeler to create, rename, update 27 | 28 | steps: 29 | - name: "Initialise Workspace" 30 | if: startsWith(runner.name, 'buildagent-') 31 | shell: bash 32 | run: sudo chown -R "$USER:$USER" "$GITHUB_WORKSPACE" 33 | 34 | - name: "Set Active Environment" 35 | shell: bash 36 | run: | 37 | { 38 | echo "ACTIVE_RUNNER_NAME=${{runner.name}}" 39 | echo "ACTIVE_HOSTNAME=$HOSTNAME" 40 | echo "ACTIVE_USER=$USER" 41 | } >> "$GITHUB_ENV" 42 | 43 | - name: "Checkout Source" 44 | uses: actions/checkout@v4.2.2 45 | with: 46 | fetch-depth: 0 47 | fetch-tags: true 48 | token: ${{secrets.SOURCE_PUSH_TOKEN}} 49 | 50 | - name: "Update Github label config" 51 | if: success() 52 | uses: crazy-max/ghaction-github-labeler@v5.3.0 53 | with: 54 | github-token: ${{secrets.SOURCE_PUSH_TOKEN}} 55 | yaml-file: .github/labels.yml 56 | skip-delete: true 57 | dry-run: false 58 | exclude: | 59 | help* 60 | *issue 61 | -------------------------------------------------------------------------------- /.gitleaks.toml: -------------------------------------------------------------------------------- 1 | title = "gitleaks config" 2 | 3 | [[rules]] 4 | id = "GL-AWS-01" 5 | description = "AWS Manager ID" 6 | regex = '''(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16}''' 7 | tags = ["key", "AWS"] 8 | 9 | [[rules]] 10 | id = "GL-AWS-02" 11 | description = "AWS Secret Key" 12 | regex = '''(?i)aws(.{0,20})?(?-i)[0-9a-zA-Z\/+]{40}''' 13 | tags = ["key", "AWS"] 14 | 15 | [[rules]] 16 | id = "GL-AWS-03" 17 | description = "AWS MWS key" 18 | regex = '''amzn\.mws\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}''' 19 | tags = ["key", "AWS", "MWS"] 20 | 21 | [[rules]] 22 | id = "GL-GITHUB-01" 23 | description = "Github" 24 | regex = '''(?i)github(.{0,20})?(?-i)[0-9a-zA-Z]{35,40}''' 25 | tags = ["key", "Github"] 26 | 27 | [[rules]] 28 | id = "GL-PRIVATEKEY-01" 29 | description = "Asymmetric Private Key" 30 | regex = '''-----BEGIN ((EC|PGP|DSA|RSA|OPENSSH) )?PRIVATE KEY( BLOCK)?-----''' 31 | tags = ["key", "AsymmetricPrivateKey"] 32 | 33 | [[rules]] 34 | id = "GL-GOOGLE-01" 35 | description = "Google API key" 36 | regex = '''AIza[0-9A-Za-z\\-_]{35}''' 37 | tags = ["key", "Google"] 38 | 39 | [[rules]] 40 | id = "GL-GOOGLE-02" 41 | description = "Google (GCP) Service Account" 42 | regex = '''"type": "service_account"''' 43 | tags = ["key", "Google"] 44 | 45 | [[rules]] 46 | id = "GL-SENDGRID-01" 47 | description = "SendGrid API Key" 48 | regex = '''SG\.[\w_]{16,32}\.[\w_]{16,64}''' 49 | tags = ["key", "SendGrid"] 50 | 51 | [[rules]] 52 | id = "GL-SLACK-01" 53 | description = "Slack Webhook" 54 | regex = '''https://hooks.slack.com/services/T[a-zA-Z0-9_]{8}/B[a-zA-Z0-9_]{8}/[a-zA-Z0-9_]{24}''' 55 | tags = ["key", "slack"] 56 | 57 | [[rules]] 58 | id = "GL-TWILIO-01" 59 | description = "Twilio API key" 60 | regex = '''(?i)twilio(.{0,20})?SK[0-9a-f]{32}''' 61 | tags = ["key", "twilio"] 62 | 63 | [[rules]] 64 | id = "GL-ETHPK-01" 65 | description = "Ethereum Private Key" 66 | regex = '''"PrivateKey":\s*"0x[a-fA-F0-9]{64}"''' 67 | tags = ["key", "ethereum", "private key"] 68 | 69 | [allowlist] 70 | description = "Allow Listed" 71 | file = '''(^\.?gitleaks.toml$|(.*?)(jpg|gif|doc|pdf|bin)$)''' 72 | regexes = [ 73 | '''(.*?)gitleaks:allow''' 74 | ] 75 | -------------------------------------------------------------------------------- /.tsqllintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "case-sensitive-variables": "error", 4 | "conditional-begin-end": "error", 5 | "count-star": "error", 6 | "cross-database-transaction": "error", 7 | "data-compression": "none", 8 | "data-type-length": "error", 9 | "delete-where": "error", 10 | "disallow-cursors": "error", 11 | "duplicate-empty-line" : "none", 12 | "duplicate-go" : "error", 13 | "full-text": "error", 14 | "information-schema": "error", 15 | "keyword-capitalization": "error", 16 | "linked-server": "error", 17 | "multi-table-alias": "error", 18 | "named-constraint": "error", 19 | "non-sargable": "error", 20 | "object-property": "error", 21 | "print-statement": "error", 22 | "schema-qualify": "error", 23 | "select-star": "error", 24 | "semicolon-termination": "none", 25 | "set-ansi": "none", 26 | "set-nocount": "none", 27 | "set-quoted-identifier": "none", 28 | "set-transaction-isolation-level": "none", 29 | "set-variable": "error", 30 | "unicode-string" : "error", 31 | "update-where" : "error", 32 | "upper-lower": "error" 33 | }, 34 | "compatibility-level": 140 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Mark Ridgwell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # credfeto-enum-source-generation 2 | 3 | C# Source generator for enums 4 | 5 | ## Using 6 | 7 | Add a reference to the ``Credfeto.Enumeration.Source.Generation`` package in each project you need the code generation to run. 8 | 9 | ```xml 10 | 11 | 15 | 16 | ``` 17 | 18 | For each enum in the project, generates a class with the following extension methods: 19 | 20 | * public static string GetName(this MyEnum value) 21 | * public static string GetDescription(this MyEnum value) 22 | 23 | Given an the example enum defined below: 24 | 25 | ```csharp 26 | public enum ExampleEnumValues 27 | { 28 | ZERO = 0, 29 | 30 | [Description("One \"1\"")] 31 | ONE = 1, 32 | 33 | SAME_AS_ONE = ONE, 34 | } 35 | ``` 36 | 37 | To get the name and value of the enum values. In release mode this can be practically instant. 38 | 39 | ```csharp 40 | ExampleEnumValues value = ExampleEnumValues.ONE; 41 | string name = value.GetName(); // ONE 42 | string description = value.GetDescription(); // One "1" 43 | bool isDefined = value.IsDefine(); // true 44 | bool isNotDefined = ((ExampleEnumValues)42).IsDefine(); // false 45 | ``` 46 | 47 | ## Enums in other assemblies 48 | 49 | Reference the following package in the project that contains the enum extensions class to generate. 50 | 51 | ```xml 52 | 53 | 57 | 58 | ``` 59 | 60 | Add an ``EnumText`` attribute to a partial static extension class for each enum you want to expose. 61 | 62 | ```csharp 63 | [EnumText(typeof(System.Net.HttpStatusCode))] 64 | [EnumText(typeof(ThirdParty.ExampleEnum))] 65 | public static partial class EnumExtensions 66 | { 67 | } 68 | ``` 69 | 70 | Will generate the same extension methods, but for the types nominated in the attributes. 71 | 72 | ## Benchmarks 73 | 74 | Benchmarks are in the Benchmark.net project ``Credfeto.Enumeration.Source.Generation.Benchmarks``, with a summary of a 75 | run below. 76 | 77 | | Method | Mean | Error | StdDev | Median | Allocated | 78 | |------------------------------- |--------------:|-----------:|-----------:|--------------:|----------:| 79 | | GetNameToString | 25.5162 ns | 0.4146 ns | 0.3675 ns | 25.5322 ns | 24 B | 80 | | GetNameReflection | 37.8875 ns | 0.3971 ns | 0.3520 ns | 37.8542 ns | 24 B | 81 | | GetNameCachedReflection | 21.6571 ns | 0.4514 ns | 0.3770 ns | 21.6841 ns | 24 B | 82 | | GetNameCodeGenerated | 0.0009 ns | 0.0039 ns | 0.0036 ns | 0.0000 ns | - | 83 | | GetDescriptionReflection | 1,380.4979 ns | 15.1089 ns | 13.3937 ns | 1,382.9476 ns | 264 B | 84 | | GetDescriptionCachedReflection | 22.8844 ns | 0.3856 ns | 0.3607 ns | 22.8364 ns | 24 B | 85 | | GetDescriptionCodeGenerated | 0.0035 ns | 0.0057 ns | 0.0053 ns | 0.0000 ns | - | 86 | | IsDefinedCodeReflection | 48.7961 ns | 0.9675 ns | 1.0352 ns | 48.5573 ns | 24 B | 87 | | IsDefinedCodeReflectionCached | 21.4452 ns | 0.3169 ns | 0.2965 ns | 21.3938 ns | 24 B | 88 | | IsDefinedCodeGenerated | 0.0012 ns | 0.0041 ns | 0.0037 ns | 0.0000 ns | - | 89 | 90 | 91 | ``` 92 | // * Warnings * 93 | ZeroMeasurement 94 | EnumBench.GetNameCodeGenerated: Default -> The method duration is indistinguishable from the empty method duration 95 | EnumBench.GetDescriptionCodeGenerated: Default -> The method duration is indistinguishable from the empty method duration 96 | EnumBench.IsDefinedCodeGenerated: Default -> The method duration is indistinguishable from the empty method duration 97 | 98 | // * Legends * 99 | Mean : Arithmetic mean of all measurements 100 | Error : Half of 99.9% confidence interval 101 | StdDev : Standard deviation of all measurements 102 | Median : Value separating the higher half of all measurements (50th percentile) 103 | Allocated : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B) 104 | 1 ns : 1 Nanosecond (0.000000001 sec) 105 | ``` 106 | 107 | ## Viewing Compiler Generated files 108 | 109 | Add the following to the csproj file: 110 | 111 | ```xml 112 | 113 | true 114 | Generated 115 | 116 | 117 | 120 | 121 | 122 | ``` 123 | 124 | ## Build Status 125 | 126 | | Branch | Status | 127 | |---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 128 | | main | [![Build: Pre-Release](https://github.com/credfeto/credfeto-enum-source-generation/actions/workflows/build-and-publish-pre-release.yml/badge.svg)](https://github.com/credfeto/credfeto-enum-source-generation/actions/workflows/build-and-publish-pre-release.yml) | 129 | | release | [![Build: Release](https://github.com/credfeto/credfeto-enum-source-generation/actions/workflows/build-and-publish-release.yml/badge.svg)](https://github.com/credfeto/credfeto-enum-source-generation/actions/workflows/build-and-publish-release.yml) | 130 | 131 | ## Changelog 132 | 133 | View [changelog](CHANGELOG.md) 134 | 135 | ## Contributors 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | | Version | Supported | 6 | | ------- | ------------------ | 7 | | latest | :white_check_mark: | 8 | | others | :x: | 9 | 10 | ## Reporting a Vulnerability 11 | 12 | Report the vulnerability here [SECURITY](../../security/advisories/new). 13 | -------------------------------------------------------------------------------- /src/.idea/.idea.Credfeto.Enumeration.Source.Generation/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Rider ignored files 5 | /modules.xml 6 | /contentModel.xml 7 | /projectSettingsUpdater.xml 8 | /.idea.Credfeto.Enumeration.Source.Generation.iml 9 | # Editor-based HTTP Client requests 10 | /httpRequests/ 11 | # Datasource local storage ignored files 12 | /dataSources/ 13 | /dataSources.local.xml 14 | -------------------------------------------------------------------------------- /src/.idea/.idea.Credfeto.Enumeration.Source.Generation/.idea/.name: -------------------------------------------------------------------------------- 1 | Credfeto.Enumeration.Source.Generation -------------------------------------------------------------------------------- /src/.idea/.idea.Credfeto.Enumeration.Source.Generation/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/.idea/.idea.Credfeto.Enumeration.Source.Generation/.idea/indexLayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/.idea/.idea.Credfeto.Enumeration.Source.Generation/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation.Attributes/Credfeto.Enumeration.Source.Generation.Attributes.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | latest 4 | AllEnabledByDefault 5 | $(SolutionDir)\CodeAnalysis.ruleset 6 | true 7 | Mark Ridgwell 8 | Mark Ridgwell 9 | true 10 | Source code generator for Enums. 11 | true 12 | true 13 | true 14 | true 15 | true 16 | true 17 | true 18 | false 19 | strict;flow-analysis 20 | true 21 | true 22 | true 23 | false 24 | Size 25 | disable 26 | true 27 | true 28 | true 29 | false 30 | true 31 | false 32 | latest 33 | en 34 | true 35 | 1591 36 | true 37 | low 38 | all 39 | enable 40 | speed 41 | Library 42 | https://raw.githubusercontent.com/credfeto/credfeto-enum-source-generation/main/LICENSE 43 | $(ReleaseNotes) 44 | C# Source code generator Enum 45 | Source Generation 46 | https://github.com/credfeto/credfeto-enum-source-generation 47 | false 48 | snupkg 49 | netstandard2.0;net8.0;net9.0 50 | true 51 | true 52 | 53 | true 54 | true 55 | 56 | 57 | 58 | true 59 | true 60 | 61 | 62 | false 63 | false 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation.Attributes/EnumTextAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Credfeto.Enumeration.Source.Generation.Attributes; 4 | 5 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)] 6 | public sealed class EnumTextAttribute : Attribute 7 | { 8 | public EnumTextAttribute(Type enumType) 9 | { 10 | this.Enum = ValidateEnumType(enumType); 11 | } 12 | 13 | public Type Enum { get; } 14 | 15 | private static Type ValidateEnumType(Type enumType) 16 | { 17 | return enumType.IsEnum ? enumType : NotAnEnum(enumType); 18 | } 19 | 20 | private static Type NotAnEnum(Type enumType) 21 | { 22 | throw new ArgumentException($"The type ({enumType.FullName}) must be an enum.", nameof(enumType)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation.Benchmarks/BenchBase.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace Credfeto.Enumeration.Source.Generation.Benchmarks; 5 | 6 | public abstract class BenchBase 7 | { 8 | [SuppressMessage( 9 | category: "codecracker.CSharp", 10 | checkId: "CC0091:MarkMembersAsStatic", 11 | Justification = "Benchmark" 12 | )] 13 | [SuppressMessage( 14 | category: "Microsoft.Performance", 15 | checkId: "CA1822:Mark methods static", 16 | Justification = "Benchmark" 17 | )] 18 | [SuppressMessage(category: "ReSharper", checkId: "UnusedParameter.Global", Justification = "Simplifies benchmarks")] 19 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 20 | protected void Test(T value) 21 | { 22 | // Doesn't do anything 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation.Benchmarks/Credfeto.Enumeration.Source.Generation.Benchmarks.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | latest 4 | AllEnabledByDefault 5 | $(SolutionDir)\CodeAnalysis.ruleset 6 | true 7 | Mark Ridgwell 8 | Mark Ridgwell 9 | true 10 | true 11 | true 12 | true 13 | true 14 | true 15 | true 16 | false 17 | strict;flow-analysis 18 | true 19 | false 20 | Size 21 | disable 22 | true 23 | false 24 | false 25 | false 26 | latest 27 | en-GB 28 | 29 | true 30 | low 31 | all 32 | enable 33 | speed 34 | Exe 35 | https://raw.githubusercontent.com/credfeto/credfeto-enum-source-generation/main/LICENSE 36 | $(ReleaseNotes) 37 | Source Generation 38 | false 39 | net9.0 40 | true 41 | true 42 | 43 | true 44 | true 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation.Benchmarks/EnumBench.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using BenchmarkDotNet.Attributes; 3 | using Credfeto.Enumeration.Source.Generation.Generics; 4 | using Credfeto.Enumeration.Source.Generation.Models; 5 | 6 | namespace Credfeto.Enumeration.Source.Generation.Benchmarks; 7 | 8 | [SimpleJob] 9 | [MemoryDiagnoser(false)] 10 | public abstract class EnumBench : BenchBase 11 | { 12 | [Benchmark] 13 | public void GetNameToString() 14 | { 15 | this.Test(ExampleEnumValues.ONE.GetNameToString()); 16 | } 17 | 18 | [Benchmark] 19 | public void GetNameReflection() 20 | { 21 | this.Test(ExampleEnumValues.ONE.GetNameReflection()); 22 | } 23 | 24 | [Benchmark] 25 | public void GetNameCachedReflection() 26 | { 27 | this.Test(ExampleEnumValues.ONE.GetNameReflectionCached()); 28 | } 29 | 30 | [Benchmark] 31 | public void GetName2CodeGenerated() 32 | { 33 | this.Test(HttpStatusCode.Accepted.GetName()); 34 | } 35 | 36 | [Benchmark] 37 | public void GetName2ToString() 38 | { 39 | this.Test(HttpStatusCode.Accepted.GetNameToString()); 40 | } 41 | 42 | [Benchmark] 43 | public void GetName2Reflection() 44 | { 45 | this.Test(HttpStatusCode.Accepted.GetNameReflection()); 46 | } 47 | 48 | [Benchmark] 49 | public void GetName2CachedReflection() 50 | { 51 | this.Test(HttpStatusCode.Accepted.GetNameReflectionCached()); 52 | } 53 | 54 | [Benchmark] 55 | public void GetNameCodeGenerated() 56 | { 57 | this.Test(ExampleEnumValues.ONE.GetName()); 58 | } 59 | 60 | [Benchmark] 61 | public void GetDescriptionReflection() 62 | { 63 | this.Test(ExampleEnumValues.ONE.GetDescriptionReflection()); 64 | } 65 | 66 | [Benchmark] 67 | public void GetDescriptionCachedReflection() 68 | { 69 | this.Test(ExampleEnumValues.ONE.GetDescriptionReflectionCached()); 70 | } 71 | 72 | [Benchmark] 73 | public void GetDescriptionCodeGenerated() 74 | { 75 | this.Test(ExampleEnumValues.ONE.GetDescription()); 76 | } 77 | 78 | [Benchmark] 79 | public void IsDefinedCodeReflection() 80 | { 81 | this.Test(ExampleEnumValues.ONE.IsDefinedReflection()); 82 | } 83 | 84 | [Benchmark] 85 | public void IsDefinedCodeReflectionCached() 86 | { 87 | this.Test(ExampleEnumValues.ONE.IsDefinedReflectionCached()); 88 | } 89 | 90 | [Benchmark] 91 | public void IsDefinedCodeGenerated() 92 | { 93 | this.Test(ExampleEnumValues.ONE.IsDefined()); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation.Benchmarks/EnumWrappers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Runtime.CompilerServices; 4 | using Credfeto.Enumeration.Source.Generation.Generics; 5 | 6 | namespace Credfeto.Enumeration.Source.Generation.Benchmarks; 7 | 8 | internal static class EnumWrappers 9 | { 10 | [SuppressMessage(category: "ReSharper", checkId: "InvokeAsExtensionMethod", Justification = "This is a benchmark.")] 11 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 12 | public static string GetNameReflectionCached(this T value) 13 | where T : Enum 14 | { 15 | return EnumHelpers.GetName(value); 16 | } 17 | 18 | [SuppressMessage(category: "ReSharper", checkId: "InvokeAsExtensionMethod", Justification = "This is a benchmark.")] 19 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 20 | public static string GetDescriptionReflectionCached(this T value) 21 | where T : Enum 22 | { 23 | return EnumHelpers.GetDescription(value); 24 | } 25 | 26 | [SuppressMessage(category: "ReSharper", checkId: "InvokeAsExtensionMethod", Justification = "This is a benchmark.")] 27 | [SuppressMessage( 28 | category: "Philips.CodeAnalysis.MaintainabilityAnalyzers", 29 | checkId: "PH2073: Call as instance", 30 | Justification = "This is a benchmark." 31 | )] 32 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 33 | public static bool IsDefinedReflectionCached(this T value) 34 | where T : Enum 35 | { 36 | return EnumHelpers.IsDefined(value); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation.Benchmarks/Program.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Running; 2 | 3 | namespace Credfeto.Enumeration.Source.Generation.Benchmarks; 4 | 5 | public static class Program 6 | { 7 | private static void Main() 8 | { 9 | RunEnumBenchmarks(); 10 | } 11 | 12 | private static void RunEnumBenchmarks() 13 | { 14 | BenchmarkRunner.Run(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation.Generics/Credfeto.Enumeration.Source.Generation.Generics.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | latest 4 | AllEnabledByDefault 5 | $(SolutionDir)\CodeAnalysis.ruleset 6 | true 7 | Mark Ridgwell 8 | Mark Ridgwell 9 | true 10 | true 11 | true 12 | true 13 | true 14 | true 15 | false 16 | strict;flow-analysis 17 | true 18 | false 19 | Size 20 | disable 21 | true 22 | false 23 | false 24 | false 25 | latest 26 | en-GB 27 | 28 | true 29 | low 30 | all 31 | enable 32 | speed 33 | Library 34 | https://raw.githubusercontent.com/credfeto/credfeto-enum-source-generation/main/LICENSE 35 | $(ReleaseNotes) 36 | Source Generation 37 | false 38 | netstandard2.0;netstandard2.1 39 | true 40 | true 41 | 42 | true 43 | true 44 | 45 | 46 | 47 | true 48 | true 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation.Generics/EnumHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Linq; 5 | using System.Reflection; 6 | using NonBlocking; 7 | 8 | namespace Credfeto.Enumeration.Source.Generation.Generics; 9 | 10 | public static class EnumHelpers 11 | { 12 | private static readonly ConcurrentDictionary CachedNames = new(); 13 | 14 | private static readonly ConcurrentDictionary CachedDescriptions = new(); 15 | 16 | private static readonly ConcurrentDictionary CachedDefined = new(); 17 | 18 | [SuppressMessage( 19 | category: "Credfeto.Enumeration.Source.Generation", 20 | checkId: "ENUM001: Use GetName", 21 | Justification = "Enum is a value type" 22 | )] 23 | [SuppressMessage( 24 | category: "ToStringWithoutOverrideAnalyzer", 25 | checkId: "ExplicitToStringWithoutOverrideAnalyzer: Use GetName", 26 | Justification = "Enum is a value type" 27 | )] 28 | public static string GetNameToString(this T value) 29 | where T : Enum 30 | { 31 | return value.ToString(); 32 | } 33 | 34 | public static string GetNameReflection(this T value) 35 | where T : Enum 36 | { 37 | return Enum.GetName(value.GetType(), value: value) ?? string.Empty; 38 | } 39 | 40 | public static string GetName(this T value) 41 | where T : Enum 42 | { 43 | if (CachedNames.TryGetValue(key: value, out string? name)) 44 | { 45 | return name; 46 | } 47 | 48 | return CachedNames.GetOrAdd(key: value, value.GetNameReflection()); 49 | } 50 | 51 | public static string GetDescriptionReflection(this T value) 52 | where T : Enum 53 | { 54 | string valueAsString = value.GetNameReflection(); 55 | FieldInfo? m = value.GetType().GetField(valueAsString); 56 | 57 | return 58 | m?.GetCustomAttributes(typeof(DescriptionAttribute), inherit: false).SingleOrDefault() 59 | is not DescriptionAttribute attribute 60 | ? valueAsString 61 | : attribute.Description; 62 | } 63 | 64 | public static bool IsDefinedReflection(this T value) 65 | where T : Enum 66 | { 67 | return Enum.IsDefined(value.GetType(), value: value); 68 | } 69 | 70 | public static string GetDescription(this T value) 71 | where T : Enum 72 | { 73 | if (CachedDescriptions.TryGetValue(key: value, out string? name)) 74 | { 75 | return name; 76 | } 77 | 78 | return CachedDescriptions.GetOrAdd(key: value, value.GetDescriptionReflection()); 79 | } 80 | 81 | public static bool IsDefined(this T value) 82 | where T : Enum 83 | { 84 | if (CachedDefined.TryGetValue(key: value, out bool defined)) 85 | { 86 | return defined; 87 | } 88 | 89 | return CachedDefined.GetOrAdd(key: value, value.IsDefinedReflection()); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation.Models.Tests/Credfeto.Enumeration.Source.Generation.Models.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | latest 4 | AllEnabledByDefault 5 | $(SolutionDir)\CodeAnalysis.ruleset 6 | true 7 | Mark Ridgwell 8 | Mark Ridgwell 9 | true 10 | true 11 | true 12 | true 13 | true 14 | true 15 | true 16 | false 17 | strict;flow-analysis 18 | true 19 | false 20 | Size 21 | disable 22 | true 23 | false 24 | false 25 | false 26 | latest 27 | en-GB 28 | 29 | true 30 | high 31 | all 32 | enable 33 | speed 34 | Exe 35 | https://raw.githubusercontent.com/credfeto/credfeto-enum-source-generation/main/LICENSE 36 | $(ReleaseNotes) 37 | Source Generation 38 | false 39 | net8.0;net9.0 40 | true 41 | true 42 | true 43 | 44 | true 45 | true 46 | true 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation.Models.Tests/EnumGetDescriptionTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Net; 5 | using Xunit; 6 | 7 | namespace Credfeto.Enumeration.Source.Generation.Models.Tests; 8 | 9 | [SuppressMessage( 10 | category: "FunFair.CodeAnalysis", 11 | checkId: "FFS0013: Test classes should be derived from TestBase", 12 | Justification = "Not in this case" 13 | )] 14 | public sealed class EnumGetDescriptionTests 15 | { 16 | [Fact] 17 | public void GetDescriptionForAliased() 18 | { 19 | Assert.Equal(expected: "One \"1\"", ExampleEnumValues.ONE.GetDescription()); 20 | Assert.Equal(expected: "One \"1\"", ExampleEnumValues.SAME_AS_ONE.GetDescription()); 21 | } 22 | 23 | [Fact] 24 | public void GetDescriptionForUnAliased() 25 | { 26 | Assert.Equal(expected: "ZERO", ExampleEnumValues.ZERO.GetDescription()); 27 | Assert.Equal(expected: "Two but one better!", ExampleEnumValues.THREE.GetDescription()); 28 | } 29 | 30 | [Fact] 31 | public void GetDescriptionForUnknown() 32 | { 33 | const ExampleEnumValues unknown = (ExampleEnumValues)72; 34 | #if NET7_0_OR_GREATER 35 | Assert.Throws(() => unknown.GetDescription()); 36 | #else 37 | Assert.Throws(() => unknown.GetDescription()); 38 | #endif 39 | } 40 | 41 | [Fact] 42 | public void GetDescriptionForExternalUnAliased() 43 | { 44 | Assert.Equal(expected: "OK", HttpStatusCode.OK.GetDescription()); 45 | Assert.Equal(expected: "Accepted", HttpStatusCode.Accepted.GetDescription()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation.Models.Tests/EnumGetNameTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Net; 5 | using Xunit; 6 | 7 | namespace Credfeto.Enumeration.Source.Generation.Models.Tests; 8 | 9 | [SuppressMessage( 10 | category: "FunFair.CodeAnalysis", 11 | checkId: "FFS0013: Test classes should be derived from TestBase", 12 | Justification = "Not in this case" 13 | )] 14 | public sealed class EnumGetNameTests 15 | { 16 | [Theory] 17 | [InlineData(ExampleEnumValues.ZERO, nameof(ExampleEnumValues.ZERO))] 18 | [InlineData(ExampleEnumValues.ONE, nameof(ExampleEnumValues.ONE))] 19 | [InlineData(ExampleEnumValues.THREE, nameof(ExampleEnumValues.THREE))] 20 | public void IsNameNameAsToString(ExampleEnumValues value, string expected) 21 | { 22 | string name = value.GetName(); 23 | 24 | Assert.Equal(expected: expected, actual: name); 25 | } 26 | 27 | [Fact] 28 | public void GetNameForAliased() 29 | { 30 | Assert.Equal(expected: "ONE", ExampleEnumValues.ONE.GetName()); 31 | Assert.Equal(expected: "ONE", ExampleEnumValues.SAME_AS_ONE.GetName()); 32 | } 33 | 34 | [Fact] 35 | public void GetNameForUnAliased() 36 | { 37 | Assert.Equal(expected: "ZERO", ExampleEnumValues.ZERO.GetName()); 38 | Assert.Equal(expected: "THREE", ExampleEnumValues.THREE.GetName()); 39 | } 40 | 41 | [Fact] 42 | public void GetNameForUnknown() 43 | { 44 | const ExampleEnumValues unknown = (ExampleEnumValues)72; 45 | 46 | #if NET7_0_OR_GREATER 47 | Assert.Throws(() => unknown.GetName()); 48 | #else 49 | Assert.Throws(() => unknown.GetName()); 50 | #endif 51 | } 52 | 53 | [Fact] 54 | public void GetNameForExternalUnAliased() 55 | { 56 | Assert.Equal(expected: "OK", HttpStatusCode.OK.GetName()); 57 | Assert.Equal(expected: "Accepted", HttpStatusCode.Accepted.GetName()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation.Models/.gitignore: -------------------------------------------------------------------------------- 1 | Generated 2 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation.Models/Credfeto.Enumeration.Source.Generation.Models.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | latest 4 | AllEnabledByDefault 5 | $(SolutionDir)\CodeAnalysis.ruleset 6 | true 7 | Mark Ridgwell 8 | Mark Ridgwell 9 | true 10 | true 11 | true 12 | true 13 | true 14 | true 15 | true 16 | false 17 | strict;flow-analysis 18 | true 19 | false 20 | Size 21 | disable 22 | true 23 | false 24 | false 25 | false 26 | latest 27 | en-GB 28 | 29 | true 30 | low 31 | all 32 | enable 33 | speed 34 | Library 35 | https://raw.githubusercontent.com/credfeto/credfeto-enum-source-generation/main/LICENSE 36 | $(ReleaseNotes) 37 | Source Generation 38 | false 39 | net8.0;net9.0 40 | true 41 | true 42 | 43 | true 44 | true 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation.Models/EnumExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using System.Net; 3 | using Credfeto.Enumeration.Source.Generation.Attributes; 4 | 5 | namespace Credfeto.Enumeration.Source.Generation.Models; 6 | 7 | [EnumText(typeof(HttpStatusCode))] 8 | [SuppressMessage( 9 | category: "ReSharper", 10 | checkId: "PartialTypeWithSinglePart", 11 | Justification = "Needed for generated code" 12 | )] 13 | public static partial class EnumExtensions; 14 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation.Models/ExampleEnumValues.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Diagnostics.CodeAnalysis; 4 | 5 | namespace Credfeto.Enumeration.Source.Generation.Models; 6 | 7 | public enum ExampleEnumValues 8 | { 9 | ZERO = 0, 10 | 11 | [Description("One \"1\"")] 12 | ONE = 1, 13 | 14 | SAME_AS_ONE = ONE, 15 | 16 | [SuppressMessage( 17 | category: "SonarAnalyzer.CSharp", 18 | checkId: "S1133: Remove deprecated code", 19 | Justification = "Used in tests" 20 | )] 21 | [Obsolete("This value is deprecated, use " + nameof(THREE) + " instead.")] 22 | [SuppressMessage(category: "ReSharper", checkId: "UnusedMember.Global", Justification = "Used in tests")] 23 | TWO = 2, 24 | 25 | [Description("Two but one better!")] 26 | THREE = 3, 27 | } 28 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29519.181 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Config", "Config", "{6BDAE5C1-D308-42EF-8B1C-60964D58A384}" 7 | ProjectSection(SolutionItems) = preProject 8 | CodeAnalysis.ruleset = CodeAnalysis.ruleset 9 | global.json = global.json 10 | ..\CHANGELOG.md = ..\CHANGELOG.md 11 | ..\README.md = ..\README.md 12 | ..\.github\workflows\build-and-publish-pre-release.yml = ..\.github\workflows\build-and-publish-pre-release.yml 13 | ..\.github\workflows\build-and-publish-release.yml = ..\.github\workflows\build-and-publish-release.yml 14 | SourceGenerator.props = SourceGenerator.props 15 | KeepGeneratedFiles.props = KeepGeneratedFiles.props 16 | EndProjectSection 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Credfeto.Enumeration.Source.Generation", "Credfeto.Enumeration.Source.Generation\Credfeto.Enumeration.Source.Generation.csproj", "{1C26D824-FFBD-4F64-A7DF-593BAD653219}" 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Credfeto.Enumeration.Source.Generation.Models", "Credfeto.Enumeration.Source.Generation.Models\Credfeto.Enumeration.Source.Generation.Models.csproj", "{50B8C49E-150D-4AC0-BE1A-D81B7FD04A0E}" 21 | EndProject 22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Credfeto.Enumeration.Source.Generation.Benchmarks", "Credfeto.Enumeration.Source.Generation.Benchmarks\Credfeto.Enumeration.Source.Generation.Benchmarks.csproj", "{C1EFBEFD-6734-43A8-A26F-0D6C7B1A92DB}" 23 | EndProject 24 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Credfeto.Enumeration.Source.Generation.Generics", "Credfeto.Enumeration.Source.Generation.Generics\Credfeto.Enumeration.Source.Generation.Generics.csproj", "{3AB18FC1-8DFC-4F23-9934-F2674C9BBB24}" 25 | EndProject 26 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Credfeto.Enumeration.Source.Generation.Attributes", "Credfeto.Enumeration.Source.Generation.Attributes\Credfeto.Enumeration.Source.Generation.Attributes.csproj", "{E7D245CE-8484-40AA-BDF7-D13EB26B9BDB}" 27 | EndProject 28 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Credfeto.Enumeration.Source.Generation.Models.Tests", "Credfeto.Enumeration.Source.Generation.Models.Tests\Credfeto.Enumeration.Source.Generation.Models.Tests.csproj", "{1482C2D9-8766-4D7F-8A52-1F1604DF8686}" 29 | EndProject 30 | Global 31 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 32 | {1C26D824-FFBD-4F64-A7DF-593BAD653219}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {1C26D824-FFBD-4F64-A7DF-593BAD653219}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {1C26D824-FFBD-4F64-A7DF-593BAD653219}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {1C26D824-FFBD-4F64-A7DF-593BAD653219}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {50B8C49E-150D-4AC0-BE1A-D81B7FD04A0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {50B8C49E-150D-4AC0-BE1A-D81B7FD04A0E}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {50B8C49E-150D-4AC0-BE1A-D81B7FD04A0E}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {50B8C49E-150D-4AC0-BE1A-D81B7FD04A0E}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {C1EFBEFD-6734-43A8-A26F-0D6C7B1A92DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {C1EFBEFD-6734-43A8-A26F-0D6C7B1A92DB}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {C1EFBEFD-6734-43A8-A26F-0D6C7B1A92DB}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {C1EFBEFD-6734-43A8-A26F-0D6C7B1A92DB}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {3AB18FC1-8DFC-4F23-9934-F2674C9BBB24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {3AB18FC1-8DFC-4F23-9934-F2674C9BBB24}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {3AB18FC1-8DFC-4F23-9934-F2674C9BBB24}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {3AB18FC1-8DFC-4F23-9934-F2674C9BBB24}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {E7D245CE-8484-40AA-BDF7-D13EB26B9BDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {E7D245CE-8484-40AA-BDF7-D13EB26B9BDB}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {E7D245CE-8484-40AA-BDF7-D13EB26B9BDB}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {E7D245CE-8484-40AA-BDF7-D13EB26B9BDB}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {1482C2D9-8766-4D7F-8A52-1F1604DF8686}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 53 | {1482C2D9-8766-4D7F-8A52-1F1604DF8686}.Debug|Any CPU.Build.0 = Debug|Any CPU 54 | {1482C2D9-8766-4D7F-8A52-1F1604DF8686}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {1482C2D9-8766-4D7F-8A52-1F1604DF8686}.Release|Any CPU.Build.0 = Release|Any CPU 56 | EndGlobalSection 57 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 58 | Debug|Any CPU = Debug|Any CPU 59 | Release|Any CPU = Release|Any CPU 60 | EndGlobalSection 61 | EndGlobal 62 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation/Builders/CodeBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using Microsoft.CodeAnalysis.Text; 4 | 5 | namespace Credfeto.Enumeration.Source.Generation.Builders; 6 | 7 | public sealed class CodeBuilder 8 | { 9 | private readonly StringBuilder _stringBuilder = new(16384); 10 | 11 | private int _indent; 12 | 13 | public SourceText Text => 14 | SourceText.From( 15 | this._stringBuilder.ToString(), 16 | encoding: Encoding.UTF8, 17 | checksumAlgorithm: SourceHashAlgorithm.Sha256 18 | ); 19 | 20 | public CodeBuilder AppendFileHeader() 21 | { 22 | return this.AppendLine("//------------------------------------------------------------------------------") 23 | .AppendLine("// ") 24 | .AppendLine("// This code was generated by a tool.") 25 | .AppendLine("// Runtime Version: Current") 26 | .AppendLine("//") 27 | .AppendLine("// Changes to this file may cause incorrect behavior and will be lost if") 28 | .AppendLine("// the code is regenerated.") 29 | .AppendLine("// ") 30 | .AppendLine("//------------------------------------------------------------------------------") 31 | .AppendBlankLine(); 32 | } 33 | 34 | public CodeBuilder AppendBlankLine() 35 | { 36 | this._stringBuilder.AppendLine(); 37 | 38 | return this; 39 | } 40 | 41 | public CodeBuilder AppendGeneratedCodeAttribute() 42 | { 43 | return this.AppendLine( 44 | $"[GeneratedCode(tool: \"{VersionInformation.Product}\", version: \"{VersionInformation.Version}\")]" 45 | ); 46 | } 47 | 48 | public CodeBuilder AppendLine(string text) 49 | { 50 | if (string.IsNullOrWhiteSpace(text)) 51 | { 52 | return this.AppendBlankLine(); 53 | } 54 | 55 | this._stringBuilder.Append(this.IndentCharacters()).AppendLine(text); 56 | 57 | return this; 58 | } 59 | 60 | public IDisposable StartBlock(string text) 61 | { 62 | return this.StartBlock(text: text, start: "{", end: "}"); 63 | } 64 | 65 | public IDisposable StartBlock(string text, string start, string end) 66 | { 67 | this.AppendLine(text); 68 | 69 | return new Indent(this, start: start, end: end); 70 | } 71 | 72 | private string IndentCharacters() 73 | { 74 | int indentCharacters = 4 * this._indent; 75 | 76 | return string.Empty.PadLeft(indentCharacters); 77 | } 78 | 79 | private sealed class Indent : IDisposable 80 | { 81 | private readonly CodeBuilder _builder; 82 | private readonly string _end; 83 | 84 | public Indent(CodeBuilder builder, string start, string end) 85 | { 86 | this._builder = builder; 87 | this._end = end; 88 | 89 | this._builder.AppendLine(start); 90 | ++this._builder._indent; 91 | } 92 | 93 | public void Dispose() 94 | { 95 | --this._builder._indent; 96 | this._builder.AppendLine(this._end); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation/Credfeto.Enumeration.Source.Generation.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | latest 4 | AllEnabledByDefault 5 | $(SolutionDir)\CodeAnalysis.ruleset 6 | true 7 | Mark Ridgwell 8 | Mark Ridgwell 9 | true 10 | Source code generator for Enums. 11 | true 12 | true 13 | true 14 | true 15 | true 16 | true 17 | true 18 | strict;flow-analysis 19 | true 20 | true 21 | true 22 | false 23 | Size 24 | disable 25 | false 26 | true 27 | true 28 | true 29 | false 30 | false 31 | latest 32 | en 33 | true 34 | 35 | true 36 | low 37 | all 38 | enable 39 | speed 40 | Library 41 | false 42 | https://raw.githubusercontent.com/credfeto/credfeto-enum-source-generation/main/LICENSE 43 | $(ReleaseNotes) 44 | C# Source code generator Enum 45 | Source Generation 46 | https://github.com/credfeto/credfeto-enum-source-generation 47 | false 48 | symbols.nupkg 49 | netstandard2.0 50 | true 51 | true 52 | True 53 | true 54 | 55 | 56 | 57 | true 58 | true 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation/Extensions/EnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace Credfeto.Enumeration.Source.Generation.Extensions; 5 | 6 | internal static class EnumerableExtensions 7 | { 8 | public static IEnumerable RemoveNulls(this IEnumerable source) 9 | { 10 | return from item in source where item is not null select item; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation/Extensions/SymbolExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Linq; 4 | using Microsoft.CodeAnalysis; 5 | 6 | namespace Credfeto.Enumeration.Source.Generation.Extensions; 7 | 8 | public static class SymbolExtensions 9 | { 10 | private static readonly Type ObsoleteType = typeof(ObsoleteAttribute); 11 | private static readonly Type DescriptionType = typeof(DescriptionAttribute); 12 | 13 | public static bool HasObsoleteAttribute(this ISymbol symbol) 14 | { 15 | return symbol.GetAttributes().Any(IsObsoleteAttribute); 16 | } 17 | 18 | public static bool IsObsoleteAttribute(this AttributeData attributeData) 19 | { 20 | return IsObsoleteAttribute(attributeData.AttributeClass ?? InvalidAttributeClass()); 21 | } 22 | 23 | private static INamedTypeSymbol InvalidAttributeClass() 24 | { 25 | throw new InvalidOperationException("AttributeClass is null"); 26 | } 27 | 28 | private static bool IsObsoleteAttribute(INamedTypeSymbol symbol) 29 | { 30 | return MatchesType(type: ObsoleteType, symbol: symbol); 31 | } 32 | 33 | public static bool IsDescriptionAttribute(this AttributeData attributeData) 34 | { 35 | return IsDescriptionAttribute(attributeData.AttributeClass ?? InvalidAttributeClass()); 36 | } 37 | 38 | private static bool IsDescriptionAttribute(INamedTypeSymbol symbol) 39 | { 40 | return MatchesType(type: DescriptionType, symbol: symbol); 41 | } 42 | 43 | private static bool MatchesType(Type type, INamedTypeSymbol symbol) 44 | { 45 | return StringComparer.Ordinal.Equals(x: symbol.Name, y: type.Name) 46 | && StringComparer.Ordinal.Equals(symbol.ContainingNamespace.ToDisplayString(), y: type.Namespace); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation/Extensions/TypeDeclarationSyntaxExtensions.cs: -------------------------------------------------------------------------------- 1 | using Credfeto.Enumeration.Source.Generation.Models; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | 6 | namespace Credfeto.Enumeration.Source.Generation.Extensions; 7 | 8 | public static class TypeDeclarationSyntaxExtensions 9 | { 10 | public static AccessType GetAccessType(this EnumDeclarationSyntax generatorSyntaxContext) 11 | { 12 | return GetAccessType(generatorSyntaxContext.Modifiers); 13 | } 14 | 15 | public static AccessType GetAccessType(this ClassDeclarationSyntax generatorSyntaxContext) 16 | { 17 | return GetAccessType(generatorSyntaxContext.Modifiers); 18 | } 19 | 20 | private static AccessType GetAccessType(in SyntaxTokenList modifiers) 21 | { 22 | bool isPublic = modifiers.Any(SyntaxKind.PublicKeyword); 23 | 24 | if (isPublic) 25 | { 26 | return AccessType.PUBLIC; 27 | } 28 | 29 | bool isPrivate = modifiers.Any(SyntaxKind.PrivateKeyword); 30 | 31 | if (isPrivate) 32 | { 33 | return AccessType.PRIVATE; 34 | } 35 | 36 | bool isInternal = modifiers.Any(SyntaxKind.InternalKeyword); 37 | 38 | bool isProtected = modifiers.Any(SyntaxKind.ProtectedKeyword); 39 | 40 | if (isProtected) 41 | { 42 | return isInternal ? AccessType.PROTECTED_INTERNAL : AccessType.PROTECTED; 43 | } 44 | 45 | return AccessType.INTERNAL; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation/Extensions/TypeInfoExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | 3 | namespace Credfeto.Enumeration.Source.Generation.Extensions; 4 | 5 | public static class TypeInfoExtensions 6 | { 7 | public static bool IsString(in this TypeInfo typeInfo) 8 | { 9 | return typeInfo.Type?.SpecialType == SpecialType.System_String; 10 | } 11 | 12 | public static bool IsEnum(in this TypeInfo typeInfo) 13 | { 14 | return typeInfo.Type is INamedTypeSymbol { EnumUnderlyingType: not null }; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation/Helpers/LiteralString.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using Microsoft.CodeAnalysis; 4 | 5 | namespace Credfeto.Enumeration.Source.Generation.Helpers; 6 | 7 | internal sealed class LiteralString : LocalizableString 8 | { 9 | private readonly string _value; 10 | 11 | public LiteralString(string value) 12 | { 13 | this._value = value; 14 | } 15 | 16 | protected override string GetText(IFormatProvider? formatProvider) 17 | { 18 | return this._value; 19 | } 20 | 21 | [SuppressMessage( 22 | category: "Meziantou.Analyzer", 23 | checkId: "MA0021:Use String Comparer to compute hash codes", 24 | Justification = "Not in net stabdard 2.0" 25 | )] 26 | protected override int GetHash() 27 | { 28 | return this._value.GetHashCode(); 29 | } 30 | 31 | protected override bool AreEqual(object? other) 32 | { 33 | return other is LiteralString otherResourceString 34 | && StringComparer.OrdinalIgnoreCase.Equals(x: this._value, y: otherResourceString._value); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation/Helpers/RuleHelpers.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | 3 | namespace Credfeto.Enumeration.Source.Generation.Helpers; 4 | 5 | internal static class RuleHelpers 6 | { 7 | public static DiagnosticDescriptor CreateRule(string code, string category, string title, string message) 8 | { 9 | LiteralString translatableTitle = new(title); 10 | LiteralString translatableMessage = new(message); 11 | 12 | return new( 13 | id: code, 14 | title: translatableTitle, 15 | messageFormat: translatableMessage, 16 | category: category, 17 | defaultSeverity: DiagnosticSeverity.Error, 18 | isEnabledByDefault: true, 19 | description: translatableMessage 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation/Helpers/SupportedDiagnosticsList.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using Microsoft.CodeAnalysis; 3 | 4 | namespace Credfeto.Enumeration.Source.Generation.Helpers; 5 | 6 | internal static class SupportedDiagnosticsList 7 | { 8 | public static ImmutableArray Build(DiagnosticDescriptor rule) 9 | { 10 | return ImmutableArray.Empty.Add(item: rule); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation/IaHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using Microsoft.CodeAnalysis.Diagnostics; 3 | 4 | namespace Credfeto.Enumeration.Source.Generation; 5 | 6 | public static class IaHelper 7 | { 8 | public static ImmutableArray For(DiagnosticAnalyzer analyzer) 9 | { 10 | return [analyzer]; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation/Models/AccessType.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis.CSharp; 2 | 3 | namespace Credfeto.Enumeration.Source.Generation.Models; 4 | 5 | public enum AccessType 6 | { 7 | PUBLIC = SyntaxKind.PublicKeyword, 8 | PRIVATE = SyntaxKind.PrivateKeyword, 9 | PROTECTED = SyntaxKind.ProtectedKeyword, 10 | PROTECTED_INTERNAL = SyntaxKind.ProtectedKeyword | SyntaxKind.InternalKeyword, 11 | INTERNAL = SyntaxKind.InternalKeyword, 12 | } 13 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation/Models/ClassEnumGeneration.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using Microsoft.CodeAnalysis; 4 | 5 | namespace Credfeto.Enumeration.Source.Generation.Models; 6 | 7 | [DebuggerDisplay("{AccessType} {Namespace}.{Name}")] 8 | public readonly record struct ClassEnumGeneration 9 | { 10 | public ClassEnumGeneration( 11 | AccessType accessType, 12 | string name, 13 | string @namespace, 14 | in IReadOnlyList enums, 15 | Location location 16 | ) 17 | { 18 | this.AccessType = accessType; 19 | this.Name = name; 20 | this.Namespace = @namespace; 21 | this.Enums = enums; 22 | this.Location = location; 23 | } 24 | 25 | public AccessType AccessType { get; } 26 | 27 | public string Name { get; } 28 | 29 | public string Namespace { get; } 30 | 31 | public IReadOnlyList Enums { get; } 32 | 33 | public Location Location { get; } 34 | } 35 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation/Models/EnumGeneration.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using Microsoft.CodeAnalysis; 4 | 5 | namespace Credfeto.Enumeration.Source.Generation.Models; 6 | 7 | [DebuggerDisplay("{AccessType} {Namespace}.{Name}")] 8 | public readonly record struct EnumGeneration 9 | { 10 | public EnumGeneration( 11 | AccessType accessType, 12 | string name, 13 | string @namespace, 14 | IReadOnlyList members, 15 | Location location, 16 | in GenerationOptions options 17 | ) 18 | { 19 | this.AccessType = accessType; 20 | this.Name = name; 21 | this.Namespace = @namespace; 22 | this.Members = members; 23 | this.Location = location; 24 | this.Options = options; 25 | } 26 | 27 | public AccessType AccessType { get; } 28 | 29 | public string Name { get; } 30 | 31 | public string Namespace { get; } 32 | 33 | public IReadOnlyList Members { get; } 34 | 35 | public Location Location { get; } 36 | 37 | public GenerationOptions Options { get; } 38 | } 39 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation/Models/ErrorInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using Microsoft.CodeAnalysis; 4 | 5 | namespace Credfeto.Enumeration.Source.Generation.Models; 6 | 7 | [DebuggerDisplay("{Location} {Exception}")] 8 | public readonly record struct ErrorInfo 9 | { 10 | public ErrorInfo(Location location, Exception exception) 11 | { 12 | this.Location = location; 13 | this.Exception = exception; 14 | } 15 | 16 | public Location Location { get; } 17 | 18 | public Exception Exception { get; } 19 | } 20 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation/Models/GenerationOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace Credfeto.Enumeration.Source.Generation.Models; 5 | 6 | [StructLayout(LayoutKind.Auto)] 7 | [DebuggerDisplay("DoesNotReturn: {HasDoesNotReturnAttribute}, UnreachableException: {SupportsUnreachableException}")] 8 | public readonly record struct GenerationOptions 9 | { 10 | public GenerationOptions(bool hasDoesNotReturnAttribute, bool supportsUnreachableException) 11 | { 12 | this.HasDoesNotReturnAttribute = hasDoesNotReturnAttribute; 13 | this.SupportsUnreachableException = supportsUnreachableException; 14 | } 15 | 16 | public bool HasDoesNotReturnAttribute { get; } 17 | 18 | public bool SupportsUnreachableException { get; } 19 | } 20 | -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation/tools/install.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | Write-Information "Installing $package to $installPath" 4 | 5 | if($project.Object.SupportsPackageDependencyResolution) 6 | { 7 | if($project.Object.SupportsPackageDependencyResolution()) 8 | { 9 | # Do not install analyzers via install.ps1, instead let the project system handle it. 10 | return 11 | } 12 | } 13 | 14 | $analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve 15 | 16 | foreach($analyzersPath in $analyzersPaths) 17 | { 18 | if (Test-Path $analyzersPath) 19 | { 20 | # Install the language agnostic analyzers. 21 | foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll) 22 | { 23 | if($project.Object.AnalyzerReferences) 24 | { 25 | $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) 26 | } 27 | } 28 | } 29 | } 30 | 31 | # $project.Type gives the language name like (C# or VB.NET) 32 | $languageFolder = "" 33 | if($project.Type -eq "C#") 34 | { 35 | $languageFolder = "cs" 36 | } 37 | if($project.Type -eq "VB.NET") 38 | { 39 | $languageFolder = "vb" 40 | } 41 | if($languageFolder -eq "") 42 | { 43 | return 44 | } 45 | 46 | foreach($analyzersPath in $analyzersPaths) 47 | { 48 | # Install language specific analyzers. 49 | $languageAnalyzersPath = join-path $analyzersPath $languageFolder 50 | if (Test-Path $languageAnalyzersPath) 51 | { 52 | foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll) 53 | { 54 | if($project.Object.AnalyzerReferences) 55 | { 56 | $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) 57 | } 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /src/Credfeto.Enumeration.Source.Generation/tools/uninstall.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | Write-Information "Removing $package from $installPath" 4 | 5 | if($project.Object.SupportsPackageDependencyResolution) 6 | { 7 | if($project.Object.SupportsPackageDependencyResolution()) 8 | { 9 | # Do not uninstall analyzers via uninstall.ps1, instead let the project system handle it. 10 | return 11 | } 12 | } 13 | 14 | $analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve 15 | 16 | foreach($analyzersPath in $analyzersPaths) 17 | { 18 | # Uninstall the language agnostic analyzers. 19 | if (Test-Path $analyzersPath) 20 | { 21 | foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll) 22 | { 23 | if($project.Object.AnalyzerReferences) 24 | { 25 | $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) 26 | } 27 | } 28 | } 29 | } 30 | 31 | # $project.Type gives the language name like (C# or VB.NET) 32 | $languageFolder = "" 33 | if($project.Type -eq "C#") 34 | { 35 | $languageFolder = "cs" 36 | } 37 | if($project.Type -eq "VB.NET") 38 | { 39 | $languageFolder = "vb" 40 | } 41 | if($languageFolder -eq "") 42 | { 43 | return 44 | } 45 | 46 | foreach($analyzersPath in $analyzersPaths) 47 | { 48 | # Uninstall language specific analyzers. 49 | $languageAnalyzersPath = join-path $analyzersPath $languageFolder 50 | if (Test-Path $languageAnalyzersPath) 51 | { 52 | foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll) 53 | { 54 | if($project.Object.AnalyzerReferences) 55 | { 56 | try 57 | { 58 | $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) 59 | } 60 | catch 61 | { 62 | Write-Warning "Failed to remove $package" 63 | } 64 | } 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | $(SolutionDir)\..\results\$(MSBuildProjectName).sarif,version=2.1 7 | 8 | 9 | 10 | 11 | true 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/KeepGeneratedFiles.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | Generated 7 | 8 | 9 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/SourceGenerator.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | $(GetTargetPathDependsOn);GetDependencyTargetPaths 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "9.0.300", 4 | "allowPrerelease": false, 5 | "rollForward": "latestPatch" 6 | } 7 | } 8 | --------------------------------------------------------------------------------