diff --git a/.gitattributes b/.gitattributes index 1ff0c42..832757f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -61,3 +61,11 @@ #*.PDF diff=astextplain #*.rtf diff=astextplain #*.RTF diff=astextplain + +############################################################################### +# Keep shell scripts and CI YAML LF-only for the Linux CI runners, regardless +# of the checkout platform's autocrlf setting. +############################################################################### +*.sh text eol=lf +*.yml text eol=lf +*.yaml text eol=lf diff --git a/.github/actions/ci-dotnet/action.yml b/.github/actions/ci-dotnet/action.yml new file mode 100644 index 0000000..e730642 --- /dev/null +++ b/.github/actions/ci-dotnet/action.yml @@ -0,0 +1,22 @@ +name: CI — .NET +description: > + Restore and Release-build ESI.NET across every target framework. Runs on + Linux; the net46x/net47x/net48 targets build against the .NET Framework + reference assemblies the SDK restores, no Mono needed. Assumes the repo is + already checked out. + +runs: + using: composite + steps: + - name: Setup .NET SDK + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '8.0.x' + + - name: Restore + shell: bash + run: dotnet restore ESI.NET.sln + + - name: Build (Release, all target frameworks) + shell: bash + run: dotnet build ESI.NET.sln --configuration Release --no-restore diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..ad56938 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,36 @@ +# Dependabot version updates. Each ecosystem is grouped, so a run opens at most +# one PR per ecosystem (plus stragglers that can't be grouped). PRs target `dev` +# — the integration branch, where CI (ci-dev.yml) runs. Security alerts are a +# separate repo setting and open PRs only for actual advisories. +version: 2 +updates: + - package-ecosystem: github-actions + directory: "/" + target-branch: dev + schedule: + interval: weekly + commit-message: + prefix: ci + groups: + actions: + patterns: + - "*" + + - package-ecosystem: nuget + directory: "/ESI.NET" + target-branch: dev + schedule: + interval: weekly + commit-message: + prefix: deps + groups: + nuget: + patterns: + - "*" + # Majors (Microsoft.IdentityModel 7.x/8.x, Microsoft.Extensions.* 9.x, …) + # tend to need code changes — take those by hand; grouped minor/patch keep + # the package graph fresh in the meantime. + ignore: + - dependency-name: "*" + update-types: + - version-update:semver-major diff --git a/.github/workflows/build-check.yml b/.github/workflows/build-check.yml deleted file mode 100644 index a8bd659..0000000 --- a/.github/workflows/build-check.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: PR Build Check - -on: - pull_request: - branches: - - master - -jobs: - build: - runs-on: ubuntu-latest - env: - BUILD_PLATFORM: 'Any CPU' - BUILD_CONFIGURATION: 'Release' - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup .NET SDK - uses: actions/setup-dotnet@v4 - with: - dotnet-version: '7.0.x' - - - name: Restore dependencies - run: dotnet restore - - - name: Build solution - run: | - dotnet build "**/*.sln" --configuration ${{ env.BUILD_CONFIGURATION }} --no-restore diff --git a/.github/workflows/ci-dev.yml b/.github/workflows/ci-dev.yml new file mode 100644 index 0000000..7165e9f --- /dev/null +++ b/.github/workflows/ci-dev.yml @@ -0,0 +1,26 @@ +name: CI (dev) + +# Per-commit coverage on the long-lived dev branch, so a break is pinned to the +# commit that caused it instead of surfacing across a whole delta at PR time. +# Separate workflow (not the `check` context) so it never touches the dev->master +# PR gate. Skips doc-only pushes. +on: + push: + branches: [dev] + paths-ignore: + - 'docs/**' + - '**.md' + +concurrency: + group: ci-dev-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: ./.github/actions/ci-dotnet diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9445fc6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,29 @@ +name: CI + +# PR gate for both branches: dev->master (the release gate) and feature->dev +# (contributor PRs). The `check` job aggregates the build and is the required +# status check on master (branch protection) — keep its name stable. +on: + pull_request: + branches: [master, dev] + +# Newer commits on the PR branch supersede an in-flight run. +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + - uses: ./.github/actions/ci-dotnet + + check: + needs: [build] + runs-on: ubuntu-latest + steps: + - run: echo "build passed" diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index 9708669..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,96 +0,0 @@ -name: Build and Release ESI.NET - -on: - push: - tags: - - '*.*.*' - workflow_dispatch: - inputs: - manual_tag: - description: 'Version tag (example 2025.1.1 (..)' - required: true - -jobs: - build: - runs-on: ubuntu-latest - env: - BUILD_PLATFORM: 'Any CPU' - BUILD_CONFIGURATION: 'Release' - - outputs: - version: ${{ steps.get_version.outputs.version }} - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup .NET SDK - uses: actions/setup-dotnet@v4 - with: - dotnet-version: '7.0.x' - - - name: Extract version from tag or input - id: get_version - shell: bash - run: | - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - echo "version=${{ github.event.inputs.manual_tag }}" >> $GITHUB_OUTPUT - else - echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT - fi - - - name: Restore dependencies - run: dotnet restore - - - name: Build solution - run: | - dotnet build ESI.NET.sln --configuration ${{ env.BUILD_CONFIGURATION }} --no-restore - - - name: Create Package - shell: bash - run: | - dotnet pack ESI.NET/ESI.NET.csproj \ - --configuration ${{ env.BUILD_CONFIGURATION }} \ - --output ./nupkgs \ - -p:PackageVersion=${{ steps.get_version.outputs.version }} - - - name: Upload package artifact - uses: actions/upload-artifact@v4 - with: - name: nuget-package - path: ./nupkgs/*.nupkg - - deploy: - needs: build - runs-on: ubuntu-latest - - steps: - - name: Download package artifact - uses: actions/download-artifact@v4 - with: - name: nuget-package - - - name: Push to NuGet.org - run: | - dotnet nuget push "nupkgs/*.nupkg" \ - --api-key ${{ secrets.NUGET_API_KEY }} \ - --source https://api.nuget.org/v3/index.json - - - name: Create GitHub Release - uses: softprops/action-gh-release@v2 - with: - tag_name: ${{ github.event.inputs.manual_tag || github.ref_name }} - name: ESI.NET ${{ needs.build.outputs.version }} - body: | - Release for version ${{ needs.build.outputs.version }}. - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Send Discord Webhook - if: success() - env: - DISCORD_WEBHOOK: ${{ github.event_name == 'workflow_dispatch' && secrets.DISCORD_TEST_WEBHOOK_URL || secrets.DISCORD_WEBHOOK_URL }} - uses: Ilshidur/action-discord@0.3.2 - with: - args: | - **ESI.NET ${{ needs.build.outputs.version }} NuGet package released** diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..0e3f5c0 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,98 @@ +name: Release + +# Fires on every push to master — i.e. every dev->master merge — and publishes a +# release: a CalVer version from today's date + existing tags, the NuGet package +# pushed to nuget.org, and a GitHub Release (which creates the tag). Doc-only and +# CI-only merges are skipped (paths-ignore); to opt any other merge out, put +# "[skip release]" in the merge-commit message. workflow_dispatch stays for +# manual drafts / re-runs — a draft build packs and attaches the .nupkg but does +# not push to NuGet. +on: + push: + branches: [master] + paths-ignore: + - 'docs/**' + - '**.md' + - '.github/**' + workflow_dispatch: + inputs: + draft: + description: "Draft: pack + attach the .nupkg, but don't push to NuGet" + type: boolean + default: false + +# One release at a time; never cancel a run that may have already published. +concurrency: + group: release + cancel-in-progress: false + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + # push: skip when the merge commit opts out. dispatch: always run. + if: >- + github.event_name == 'workflow_dispatch' || + !contains(github.event.head_commit.message, '[skip release]') + + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 # need all tags so the CalVer build segment is correct + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '8.0.x' + + - name: Compute version + id: version + shell: bash + run: echo "value=$(bash scripts/compute-version.sh)" >> "$GITHUB_OUTPUT" + + - name: Pack + shell: bash + run: >- + dotnet pack ESI.NET/ESI.NET.csproj + --configuration Release + --output ./nupkgs + -p:Version=${{ steps.version.outputs.value }} + -p:ContinuousIntegrationBuild=true + + - name: Upload package artifact + uses: actions/upload-artifact@v4 + with: + name: nuget-package + path: ./nupkgs/*.nupkg + + - name: Push to NuGet.org + if: ${{ !inputs.draft }} + shell: bash + run: >- + dotnet nuget push "nupkgs/*.nupkg" + --api-key ${{ secrets.NUGET_API_KEY }} + --source https://api.nuget.org/v3/index.json + --skip-duplicate + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.version.outputs.value }} + name: ESI.NET ${{ steps.version.outputs.value }} + draft: ${{ inputs.draft || false }} + generate_release_notes: true + files: ./nupkgs/*.nupkg + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Send Discord webhook + if: ${{ success() && !inputs.draft }} + env: + DISCORD_WEBHOOK: ${{ github.event_name == 'workflow_dispatch' && secrets.DISCORD_TEST_WEBHOOK_URL || secrets.DISCORD_WEBHOOK_URL }} + uses: Ilshidur/action-discord@0.3.2 + with: + args: | + **ESI.NET ${{ steps.version.outputs.value }} NuGet package released** diff --git a/ESI.NET/ESI.NET.csproj b/ESI.NET/ESI.NET.csproj index cb1585f..b010daa 100644 --- a/ESI.NET/ESI.NET.csproj +++ b/ESI.NET/ESI.NET.csproj @@ -1,16 +1,11 @@  - - SAK - SAK - SAK - SAK - - netcoreapp3.1;netstandard2.0;net462;net47;net471;net472;net48;net6.0;net7.0 true - 2023.12.12 + + 0.0.0-dev Psianna Archeia Sukebe Corporation .NET Wrapper for the Eve Online API @@ -40,10 +35,4 @@ - - - Always - - - diff --git a/ESI.NET/GetBuildVersion.psm1 b/ESI.NET/GetBuildVersion.psm1 deleted file mode 100644 index 7c8b304..0000000 --- a/ESI.NET/GetBuildVersion.psm1 +++ /dev/null @@ -1,34 +0,0 @@ -Function GetBuildVersion { - Param ( - [string]$VersionString - ) - - # Process through regex - $VersionString -match "(?\d+)(\.(?\d+))?(\.(?\d+))?(\-(?
[0-9A-Za-z\-\.]+))?(\+(?\d+))?" | Out-Null
-
-    if ($matches -eq $null) {
-        return "1.0.0-build"
-    }
-
-    # Extract the build metadata
-    $BuildRevision = [uint64]$matches['build']
-    # Extract the pre-release tag
-    $PreReleaseTag = [string]$matches['pre']
-    # Extract the patch
-    $Patch = [uint64]$matches['patch']
-    # Extract the minor
-    $Minor = [uint64]$matches['minor']
-    # Extract the major
-    $Major = [uint64]$matches['major']
-
-    $Version = [string]$Major + '.' + [string]$Minor + '.' + [string]$Patch;
-    if ($PreReleaseTag -ne [string]::Empty) {
-        $Version = $Version + '-' + $PreReleaseTag
-    }
-
-    if ($BuildRevision -ne 0) {
-        $Version = $Version + '.' + [string]$BuildRevision
-    }
-
-    return $Version
-}
\ No newline at end of file
diff --git a/scripts/compute-version.sh b/scripts/compute-version.sh
new file mode 100755
index 0000000..1b2ece2
--- /dev/null
+++ b/scripts/compute-version.sh
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+# CalVer generator: YYYY.(MM*100+DD).BUILD
+#
+#   major = calendar year            e.g. 2026
+#   minor = month*100 + day          e.g. Sep 9 -> 909, Jan 5 -> 105
+#   build = 1 for the day's first release, then +1 per additional same-day build
+#
+# The build segment is derived from existing git tags (..*), so
+# nothing needs to be committed or hand-incremented. Prints just the version
+# string to stdout for the release workflow to consume; diagnostics go to stderr
+# so VERSION=$(scripts/compute-version.sh) stays clean.
+#
+# Tags here are un-prefixed (2026.909.1), matching this repo's existing tag
+# history and the release workflow's tag_name — dev-prompt prefixes them with a
+# leading `v`, this is the one intentional deviation.
+set -euo pipefail
+
+major=$(date -u +%Y)
+month=$(date -u +%m)
+day=$(date -u +%d)
+# 10# forces base-10 so a leading zero (08, 09) isn't read as octal.
+minor=$(( 10#$month * 100 + 10#$day ))
+
+build=1
+tags=$(git tag --list "${major}.${minor}.*" || true)
+if [ -n "$tags" ]; then
+  highest=$(printf '%s\n' "$tags" \
+    | sed -n "s/^${major}\.${minor}\.\([0-9][0-9]*\)$/\1/p" \
+    | sort -n | tail -1)
+  if [ -n "$highest" ]; then
+    build=$(( highest + 1 ))
+  fi
+fi
+
+version="${major}.${minor}.${build}"
+echo "computed version: ${version}" >&2
+printf '%s' "$version"