Skip to content

Commit

Permalink
Merge pull request #208 from JeremiahSanders/release/1.13.0
Browse files Browse the repository at this point in the history
Release/1.13.0
  • Loading branch information
JeremiahSanders authored Nov 24, 2024
2 parents e35f3cd + 1da2853 commit 0c6b4df
Show file tree
Hide file tree
Showing 152 changed files with 3,456 additions and 2,777 deletions.
497 changes: 362 additions & 135 deletions .editorconfig

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion .github/workflows/publish-prerelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:

steps:
- name: Checkout latest commit
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Execute publish script - Publish project artifacts
run: bin/cicee-exec-publish.sh
env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:

steps:
- name: Checkout latest commit
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Execute publish script - Publish project artifacts
run: bin/cicee-exec-publish.sh
env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/validate-project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:

steps:
- name: Checkout latest commit
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Execute verification script - Validate source
run: bin/cicee-exec-validate.sh
env:
Expand Down
2 changes: 1 addition & 1 deletion .project-metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "cicee",
"description": "Runs continuous integration workloads via docker-compose, locally or on a build server.",
"title": "Continuous Integration Containerized Execution Environment (CICEE)",
"version": "1.12.0",
"version": "1.13.0",
"ciEnvironment": {
"variables": [
{
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ CICEE also provides a [continuous integration shell function library][cicee-lib]

* `bash`: bash shell
* `docker`: Docker command-line interface
* `dotnet`: .NET SDK (`6.x`, `7.x`, and `8.x` supported)
* `dotnet`: .NET SDK (`6.x`, `7.x`, `8.x`, and `9.x` supported)

## Why use CICEE?

Expand Down
21 changes: 21 additions & 0 deletions ci/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,24 @@ FROM gnosian/ci-env-dotnet AS build-environment

# Add exception for known `cicee exec` mount directory. Without this, GitHub Actions fails to resolve current commit SHA (which defaults to "0000000").
RUN git config --global --add safe.directory /code

# .NET identifiers
ARG DOTNET_7_VERSION=7.0.410
ARG DOTNET_7_SHA_AMD64=20b8e02979328e4c4a14493f7791ed419aabd0175233db80cd60e2c004b829b3e8301281ea86b27ba818372473accf5a6d553e5354c54917c8e84d25f5855caa
ARG DOTNET_7_SHA_ARM64=2db6a3b9a532d2f59a2b459e634206913a9585c821f3f578a421e3bae346a92dd9b85b76ebde343ca3057275f7ec4d0bca71cbb7f2badb6dcdb516244e84da46

# Install .NET 7 SDK
# See: https://github.com/dotnet/dotnet-docker/blob/4a40f7eeecad2a3f15541fbb84962f8789d23cb0/src/sdk/7.0/bullseye-slim/amd64/Dockerfile
# https://github.com/dotnet/dotnet-docker/blob/4a40f7eeecad2a3f15541fbb84962f8789d23cb0/src/sdk/7.0/bullseye-slim/arm64v8/Dockerfile
RUN if [ "$(dpkg --print-architecture)" = "arm64" ]; then \
curl -SL --output dotnet.tar.gz https://dotnetcli.azureedge.net/dotnet/Sdk/${DOTNET_7_VERSION}/dotnet-sdk-${DOTNET_7_VERSION}-linux-arm64.tar.gz \
&& echo "${DOTNET_7_SHA_ARM64} dotnet.tar.gz" | sha512sum -c - ; \
else \
curl -SL --output dotnet.tar.gz https://dotnetcli.azureedge.net/dotnet/Sdk/${DOTNET_7_VERSION}/dotnet-sdk-${DOTNET_7_VERSION}-linux-x64.tar.gz \
&& echo "${DOTNET_7_SHA_AMD64} dotnet.tar.gz" | sha512sum -c - ; \
fi \
&& mkdir -p /usr/share/dotnet \
&& tar -oxzf dotnet.tar.gz -C /usr/share/dotnet ./packs ./sdk ./sdk-manifests ./templates ./LICENSE.txt ./ThirdPartyNotices.txt \
&& rm dotnet.tar.gz \
# Trigger first run experience by running arbitrary cmd
&& dotnet help
12 changes: 11 additions & 1 deletion ci/bin/compose.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,19 @@ declare SCRIPT_LOCATION="$(dirname "${BASH_SOURCE[0]}")"
declare PROJECT_ROOT="${PROJECT_ROOT:-$(cd "${SCRIPT_LOCATION}/../.." && pwd)}"

__initialize() {
local targetFramework="net8.0"
# Publish the application so we can work with CICEE similarly to other projects
# NOTE: Previous implementations used `dotnet run -- lib`. This stopped working.
# When using `dotnet run` the raw output to STDOUT is prefixed with invisible control characters. Those characters trigger file not found responses from `source <path>`.
# However, if the DLL is executed with `dotnet <dll>` then the output of STDOUT lacks the control characters and it can be loaded with `source`.
dotnet publish "${PROJECT_ROOT}/src" --framework "${targetFramework}"
# Load the CICEE CI action library and project CI workflow library.
# Then execute the ci-env-init, ci-env-display, and ci-env-require functions, provided by the CI action library.
source "$(dotnet run --project src --framework net7.0 -- lib)" &&
local ciLibPath="$(dotnet "${PROJECT_ROOT}/src/bin/Release/${targetFramework}/publish/cicee.dll" lib)"

printf "Loading CI library entry point: %s\n" "${ciLibPath}" &&
source "${ciLibPath}" &&
printf "Loading CI workflows: %s\n\n" "${PROJECT_ROOT}/ci/libexec/ci-workflows.sh" &&
source "${PROJECT_ROOT}/ci/libexec/ci-workflows.sh" &&
ci-env-init &&
ci-env-display &&
Expand Down
12 changes: 11 additions & 1 deletion ci/bin/publish.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,19 @@ declare SCRIPT_LOCATION="$(dirname "${BASH_SOURCE[0]}")"
declare PROJECT_ROOT="${PROJECT_ROOT:-$(cd "${SCRIPT_LOCATION}/../.." && pwd)}"

__initialize() {
local targetFramework="net8.0"
# Publish the application so we can work with CICEE similarly to other projects
# NOTE: Previous implementations used `dotnet run -- lib`. This stopped working.
# When using `dotnet run` the raw output to STDOUT is prefixed with invisible control characters. Those characters trigger file not found responses from `source <path>`.
# However, if the DLL is executed with `dotnet <dll>` then the output of STDOUT lacks the control characters and it can be loaded with `source`.
dotnet publish "${PROJECT_ROOT}/src" --framework "${targetFramework}"
# Load the CICEE CI action library and project CI workflow library.
# Then execute the ci-env-init, ci-env-display, and ci-env-require functions, provided by the CI action library.
source "$(dotnet run --project src --framework net7.0 -- lib)" &&
local ciLibPath="$(dotnet "${PROJECT_ROOT}/src/bin/Release/${targetFramework}/publish/cicee.dll" lib)"

printf "Loading CI library entry point: %s\n" "${ciLibPath}" &&
source "${ciLibPath}" &&
printf "Loading CI workflows: %s\n\n" "${PROJECT_ROOT}/ci/libexec/ci-workflows.sh" &&
source "${PROJECT_ROOT}/ci/libexec/ci-workflows.sh" &&
ci-env-init &&
ci-env-display &&
Expand Down
12 changes: 11 additions & 1 deletion ci/bin/validate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,19 @@ declare SCRIPT_LOCATION="$(dirname "${BASH_SOURCE[0]}")"
declare PROJECT_ROOT="${PROJECT_ROOT:-$(cd "${SCRIPT_LOCATION}/../.." && pwd)}"

__initialize() {
local targetFramework="net8.0"
# Publish the application so we can work with CICEE similarly to other projects
# NOTE: Previous implementations used `dotnet run -- lib`. This stopped working.
# When using `dotnet run` the raw output to STDOUT is prefixed with invisible control characters. Those characters trigger file not found responses from `source <path>`.
# However, if the DLL is executed with `dotnet <dll>` then the output of STDOUT lacks the control characters and it can be loaded with `source`.
dotnet publish "${PROJECT_ROOT}/src" --framework "${targetFramework}"
# Load the CICEE CI action library and project CI workflow library.
# Then execute the ci-env-init, ci-env-display, and ci-env-require functions, provided by the CI action library.
source "$(dotnet run --project src --framework net7.0 -- lib)" &&
local ciLibPath="$(dotnet "${PROJECT_ROOT}/src/bin/Release/${targetFramework}/publish/cicee.dll" lib)"

printf "Loading CI library entry point: %s\n" "${ciLibPath}" &&
source "${ciLibPath}" &&
printf "Loading CI workflows: %s\n\n" "${PROJECT_ROOT}/ci/libexec/ci-workflows.sh" &&
source "${PROJECT_ROOT}/ci/libexec/ci-workflows.sh" &&
ci-env-init &&
ci-env-display &&
Expand Down
2 changes: 0 additions & 2 deletions ci/docker-compose.dependencies.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: "3.7"

##
# Project-specific CI environment dependencies
##
Expand Down
2 changes: 0 additions & 2 deletions ci/docker-compose.project.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: "3.7"

##
# Project-specific CI environment extensions
##
Expand Down
13 changes: 12 additions & 1 deletion ci/libexec/ci-workflows.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ ci-validate() {
# Compose the project's artifacts, e.g., compiled binaries, Docker images.
#--
ci-compose() {
printf "\nBeginning 'dotnet restore'...\n\n" &&
rm -rfv \
"${PROJECT_ROOT}/build" &&
printf "\n\nBuild artifacts cleaned.\n\n\n" &&
printf "\nBeginning 'dotnet restore'...\n\n" &&
ci-dotnet-restore &&
printf "\nBeginning 'dotnet publish' targeting .NET 6...\n\n" &&
dotnet publish "${PROJECT_ROOT}/src" \
Expand All @@ -76,6 +79,14 @@ ci-compose() {
--framework net8.0 \
-p:GenerateDocumentationFile=true &&
printf "\nCompleted 'dotnet publish' targeting .NET 8.\n\n" &&
printf "\nBeginning 'dotnet publish' targeting .NET 9...\n\n" &&
dotnet publish "${PROJECT_ROOT}/src" \
--configuration Release \
--output "${BUILD_UNPACKAGED_DIST}/net9.0" \
-p:Version="${PROJECT_VERSION_DIST}" \
--framework net9.0 \
-p:GenerateDocumentationFile=true &&
printf "\nCompleted 'dotnet publish' targeting .NET 9.\n\n" &&
printf "\nBeginning 'dotnet pack'...\n\n" &&
ci-dotnet-pack -p:GenerateDocumentationFile=true &&
printf "\nCompleted 'dotnet pack'.\n\n"
Expand Down
17 changes: 8 additions & 9 deletions src/CiEnv/Conventions.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
namespace Cicee.CiEnv
namespace Cicee.CiEnv;

public static class Conventions
{
public static class Conventions
{
public const string CiDirectoryName = "ci";
public const string CiBinDirectoryName = "bin";
public const string CiLibDirectoryName = "lib";
public const string CiLibExecDirectoryName = "libexec";
public const string CiLibExecWorkflowsDirectoryName = "workflows";
}
public const string CiDirectoryName = "ci";
public const string CiBinDirectoryName = "bin";
public const string CiLibDirectoryName = "lib";
public const string CiLibExecDirectoryName = "libexec";
public const string CiLibExecWorkflowsDirectoryName = "workflows";
}
36 changes: 17 additions & 19 deletions src/CiEnv/ProjectContinuousIntegrationEnvironmentDefinition.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
using System;
using System.Linq;

namespace Cicee.CiEnv
namespace Cicee.CiEnv;

public record ProjectContinuousIntegrationEnvironmentDefinition
{
public record ProjectContinuousIntegrationEnvironmentDefinition
{
public ProjectEnvironmentVariable[] Variables { get; init; } =
Array.Empty<ProjectEnvironmentVariable>();
public ProjectEnvironmentVariable[] Variables { get; init; } = Array.Empty<ProjectEnvironmentVariable>();

public virtual bool Equals(ProjectContinuousIntegrationEnvironmentDefinition? other)
public virtual bool Equals(ProjectContinuousIntegrationEnvironmentDefinition? other)
{
if (ReferenceEquals(objA: null, other))
{
if (ReferenceEquals(objA: null, other))
{
return false;
}

if (ReferenceEquals(objA: this, other))
{
return true;
}

return Variables.SequenceEqual(other.Variables);
return false;
}

public override int GetHashCode()
if (ReferenceEquals(this, other))
{
return Variables.GetHashCode();
return true;
}

return Variables.SequenceEqual(other.Variables);
}

public override int GetHashCode()
{
return Variables.GetHashCode();
}
}
79 changes: 36 additions & 43 deletions src/CiEnv/ProjectEnvironmentHelpers.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;

using Cicee.Commands;

using LanguageExt;
using LanguageExt.Common;

Expand All @@ -12,44 +14,34 @@ public static class ProjectEnvironmentHelpers
internal const string SecretString = "***redacted***";

public static IReadOnlyDictionary<ProjectEnvironmentVariable, string> GetEnvironmentDisplay(
Func<IReadOnlyDictionary<string, string>> getEnvironmentVariables,
ProjectMetadata projectMetadata
)
Func<IReadOnlyDictionary<string, string>> getEnvironmentVariables, ProjectMetadata projectMetadata)
{
var knownEnvironment = getEnvironmentVariables();
IReadOnlyDictionary<string, string> knownEnvironment = getEnvironmentVariables();

return projectMetadata.CiEnvironment.Variables.ToDictionary(variable => variable, GetVariableValue);

string GetVariableValue(ProjectEnvironmentVariable variable)
{
var possibleValue = knownEnvironment.FirstOrDefault(kvp =>
kvp.Key.Equals(variable.Name, StringComparison.InvariantCultureIgnoreCase)
KeyValuePair<string, string> possibleValue = knownEnvironment.FirstOrDefault(
kvp => kvp.Key.Equals(variable.Name, StringComparison.InvariantCultureIgnoreCase)
);
var hasValue = !default(KeyValuePair<string, string>).Equals(possibleValue);
return hasValue
? variable.Secret ? SecretString : possibleValue.Value
: string.Empty;
bool hasValue = !default(KeyValuePair<string, string>).Equals(possibleValue);
return hasValue ? variable.Secret ? SecretString : possibleValue.Value : string.Empty;
}

return projectMetadata.CiEnvironment.Variables.ToDictionary(variable => variable, GetVariableValue);
}

public static Result<ProjectMetadata> ValidateEnvironment(
Func<IReadOnlyDictionary<string, string>> getEnvironmentVariables,
ProjectMetadata projectMetadata
)
Func<IReadOnlyDictionary<string, string>> getEnvironmentVariables, ProjectMetadata projectMetadata)
{
var knownEnvironment = getEnvironmentVariables();
var knownVariables = knownEnvironment.Keys.ToArray();
var missingVariables = projectMetadata.CiEnvironment.Variables
IReadOnlyDictionary<string, string> knownEnvironment = getEnvironmentVariables();
string[] knownVariables = knownEnvironment.Keys.ToArray();
string[] missingVariables = projectMetadata.CiEnvironment.Variables
.Where(envVariable => envVariable.Required && !knownVariables.Contains(envVariable.Name))
.Select(envVariable => envVariable.Name)
.OrderBy(Prelude.identity)
.ToArray();
.Select(envVariable => envVariable.Name).OrderBy(Prelude.identity).ToArray();

return missingVariables.Any()
? new Result<ProjectMetadata>(
new BadRequestException(
$"Missing environment variables: {string.Join(", ", missingVariables)}"
)
new BadRequestException($"Missing environment variables: {string.Join(separator: ", ", missingVariables)}")
)
: new Result<ProjectMetadata>(projectMetadata);
}
Expand All @@ -58,36 +50,37 @@ public static void DisplayProjectEnvironmentValues(Action<string> standardOutWri
Action<ConsoleColor?, string> standardOutWrite,
IReadOnlyDictionary<ProjectEnvironmentVariable, string> environmentVariableDisplayValues)
{
standardOutWriteLine(obj: "CI Environment:");
if (environmentVariableDisplayValues.Any())
{
WriteEnvironmentVariables(environmentVariableDisplayValues);
}
else
{
standardOutWriteLine(obj: " No CI environment variables defined.");
}

return;

void WriteEnvironmentVariables(IReadOnlyDictionary<ProjectEnvironmentVariable, string> environmentDisplay)
{
var width = environmentDisplay.Keys.Max(value => value.Name.Length) + 1;
foreach (var (key, value) in environmentDisplay.OrderBy(kvp => kvp.Key.Name))
int width = environmentDisplay.Keys.Max(value => value.Name.Length) + 1;
foreach ((ProjectEnvironmentVariable key, string value) in environmentDisplay.OrderBy(kvp => kvp.Key.Name))
{
var isPopulated = value != string.Empty;
bool isPopulated = value != string.Empty;
ConsoleColor? nameColor = key.Required && !isPopulated ? ConsoleColor.Red : null;
ConsoleColor? valueColor = key.Secret && isPopulated ? ConsoleColor.Yellow
: isPopulated ? ConsoleColor.Blue
: ConsoleColor.DarkGray;
var valueOrDefault = isPopulated || string.IsNullOrWhiteSpace(key.DefaultValue)
ConsoleColor? valueColor = key.Secret && isPopulated ? ConsoleColor.Yellow :
isPopulated ? ConsoleColor.Blue : ConsoleColor.DarkGray;
string valueOrDefault = isPopulated || string.IsNullOrWhiteSpace(key.DefaultValue)
? value // When the value is populated or no default exists, display value.
// If there is a default, but no value, and it's a secret, show the secret placeholder, else the default.
: $"<{(key.Secret ? SecretString : key.DefaultValue)}>";

standardOutWrite(nameColor, $" {key.Name.PadRight(width, paddingChar: ' ')}");
standardOutWrite(arg1: null, ": ");
standardOutWrite(arg1: null, arg2: ": ");
standardOutWrite(valueColor, valueOrDefault);
standardOutWrite(arg1: null, Environment.NewLine);
}
}

standardOutWriteLine("CI Environment:");
if (environmentVariableDisplayValues.Any())
{
WriteEnvironmentVariables(environmentVariableDisplayValues);
}
else
{
standardOutWriteLine(" No CI environment variables defined.");
}
}
}
Loading

0 comments on commit 0c6b4df

Please sign in to comment.