diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2237645 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Rohith Reddy + +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. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..8020a0d --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +# ✨ Publish NuGet +GitHub action to build, pack & publish nuget pacakges automatically when a project version is updated + +## Usage +Create a new `.github/workflows/publish-nuget.yml` file: + +```yaml +name: publish to nuget +on: + push: + branches: + - master # Your default release branch +jobs: + publish: + name: publish to nuget + runs-on: ubuntu-latest + steps: + # Checkout + - uses: actions/checkout@v2 + with: + fetch-depth: 2 # This must be >= 2 to compare commits + + # Optional step, add only for a specific dotnet version that doesn't come with ubuntu-latest + # For a list of software that comes pre-installed with ubuntu-latest visit bit.ly/2synnZl + # - name: Setup dotnet + # uses: actions/setup-dotnet@v1 + # with: + # dotnet-version: 3.1.100 + + # Publish + - name: Publish if version is updated + uses: rohith/publish-nuget@v1 + # with: # All inputs are optional (details given below) + # project_dir: src # Defaults to repository root + # tag_format: v* # [*] gets replaced with version + # nuget_key: ${{secrets.NUGET_API_KEY}} # nuget.org API key +``` + +Project version updates are monitored on every push / PR merge to master & a new tag is created to denote the updated version. If a `nuget_key` is passed then the project gets built, packed & published to nuget.org + +## Inputs +All these inputs are optional + +Input | Description +--- | --- +project_dir | Directory path containing the project file, defaults to repository root +tag_format | Defaults to `v*` - `[*]` is a placeholder for the actual project version +nuget_key | API key to authorize the package upload to nuget.org + +**Note:** +`project_dir` & `tag_format` have default values but a package cannot be published without the `nuget_key` + +## License +[MIT](LICENSE) \ No newline at end of file diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..4df4a5c --- /dev/null +++ b/action.yml @@ -0,0 +1,24 @@ +name: Publish NuGet +author: Rohith Reddy (@rohith) +description: Build, Pack & Publish NuGet packages with dotnet (.net core) on project version change + +inputs: + project_dir: + description: Project (csproj) directory path relative from the root of repository + required: false + default: . + tag_format: + description: Format of the tag to be created, `*` is placeholder for actual version + required: false + default: v* + nuget_key: + description: API key for the NuGet feed + required: false + +runs: + using: node12 + main: index.js + +branding: + icon: package + color: blue \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..02fafcb --- /dev/null +++ b/index.js @@ -0,0 +1,74 @@ +const resolve = require("path").resolve, + execSync = require("child_process").execSync, + { readdirSync, readFileSync } = require("fs") + +function run() { + // check fetch-depth + const commitCount = execSync("git rev-list --count HEAD", { encoding: "utf-8" }) + if (commitCount < 2) { + failure("😤 commit history needs to be >= 2") + return + } + + // find project + const repoDir = process.env.GITHUB_WORKSPACE, + projDir = resolve(repoDir, process.env.INPUT_PROJECT_DIR), + projFiles = readdirSync(projDir).filter(f => f.endsWith(".csproj")) + + if (projFiles.length === 0) { + failure("😭 project not found") + return + } + + // check for version changes + const projName = projFiles[0], + projPath = resolve(projDir, projName), + versionRegex = /(.*)<\/Version>/, + gitDiff = execSync(`git diff -U0 HEAD^ -- ${projPath}`, { encoding: "utf-8" }), + isVersionChanged = versionRegex.test(gitDiff) + + if (!isVersionChanged) { + console.log(`🥱 no version change in ${projName}`) + return + } + + console.log(`👍 found version change in ${projName}`) + + // create tag + const projContents = readFileSync(projPath, { encoding: "utf-8" }), + newVersion = versionRegex.exec(projContents)[1], + tagFormat = process.env.INPUT_TAG_FORMAT, + tag = tagFormat.replace("*", newVersion), + istagPresent = execSync("git tag -l --contains", { encoding: "utf-8" }).indexOf(tag) >= 0 + + if (istagPresent) { + console.log(`😢 tag named ${newVersion} already exists`) + return + } + + execSync(`git tag ${tag}`, { encoding: "utf-8" }) + execSync(`git push origin ${tag}`, { encoding: "utf-8" }) + + // pack & push + const nugetKey = process.env.INPUT_NUGET_KEY + + if (!nugetKey) + return + + if (!execSync("command -v dotnet", { encoding: "utf-8" })) { + failure("😭 dotnet not found") + return + } + + execSync(`dotnet pack -c Release ${projPath} -o .`, { encoding: "utf-8" }) + + if (nugetKey) + execSync(`dotnet nuget push *.nupkg -s https://api.nuget.org/v3/index.json -k ${nugetKey}`, { encoding: "utf-8" }) +} + +function failure(msg) { + process.exitCode = 1 + console.log(msg) +} + +run() \ No newline at end of file