commit f3b18dc54a8b466be5dd6087a1b84ddea0ee7e3a Author: D. Moonfire Date: Mon Sep 5 16:41:27 2022 -0500 feat: initial commit diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 0000000..7720a5a --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,18 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "gitversion.tool": { + "version": "5.9.0", + "commands": [ + "dotnet-gitversion" + ] + }, + "dotnet-reportgenerator-globaltool": { + "version": "5.1.3", + "commands": [ + "reportgenerator" + ] + } + } +} \ No newline at end of file diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..819c8e1 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,122 @@ +# EditorConfig is awesome: https://EditorConfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 + +# Microsoft .NET properties +csharp_new_line_before_members_in_object_initializers = false +csharp_preferred_modifier_order = public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion +csharp_space_after_cast = false +csharp_style_var_elsewhere = false:hint +csharp_style_var_for_built_in_types = false:hint +csharp_style_var_when_type_is_apparent = true:hint +csharp_preserve_single_line_statements = false +csharp_preserve_single_line_blocks = true +dotnet_style_predefined_type_for_locals_parameters_members = true:hint +dotnet_style_predefined_type_for_member_access = true:hint +dotnet_style_qualification_for_event = true:hint +dotnet_style_qualification_for_field = true:hint +dotnet_style_qualification_for_method = true:hint +dotnet_style_qualification_for_property = true:hint +dotnet_style_require_accessibility_modifiers = for_non_interface_members:hint + +# ReSharper properties +resharper_alignment_tab_fill_style = optimal_fill +resharper_apply_on_completion = true +resharper_blank_lines_after_control_transfer_statements = 1 +resharper_blank_lines_around_single_line_auto_property = 1 +resharper_blank_lines_around_single_line_property = 1 +resharper_blank_lines_before_single_line_comment = 1 +resharper_blank_lines_between_using_groups = 1 +resharper_braces_for_for = required +resharper_braces_for_foreach = required +resharper_braces_for_ifelse = required +resharper_braces_for_while = required +resharper_can_use_global_alias = false +resharper_csharp_blank_lines_around_single_line_field = 1 +resharper_csharp_blank_lines_around_single_line_invocable = 1 +resharper_csharp_indent_style = tab +resharper_csharp_insert_final_newline = true +resharper_csharp_keep_blank_lines_in_code = 1 +resharper_csharp_keep_blank_lines_in_declarations = 1 +resharper_csharp_new_line_before_while = true +resharper_csharp_use_indent_from_vs = false +resharper_csharp_wrap_arguments_style = chop_if_long +resharper_csharp_wrap_extends_list_style = chop_if_long +resharper_csharp_wrap_parameters_style = chop_if_long +resharper_css_insert_final_newline = false +resharper_enforce_line_ending_style = true +resharper_html_insert_final_newline = false +resharper_indent_nested_fixed_stmt = true +resharper_js_indent_style = tab +resharper_js_insert_final_newline = true +resharper_js_keep_blank_lines_in_code = 1 +resharper_js_stick_comment = false +resharper_js_use_indent_from_vs = false +resharper_js_wrap_before_binary_opsign = true +resharper_js_wrap_chained_method_calls = chop_if_long +resharper_keep_blank_lines_between_declarations = 1 +resharper_min_blank_lines_after_imports = 1 +resharper_place_attribute_on_same_line = False +resharper_place_constructor_initializer_on_same_line = false +resharper_place_type_constraints_on_same_line = false +resharper_protobuf_insert_final_newline = false +resharper_qualified_using_at_nested_scope = true +resharper_resx_insert_final_newline = false +resharper_space_within_single_line_array_initializer_braces = true +resharper_use_indents_from_main_language_in_file = false +resharper_vb_insert_final_newline = false +resharper_wrap_after_declaration_lpar = true +resharper_wrap_after_invocation_lpar = true +resharper_wrap_before_extends_colon = true +resharper_wrap_before_first_type_parameter_constraint = true +resharper_wrap_before_type_parameter_langle = true +resharper_xmldoc_indent_child_elements = ZeroIndent +resharper_xmldoc_indent_text = ZeroIndent +resharper_xmldoc_insert_final_newline = false +resharper_xml_insert_final_newline = false + +# ReSharper inspection severities +resharper_check_namespace_highlighting = none +resharper_convert_to_auto_property_highlighting = none +resharper_localizable_element_highlighting = none +resharper_redundant_comma_in_attribute_list_highlighting = none +resharper_redundant_comma_in_enum_declaration_highlighting = none +resharper_redundant_comma_in_initializer_highlighting = none +resharper_string_compare_to_is_culture_specific_highlighting = none +resharper_string_index_of_is_culture_specific_1_highlighting = none +resharper_use_null_propagation_highlighting = none +resharper_use_object_or_collection_initializer_highlighting = hint +resharper_use_string_interpolation_highlighting = hint + +# Matches the exact files either package.json or .travis.yml +[{package.json,.travis.yml}] +indent_style = space +indent_size = 2 +tab_width = 2 + +[*.{cs,js,json,jsx,proto,resjson,ts,tsx}] +indent_style = space +indent_size = 4 +tab_width = 4 + +[*.{asax,ascx,aspx,cshtml,css,htm,html,master,razor,skin,vb,xaml,xamlx,xoml}] +indent_style = space +indent_size = 4 +tab_width = 4 + +[*.{appxmanifest,build,config,csproj,dbml,discomap,dtd,jsproj,lsproj,njsproj,nuspec,proj,props,resw,resx,StyleCop,targets,tasks,vbproj,xml,xsd}] +indent_style = space +indent_size = 2 +tab_width = 2 + +[*.proto] +indent_style = space +indent_size = 2 +tab_width = 2 diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..5816063 --- /dev/null +++ b/.envrc @@ -0,0 +1,2 @@ +export PATH=$PWD/scripts:$PATH +use flake || use nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..53987a3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +launchSettings.json + +*~ +*.user +Directory.Build.props + +obj/ +[Bb]in/ +.vs/ +.vscode/ +.idea/ +_ReSharper.Caches/ +node_modules/ + +# NixOS +.direnv/ + +# Tests and Coverage +coverage +TestResults/ +tests/artifacts/ + +# Lefthook +.lefthook-local/ +lefthook-local.yml diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..f1a0e24 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,8 @@ +*~ +flake.* + +node_modules/ +.direnv/ +.config/ +obj/ +bin/ diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100644 index 0000000..3f25d63 --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1,36 @@ +clone: + git: + image: woodpeckerci/plugin-git + settings: + tags: true + +pipeline: + build: + image: registry.gitlab.com/dmoonfire/nix-flake-docker:latest + commands: + - nix develop --command scripts/build.sh + when: + event: [push, pull_request, tag] + tag: v* + + test: + image: registry.gitlab.com/dmoonfire/nix-flake-docker:latest + commands: + - nix develop --command scripts/test.sh + when: + event: [push, pull_request] + #paths: + # - ./**/*test-result.xml + # - ./coverage/Cobertura.xml + # - ./coverage/Summary.* + # - ./**/*.nupkg + + release-main: + image: registry.gitlab.com/dmoonfire/nix-flake-docker:latest + commands: + - nix develop --command scripts/release.sh + secrets: + - gitea_token + when: + event: push + branch: main diff --git a/CODE-OF-CONDUCT.md b/CODE-OF-CONDUCT.md new file mode 100644 index 0000000..5aa66ee --- /dev/null +++ b/CODE-OF-CONDUCT.md @@ -0,0 +1,132 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +- Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or advances of + any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, + without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +[INSERT CONTACT METHOD]. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][mozilla coc]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][faq]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[mozilla coc]: https://github.com/mozilla/diversity +[faq]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..02b160f --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Moonfire Games + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 0000000..ff47af7 --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..b67b61d --- /dev/null +++ b/flake.lock @@ -0,0 +1,42 @@ +{ + "nodes": { + "flake-utils": { + "locked": { + "lastModified": 1659877975, + "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1662019588, + "narHash": "sha256-oPEjHKGGVbBXqwwL+UjsveJzghWiWV0n9ogo1X6l4cw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "2da64a81275b68fdad38af669afeda43d401e94b", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-unstable", + "type": "indirect" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..3de25d3 --- /dev/null +++ b/flake.nix @@ -0,0 +1,24 @@ +{ + description = "A .NET core library for easily building CLI tools"; + + inputs = { + nixpkgs.url = "nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let pkgs = nixpkgs.legacyPackages.${system}; + in { + devShell = pkgs.mkShell { + buildInputs = [ + pkgs.dotnet-sdk + pkgs.lefthook + pkgs.convco + pkgs.nodePackages.prettier + pkgs.nixfmt + pkgs.jq + ]; + }; + }); +} diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 0000000..43a0f2b --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,22 @@ +pre-commit: + parallel: true + commands: + dotnet-format: + glob: "*.cs" + run: dotnet format + prettier: + run: prettier . --write --loglevel warn + nixfmt: + run: nixfmt flake.nix + +commit-msg: + commands: + commit-check: + run: convco check -n 1 + +skip_output: + - meta # Skips lefthook version printing + - summary # Skips summary block (successful and failed steps) printing + - success # Skips successful steps printing + - failure # Skips failed steps printing + - execution # Skips printing successfully executed commands and their output (but still prints failed executions) diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..f357938 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,23 @@ +# Scripts Directory + +This directory contains the basic scripts for working with the library. + +## `setup.sh` + +This verifies the environment is correct and makes sure everything is configured. + +## `build.sh` + +This builds the project and creates the binaries in debug mode. + +## `test.sh` + +This runs any required tests. + +## `format.sh` + +This is used to format the code base using our standards. It matches the commands in the `lefthook` pre-commit hook. + +## `release.sh` + +Intended to run in a CI environment, this creates a NuGet package and publishes it. diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..66f32c5 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env sh + +cd $(dirname $0)/.. +./scripts/setup.sh || exit 1 + +echo "$(basename $0): building project" +dotnet build diff --git a/scripts/format.sh b/scripts/format.sh new file mode 100755 index 0000000..7b31af0 --- /dev/null +++ b/scripts/format.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env sh + +cd $(dirname $0)/.. +lefthook run pre-commit diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 0000000..6e27208 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env sh + +cd $(dirname $0)/.. +./scripts/setup.sh || exit 1 + +# Verify the input. +if [ "x$GITEA_TOKEN" = "x" ] +then + echo "the environment variable GITEA_TOKEN is not defined" + exit 1 +fi + +# Clean up everything from the previous runs. +echo "$(basename $0): cleaning project" +dotnet clean + +# Version the file based on the Git repository. +echo "$(basename $0): setting project version" +(cd src && dotnet dotnet-gitversion /updateprojectfiles) +SEMVER="v$(dotnet gitversion /output json | jq -r .SemVer)" + +if [ "x$SEMVER" = "x" ] +then + echo "$(basename $0): cannot figure out the semantic version" + exit 1 +fi + +# Build to pick up the new version. +echo "$(basename $0): building project $SEMVER" +dotnet build || exit 1 + +# Create and publish the NuGet packages. +echo "$(basename $0): registering NuGet source" +dotnet nuget add source --name mfgames --username dmoonfire --password $GITEA_TOKEN https://src.mfgames.com/api/packages/mfgames-cil/nuget/index.json --store-password-in-clear-text || exit 1 + +echo "$(basename $0): publishing NuGet package" +dotnet pack --include-symbols --include-source || exit 1 +dotnet nuget push --source mfgames src/*/bin/Debug/*.nupkg || exit 1 + +# Tag and push, but only if we don't have a tag. +if ! git tag | grep $SEMVER >& /dev/null +then + echo "$(basename $0): tagging and pushing" + git tag $SEMVER + git push origin $SEMVER +else + echo "$(basename $0): not tagging, already exists" +fi diff --git a/scripts/setup.sh b/scripts/setup.sh new file mode 100755 index 0000000..3ee77ae --- /dev/null +++ b/scripts/setup.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env sh + +# Normalize our environment. +cd $(dirname $0)/.. + +# Make sure we have the needed executables installed. +for e in dotnet lefthook prettier nixfmt +do + if ! which $e >& /dev/null + then + echo "Cannot find '$e' in the path" + exit 1 + fi +done + +# Make sure we have lefthook is installed. +if [ ! -f .git/hooks/pre-commit ] +then + echo "$(basename $0): installing lefthook" + lefthook install +fi + +# Make sure our tools are installed. +echo "$(basename $0): install .NET tools" +dotnet tool restore + +# Everything is good. +exit 0 diff --git a/scripts/test.sh b/scripts/test.sh new file mode 100755 index 0000000..bb106ee --- /dev/null +++ b/scripts/test.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env sh + +cd $(dirname $0)/.. +./scripts/setup.sh || exit 1 + +dotnet test --test-adapter-path:. --logger:"junit;LogFilePath=../artifacts/{assembly}-test-result.xml;MethodFormat=Default;FailureBodyFormat=Verbose" --collect:"XPlat Code Coverage" +dotnet tool run reportgenerator -reports:tests/*/TestResults/*/coverage.cobertura.xml -targetdir:./coverage "-reporttypes:Cobertura;TextSummary" +grep "Line coverage" coverage/Summary.txt diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000..cbaf845 --- /dev/null +++ b/src/README.md @@ -0,0 +1 @@ +# Source Directories diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..6756246 --- /dev/null +++ b/tests/README.md @@ -0,0 +1 @@ +# Test Projects