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

Additional options for running the standardised build process #50

Merged
merged 22 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
db547c4
Initial version of scripted build workflow run within a single job
JamesDawson Sep 6, 2024
96f5e52
Make 'buildTasks' parameter not required
JamesDawson Sep 6, 2024
bdbfc81
Remove redundant inputs
JamesDawson Sep 6, 2024
24d5fa7
Remove permission demands
JamesDawson Sep 6, 2024
0299d3d
Remove redundant caching-related inputs
JamesDawson Sep 6, 2024
0cf34a4
Fix broken ternary expression
JamesDawson Sep 6, 2024
4fd1f6d
Updated README
JamesDawson Sep 6, 2024
a5fd7e2
Add CI validation for new single job workflow
JamesDawson Sep 6, 2024
7ae5193
Update 'run-scripted-build' composite action to suppress cache-relate…
JamesDawson Sep 6, 2024
250fa9e
Add composite action as an alternative option for running the build p…
JamesDawson Sep 7, 2024
f69ac00
Add checkout step to workflow that tests the build process composite …
JamesDawson Sep 7, 2024
6336a9c
Switch references to secrets and vars to inputs
JamesDawson Sep 7, 2024
6f6256b
Remove lowercase
JamesDawson Sep 7, 2024
dd678de
Add 'prepare-env-vars-and-secrets' to ci-composite-action - the value…
JamesDawson Sep 7, 2024
cdd6a5e
Fixed referenced outputs
JamesDawson Sep 9, 2024
ff894fa
Updated README
JamesDawson Sep 9, 2024
fd8ba0f
Refactor 'scripted-build-single-job-workflow' to use 'run-build-proce…
JamesDawson Sep 9, 2024
29cf75f
Update triggers on validation workflows
JamesDawson Sep 9, 2024
3aa0f08
Test reference actions via local path in reusable workflow
JamesDawson Sep 9, 2024
01514cc
Revert "Test reference actions via local path in reusable workflow"
JamesDawson Sep 9, 2024
226f788
Updated README
JamesDawson Sep 9, 2024
0abdd4b
Switch branch references ahead of merge
JamesDawson Sep 9, 2024
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
62 changes: 62 additions & 0 deletions .github/workflows/ci-composite-action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: ci-compositie-action
on:
pull_request:
branches:
- main
paths:
- .github/workflows/ci-composite-action.yml
- actions/**
workflow_dispatch:
inputs:
forcePublish:
description: When true the Publish stage will always be run, otherwise it only runs for tagged versions.
required: false
default: false
type: boolean

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
actions: write # enable cache clean-up
checks: write # enable test result annotations
contents: write # enable creating releases
issues: read
packages: write # enable publishing packages
pull-requests: write # enable test result annotations

jobs:
build:
name: Build
runs-on: ubuntu-latest
outputs:
semver: ${{ steps.run_build.outputs.semver }}
major: ${{ steps.run_build.outputs.major }}
majorMinor: ${{ steps.run_build.outputs.majorMinor }}
preReleaseTag: ${{ steps.run_build.outputs.preReleaseTag }}

steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
with:
fetch-depth: 0
- uses: ./actions/prepare-env-vars-and-secrets
id: prepareEnvVarsAndSecrets
with:
environmentVariablesYaml: |
BUILDVAR_NuGetPublishSource: "${{ startsWith(github.ref, 'refs/tags/') && 'https://api.nuget.org/v3/index.json' || 'https://nuget.pkg.github.com/endjin/index.json' }}"
secretsYaml: |
NUGET_API_KEY: "${{ startsWith(github.ref, 'refs/tags/') && secrets.ENDJIN_NUGET_APIKEY || secrets.ENDJIN_GITHUB_PUBLISHER_PAT }}"
SBOM_ANALYSIS_RELEASE_READER_PAT: "${{ secrets.ENDJIN_GITHUB_READER_PAT }}"
- uses: ./actions/run-build-process
id: run_build
with:
netSdkVersion: '8.x'
# workflow_dispatch inputs are always strings, the type property is just for the UI
forcePublish: ${{ github.event.inputs.forcePublish == 'true' }}
sbomOutputStorageAccountName: ${{ vars.SBOM_OUTPUT_STORAGE_ACCOUNT_NAME }}
sbomOutputStorageContainerName: ${{ vars.SBOM_OUTPUT_STORAGE_CONTAINER_NAME }}
buildEnv: ${{ steps.prepareEnvVarsAndSecrets.outputs.environmentVariablesYamlBase64}}
buildSecrets: ${{ steps.prepareEnvVarsAndSecrets.outputs.secretsYamlBase64 }}
token: ${{ secrets.GITHUB_TOKEN }}

4 changes: 4 additions & 0 deletions .github/workflows/ci-matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ on:
pull_request:
branches:
- main
paths:
- .github/workflows/ci-matrix.yml
- .github/workflows/scripted-build-matrix-pipeline.yml
- actions/**
workflow_dispatch:
inputs:
forcePublish:
Expand Down
62 changes: 62 additions & 0 deletions .github/workflows/ci-single-job.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: ci-single-job
on:
pull_request:
branches:
- main
paths:
- .github/workflows/ci-single-job.yml
- .github/workflows/scripted-build-single-job-pipeline.yml
- actions/**
workflow_dispatch:
inputs:
forcePublish:
description: When true the Publish stage will always be run, otherwise it only runs for tagged versions.
required: false
default: false
type: boolean

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
actions: write # enable cache clean-up
checks: write # enable test result annotations
contents: write # enable creating releases
issues: read
packages: write # enable publishing packages
pull-requests: write # enable test result annotations

jobs:
prepareConfig:
name: Prepare Configuration
runs-on: ubuntu-latest
outputs:
RESOLVED_ENV_VARS: ${{ steps.prepareEnvVarsAndSecrets.outputs.environmentVariablesYamlBase64 }}
RESOLVED_SECRETS: ${{ steps.prepareEnvVarsAndSecrets.outputs.secretsYamlBase64 }}
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
fetch-depth: 0

# Declare any environment variables and/or secrets that need to be available inside the build process
- uses: ./actions/prepare-env-vars-and-secrets
id: prepareEnvVarsAndSecrets
with:
environmentVariablesYaml: |
BUILDVAR_NuGetPublishSource: "${{ startsWith(github.ref, 'refs/tags/') && 'https://api.nuget.org/v3/index.json' || 'https://nuget.pkg.github.com/endjin/index.json' }}"
secretsYaml: |
NUGET_API_KEY: "${{ startsWith(github.ref, 'refs/tags/') && secrets.ENDJIN_NUGET_APIKEY || secrets.ENDJIN_GITHUB_PUBLISHER_PAT }}"
SBOM_ANALYSIS_RELEASE_READER_PAT: "${{ secrets.ENDJIN_GITHUB_READER_PAT }}"

build:
needs: prepareConfig
uses: ./.github/workflows/scripted-build-single-job-pipeline.yml
with:
netSdkVersion: '8.x'
# workflow_dispatch inputs are always strings, the type property is just for the UI
forcePublish: ${{ github.event.inputs.forcePublish == 'true' }}
buildEnv: ${{ needs.prepareConfig.outputs.RESOLVED_ENV_VARS }}
secrets:
buildAzureCredentials: ${{ secrets.ENDJIN_PROD_ACR_READER_CREDENTIALS }}
buildSecrets: ${{ needs.prepareConfig.outputs.RESOLVED_SECRETS }}
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ on:
pull_request:
branches:
- main
paths:
- .github/workflows/ci.yml
- .github/workflows/scripted-build-pipeline.yml
- actions/**
workflow_dispatch:
inputs:
forcePublish:
Expand Down
94 changes: 94 additions & 0 deletions .github/workflows/scripted-build-single-job-pipeline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
on:
workflow_call:
inputs:
netSdkVersion:
description: The primary .NET SDK version required for the build process, as per the syntax required by the 'setup-dotnet' action.
required: true
type: string
default: '8.0.x'
additionalNetSdkVersion:
description: An additional .NET SDK version required for the build process, as per the syntax required by the 'setup-dotnet' action.
required: false
type: string
pythonVersion:
description: Specify an additional Python version required for the build process
required: false
type: string
configuration:
description: The target build configuration.
required: false
default: 'Release'
type: string
buildEnv:
description: A JSON object representing the environment variables required when running the build script.
required: false
type: string
buildArtifactName:
description: If set, during the test phase, uploads a GitHub artifact with the provided name (path must be specified in `artifactPath`)
required: false
type: string
buildArtifactPath:
description: If set, during the test phase, uploads a GitHub artifact with the provided path (name must be specified in `artifactName`). The path can be a file, directory or wildcard pattern; multiple paths can be specified using newline demiliter.
required: false
type: string
forcePublish:
description: When true, the Publish stage will be run regardless of the current branch or tag.
required: false
default: false
type: boolean
buildScriptPath:
description: The path to the build script to run.
required: false
default: ./build.ps1
type: string
buildTasks:
description: The tasks that need to be run as part of the build process, formatted as a comma-delimited string (e.g. 'FullBuild' or 'Build,Test').
required: false
default: ''
type: string
runsOn:
description: The operating system to run all stages of this workflow.
required: false
default: ubuntu-latest
type: string

secrets:
buildAzureCredentials:
required: false
buildSecrets:
description: A YAML string representing a dictionary of secrets required when running the 'compile' stage of this workflow.
required: false

jobs:
build:
name: Build
runs-on: ${{ inputs.runsOn }}
outputs:
semver: ${{ steps.run_build.outputs.semver }}
major: ${{ steps.run_build.outputs.major }}
majorMinor: ${{ steps.run_build.outputs.majorMinor }}
preReleaseTag: ${{ steps.run_build.outputs.preReleaseTag }}

steps:
- uses: endjin/Endjin.RecommendedPractices.GitHubActions/actions/run-build-process@main
id: run_build
with:
netSdkVersion: ${{ inputs.netSdkVersion }}
additionalNetSdkVersion: ${{ inputs.additionalNetSdkVersion }}
buildArtifactName: ${{ inputs.buildArtifactName }}
buildArtifactPath: ${{ inputs.buildArtifactPath }}
buildScriptPath: ${{ inputs.buildScriptPath }}
buildTasks: ${{ inputs.buildTasks }}
codeCoverageSummaryDir: ${{ vars.CODE_COVERAGE_SUMMARY_DIR || '_codeCoverage' }}
codeCoverageSummaryFile: ${{ vars.CODE_COVERAGE_SUMMARY_FILE || 'SummaryGithub.md' }}
configuration: ${{ inputs.configuration }}
pythonVersion: ${{ inputs.pythonVersion }}
runsOn: ${{ inputs.runsOn }}
# workflow_dispatch inputs are always strings, the type property is just for the UI
forcePublish: ${{ github.event.inputs.forcePublish == 'true' }}
sbomOutputStorageAccountName: ${{ vars.SBOM_OUTPUT_STORAGE_ACCOUNT_NAME }}
sbomOutputStorageContainerName: ${{ vars.SBOM_OUTPUT_STORAGE_CONTAINER_NAME }}
buildEnv: ${{ inputs.buildEnv }}
buildSecrets: ${{ secrets.buildSecrets }}
buildAzureCredentials: ${{ secrets.buildAzureCredentials }}
token: ${{ secrets.GITHUB_TOKEN }}
98 changes: 85 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,104 @@

This repository contains [re-usable GitHub Action workflows](https://docs.github.com/en/actions/using-workflows/reusing-workflows) and [composite actions](https://docs.github.com/en/actions/creating-actions/creating-a-composite-action) for our standardised CI processes.

Our standardised build process is divided into the following phases:
- Compile
- Test
- Analyse
- Package
- Publish

By default, the 'Publish' phase is only executed for tagged versions or when manually triggered with the 'Force Publish' option enabled.

> ***USAGE TIP**: For smaller/less complex repositories, you will likely get the quickest build times by using the `run-build-process` composite action, an example of how to consume this in your repo's `build.yml` can be found [here](.github/workflows/ci-composite-action.yml)*.

## Reusable Workflows

### Multi-Job Workflows
These run the logical phases of the build process using discrete jobs, which can be beneficial for large builds due to the parallelisation when running tests and building packages.

- `scripted-build-pipeline` - encapsulates our standard CI build process, using separate jobs for Compile, Test, Package & Publish phases
- `scripted-build-matrix-pipeline` - as above, except the Test phase includes [matrix](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/running-variations-of-jobs-in-a-workflow) support

The diagram below shows the high-level process that the non-matrix multi-job workflow implements:

```mermaid
graph LR
compile["Compile"]-->analyse["Code Analysis"]
analyse-->test["Run Tests"]
test-->pubtests["Publish Test Results"]
analyse-->package["Build Packages"]
pubtests-->publish["Publish Packages"]
package-->publish
```

The diagram below illustrates the different high-level process for the matrix-enabled version of the multi-job workflow:

```mermaid
graph LR
compile["Compile"]-->analyse["Code Analysis"]
analyse-->test1["Run Tests (matrix 1)"]
analyse-->test2["Run Tests (matrix 2)"]
test1-->pubtests["Publish Test Results"]
test2-->pubtests["Publish Test Results"]
analyse-->package["Build Packages"]
pubtests-->publish["Publish Packages"]
package-->publish
```


### Single-Job Workflow
This runs the logical phases of the build process as a single job, closely mimicking the local developer build.

***NOTE**: A consuming build will still require a second job in order to support passing arbitrary environment variables and secrets to this workflow. See the [example](.github/workflows/ci-single-job.yml) for more details.*

- `scripted-build-single-job-pipeline` - encapsulates our standard CI build process, using a single job

This diagram shows the default sequence of the build process implemented by the single-job workflow implement (NOTE: This can altered by overriding the `buildTasks` input parameter):

```mermaid
graph LR
compile["Compile"]-->test["Run Tests"]
test-->analyse["Code Analysis"]
analyse-->package["Build Packages"]
package-->publish["Publish Packages"]
publish-->pubtests["Publish Test Results"]
```


## Composite Actions

### Orchestration Composite Actions
This are used as alternatives to reusable workflows to encapsulate complete processes.

- `run-build-process` - provides an alternative to using the reusable workflows and encapsulates the complete build process. This allows the consuming CI build to be run a single job, with the trade-off of requiring somewhat more boilerplate.

The `run-build-process` action implements the same logical build process as the [Single-Job Workflow](#single-job-workflows) (NOTE: This can altered by overriding the `buildTasks` input parameter)

```mermaid
graph LR
compile["Compile"]-->test["Run Tests"]
test-->analyse["Code Analysis"]
analyse-->package["Build Packages"]
package-->publish["Publish Packages"]
publish-->pubtests["Publish Test Results"]
```


### Feature Composite Actions
These composite actions are used to encapsulated specific functionality so it can be easily re-used between workflows.

- `prepare-env-vars-and-secrets` - provides a workaround for not natively being able to pass arbitrary environment variables and secrets to a reusable workflow. Based on assembling the required values into 2 well-known variables that act as containers for the variables and secrets that need to be passed.
- `run-scripted-build` - encapsulates the steps for executing our [PowerShell-based build tooling](https://www.powershellgallery.com/packages/Endjin.RecommendedPractices.Build) - typically used via one of the above reusable workflows.
- `set-env-vars-and-secrets` - the consuming side of the workaround for passing arbitrary environment variables and secrets. Unwraps the bundled environment variables and secrets so they are available to the running workflow.

## Examples

The following serve as examples of using the reusable workflows found in this repo:
The following workflows serve as examples of how to consume the different reusable workflows and composite actions found in this repo:

- [ci.yml](.github/workflows/ci.yml) - used for validating changes to the `scripted-build-pipeline` reusable workflow
- [ci-matrix.yml](.github/workflows/ci-matrix.yml) - used for validating changes to the `scripted-build-matrix-pipeline` reusable workflow
- [ci-single-job.yml](.github/workflows/ci-single-job.yml) - used for validating changes to the `scripted-build-single-job-pipeline` reusable workflow
- [ci-composite-action](.github/workflows/ci-composite-action.yml) - used for validating change to the `run-build-process` composite action

## CI Build Process Overview

The diagram below illustrates the high-level process that workflows implementing our standard CI build use:

```mermaid
graph LR
compile["Compile"]-->analyse["Code Analysis"]
analyse-->test["Run Tests"]
test-->pubtests["Publish Test Results"]
analyse-->package["Build Packages"]
pubtests-->publish["Publish Packages"]
package-->publish
```
Loading
Loading