Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Single step multiple project-nuget Deploy. #1

Merged
merged 6 commits into from
May 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,15 @@ jobs:
id: publish_nuget
uses: rohith/publish-nuget@v2
with:
# Filepath of the solution of which contains all the projects to be packed, relative to root of repository
SOLUTION_FILE_PATH: solution.sln

# Filepath of the project to be packaged, relative to root of repository
PROJECT_FILE_PATH: Core/Core.csproj

# Path to store all generated nuget packages, relative to root of repository
PACKAGE_PATH: artifacts/

# NuGet package id, used for version detection & defaults to project name
# PACKAGE_NAME: Core

Expand Down Expand Up @@ -64,7 +70,9 @@ jobs:

Input | Default Value | Description
--- | --- | ---
PROJECT_FILE_PATH | | Filepath of the project to be packaged, relative to root of repository
SOLUTION_FILE_PATH | | Filepath of the solution of which contains all the projects to be packed, relative to root of repository
PROJECT_FILE_PATH | | Filepath of the project to be packaged or a glob of projects in the form of \*\*/\*.csproj, relative to root of repository
PACKAGE_PATH | | Path to store all generated nuget packages, relative to root of repository
PACKAGE_NAME | | NuGet package id, used for version detection & defaults to project name
VERSION_FILE_PATH | `[PROJECT_FILE_PATH]` | Filepath with version info, relative to root of repository & defaults to PROJECT_FILE_PATH
VERSION_REGEX | `^\s*<Version>(.*)<\/Version>\s*$` | Regex pattern to extract version info in a capturing group
Expand All @@ -88,7 +96,7 @@ SYMBOLS_PACKAGE_PATH | Path to the generated symbols package
**FYI:**
- Outputs may or may not be set depending on the action inputs or if the action failed
- `NUGET_SOURCE` must support `/v3-flatcontainer/PACKAGE_NAME/index.json` for version change detection to work
- Multiple projects can make use of steps to configure each project individually, common inputs between steps can be given as `env` for [job / workflow](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#env)
- Multiple projects can use file globbing to package each of them up and push them.

## License
[MIT](LICENSE)
10 changes: 8 additions & 2 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@ author: Rohith Reddy (@rohith)
description: Build, Pack & Publish a NuGet package with dotnet core on project version change

inputs:
SOLUTION_FILE_PATH:
description: Filepath of the solution of which contains all the projects to be packed, relative to root of repository
required: true
PROJECT_FILE_PATH:
description: Filepath of the project to be packaged, relative to root of repository
description: Filepath of the project to be packaged or a glob of projects in the form of **/*.csproj, relative to root of repository
required: true
PACKAGE_PATH:
description: Path to store all generated nuget packages, relative to root of repository
required: true
PACKAGE_NAME:
description: NuGet package id, used for version detection & defaults to project name
Expand Down Expand Up @@ -61,4 +67,4 @@ runs:

branding:
icon: package
color: blue
color: blue
77 changes: 54 additions & 23 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ const os = require("os"),
fs = require("fs"),
path = require("path"),
https = require("https"),
spawnSync = require("child_process").spawnSync
spawnSync = require("child_process").spawnSync,
globfs = require("glob-fs")(),
hasGlob = require("has-glob")

class Action {
constructor() {
this.solutionFile = process.env.SOLUTION_FILE_PATH
this.packagePath = process.env.PACKAGE_PATH
this.projectFile = process.env.INPUT_PROJECT_FILE_PATH
this.packageName = process.env.INPUT_PACKAGE_NAME || process.env.PACKAGE_NAME
this.versionFile = process.env.INPUT_VERSION_FILE_PATH || process.env.VERSION_FILE_PATH || this.projectFile
Expand Down Expand Up @@ -55,34 +59,14 @@ class Action {

console.log(`NuGet Source: ${this.nugetSource}`)

fs.readdirSync(".").filter(fn => /\.s?nupkg$/.test(fn)).forEach(fn => fs.unlinkSync(fn))

this._executeInProcess(`dotnet build -c Release ${this.projectFile}`)

this._executeInProcess(`dotnet pack ${this.includeSymbols ? "--include-symbols -p:SymbolPackageFormat=snupkg" : ""} --no-build -c Release ${this.projectFile} -o .`)

const packages = fs.readdirSync(".").filter(fn => fn.endsWith("nupkg"))
console.log(`Generated Package(s): ${packages.join(", ")}`)

const pushCmd = `dotnet nuget push *.nupkg -s ${this.nugetSource}/v3/index.json -k ${this.nugetKey} --skip-duplicate ${!this.includeSymbols ? "-n 1" : ""}`,
const pushCmd = `dotnet nuget push ${this.packagePath}/${name}.${version}.nupkg -s ${this.nugetSource}/v3/index.json -k ${this.nugetKey} --skip-duplicate ${!this.includeSymbols ? "-n 1" : ""}`,
pushOutput = this._executeCommand(pushCmd, { encoding: "utf-8" }).stdout

console.log(pushOutput)

if (/error/.test(pushOutput))
this._printErrorAndExit(`${/error.*/.exec(pushOutput)[0]}`)

const packageFilename = packages.filter(p => p.endsWith(".nupkg"))[0],
symbolsFilename = packages.filter(p => p.endsWith(".snupkg"))[0]

process.stdout.write(`::set-output name=PACKAGE_NAME::${packageFilename}` + os.EOL)
process.stdout.write(`::set-output name=PACKAGE_PATH::${path.resolve(packageFilename)}` + os.EOL)

if (symbolsFilename) {
process.stdout.write(`::set-output name=SYMBOLS_PACKAGE_NAME::${symbolsFilename}` + os.EOL)
process.stdout.write(`::set-output name=SYMBOLS_PACKAGE_PATH::${path.resolve(symbolsFilename)}` + os.EOL)
}

if (this.tagCommit)
this._tagCommit(version)
}
Expand Down Expand Up @@ -114,7 +98,8 @@ class Action {
})
}

run() {
_run_internal()
{
if (!this.projectFile || !fs.existsSync(this.projectFile))
this._printErrorAndExit("project file not found")

Expand All @@ -140,6 +125,52 @@ class Action {

this._checkForUpdate()
}

run() {
if (!this.solutionFile || !fs.existsSync(this.solutionFile)) {
this._printErrorAndExit("solution file not found")
}

if (!this.packagePath || !fs.existsSync(this.packagePath)) {
this._printErrorAndExit("PACKAGE_PATH not provided.")
}

// nuke ane normal .nupkg/.snupkg inside the user specified package path
// and then build the packages for the resulting projects inside of the
// solution file specified.
fs.readdirSync(this.packagePath).filter(fn => /\.s?nupkg$/.test(fn)).forEach(fn => fs.unlinkSync(fn))
this._executeInProcess(`dotnet build -c Release ${this.solutionFile}`)
this._executeInProcess(`dotnet pack ${this.includeSymbols ? "--include-symbols -p:SymbolPackageFormat=snupkg" : ""} --no-build --no-restore -c Release ${this.solutionFile} -o ${this.packagePath}`)
const packages = fs.readdirSync(this.packagePath).filter(fn => fn.endsWith("nupkg"))
console.log(`Generated Package(s): ${packages.join(", ")}`)

// TODO: output all of the package names and paths.
const packageFilename = packages.filter(p => p.endsWith(".nupkg"))[0],
symbolsFilename = packages.filter(p => p.endsWith(".snupkg"))[0]
process.stdout.write(`::set-output name=PACKAGE_NAME::${packageFilename}` + os.EOL)
process.stdout.write(`::set-output name=PACKAGE_PATH::${path.resolve(packageFilename)}` + os.EOL)
if (symbolsFilename) {
process.stdout.write(`::set-output name=SYMBOLS_PACKAGE_NAME::${symbolsFilename}` + os.EOL)
process.stdout.write(`::set-output name=SYMBOLS_PACKAGE_PATH::${path.resolve(symbolsFilename)}` + os.EOL)
}

if (!hasGlob(this.projectFile) && !hasGlob(this.versionFile)) {
this._run_internal()
}

// it has a glob, now we need to recursively obtain all files
// represented in the glob and match them up. After that we
// need to reset the projectFile, and versionFile variables on
// the object instance each time and call _run_internal() for
// each file found that matches in the glob.
let tmp = this.projectFile
glob.on('include', function (file) {
this.projectFile = file.relative
this.versionFile = file.relative
this._run_internal()
})
glob.readdirSync(this.projectFile);
}
}

new Action().run()