{"id":17710534,"url":"https://github.com/tragiccode/csharp-library-template","last_synced_at":"2026-03-19T01:50:50.995Z","repository":{"id":43442960,"uuid":"383250756","full_name":"TraGicCode/csharp-library-template","owner":"TraGicCode","description":null,"archived":false,"fork":false,"pushed_at":"2023-03-27T05:06:29.000Z","size":39,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-31T09:12:12.727Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TraGicCode.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-05T19:56:08.000Z","updated_at":"2022-02-04T22:24:36.000Z","dependencies_parsed_at":"2024-10-31T00:47:26.502Z","dependency_job_id":null,"html_url":"https://github.com/TraGicCode/csharp-library-template","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/TraGicCode/csharp-library-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TraGicCode%2Fcsharp-library-template","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TraGicCode%2Fcsharp-library-template/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TraGicCode%2Fcsharp-library-template/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TraGicCode%2Fcsharp-library-template/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TraGicCode","download_url":"https://codeload.github.com/TraGicCode/csharp-library-template/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TraGicCode%2Fcsharp-library-template/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28304263,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-11T11:18:18.743Z","status":"ssl_error","status_checked_at":"2026-01-11T11:07:56.842Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-25T07:06:34.019Z","updated_at":"2026-01-11T13:02:04.210Z","avatar_url":"https://github.com/TraGicCode.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Summary\n\nTemplates to help provide consistency and reduce overhead required for creating and maintaining my open-source csharp projects.\n\n## Installing modulesync\n\n### windows\n\n```\nchoco install ruby -y\nchoco install msys2 -y\nUpdate-SessionEnvironment\nridk install 2 3\ngem install modulesync\nmsync --help\n```\n\n# Creating a new github repository\n\n1. Navigate to the directory in which you want the git repo to be cloned into\n1. Create github repository with basic readme ( NOTE: at least 1 file must exist within the github repository )\n\n```\n\u003e cd C:\\Source\\tragiccode\\\n\u003e gh repo create NServiceBus.CustomChecks.SqlServer --gitignore VisualStudio --public -y\n\u003e cd C:\\Source\\tragiccode\\csharp-library-template\n```\n1. Update `managed_modules.yml` with the name of the new gitub repository\n1. Update the :global: section of the `config_defaults.yml` to contain the new github repository and appropriate library_type ( as of now only nservicebus-custom-check exists )\n1. The first time you run modulesync you will probably want to add a .sync.yml to provide customizations/additions specific to the new github repository (Ex: nuget package tags ).  Follow the workflow\n   below for adding a .sync.yml and changing/adding values to it.\n\n\n# Workflow for adding .sync.yml and/or adding values to it\n\n1. Get the projects to get cloned and sync to run\n  - msync update --noop\n1. Add and/or update .sync.yml with new changes\n1. Run msync offline to prevent loosing changes\n  - msync update --offline\n1. verify results\n1. run ./scripts/commit-and-push-sync-file-changes.ps1\n  a. Loop through each module and make a commit to the modulesync branch ( which msync is already switched to ) to indicate you updated/added the file manually\n  b. Now run msync to push the branch and changes and create the pr \n    - msync update --pr\n\n## Example Use Cases\n\n\n## Prevent msync from trying to change/update a file\n\nSometimes you might not want msync to manage a file or set of files at all.  In this case, you can simply inform msync the file should be `unmanaged`\n\nCommon Examples of when you would do this:\n- If you have a file that has to many deviations from the current templates and you would like to no longer manage it simply add the following to the repo's .sync.yml.\n- If you want to utilize msync for initial creationg of github files but after the initial sync never change and be allowed to deviate to reduce github repo setup overhead\n\n.sync.yml\n```\n---\nappveyor.yml:\n    unmanaged: true\n```\n\n\n## Remove/Delete a file that isn't applicable\n\nIf a file is not applicable for your library then you can update the .sync.yml to ensure the file will be deleted and not be commited as part of the repository.\n\n.sync.yml\n```\n---\nappveyor.yml\n    delete: true\n```\n\n## Adding module specific items to .gitignore\n\nSometimes you want to provide a customization point for modules to apply any \"extra\" stuff they might need to a file.  The below is a great example of how to do this.\n\n.sync.yml\n```\n.gitignore:\n  paths:\n    - .puppet-lint.rc\n```\n\n.gitignore\n\n```\n# Managed by modulesync - DO NOT EDIT\n# https://voxpupuli.org/docs/updating-files-managed-with-modulesync/\n\npkg/\nGemfile.lock\nGemfile.local\nvendor/\n.vendor/\nspec/fixtures/manifests/\nspec/fixtures/modules/\n.vagrant/\n.bundle/\n.ruby-version\ncoverage/\nlog/\n.idea/\n.dependencies/\n.librarian/\nPuppetfile.lock\n*.iml\n.*.sw?\n.yardoc/\nGuardfile\n\u003c% if ! @configs['paths'].nil? -%\u003e\n\u003c% @configs['paths'].each do |path| -%\u003e\n\u003c%= path %\u003e\n\u003c% end -%\u003e\n\u003c% end -%\u003e\n```\n\nHere is another example of where there is no sane default that can be applied but the code is written in a way that it wont blow up\n\n```\n\u003c%- (@configs['environment'] || []).each do |key, value| -%\u003e\n  \u003c%= key %\u003e: \u003c%= value %\u003e\n\u003c%- end -%\u003e\n```\n\n\n# Configuration that is has no default, but is optional and is defined in the modules .sync.yml\n\nhttps://github.com/puppetlabs/pdk-templates/blob/main/moduleroot/spec/default_facts.yml.erb\nShows how to have something optional that has no sane default in default_config.yml\n\n## Explicitly excluding certain defaults\n\nBelow shows an example on how to utilize defaults, add .sync.yml extras, AND exclude certain defaults is the module needs to.\n\n```\n\u003c%- (((@configs['matrix']) + (@configs['matrix_extras'] || [])) - (@configs['remove_includes'] || [])).each do |matrix| -%\u003e\n```\n\n## Combining default configurations + .sync.yml configurations\n\nSometimes you want to have some defaults that might change in the future along with customizations from a module.  Below is an example on how to merge the configurations together\n\n\n.sync.yml\n```\n---\nGemfile:\n  optional:\n    ':test':\n      - gem: puppet-lint-param-docs\n```\n\nconfig_defaults.yml\n```\nGemfile:\n  puppet_version: '\u003e= 6.0'\n  required:\n    ':test':\n      - gem: voxpupuli-test\n        version: '~\u003e 2.1'\n      - gem: coveralls\n      - gem: simplecov-console\n    ':development':\n      - gem: guard-rake\n      - gem: overcommit\n        version: '\u003e= 0.39.1'\n    ':system_tests':\n      - gem: puppet_metadata\n        version: '~\u003e 0.3.0'\n      - gem: voxpupuli-acceptance\n    ':release':\n      - gem: github_changelog_generator\n        version: '\u003e= 1.16.1'\n      - gem: puppet-blacksmith\n      - gem: voxpupuli-release\n      - gem: puppet-strings\n        version: '\u003e= 2.2'\n```\n\n```\nsource ENV['GEM_SOURCE'] || \"https://rubygems.org\"\n\n\u003c% groups = {} -%\u003e\n\u003c% (@configs['required'].keys + ((@configs['optional'] || {}).keys)).uniq.each do |key| -%\u003e\n\u003c%   groups[key] = (@configs['required'][key] || []) + ((@configs['optional'] || {})[key] || []) -%\u003e\n\u003c% end -%\u003e\n\u003c% -%\u003e\n\u003c% groups.each do |group, gems| -%\u003e\ngroup \u003c%= group %\u003e do\n\u003c% maxlen = gems.map! do |gem| -%\u003e\n\u003c%            gem['platforms'].map!{|a| a.to_sym} unless gem['platforms'].nil? -%\u003e\n\u003c%            { -%\u003e\n\u003c%              'gem'           =\u003e gem['gem'], -%\u003e\n\u003c%              'version'       =\u003e gem['version'], -%\u003e\n\u003c%              'platforms'     =\u003e gem['platforms'], -%\u003e\n\u003c%              'require'       =\u003e gem['require'], -%\u003e\n\u003c%              'git'           =\u003e gem['git'], -%\u003e\n\u003c%              'branch'        =\u003e gem['branch'], -%\u003e\n\u003c%              'ruby-version'  =\u003e gem['ruby-version'], -%\u003e\n\u003c%              'ruby-operator' =\u003e gem['ruby-operator'], -%\u003e\n\u003c%              'length'        =\u003e gem['gem'].length + ((\"', '\".length if gem['version']) || 0) + gem['version'].to_s.length -%\u003e\n\u003c%            } -%\u003e\n\u003c%          end.map do |gem| -%\u003e\n\u003c%            gem['length'] -%\u003e\n\u003c%          end.max -%\u003e\n\u003c% gems.each do |gem| -%\u003e\n  gem '\u003c%= gem['gem'] %\u003e'\u003c%= \", '#{gem['version']}'\" if gem['version'] %\u003e, \u003c%= ' ' * (maxlen - gem['length']) %\u003e :require =\u003e false\u003c%= \", :git =\u003e '#{gem['git']}'\" if gem['git'] %\u003e\u003c%= \", :branch =\u003e '#{gem['branch']}'\" if gem['branch'] %\u003e\u003c%= \", :platforms =\u003e #{gem['platforms']}\" if gem['platforms'] %\u003e\u003c%= \" if RUBY_VERSION #{gem['ruby-operator']} '#{gem['ruby-version']}'\" if (gem['ruby-operator'] \u0026\u0026 gem['ruby-version']) %\u003e\n\u003c% end -%\u003e\nend\n\u003c% end -%\u003e\ngem 'puppetlabs_spec_helper', '\u003e= 2', '\u003c 4', :require =\u003e false\ngem 'rake', :require =\u003e false\ngem 'facter', ENV['FACTER_GEM_VERSION'], :require =\u003e false, :groups =\u003e [:test]\n\npuppetversion = ENV['PUPPET_VERSION'] || '\u003c%= @configs['puppet_version'] %\u003e'\ngem 'puppet', puppetversion, :require =\u003e false, :groups =\u003e [:test]\n```\n\n\n## Adding a here doc string\n\nBelow shows an example of adding a multi-line string to a template using here doc style strings\n\n```\nGemfile:\n  optional:\n    ':acceptance':\n      - gem: beaker\n      - gem: beaker-rspec\n      - gem: beaker-puppet_install_helper\n      - gem: beaker-module_install_helper\n      - gem: vagrant-wrapper\nspec/spec_helper.rb:\n  spec_overrides: |-\n    # Add coverage report.\n    RSpec.configure do |c|\n      c.after(:suite) do\n        RSpec::Puppet::Coverage.report!\n      end\n    end\n```\n\n# Add helper function as top of function\n\nTo help keep the template clean, you can create a helper function at the top of t he file like so. \n```\n\u003c%\ndef requires(item)\n  if item.is_a? String\n    line = \"require '#{item}'\"\n  elsif item.is_a? Hash\n    line = \"require '#{item['require']}'\" unless item['require'].nil?\n    line = \"#{line} if #{item['conditional']}\" unless item['require'].nil? and item['conditional'].nil?\n  end\n  line\nend\n-%\u003e\n```\n\n\nTODO: Investigate extracting this to a file and being able to `require` it into the template that needs to use it\n\n\n# Add content based on if certain directories/files exist in the repository\n\n```\n\u003c%- if Dir[File.join(@metadata[:workdir], 'spec', 'acceptance', '**', '*_spec.rb')].any? -%\u003e\n\n  acceptance:\n    needs: setup_matrix\n    runs-on: ubuntu-latest\n    env:\n      BUNDLE_WITHOUT: development:test:release\n    strategy:\n      fail-fast: false\n      matrix:\n        setfile: ${{fromJson(needs.setup_matrix.outputs.beaker_setfiles)}}\n        puppet: ${{fromJson(needs.setup_matrix.outputs.puppet_major_versions)}}\n        \u003c%- @configs['beaker_fact_matrix'].each do |option, values| -%\u003e\n        \u003c%= option %\u003e:\n        \u003c%- values.each do |value| -%\u003e\n          - \"\u003c%= value %\u003e\"\n        \u003c%- end -%\u003e\n        \u003c%- end -%\u003e\n        \u003c%- if @configs['excludes'].any? -%\u003e\n        exclude:\n        \u003c%- @configs['excludes'].each do |exclude| -%\u003e\n        \u003c%- exclude.each do |key, value| -%\u003e\n          \u003c%= key == exclude.first.first ? '-' : ' ' %\u003e \u003c%= key %\u003e: \"\u003c%= value %\u003e\"\n        \u003c%- end -%\u003e\n        \u003c%- end -%\u003e\n        \u003c%- end -%\u003e\n    \u003c%-\n      name = ['${{ matrix.puppet.name }}', '${{ matrix.setfile.name }}']\n      @configs['beaker_fact_matrix'].each_key do |option|\n        name \u003c\u003c \"#{option.tr('_', ' ').capitalize} ${{ matrix.#{option} }}\"\n      end\n    -%\u003e\n    name: \u003c%= name.join(' - ') %\u003e\n    steps:\n      - uses: actions/checkout@v2\n      - name: Setup ruby\n        uses: ruby/setup-ruby@v1\n        with:\n          ruby-version: '3.0'\n          bundler-cache: true\n      - name: Run tests\n        run: bundle exec rake beaker\n        env:\n          BEAKER_PUPPET_COLLECTION: ${{ matrix.puppet.collection }}\n          BEAKER_setfile: ${{ matrix.setfile.value }}\n          \u003c%- @configs['beaker_fact_matrix'].keys.each do |fact| -%\u003e\n          BEAKER_FACTER_\u003c%= fact.upcase %\u003e: ${{ matrix.\u003c%= fact %\u003e }}\n          \u003c%- end -%\u003e\n\u003c%- end -%\u003e\n```\n\n\n## Important Notes\n\n- Templates MUST have a .erb extension. \n- Static files ( that are not templates ) also must have a .erb extension or they wont get moved to your target github repos.\n- Default configuration values for files live in `config_defaults.yml`\n- To Override or extend values in `config_defaults.yml` simply add a `.sync.yml` at the root of your module repo\n    - To override simply use the same config but ovewrite the value\n    - to extend you could, for example, have a set of \"required\" gems that are added to all Gemfiles, and a set of \"optional\" gems that a single module might add.\n    - you can also add more complicated ruby that like ensures arrays from both files are unique when it combines them or alows you to exclude certain items from the      config_defaults.yml array.\n- I think Arrays and hashes get merged together\n    - if a key conflicts it's overwritten\n    - single vlaues overwrite as well\n    - hashes with different keys get merged\n    - arrays get merged\n- Values are accessed with the @configs hash\n- `:globals` allows you to define defaults that are accessed from every file ( Maybe something like library_type )\n\n\nDocumentation from puppetlabs on how to use modulesync\nhttps://github.com/puppetlabs/modulesync_configs\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftragiccode%2Fcsharp-library-template","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftragiccode%2Fcsharp-library-template","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftragiccode%2Fcsharp-library-template/lists"}