Skip to content

Commit

Permalink
Merge pull request #214 from tgharold/20241016-1313
Browse files Browse the repository at this point in the history
Create combined .NET / NPM / JFrog workflows
  • Loading branch information
lightyeare authored Oct 16, 2024
2 parents 2a51bc3 + 5be5d84 commit 99110dd
Show file tree
Hide file tree
Showing 3 changed files with 1,265 additions and 0 deletions.
359 changes: 359 additions & 0 deletions .github/workflows/dotnet-npm-build-jfrog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,359 @@
name: Build (.NET/NPM)

# A combined workflow that does both 'dotnet build' and 'npm run build'.
# Note that the NPM side only handles a single package.json file, so
# the 'npm_project_directory' input is generally going to be required
# but the 'dotnet build' command can usually be run from the solution folder.

# Uses JFrog Artifactory as the sole upstream repository for resolving packages.
# It's expected that you point at a 'virtual' Artifactory repository which can also
# resolve any NuGet / NPM packages which you consume.

# The "jfrog/setup-jfrog-cli" action requires "id-token: write" or else you will get
# an error about: "Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable".

# https://docs.jfrog-applications.jfrog.io/jfrog-applications/jfrog-cli/cli-for-jfrog-artifactory/build-integration#aggregating-published-builds

permissions:
contents: read
id-token: write

on:

workflow_call:

inputs:

configuration:
required: false
type: string
default: "Release"

dotnet_project_directory:
description: Location of the solution file for the dotnet solution. Defaults to the root directory.
required: false
type: string
default: ./

dotnet_restore_verbosity:
description: 'The dotnet restore "--verbosity=" flag. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]. The default is minimal.'
required: false
type: string
default: minimal

dotnet_version:
required: false
type: string
default: "6.0"

jfrog_api_base_url:
description: 'JFrog platform url (for example: https://rimdev.jfrog.io/)'
required: true
type: string

jfrog_build_name:
description: 'JFrog build name.'
required: true
type: string

jfrog_build_number:
description: 'JFrog build number. Can be an integer, a semantic version, or a string.'
required: true
type: string

jfrog_cli_log_level:
description: 'Set the log level for the JFrog CLI. Default is ERROR. Values are: (DEBUG, INFO, WARN, ERROR).'
required: false
default: ERROR
type: string

jfrog_npm_feed_repo:
description: The 'virtual' JFrog Artifactory repository identifier for NPM package retrieval.
required: true
type: string

jfrog_nuget_feed_repo:
description: The 'virtual' JFrog Artifactory repository identifier for NuGet package retrieval.
required: true
type: string

jfrog_oidc_provider_name:
description: The OIDC Integration Provider Name to use for authentication from the GitHub Action to the JFrog instance.
required: true
type: string

node_version:
description: The node version to install such as '18.x'. It is best to stick to LTS releases of nodejs to avoid slow build times.
required: false
type: string
default: '18.x'

npm_package_json_filename:
description: Name of the 'package.json' file if not the default name.
required: false
type: string
default: package.json

npm_project_directory:
description: Location of the package.json file for the NPM package.
required: false
type: string
default: ./

npm_run_build_script_name:
description: The name of the NPM script which must be executed to build the project. Defaults to 'ci:build'.
required: false
type: string
default: 'ci:build'

npm_version:
description: 'NPM version string for package.json file.'
required: true
type: string

persisted_workspace_artifact_suffix:
description: By default, each persisted workspace artifact gets a random suffix appended to the base name. This input can be used to provide a more meaningful name suffix.
default:
type: string
required: false

outputs:

configuration:
value: ${{ inputs.configuration }}

dotnet_version:
value: ${{ inputs.dotnet_version }}

jfrog_build_name:
description: The JFrog build name for the 'dotnet-build' step is suffixed with '-dotnet-build'.
value: ${{ jobs.build.outputs.jfrog_build_name }}

node_version:
value: ${{ inputs.node_version }}

npm_package_json_filename:
value: ${{ inputs.npm_package_json_filename }}

npm_project_directory:
value: ${{ inputs.npm_project_directory }}

persisted_workspace_artifact_name:
description: Name of the artifact which contains the persisted workspace directory.
value: ${{ jobs.build.outputs.persisted_workspace_artifact_name }}

dotnet_project_directory:
value: ${{ inputs.dotnet_project_directory }}

jobs:

build:
name: Build (.NET/NPM)
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.dotnet_project_directory }}

outputs:
jfrog_build_name: ${{ env.JFROG_CLI_BUILD_NAME }}
persisted_workspace_artifact_name: ${{ steps.persist-workspace.outputs.artifact_name }}

env:
CONFIGURATION: ${{ inputs.configuration }}
DOTNET_RESTORE_VERBOSITY: ${{ inputs.dotnet_restore_verbosity }}
JFROG_API_BASE_URL: ${{ inputs.jfrog_api_base_url }}
JFROG_CLI_BUILD_NAME: "${{ inputs.jfrog_build_name }}-dotnet-npm-build"
JFROG_CLI_BUILD_NUMBER: ${{ inputs.jfrog_build_number }}
JFROG_CLI_LOG_LEVEL: ${{ inputs.jfrog_cli_log_level }}
JFROG_NPM_FEED_REPO: ${{ inputs.jfrog_npm_feed_repo }}
JFROG_NUGET_FEED_REPO: ${{ inputs.jfrog_nuget_feed_repo }}
JFROG_OIDC_PROVIDER_NAME: ${{ inputs.jfrog_oidc_provider_name }}
NPM_RUN_BUILD_SCRIPT_NAME: ${{ inputs.npm_run_build_script_name }}
NPMPACKAGEJSONFILENAME: ${{ inputs.npm_package_json_filename }}
NPMPROJECTDIRECTORY: ${{ inputs.npm_project_directory }}
NPMVERSION: ${{ inputs.npm_version }}
NUGETHASHFILES: "${{ inputs.dotnet_project_directory }}**/*.csproj"
DOTNETPROJECTDIRECTORY: ${{ inputs.dotnet_project_directory }}

steps:

- name: Validate inputs.configuration
uses: ritterim/public-github-actions/actions/[email protected]
with:
case_sensitive: false
regex_pattern: "^debug|release$"
value: ${{ env.CONFIGURATION }}

- name: Validate inputs.dotnet_project_directory
uses: ritterim/public-github-actions/actions/[email protected]
with:
path_name: ${{ env.DOTNETPROJECTDIRECTORY }}

- name: Validate inputs.jfrog_build_name
uses: ritterim/public-github-actions/actions/[email protected]
with: # This regex pattern is a bit of a guess
regex_pattern: '^[A-Za-z0-9\-]{5,55}$'
value: ${{ inputs.jfrog_build_name }}

- name: Validate inputs.jfrog_npm_feed_repo
uses: ritterim/public-github-actions/actions/[email protected]
with:
name: ${{ env.JFROG_NPM_FEED_REPO }}

- name: Validate inputs.jfrog_nuget_feed_repo
uses: ritterim/public-github-actions/actions/[email protected]
with:
name: ${{ env.JFROG_NUGET_FEED_REPO }}

- name: Validate inputs.jfrog_oidc_provider_name
uses: ritterim/public-github-actions/actions/[email protected]
with: # This regex pattern is a bit of a guess
regex_pattern: '^[A-Za-z0-9\-]{5,55}$'
value: ${{ env.JFROG_OIDC_PROVIDER_NAME }}

- name: Validate inputs.npm_package_json_filename
uses: ritterim/public-github-actions/actions/[email protected]
with:
file_name: ${{ env.NPMPACKAGEJSONFILENAME }}

- name: Validate inputs.npm_project_directory
uses: ritterim/public-github-actions/actions/[email protected]
with:
path_name: ${{ env.NPMPROJECTDIRECTORY }}

- name: Validate inputs.npm_run_build_script_name
uses: ritterim/public-github-actions/actions/[email protected]
with: # This regex pattern is a bit of a guess
regex_pattern: '^[A-Za-z0-9\-\:]{5,35}$'
value: ${{ env.NPM_RUN_BUILD_SCRIPT_NAME }}

- name: Validate inputs.npm_version
uses: ritterim/public-github-actions/actions/[email protected]
with:
version: ${{ env.NPMVERSION }}

- name: github context debug information
working-directory: ./
run: |
echo "github.base_ref=${{ github.base_ref }}"
echo "github.head_ref=${{ github.head_ref }}"
echo "github.ref=${{ github.ref }}"
echo "github.ref_name=${{ github.ref_name }}"
echo "github.repository=${{ github.repository }}"
echo "github.repository_owner=${{ github.repository_owner }}"
echo "github.run_id=${{ github.run_id }}"
echo "github.run_number=${{ github.run_number }}"
echo "github.run_attempt=${{ github.run_attempt }}"
echo "github.sha=${{ github.sha }}"
- name: Checkout Project
uses: actions/checkout@v4
with:
ref: ${{ github.ref }}

# This creates the setup-jfrog-cli-server server ID
- name: Install JFrog CLI
uses: jfrog/setup-jfrog-cli@v4
env:
JF_URL: ${{ env.JFROG_API_BASE_URL }}
with:
oidc-provider-name: ${{ env.JFROG_OIDC_PROVIDER_NAME }}

- name: jf config show
run: jf config show

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ inputs.dotnet_version }}

- name: Setup ~/.nuget/packages cache
uses: actions/cache@v4
with:
key: nuget-packages-${{ runner.os }}-${{ hashFiles(env.NUGETHASHFILES) }}
path: |
~/.nuget/packages
- run: dotnet nuget list source

- name: Remove any pre-defined NuGet sources
run: |
sources=$(dotnet nuget list source | grep '\[Enabled\]' | awk '{print $2}')
echo "$sources"
echo "$sources" | xargs -I % dotnet nuget remove source %
- run: dotnet nuget list source

- name: Configure .NET / NuGet using JFrog CLI
run: jf dotnet-config --global --server-id-resolve setup-jfrog-cli-server --repo-resolve "${JFROG_NUGET_FEED_REPO}"

- run: dotnet nuget list source

# See this for why setup-node can be slow: https://github.com/actions/setup-node/issues/726#issuecomment-1527198808
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node_version }}
cache: 'npm'
cache-dependency-path: ${{ inputs.npm_project_directory }}/${{ inputs.npm_package_json_filename }}

- name: Check NPM configuration, registry, etc.
run: |
npm config list
npm config get registry
- name: Configure NPM using JFrog CLI
run: jf npm-config --global --server-id-resolve setup-jfrog-cli-server --repo-resolve "${JFROG_NPM_FEED_REPO}"

- name: Check NPM configuration, registry, etc.
run: |
npm config list
npm config get registry
- run: git rev-parse --verify HEAD

- name: .NET Restore using JFrog CLI
run: jf dotnet restore --build-name="${JFROG_CLI_BUILD_NAME}" --build-number="${JFROG_CLI_BUILD_NUMBER}" --verbosity="${DOTNET_RESTORE_VERBOSITY}"

- name: npm version config
working-directory: ${{ env.NPMPROJECTDIRECTORY }}
run: |
npm config set allow-same-version=true
npm config set git-tag-version=false
npm config set sign-git-tag=false
# Note the use of '--ignore-scripts' here to prevent 'npm version' from running any scripts in the package.json
- run: npm version --ignore-scripts "${NPMVERSION}"
working-directory: ${{ env.NPMPROJECTDIRECTORY }}

# https://jfrog.com/help/r/artifactory-how-to-troubleshoot-long-npm-install-times-with-s3-redirect-enabled/artifactory-how-to-troubleshoot-long-npm-install-times-with-s3-redirect-enabled
# > sometimes the npm install process will appear to hang for several minutes, causing long build times for npm projects
# > Any npm configuration flag that disables the progress bar will alleviate this issue
- run: jf npm ci --npm-args="--no-progress"
working-directory: ${{ env.NPMPROJECTDIRECTORY }}

- run: jf npm run ${NPM_RUN_BUILD_SCRIPT_NAME}
working-directory: ${{ env.NPMPROJECTDIRECTORY }}

- run: ls -la
working-directory: ${{ env.NPMPROJECTDIRECTORY }}

- name: jf dotnet build
run: jf dotnet build --configuration "${CONFIGURATION}"

- run: ls -la

- name: Persist Workspace
id: persist-workspace
uses: ritterim/public-github-actions/forks/[email protected]
with:
artifact_name_suffix: ${{ inputs.persisted_workspace_artifact_suffix }}

- name: Collect JFrog Build Information
run: jf rt build-collect-env "${JFROG_CLI_BUILD_NAME}" "${JFROG_CLI_BUILD_NUMBER}"

- name: Collect JFrog 'git' Information
run: jf rt build-add-git "${JFROG_CLI_BUILD_NAME}" "${JFROG_CLI_BUILD_NUMBER}"

- name: Push JFrog Build Information
run: jf rt build-publish "${JFROG_CLI_BUILD_NAME}" "${JFROG_CLI_BUILD_NUMBER}"
Loading

0 comments on commit 99110dd

Please sign in to comment.