diff --git a/.gitattributes b/.gitattributes index 462913965..9a5d6f371 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ # Normalize line endings. -* text=lf +* text=auto eol=lf diff --git a/.github/workflows/deploy-package.yml b/.github/workflows/deploy-package.yml index e8bcf4d7d..0a754c26d 100644 --- a/.github/workflows/deploy-package.yml +++ b/.github/workflows/deploy-package.yml @@ -7,15 +7,20 @@ on: description: Deployment environment type: choice options: - - staging + - pkg.github.com - nuget.org - default: staging + default: pkg.github.com required: true preview: description: Append preview suffix type: boolean default: true required: true + dry_run: + description: 'Dry-run only (no deploy)' + type: boolean + default: true + required: true concurrency: group: ${{ inputs.environment }} @@ -25,7 +30,9 @@ jobs: build: runs-on: ubuntu-latest outputs: - version: ${{ steps.compose.outputs.version }} + version: ${{ steps.version_info.outputs.version }} + pkg_url: ${{ steps.package_info.outputs.pkg_url }} + pkg_name: ${{ steps.package_info.outputs.pkg_name }} steps: @@ -34,12 +41,21 @@ jobs: with: fetch-depth: 0 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: "9.x" + dotnet-quality: "ga" + - name: Setup GitVersion uses: gittools/actions/gitversion/setup@v1.2.0 with: versionSpec: "5.x" preferLatestVersion: true + - name: Install dependencies + run: sudo apt-get update && sudo apt-get install -y libxml2-utils + - name: Determine version id: gitversion uses: gittools/actions/gitversion/execute@v1.2.0 @@ -49,29 +65,38 @@ jobs: configFilePath: src/gitversion.yml - name: Compose version - id: compose + id: version_info run: | - ver=${{ steps.gitversion.outputs.majorMinorPatch }}${{ inputs.preview && '-preview.' || '' }}${{ inputs.preview && steps.gitversion.outputs.preReleaseNumber || inputs.preview && github.run_number || '' }} - echo "version=$ver" >> "$GITHUB_OUTPUT" + # get base version + base="${{ steps.gitversion.outputs.majorMinorPatch }}" - - name: Update release notes URL - uses: jacobtomlinson/gha-find-replace@v3 - with: - find: "https://github.com/DaveSkender/Stock.Indicators/releases" - replace: "https://github.com/DaveSkender/Stock.Indicators/releases/tag/${{ steps.compose.outputs.version }}" - regex: false + # determine preview suffix + preview_tag="${{ inputs.preview && '-preview.' || '' }}" - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: "9.x" - dotnet-quality: "ga" + # determine preview number + preview_num="${{ inputs.preview && steps.gitversion.outputs.preReleaseNumber || '' }}" + + # combine all parts + ver="${base}${preview_tag}${preview_num}" + + echo "version=$ver" >> "$GITHUB_OUTPUT" + + - name: Compose package info + id: package_info + run: | + PACKAGE_NAME=$(xmllint --xpath "//PropertyGroup/PackageId/text()" src/Indicators.csproj) + echo "pkg_name=${PACKAGE_NAME}" >> $GITHUB_OUTPUT + if [[ "${{ inputs.environment }}" == "nuget.org" ]]; then + echo "pkg_url=https://www.nuget.org/packages/${PACKAGE_NAME}/${{ steps.version_info.outputs.version }}" >> $GITHUB_OUTPUT + else + echo "pkg_url=https://github.com/${{ github.repository }}/pkgs/nuget/${PACKAGE_NAME}" >> $GITHUB_OUTPUT + fi - name: Build library run: > dotnet build src/Indicators.csproj --configuration Release - --property:Version=${{ steps.compose.outputs.version }} + --property:Version=${{ steps.version_info.outputs.version }} --property:ContinuousIntegrationBuild=true -warnAsError @@ -82,7 +107,7 @@ jobs: --no-build --include-symbols --output NuGet - -p:PackageVersion=${{ steps.compose.outputs.version }} + -p:PackageVersion=${{ steps.version_info.outputs.version }} - name: Save package uses: actions/upload-artifact@v4 @@ -100,74 +125,78 @@ jobs: echo "| Minor | ${{ steps.gitversion.outputs.minor }} |" echo "| Patch | ${{ steps.gitversion.outputs.patch }} |" echo "| Base | ${{ steps.gitversion.outputs.majorMinorPatch }} |" - echo "| Composed | ${{ steps.compose.outputs.version }} |" + echo "| Composed | ${{ steps.version_info.outputs.version }} |" } >> $GITHUB_STEP_SUMMARY deploy: needs: build runs-on: ubuntu-latest + if: success() permissions: contents: write packages: write environment: - name: ${{ inputs.environment }} - url: "${{ vars.NUGET_DOWNLOAD_PREFIX }}${{ needs.build.outputs.version }}" + name: ${{ !inputs.dry_run && inputs.environment || '' }} + url: ${{ needs.build.outputs.pkg_url }} steps: - - name: Pre-flight summary - run: | - { - echo "| Parameter | Value |" - echo "| :-------------- | :--------------------------------- |" - echo "| Environment | ${{ inputs.environment }} |" - echo "| Publishing URL | ${{ vars.NUGET_PUBLISH_URL }} |" - echo "| Download URL | ${{ vars.NUGET_DOWNLOAD_PREFIX }} |" - echo "| Version ID | ${{ needs.build.outputs.version }} |" - } >> $GITHUB_STEP_SUMMARY - - name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: "9.x" dotnet-quality: "ga" - - name: Setup NuGet - uses: nuget/setup-nuget@v2 - with: - nuget-api-key: ${{ secrets.NUGET_TOKEN }} - nuget-version: '6.x' - - name: Download package uses: actions/download-artifact@v4 with: name: packages path: NuGet - - name: Publish to GitHub Packages (staging) - if: inputs.environment == 'staging' - run: | - dotnet nuget push NuGet/*.nupkg --source "https://nuget.pkg.github.com/DaveSkender/index.json" --api-key ${{ secrets.GITHUB_TOKEN }} --skip-duplicate - - - name: Publish to NuGet.org - if: inputs.environment == 'nuget.org' - run: | - dotnet new nugetconfig --force - nuget setApiKey ${{ secrets.NUGET_TOKEN }} -src nuget -ConfigFile nuget.config - nuget push NuGet/*.nupkg -src nuget -NonInteractive -ConfigFile nuget.config -Verbosity Detailed + - name: Publish package + if: ${{ !inputs.dry_run }} + env: + API_KEY: ${{ inputs.environment == 'nuget.org' && secrets.NUGET_TOKEN || secrets.GITHUB_TOKEN }} + run: > + dotnet nuget push NuGet/*.nupkg + --source "${{ vars.NUGET_PUBLISH_URL }}" + --api-key "$API_KEY" + --skip-duplicate - name: Tag and draft release note uses: ncipollo/release-action@v1 - if: inputs.environment == 'nuget.org' + if: ${{ !inputs.dry_run && inputs.environment == 'nuget.org' }} with: body: | - Weโ€™ve released a new Stock Indicators for .NET NuGet package. - See [Skender.Stock.Indicators @ NuGet.org](${{ vars.NUGET_DOWNLOAD_PREFIX }}${{ needs.build.outputs.version }}) for more information. + ## Release ${{ needs.build.outputs.version }} + + ๐Ÿ“ฆ Package deployed to [${{ inputs.environment }}](${{ needs.build.outputs.pkg_url }}) + + ### Package Details + - **Name**: ${{ needs.build.outputs.pkg_name }} + - **Version**: ${{ needs.build.outputs.version }} + - **Preview**: ${{ inputs.preview && 'Yes' || 'No' }} generateReleaseNotes: true draft: true makeLatest: ${{ !inputs.preview }} prerelease: ${{ inputs.preview }} - tag: ${{ needs.build.outputs.version }} - commit: ${{ github.ref_name }} + tag: v${{ needs.build.outputs.version }} + commit: ${{ github.sha }} + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Deployment summary + if: always() + run: | + { + echo "## Package Deployment" + echo "| Parameter | Value |" + echo "|:------------|:------|" + echo "| Mode | ${{ inputs.dry_run && '๐Ÿ” DRY RUN' || '๐Ÿš€ DEPLOY' }} |" + echo "| Status | ${{ job.status == 'success' && 'โœ… Success' || 'โŒ Failed' }} |" + echo "| Environment | ${{ inputs.environment }} |" + echo "| Version | ${{ needs.build.outputs.version }} |" + echo "| Package | [${{ needs.build.outputs.pkg_name }}](${{ needs.build.outputs.pkg_url }}) |" + echo "| Preview | ${{ inputs.preview && 'โœ“' || 'โœ—' }} |" + } >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/deploy-website.yml b/.github/workflows/deploy-website.yml index 58058c1a0..13e627773 100644 --- a/.github/workflows/deploy-website.yml +++ b/.github/workflows/deploy-website.yml @@ -12,10 +12,16 @@ jobs: deploy: name: Cloudflare Pages runs-on: ubuntu-latest + defaults: + run: + working-directory: docs + env: + BUNDLE_GEMFILE: ${{github.workspace}}/docs/Gemfile + JEKYLL_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} environment: name: stockindicators.dev - url: ${{ steps.deploy.outputs.deployment-alias-url }} + url: ${{ steps.deploy.outputs.pages-deployment-alias-url }} steps: - name: Checkout source @@ -24,9 +30,11 @@ jobs: - name: Setup Ruby uses: ruby/setup-ruby@v1 with: - working-directory: docs ruby-version: 3.3 + - name: Install dependencies + run: bundle install + - name: Define tag id: tag run: echo "version=$(date +'%Y.%m.%d')-${{ github.run_number }}" >> $GITHUB_OUTPUT @@ -38,28 +46,16 @@ jobs: replace: "${{ steps.tag.outputs.version }}" regex: false - - name: Install GEMs - working-directory: docs - env: - BUNDLE_GEMFILE: ${{github.workspace}}/docs/GemFile - run: | - pwd - bundle install - - name: Build site (production) if: github.ref == 'refs/heads/main' - working-directory: docs env: JEKYLL_ENV: production - BUNDLE_GEMFILE: ${{github.workspace}}/docs/GemFile run: bundle exec jekyll build - name: Build site (preview) if: github.ref != 'refs/heads/main' - working-directory: docs env: JEKYLL_ENV: preview - BUNDLE_GEMFILE: ${{github.workspace}}/docs/GemFile run: bundle exec jekyll build - name: Publish to Cloudflare Pages diff --git a/.github/workflows/lint-pull-request.yml b/.github/workflows/lint-pull-request.yml index dd068cb0c..4e9507808 100644 --- a/.github/workflows/lint-pull-request.yml +++ b/.github/workflows/lint-pull-request.yml @@ -1,11 +1,11 @@ name: Pull request on: - pull_request_target: + pull_request: types: - opened - edited - - synchronize + - unlabeled permissions: pull-requests: write @@ -14,59 +14,67 @@ jobs: main: name: lint PR title runs-on: ubuntu-latest + steps: - uses: amannn/action-semantic-pull-request@v5 id: lint_pr_title env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - - # Configure additional validation for the subject based on a regex. - # We enforce that the subject starts with an uppercase character. subjectPattern: ^([A-Z]).+$ - - # If `subjectPattern` is configured, you can use this property to override - # the default error message that is shown when the pattern doesn't match. - # The variables `subject` and `title` can be used within the message. subjectPatternError: > - The subject "**{subject}**" found in the pull request title "*{title}*" - didn't match the configured pattern. Please ensure that the subject - starts with an uppercase character. - - # If the PR contains one of these newline-delimited labels, the - # validation is skipped. If you want to rerun the validation when - # labels change, you might want to use the `labeled` and `unlabeled` - # event triggers in your workflow. + The subject "**{subject}**" must start with an uppercase character. + Example: "Add feature" instead of "add feature" ignoreLabels: | bot dependencies - uses: marocchino/sticky-pull-request-comment@v2 - # When the previous steps fails, the workflow would stop. By adding this - # condition you can continue the execution with the populated error message. if: always() && (steps.lint_pr_title.outputs.error_message != null) with: header: pr-title-lint-error message: | - ### Hey there and thank you for opening this pull request! ๐Ÿ‘‹๐Ÿผ + ### โš ๏ธ Invalid Pull Request title + + Your PR title must follow the format: `type: Subject` where: + - `type` is one of the conventional commit types (in lowercase) + - `Subject` starts with an uppercase letter - It looks like your proposed **_Pull request title_** needs to be adjusted. + > [!CAUTION] + > ${{ steps.lint_pr_title.outputs.error_message }} - >๐Ÿšฉ **Error** ยป ${{ steps.lint_pr_title.outputs.error_message }} + #### Valid examples - #### Pull request title naming convention + - `feat: Add API endpoint for market data` + - `fix: Resolve WebSocket connection issues` + - `chore: Update NuGet dependencies` - Our PR title name taxonomy is `type: Subject`, where **type** is typically - *feat*, *fix*, or *chore*, and **subject** is a phrase (proper noun) that starts - with a capitalized letter. The *chore* type usually has a subject that starts - with an action verb like *Add* or *Update*. Examples: +
+ see more valid examples - - _feat: Admin portal login_ - - _fix: Divide by zero in X calculation_ - - _chore: Update packages_ - - _docs: Improve setup guidance_ + #### Features & fixes + - `feat: Add API endpoint for market data` + - `fix: Resolve WebSocket connection issues` - See the [Conventional Commits specification](https://www.conventionalcommits.org) for more information. + #### Code quality + - `style: Format trading strategy classes` + - `refactor: Restructure trading engine components` + - `perf: Optimize trade order execution flow` + + #### Documentation & testing + - `docs: Update API documentation` + - `test: Add unit tests for sign-in flow` + + #### Infrastructure + - `build: Update .NET SDK version to 8.0` + - `ci: Add workflow for performance testing` + - `chore: Update NuGet dependencies` + + #### Other + - `revert: Remove faulty market data provider` + + See [Conventional Commits](https://www.conventionalcommits.org) for more details. +
# Delete a previous comment when the issue has been resolved - if: ${{ steps.lint_pr_title.outputs.error_message == null }} diff --git a/.github/workflows/lock-issues-pr.yml b/.github/workflows/lock-issues-pr.yml index ffb20549b..000093ade 100644 --- a/.github/workflows/lock-issues-pr.yml +++ b/.github/workflows/lock-issues-pr.yml @@ -16,6 +16,8 @@ concurrency: jobs: lock: runs-on: ubuntu-latest + timeout-minutes: 10 + steps: - uses: dessant/lock-threads@v5 with: diff --git a/.github/workflows/test-codeql.yml b/.github/workflows/test-codeql.yml deleted file mode 100644 index 9a585cb6e..000000000 --- a/.github/workflows/test-codeql.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: CodeQL - -on: - push: - branches: ["main"] - - pull_request: - branches: ["*"] - - schedule: - - cron: '37 14 * * 3' - -jobs: - - analyze: - name: analyze - runs-on: 'ubuntu-latest' - - permissions: - security-events: write - packages: read - actions: read - contents: read - - steps: - - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: csharp - build-mode: manual - - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 9.x - dotnet-quality: "ga" - - - name: Build library - run: > - dotnet build - --configuration Release - --property:ContinuousIntegrationBuild=true - -warnAsError - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - with: - category: "/language:csharp" diff --git a/.github/workflows/test-indicators.yml b/.github/workflows/test-indicators.yml index 65b447340..c44e5832c 100644 --- a/.github/workflows/test-indicators.yml +++ b/.github/workflows/test-indicators.yml @@ -1,11 +1,11 @@ -name: Indicators +name: Test Indicators on: push: branches: ["main"] - pull_request: branches: ["*"] + workflow_dispatch: jobs: test: @@ -20,18 +20,17 @@ jobs: strategy: matrix: os: [windows-latest, ubuntu-latest, macos-latest] - dotnet-version: ["9.x"] - # TODO: restore when runners have 9.x on all - # ["2.1.x", "6.x", "9.x"] + dotnet-version: ["6.0.x", "9.0.x"] env: # identifying primary configuration so only one reports coverage - IS_PRIMARY: ${{ matrix.os == 'ubuntu-latest' && matrix.dotnet-version == '9.x' }} + IS_PRIMARY: ${{ matrix.os == 'ubuntu-latest' && matrix.dotnet-version == '9.0.x' }} - # .NET SDK versions in the matrix that support `ga` quality spec - # versions before 5.x do not support it - SUPPORT_GA: ${{ contains(fromJson('["6.x", "9.x"]'), matrix.dotnet-version) }} + # Identifies the current target framework + TARGET_FRAMEWORK: > + ${{ matrix.dotnet-version == '6.0.x' && 'net6.0' || + matrix.dotnet-version == '9.0.x' && 'net9.0' }} steps: @@ -39,19 +38,11 @@ jobs: uses: actions/checkout@v4 - name: Setup .NET - id: dotnet-new uses: actions/setup-dotnet@v4 - if: env.SUPPORT_GA == 'true' with: - dotnet-version: ${{ matrix.dotnet-version }} + dotnet-version: "9.x" dotnet-quality: "ga" - - name: Setup .NET (older) - uses: actions/setup-dotnet@v4 - if: env.SUPPORT_GA == 'false' - with: - dotnet-version: ${{ matrix.dotnet-version }} - - name: Build library run: > dotnet build @@ -66,6 +57,7 @@ jobs: run: > dotnet test tests/indicators/Tests.Indicators.csproj --configuration Release + --property:TestFramework="${{ env.TARGET_FRAMEWORK }}" --no-build --verbosity normal --logger trx @@ -84,8 +76,8 @@ jobs: --logger trx --results-directory ./test-other - - name: Post test summary - uses: dorny/test-reporter@v1 + - name: Post test results + uses: dorny/test-reporter@v1.9.1 if: env.IS_PRIMARY == 'true' && always() with: name: Test results diff --git a/.github/workflows/test-website-a11y.yml b/.github/workflows/test-website-a11y.yml index 510726e8a..ad193a5d5 100644 --- a/.github/workflows/test-website-a11y.yml +++ b/.github/workflows/test-website-a11y.yml @@ -4,19 +4,23 @@ on: pull_request: branches: ["*"] paths: - - 'docs/**' - - ".github/workflows/test-website-a11y.yml" + - docs/** + - .github/workflows/test-website-a11y.yml -env: - JEKYLL_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# Prevent multiple concurrent runs +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: test: - name: test runs-on: ubuntu-latest - + defaults: + run: + working-directory: docs env: - BUNDLE_GEMFILE: ${{github.workspace}}/docs/GemFile + BUNDLE_GEMFILE: ${{github.workspace}}/docs/Gemfile + JEKYLL_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Checkout source @@ -25,33 +29,34 @@ jobs: - name: Setup Ruby uses: ruby/setup-ruby@v1 with: - working-directory: docs ruby-version: 3.3 - - name: Install GEMs - working-directory: docs + - name: Install dependencies run: | - pwd bundle install + npm install -g pa11y-ci + + - name: Use 'localhost' + uses: jacobtomlinson/gha-find-replace@v3 + with: + find: "https://dotnet.stockindicators.dev" + replace: "http://127.0.0.1:4000" + regex: false - name: Build site - working-directory: docs run: bundle exec jekyll build - name: Serve site - working-directory: docs - run: bundle exec jekyll serve --detach + run: bundle exec jekyll serve --port 4000 --detach - name: Show environment - working-directory: docs run: npx pa11y --environment - name: Test accessibility - working-directory: docs - run: | - npx pa11y-ci \ - --sitemap http://127.0.0.1:4000/sitemap.xml \ - --sitemap-exclude "/*.pdf" + run: > + pa11y-ci + --sitemap http://127.0.0.1:4000/sitemap.xml + --config ./.pa11yci - name: Kill site (failsafe) if: always() diff --git a/.github/workflows/test-website-links.yml b/.github/workflows/test-website-links.yml index c79ebcea2..0c40dbd16 100644 --- a/.github/workflows/test-website-links.yml +++ b/.github/workflows/test-website-links.yml @@ -4,16 +4,23 @@ on: pull_request: branches: ["*"] paths: - - 'docs/**' - - ".github/workflows/test-website-links.yml" + - docs/** + - .github/workflows/test-website-links.yml -env: - JEKYLL_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# Prevent multiple concurrent runs +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: test: - name: test runs-on: ubuntu-latest + defaults: + run: + working-directory: docs + env: + BUNDLE_GEMFILE: ${{github.workspace}}/docs/Gemfile + JEKYLL_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Checkout source @@ -22,21 +29,12 @@ jobs: - name: Setup Ruby uses: ruby/setup-ruby@v1 with: - working-directory: docs ruby-version: 3.3 - - name: Install GEMs - working-directory: docs - env: - BUNDLE_GEMFILE: ${{github.workspace}}/docs/GemFile + - name: Install dependencies run: | - pwd bundle install - - - name: Setup HTML Proofer - run: | gem install html-proofer - htmlproofer --help - name: Replace "data-src" uses: jacobtomlinson/gha-find-replace@v3 @@ -45,7 +43,7 @@ jobs: replace: "src" regex: false - - name: Replace "dotnet.stockindicators.dev" + - name: Use 'localhost' uses: jacobtomlinson/gha-find-replace@v3 with: find: "https://dotnet.stockindicators.dev" @@ -53,27 +51,19 @@ jobs: regex: false - name: Build site - working-directory: docs - env: - BUNDLE_GEMFILE: ${{github.workspace}}/docs/GemFile - run: bundle exec jekyll build --trace + run: bundle exec jekyll build - name: Serve site - working-directory: docs - env: - BUNDLE_GEMFILE: ${{github.workspace}}/docs/GemFile - run: bundle exec jekyll serve --detach + run: bundle exec jekyll serve --port 4000 --detach # see help in setup step - name: Test for broken URLs - working-directory: docs - run: | - htmlproofer _site \ - --no-enforce-https \ - --no-check-external-hash \ - --ignore-status-codes "0,302,403,406,408,429,503,999" \ - --swap-urls "https\://dotnet.stockindicators.dev:http\://127.0.0.1:4000" \ - --ignore-urls "/fonts.gstatic.com/" + run: > + htmlproofer _site + --no-enforce-https + --no-check-external-hash + --ignore-status-codes "0,302,403,406,408,429,503,999" + --ignore-urls "/fonts.gstatic.com/" - name: Kill site (failsafe) if: always() diff --git a/.gitignore b/.gitignore index 7a97cd5dc..b06c8feb4 100644 --- a/.gitignore +++ b/.gitignore @@ -133,6 +133,9 @@ _TeamCity* *.coverage *.coveragexml +# Visual Studio live unit testing +*.lutconfig + # NCrunch _NCrunch_* .*crunch*.local.xml @@ -218,7 +221,7 @@ ClientBin/ *.publishsettings orleans.codegen.cs -# Including strong name files can present a security risk +# Including strong name files can present a security risk # (https://github.com/github/gitignore/pull/2483#issue-259490424) #*.snk @@ -314,7 +317,7 @@ __pycache__/ # OpenCover UI analysis results OpenCover/ -# Azure Stream Analytics local run output +# Azure Stream Analytics local run output ASALocalRun/ # MSBuild Binary and Structured Log @@ -323,11 +326,11 @@ ASALocalRun/ # NVidia Nsight GPU debugger configuration file *.nvuser -# MFractors (Xamarin productivity tool) working folder +# MFractors (Xamarin productivity tool) working folder .mfractor/ # Jekyll site _site/ # zip artifacts -.DS_Store \ No newline at end of file +.DS_Store diff --git a/docs/.pa11yci b/docs/.pa11yci index 026b63583..58454b2d5 100644 --- a/docs/.pa11yci +++ b/docs/.pa11yci @@ -1,8 +1,16 @@ { "defaults": { "concurrency": 1, + "timeout": 30000, + "wait": 1000, "standard": "WCAG2AA", - "runners": ["htmlcs"], - "hideElements": "#searchzone" + "hideElements": "#searchzone", + "port": 4000, + "chromeLaunchConfig": { + "args": [ + "--no-sandbox", + "--disable-setuid-sandbox" + ] + } } } diff --git a/docs/GemFile b/docs/Gemfile similarity index 100% rename from docs/GemFile rename to docs/Gemfile diff --git a/docs/GemFile.lock b/docs/Gemfile.lock similarity index 95% rename from docs/GemFile.lock rename to docs/Gemfile.lock index 800569ef8..e9ca2ba73 100644 --- a/docs/GemFile.lock +++ b/docs/Gemfile.lock @@ -1,7 +1,7 @@ GEM remote: https://rubygems.org/ specs: - activesupport (8.0.0) + activesupport (8.0.1) base64 benchmark (>= 0.3) bigdecimal @@ -18,7 +18,7 @@ GEM public_suffix (>= 2.0.2, < 7.0) base64 (0.2.0) benchmark (0.4.0) - bigdecimal (3.1.8) + bigdecimal (3.1.9) coffee-script (2.4.1) coffee-script-source execjs @@ -28,7 +28,7 @@ GEM concurrent-ruby (1.3.4) connection_pool (2.4.1) cssminify2 (2.0.1) - csv (3.3.0) + csv (3.3.2) dnsruby (1.72.3) base64 (~> 0.2.0) simpleidn (~> 0.2.1) @@ -40,14 +40,13 @@ GEM ffi (>= 1.15.0) eventmachine (1.2.7) execjs (2.10.0) - faraday (2.12.1) + faraday (2.12.2) faraday-net_http (>= 2.0, < 3.5) json logger faraday-net_http (3.4.0) net-http (>= 0.5.0) ffi (1.17.0-x64-mingw-ucrt) - ffi (1.17.0-x86_64-linux-gnu) forwardable-extended (2.6.0) gemoji (4.1.0) github-pages (232) @@ -227,7 +226,7 @@ GEM gemoji (>= 3, < 5) html-pipeline (~> 2.2) jekyll (>= 3.0, < 5.0) - json (2.8.2) + json (2.9.1) json-minify (0.0.3) json (> 0) kramdown (2.4.0) @@ -238,18 +237,16 @@ GEM listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - logger (1.6.1) + logger (1.6.4) mercenary (0.3.6) minima (2.5.1) jekyll (>= 3.5, < 5.0) jekyll-feed (~> 0.9) jekyll-seo-tag (~> 2.1) - minitest (5.25.2) - net-http (0.5.0) + minitest (5.25.4) + net-http (0.6.0) uri - nokogiri (1.16.7-x64-mingw-ucrt) - racc (~> 1.4) - nokogiri (1.16.7-x86_64-linux) + nokogiri (1.18.0-x64-mingw-ucrt) racc (~> 1.4) octokit (4.25.1) faraday (>= 1, < 3) @@ -261,7 +258,7 @@ GEM rb-fsevent (0.11.2) rb-inotify (0.11.1) ffi (~> 1.0) - rexml (3.3.9) + rexml (3.4.0) rouge (3.30.0) rubyzip (2.3.2) safe_yaml (1.0.5) @@ -273,7 +270,7 @@ GEM sawyer (0.9.2) addressable (>= 2.3.5) faraday (>= 0.17.3, < 3) - securerandom (0.3.2) + securerandom (0.4.1) simpleidn (0.2.3) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) @@ -286,11 +283,10 @@ GEM unicode-display_width (1.8.0) uri (1.0.2) wdm (0.2.0) - webrick (1.9.0) + webrick (1.9.1) PLATFORMS x64-mingw-ucrt - x86_64-linux DEPENDENCIES faraday @@ -305,4 +301,4 @@ DEPENDENCIES webrick BUNDLED WITH - 2.4.7 + 2.5.18 diff --git a/docs/_config.yml b/docs/_config.yml index 0f941f5fd..d5f0d975b 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -55,7 +55,7 @@ exclude: "docs/README.md", "examples/Backtest", "examples/ConsoleApp", - "GemFile", + "Gemfile", "node_modules", "vendor", ".devcontainer" diff --git a/docs/pages/home.md b/docs/pages/home.md index 7915db21e..ce548079c 100644 --- a/docs/pages/home.md +++ b/docs/pages/home.md @@ -70,7 +70,7 @@ See the [guide]({{site.baseurl}}/guide/#content) and the [full list of indicator Our [NuGet library](https://www.nuget.org/packages/Skender.Stock.Indicators) directly targets all current frameworks for peak performance, including the .NET Standard for older framework compatibility. - .NET 9.0, 8.0, 6.0 -- .NET Standard 2.1 +- .NET Standard 2.1, 2.0 The compiled library package is [Common Language Specification (CLS) compliant](https://docs.microsoft.com/en-us/dotnet/standard/common-type-system) and can be used in other programming languages, including Python and everything in the .NET universe. diff --git a/src/Indicators.csproj b/src/Indicators.csproj index 907e5dad4..12e488c58 100644 --- a/src/Indicators.csproj +++ b/src/Indicators.csproj @@ -1,7 +1,8 @@ - net9.0;net8.0;net6.0;netstandard2.1 + net9.0;net8.0;net6.0;netstandard2.1;netstandard2.0 + 13.0 Dave Skender Stock Indicators for .NET @@ -34,7 +35,6 @@ Alligator;Gator;Fractal;Chaos;Choppiness;Endpoint;WMA;ZigZag;.NET;C#;Library;Package; README.md - https://github.com/DaveSkender/Stock.Indicators/releases Apache-2.0 icon.png diff --git a/tests/indicators/_Initialize.cs b/tests/indicators/_Initialize.cs index 3b09c9e0f..bdbe00b75 100644 --- a/tests/indicators/_Initialize.cs +++ b/tests/indicators/_Initialize.cs @@ -1,5 +1,7 @@ using System.Globalization; +using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.Versioning; // GLOBALS & INITIALIZATION OF TEST DATA @@ -8,6 +10,9 @@ [assembly: InternalsVisibleTo("Tests.Performance")] namespace Tests.Common; +/// +/// Base class for all test classes, providing common test data and utilities. +/// [TestClass] public abstract class TestBase { @@ -27,3 +32,37 @@ public abstract class TestBase internal static readonly IEnumerable zeroesQuotes = TestData.GetZeros(); internal static readonly IEnumerable<(DateTime, double)> tupleNanny = TestData.GetTupleNaN(); } + +/// +/// Test class for the startup of the test project. +/// +[TestClass] +public class Startup +{ + /// + /// Displays the assembly location, name, version, and target framework + /// as a sanity check for test runner targeting. + /// + [TestMethod] + [TestCategory("ShowMe")] + public void ShowFramework() + { + // Get the assembly of any type from your Indicators project + Assembly assembly = typeof(Indicator).Assembly; + + Console.WriteLine($"Assembly Location: {assembly.Location}"); + Console.WriteLine($"Assembly Name: {assembly.GetName().Name}"); + Console.WriteLine($"Assembly Version: {assembly.GetName().Version}"); + + // Get the target framework the assembly was built for + TargetFrameworkAttribute targetFrameworkAttribute = assembly + .GetCustomAttribute(); + + string frameworkName + = targetFrameworkAttribute?.FrameworkName ?? "Unknown"; + + Console.WriteLine($"Target Framework: {frameworkName}"); + + frameworkName.Should().NotBe("Unknown"); + } +}