diff --git a/.editorconfig b/.editorconfig
index dece05a..667d8fb 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,13 +1,24 @@
-# top-most EditorConfig file
+# Remove the line below if you want to inherit .editorconfig settings from higher directories
root = true
-# Don't use tabs for indentation.
+#### Core EditorConfig Options ####
[*]
+
+# Global indentation
indent_style = space
+
+# New line preferences
+end_of_line = crlf
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+# Guidelines
guidelines = 100
-# (Please don't specify an indent_size here; that has too many unintended consequences.)
+guidelines_style = 2.5px solid 40ff0000
+# Indentation
# Code files
+
[*.{cs,csx,vb,vbx}]
indent_size = 4
@@ -23,54 +34,264 @@ indent_size = 2
[*.json]
indent_size = 2
-# Dotnet code style settings:
-[*.{cs,vb}]
-# Sort using and Import directives with System.* appearing first
-dotnet_sort_system_directives_first = true
-# Avoid "this." and "Me." if not necessary
-dotnet_style_qualification_for_field = false:suggestion
-dotnet_style_qualification_for_property = false:suggestion
-dotnet_style_qualification_for_method = false:suggestion
-dotnet_style_qualification_for_event = false:suggestion
-
-# Use language keywords instead of framework type names for type references
-dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
-dotnet_style_predefined_type_for_member_access = true:suggestion
-
-# Suggest more modern language features when available
-dotnet_style_object_initializer = true:suggestion
-dotnet_style_collection_initializer = true:suggestion
-dotnet_style_coalesce_expression = true:suggestion
-dotnet_style_null_propagation = true:suggestion
-dotnet_style_explicit_tuple_names = true:suggestion
-
-# CSharp code style settings:
+#### Genereated Code flags ####
+[src/Ops.DataProvider.SqlServer.Ops/Migrations/*]
+generated_code = true
+
+[src/Ops.DataProvider.SqlServer.Promenade/Migrations/*]
+generated_code = true
+
+#### .NET Code Actions ####
[*.cs]
-# Prefer `var` where obvious
-csharp_style_var_when_type_is_apparent = true:suggestion
-
-# Prefer method-like constructs to have a block body
-csharp_style_expression_bodied_methods = false:none
-csharp_style_expression_bodied_constructors = false:none
-csharp_style_expression_bodied_operators = false:none
-
-# Prefer property-like constructs to have an expression-body
-csharp_style_expression_bodied_properties = true:none
-csharp_style_expression_bodied_indexers = true:none
-csharp_style_expression_bodied_accessors = true:none
-
-# Suggest more modern language features when available
-csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
-csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
-csharp_style_inlined_variable_declaration = true:suggestion
-csharp_style_throw_expression = true:suggestion
-csharp_style_conditional_delegate_call = true:suggestion
-
-# Newline settings
-csharp_new_line_before_open_brace = all
-csharp_new_line_before_else = true
+
+# Type members
+dotnet_hide_advanced_members = false
+dotnet_member_insertion_location = with_other_members_of_the_same_kind
+dotnet_property_generation_behavior = prefer_throwing_properties
+
+# Symbol search
+dotnet_search_reference_assemblies = true
+
+#### .NET Coding Conventions ####
+
+# Organize usings
+dotnet_separate_import_directive_groups = false
+dotnet_sort_system_directives_first = true
+file_header_template = unset
+
+# this. and Me. preferences
+dotnet_style_qualification_for_event = false
+dotnet_style_qualification_for_field = false
+dotnet_style_qualification_for_method = false
+dotnet_style_qualification_for_property = false
+
+# Language keywords vs BCL types preferences
+dotnet_style_predefined_type_for_locals_parameters_members = true
+dotnet_style_predefined_type_for_member_access = true
+
+# Parentheses preferences
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
+
+# Modifier preferences
+dotnet_style_require_accessibility_modifiers = for_non_interface_members
+
+# Expression-level preferences
+dotnet_prefer_system_hash_code = true
+dotnet_style_coalesce_expression = true
+dotnet_style_collection_initializer = true
+dotnet_style_explicit_tuple_names = true
+dotnet_style_namespace_match_folder = true
+dotnet_style_null_propagation = true
+dotnet_style_object_initializer = true
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+dotnet_style_prefer_auto_properties = true
+dotnet_style_prefer_collection_expression = when_types_loosely_match
+dotnet_style_prefer_compound_assignment = true
+dotnet_style_prefer_conditional_expression_over_assignment = true
+dotnet_style_prefer_conditional_expression_over_return = true
+dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed
+dotnet_style_prefer_inferred_anonymous_type_member_names = true
+dotnet_style_prefer_inferred_tuple_names = true
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true
+dotnet_style_prefer_non_hidden_explicit_cast_in_source = true
+dotnet_style_prefer_simplified_boolean_expressions = true
+dotnet_style_prefer_simplified_interpolation = true
+
+# Field preferences
+dotnet_style_readonly_field = true
+
+# Parameter preferences
+dotnet_code_quality_unused_parameters = all
+
+# Suppression preferences
+dotnet_remove_unnecessary_suppression_exclusions = none
+
+# New line preferences
+dotnet_style_allow_multiple_blank_lines_experimental = true
+dotnet_style_allow_statement_immediately_after_block_experimental = true
+
+#### C# Coding Conventions ####
+
+# var preferences
+csharp_style_var_elsewhere = false
+csharp_style_var_for_built_in_types = false
+csharp_style_var_when_type_is_apparent = true
+
+# Expression-bodied members
+csharp_style_expression_bodied_accessors = true
+csharp_style_expression_bodied_constructors = false
+csharp_style_expression_bodied_indexers = true
+csharp_style_expression_bodied_lambdas = true
+csharp_style_expression_bodied_local_functions = false
+csharp_style_expression_bodied_methods = false
+csharp_style_expression_bodied_operators = false
+csharp_style_expression_bodied_properties = true
+
+# Pattern matching preferences
+csharp_style_pattern_matching_over_as_with_null_check = true
+csharp_style_pattern_matching_over_is_with_cast_check = true
+csharp_style_prefer_extended_property_pattern = true
+csharp_style_prefer_not_pattern = true
+csharp_style_prefer_pattern_matching = true
+csharp_style_prefer_switch_expression = true
+
+# Null-checking preferences
+csharp_style_conditional_delegate_call = true
+
+# Modifier preferences
+csharp_prefer_static_anonymous_function = true
+csharp_prefer_static_local_function = true
+csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async
+csharp_style_prefer_readonly_struct = true
+csharp_style_prefer_readonly_struct_member = true
+
+# Code-block preferences
+csharp_prefer_braces = true
+csharp_prefer_simple_using_statement = true
+csharp_prefer_system_threading_lock = true
+csharp_style_namespace_declarations = block_scoped
+csharp_style_prefer_method_group_conversion = true
+csharp_style_prefer_primary_constructors = true
+csharp_style_prefer_simple_property_accessors = true
+csharp_style_prefer_top_level_statements = true
+
+# Expression-level preferences
+csharp_prefer_simple_default_expression = true
+csharp_style_deconstructed_variable_declaration = true
+csharp_style_implicit_object_creation_when_type_is_apparent = true
+csharp_style_inlined_variable_declaration = true
+csharp_style_prefer_implicitly_typed_lambda_expression = true
+csharp_style_prefer_index_operator = true
+csharp_style_prefer_local_over_anonymous_function = true
+csharp_style_prefer_null_check_over_type_check = true
+csharp_style_prefer_range_operator = true
+csharp_style_prefer_tuple_swap = true
+csharp_style_prefer_unbound_generic_type_in_nameof = true
+csharp_style_prefer_utf8_string_literals = true
+csharp_style_throw_expression = true
+csharp_style_unused_value_assignment_preference = discard_variable
+csharp_style_unused_value_expression_statement_preference = discard_variable
+
+# 'using' directive preferences
+csharp_using_directive_placement = outside_namespace
+
+# New line preferences
+csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
+csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true
+csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true
+csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true
+csharp_style_allow_embedded_statements_on_same_line_experimental = true
+
+#### C# Formatting Rules ####
+
+# New line preferences
csharp_new_line_before_catch = true
+csharp_new_line_before_else = true
csharp_new_line_before_finally = true
-csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
-insert_final_newline=true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_open_brace = all
+csharp_new_line_between_query_expression_clauses = true
+
+# Indentation preferences
+csharp_indent_block_contents = true
+csharp_indent_braces = false
+csharp_indent_case_contents = true
+csharp_indent_case_contents_when_block = true
+csharp_indent_labels = one_less_than_current
+csharp_indent_switch_labels = true
+
+# Space preferences
+csharp_space_after_cast = false
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_after_comma = true
+csharp_space_after_dot = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_after_semicolon_in_for_statement = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_around_declaration_statements = false
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_before_comma = false
+csharp_space_before_dot = false
+csharp_space_before_open_square_brackets = false
+csharp_space_before_semicolon_in_for_statement = false
+csharp_space_between_empty_square_brackets = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_declaration_name_and_open_parenthesis = false
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_between_square_brackets = false
+
+# Wrapping preferences
+csharp_preserve_single_line_blocks = true
+csharp_preserve_single_line_statements = true
+
+#### Naming styles ####
+
+# Naming rules
+
+dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
+dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
+dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
+
+dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.types_should_be_pascal_case.symbols = types
+dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
+
+dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
+
+# Symbol specifications
+
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.interface.required_modifiers =
+
+dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.types.required_modifiers =
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.non_field_members.required_modifiers =
+
+# Naming styles
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+
+dotnet_naming_style.begins_with_i.required_prefix = I
+dotnet_naming_style.begins_with_i.required_suffix =
+dotnet_naming_style.begins_with_i.word_separator =
+dotnet_naming_style.begins_with_i.capitalization = pascal_case
+
+# Diagnostic rules migrated from ruleset
+
+# XML comment analysis is disabled due to project configuration
+dotnet_diagnostic.SA0001.severity = none
+
+# Prefix local calls with this
+dotnet_diagnostic.SA1101.severity = none
+
+# TODO turn this back on once most of the project is refactored
+# Split parameters should start on line after declaration
+dotnet_diagnostic.SA1116.severity = none
+
+# Using directives should be placed correctly
+dotnet_diagnostic.SA1200.severity = none
+
+# TODO turn this back on once everything is documented
+# Elements should be documented
+dotnet_diagnostic.SA1600.severity = none
+
+# File should have header
+dotnet_diagnostic.SA1633.severity = none
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
deleted file mode 100644
index 33c3135..0000000
--- a/.github/workflows/build.yml
+++ /dev/null
@@ -1,31 +0,0 @@
-name: "Build - action"
-
-on: [push, pull_request]
-
-jobs:
- build-docker-image:
- name: "ImageOptimApi Docker"
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v3
-
- - name: Create environment file
- run: echo NUGET_API_KEY=${{ secrets.NUGET_API_KEY }} >> release.env
-
- - name: Run build.bash
- env:
- BLD_DOCKER_IMAGE: imageoptimapi
- CR_OWNER: ${{secrets.CR_OWNER}}
- CR_PASSWORD: ${{secrets.CR_PASSWORD}}
- CR_USER: ${{secrets.CR_USER}}
- GHCR_OWNER: ${{secrets.GHCR_OWNER}}
- GHCR_PAT: ${{secrets.GHCR_PAT}}
- GHCR_USER: ${{secrets.GHCR_USER}}
- run: ./build.bash -p
-
- - uses: actions/upload-artifact@v3
- with:
- name: ImageOptimApi.nupkg
- path: package/ImageOptimApi.*.nupkg
- if-no-files-found: ignore
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..4f660cd
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,68 @@
+name: ci
+run-name: ${{ github.actor }} is running ci
+
+on: [push, pull_request]
+
+jobs:
+ build-docker-image:
+ name: "ImageOptimApi Container"
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v7
+
+ - name: Run build.bash
+ env:
+ BLD_DOCKER_IMAGE: imageoptimapi
+ CR_OWNER: ${{secrets.CR_OWNER}}
+ CR_PASSWORD: ${{secrets.CR_PASSWORD}}
+ CR_USER: ${{secrets.CR_USER}}
+ GHCR_OWNER: ${{secrets.GHCR_OWNER}}
+ GHCR_PAT: ${{secrets.GHCR_PAT}}
+ GHCR_USER: ${{secrets.GHCR_USER}}
+ run: ./build.bash -p
+
+ - uses: actions/upload-artifact@v7
+ with:
+ name: ImageOptimApi.nupkg
+ path: package/ImageOptimApi.*.nupkg
+ if-no-files-found: ignore
+
+ push-nupkg-to-nuget:
+ if: contains( github.ref, 'release' )
+ name: "Push ImageOptimApi Nupkg"
+ permissions:
+ id-token: write
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v7
+
+ - name: Run build.bash
+ env:
+ BLD_DOCKER_IMAGE: imageoptimapi
+ CR_OWNER: ${{secrets.CR_OWNER}}
+ CR_PASSWORD: ${{secrets.CR_PASSWORD}}
+ CR_USER: ${{secrets.CR_USER}}
+ GHCR_OWNER: ${{secrets.GHCR_OWNER}}
+ GHCR_PAT: ${{secrets.GHCR_PAT}}
+ GHCR_USER: ${{secrets.GHCR_USER}}
+ run: ./build.bash -p
+
+ - uses: actions/upload-artifact@v7
+ with:
+ name: ImageOptimApi.nupkg
+ path: package/ImageOptimApi.*.nupkg
+ if-no-files-found: ignore
+
+ # Get a short-lived NuGet API key
+ - name: NuGet login (OIDC → temp API key)
+ uses: NuGet/login@v1
+ id: login
+ with:
+ user: ${{ secrets.NUGET_USER }}
+
+ # Push the package
+ - name: NuGet push
+ run: dotnet nuget push package/ImageOptimApi.*.nupkg --api-key ${{steps.login.outputs.NUGET_API_KEY}} --source https://api.nuget.org/v3/index.json
+
diff --git a/.github/workflows/packages.yml b/.github/workflows/packages.yml
index 1a2c926..b04a5b6 100644
--- a/.github/workflows/packages.yml
+++ b/.github/workflows/packages.yml
@@ -1,9 +1,8 @@
-name: "Packages - action"
+name: dotnet outdated
+run-name: ${{ github.actor }} is running dotnet outdated
on:
pull_request:
- schedule:
- - cron: '0 5 * * 5'
jobs:
dotnet-outdated:
@@ -11,6 +10,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v7
- - uses: mcld/dotnet-outdated-action@v3
+ - uses: mcld/dotnet-outdated-action@v4.1
diff --git a/.sa1201ierrc b/.sa1201ierrc
new file mode 100644
index 0000000..7cfa256
--- /dev/null
+++ b/.sa1201ierrc
@@ -0,0 +1,36 @@
+{
+ "alphabeticalSort": true,
+ "sortTopLevelTypes": true,
+ "staticMembersFirst": true,
+ "constMembersFirst": true,
+ "insertBlankLineBetweenMembers": false,
+ "accessLevelOrder": [
+ "Public",
+ "Internal",
+ "ProtectedInternal",
+ "Protected",
+ "PrivateProtected",
+ "Private"
+ ],
+ "memberTypeOrder": [
+ "Field",
+ "Constructor",
+ "Destructor",
+ "Delegate",
+ "Event",
+ "Enum",
+ "Interface",
+ "Property",
+ "Indexer",
+ "Method",
+ "Struct",
+ "Class"
+ ],
+ "topLevelTypeOrder": [
+ "Enum",
+ "Interface",
+ "Struct",
+ "Class"
+ ],
+ "_comment": "SA1201ier configuration file. See documentation for available options."
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 51f9384..a2b9b4d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [1.2.0]
+
+### Added
+
+- Ability to work on an image byte stream
+
+### Changed
+
+- Updated library references to .NET 8.0
+- Improved build.bash script
+
## [1.1.0]
### Changed
@@ -17,5 +28,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Everything, initial release
+[1.2.0]: https://github.com/MCLD/dotnet-imageoptim-api/releases/tag/v1.2.0
[1.1.0]: https://github.com/MCLD/dotnet-imageoptim-api/releases/tag/v1.1.0
[1.0.0]: https://github.com/MCLD/dotnet-imageoptim-api/releases/tag/v1.0.0
diff --git a/Dockerfile b/Dockerfile
index 756634a..c8b7cd3 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
# Get build image
-FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
+FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /app
@@ -22,7 +22,7 @@ RUN dotnet pack -c Release ImageOptimApi -o "/app/publish/"
RUN cp /app/release-publish.bash "/app/publish/"
# Get runtime image
-FROM mcr.microsoft.com/dotnet/sdk:7.0 AS publish
+FROM mcr.microsoft.com/dotnet/sdk:8.0 AS publish
WORKDIR /app
@@ -57,3 +57,4 @@ COPY --from=build "/app/publish/" .
# Set entrypoint
ENTRYPOINT ["/app/release-publish.bash"]
+
diff --git a/ImageOptimApi.Console/ImageOptimApi.Console.csproj b/ImageOptimApi.Console/ImageOptimApi.Console.csproj
index e6f2e29..b355d1e 100644
--- a/ImageOptimApi.Console/ImageOptimApi.Console.csproj
+++ b/ImageOptimApi.Console/ImageOptimApi.Console.csproj
@@ -12,14 +12,14 @@
MIT
https://github.com/MCLD/dotnet-imageoptim-api
https://github.com/MCLD/dotnet-imageoptim-api
- net7.0
- 1.1.0
+ net8.0
+ 1.2.0
-
-
+
+
diff --git a/ImageOptimApi.Console/OptionException.cs b/ImageOptimApi.Console/OptionException.cs
index 5e154b5..23c3b5b 100644
--- a/ImageOptimApi.Console/OptionException.cs
+++ b/ImageOptimApi.Console/OptionException.cs
@@ -1,10 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace ImageOptimApi.Console
+namespace ImageOptimApi.Console
{
internal class OptionException : Exception
{
@@ -16,7 +10,7 @@ public OptionException(string? message) : base(message)
{
}
- public OptionException(string? message, Exception? innerException)
+ public OptionException(string? message, Exception? innerException)
: base(message, innerException)
{
}
diff --git a/ImageOptimApi.Console/Options.cs b/ImageOptimApi.Console/Options.cs
index 3dafda9..cd4c301 100644
--- a/ImageOptimApi.Console/Options.cs
+++ b/ImageOptimApi.Console/Options.cs
@@ -69,4 +69,4 @@ internal class Options
HelpText = "Maximum image width. If not specified, the height will vary depending on image's aspect ratio. Dimensions are specified in CSS pixels.")]
public int? Width { get; set; }
}
-}
\ No newline at end of file
+}
diff --git a/ImageOptimApi.Console/Program.cs b/ImageOptimApi.Console/Program.cs
index 8f04c31..2e59f6f 100644
--- a/ImageOptimApi.Console/Program.cs
+++ b/ImageOptimApi.Console/Program.cs
@@ -1,8 +1,8 @@
-using CommandLine;
+using System.Net.Http.Headers;
+using System.Reflection;
+using CommandLine;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
-using System.Net.Http.Headers;
-using System.Reflection;
namespace ImageOptimApi.Console
{
@@ -80,7 +80,7 @@ private static async Task Main(string[] args)
var title = Assembly
.GetEntryAssembly()?
.GetCustomAttribute()?
- .Title ?? nameof(ImageOptimApi) + '.' + nameof(ImageOptimApi.Console);
+ .Title ?? (nameof(ImageOptimApi) + '.' + nameof(ImageOptimApi.Console));
var version = Assembly
.GetEntryAssembly()?
.GetCustomAttribute()?
@@ -96,7 +96,8 @@ private static async Task Main(string[] args)
.ConfigureHttpClient(_ =>
{
_.Timeout = TimeSpan.FromSeconds(30);
- _.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(title, version));
+ _.DefaultRequestHeaders.UserAgent
+ .Add(new ProductInfoHeaderValue(title, version));
});
_provider = services.BuildServiceProvider();
@@ -194,11 +195,13 @@ private static async Task RunOptionsAsync(Options options)
{
if (string.IsNullOrEmpty(inputFilePath))
{
- System.Console.WriteLine($"Optimized {inputFilename} to {outputFilename} {result.File.Length:N0} bytes in {result.ElapsedSeconds:N0}s");
+ System.Console.WriteLine(
+ $"Optimized {inputFilename} to {outputFilename} {result.File.Length:N0} bytes in {result.ElapsedSeconds:N0}s");
}
else
{
- System.Console.WriteLine($"Optimized {inputFilename} to {outputFilename} from {result.OriginalSize:N0} to {result.File.Length:N0} bytes in {result.ElapsedSeconds:N0}s");
+ System.Console.WriteLine(
+ $"Optimized {inputFilename} to {outputFilename} from {result.OriginalSize:N0} to {result.File.Length:N0} bytes in {result.ElapsedSeconds:N0}s");
}
if (!string.IsNullOrEmpty(options.OutputPath))
@@ -206,7 +209,9 @@ private static async Task RunOptionsAsync(Options options)
Directory.CreateDirectory(options.OutputPath);
}
- await File.WriteAllBytesAsync(Path.Combine(options.OutputPath, outputFilename), result.File);
+ await File.WriteAllBytesAsync(
+ Path.Combine(options.OutputPath, outputFilename),
+ result.File);
return 1;
}
else
diff --git a/ImageOptimApi/Client.cs b/ImageOptimApi/Client.cs
index eb1c155..417ed0f 100644
--- a/ImageOptimApi/Client.cs
+++ b/ImageOptimApi/Client.cs
@@ -1,5 +1,3 @@
-using Microsoft.AspNetCore.StaticFiles;
-using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -8,6 +6,8 @@
using System.Net.Http.Headers;
using System.Reflection;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.StaticFiles;
+using Microsoft.Extensions.Logging;
namespace ImageOptimApi
{
@@ -50,26 +50,6 @@ public Client(HttpClient httpClient, ILogger logger)
public string Username { get; set; }
public int? Width { get; set; }
- public Task OptimizeAsync(Uri imageUri)
- {
- if (imageUri == null || string.IsNullOrEmpty(imageUri.AbsoluteUri))
- {
- throw new ArgumentNullException(nameof(imageUri));
- }
-
- return OptimizeImageInternalAsync(null, imageUri);
- }
-
- public Task OptimizeAsync(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentNullException(nameof(path));
- }
-
- return OptimizeImageInternalAsync(path, null);
- }
-
private static string ConvertCropType(CropType cropType) => cropType switch
{
CropType.Auto => "crop=auto",
@@ -97,8 +77,37 @@ public Task OptimizeAsync(string path)
_ => "medium"
};
- private async Task OptimizeImageInternalAsync(string path, Uri imageUri)
+ public Task OptimizeAsync(Uri imageUri)
{
+ return imageUri == null || string.IsNullOrEmpty(imageUri.AbsoluteUri)
+ ? throw new ArgumentNullException(nameof(imageUri))
+ : OptimizeImageInternalAsync(null, imageUri, null, null);
+ }
+
+ public Task OptimizeAsync(string path)
+ {
+ return string.IsNullOrEmpty(path)
+ ? throw new ArgumentNullException(nameof(path))
+ : OptimizeImageInternalAsync(path, null, null, null);
+ }
+
+ public Task OptimizeAsync(byte[] imageBytes, string filename)
+ {
+ return OptimizeImageInternalAsync(null, null, imageBytes, filename);
+ }
+
+ private async Task OptimizeImageInternalAsync(string path,
+ Uri imageUri,
+ byte[] imageBytes,
+ string imageFilename)
+ {
+ if (string.IsNullOrWhiteSpace(path)
+ && imageUri == null
+ && (imageBytes == null || string.IsNullOrWhiteSpace(imageFilename)))
+ {
+ throw new ArgumentException("You must supply an iamge path, an image URI, or image bytes along with a filename.");
+ }
+
var sw = Stopwatch.StartNew();
_logger.LogDebug("Preparing parameters");
var urlPath = PrepareParameters(_httpClient.Timeout);
@@ -111,25 +120,38 @@ private async Task OptimizeImageInternalAsync(string path,
string contentType = null;
Uri requestUri;
- if (string.IsNullOrEmpty(path))
+ if (imageUri != null)
{
requestUri = new Uri(BaseAddress + urlPath + imageUri);
_logger.LogDebug("Using image from URL, image path: {ImagePath}", imageUri);
}
else
{
- if (!System.IO.File.Exists(path))
+ if (!string.IsNullOrEmpty(path))
{
- throw new ParameterException($"File not found: {path}");
+ if (!System.IO.File.Exists(path))
+ {
+ throw new ParameterException($"File not found: {path}");
+ }
+ filename = System.IO.Path.GetFileName(path);
+ var provider = new FileExtensionContentTypeProvider();
+ if (!provider.TryGetContentType(filename, out contentType))
+ {
+ throw new ParameterException($"Unable to determine type of file: {filename}");
+ }
+ _logger.LogDebug("Reading file at path: {ImagePath}", path);
+ image = await System.IO.File.ReadAllBytesAsync(path);
}
- filename = System.IO.Path.GetFileName(path);
- var provider = new FileExtensionContentTypeProvider();
- if (!provider.TryGetContentType(filename, out contentType))
+ else
{
- throw new ParameterException($"Unable to determine type of file: {filename}");
+ filename = imageFilename;
+ var provider = new FileExtensionContentTypeProvider();
+ if (!provider.TryGetContentType(filename, out contentType))
+ {
+ throw new ParameterException($"Unable to determine type of file: {filename}");
+ }
+ image = imageBytes;
}
- _logger.LogDebug("Reading file at path: {ImagePath}", path);
- image = await System.IO.File.ReadAllBytesAsync(path);
optimized.OriginalSize = image.Length;
requestUri = new Uri(BaseAddress + urlPath);
}
@@ -141,7 +163,7 @@ private async Task OptimizeImageInternalAsync(string path,
{
if (image != null)
{
- form = new MultipartFormDataContent();
+ form = [];
byteContent = new ByteArrayContent(image);
byteContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType);
form.Add(byteContent, name: "file", fileName: filename);
@@ -174,7 +196,7 @@ private async Task OptimizeImageInternalAsync(string path,
if (DisableWebCall)
{
- optimized.File = image ?? new byte[] { 0xff };
+ optimized.File = image ?? [0xff];
optimized.Status = Status.TestSuccess;
optimized.StatusMessage = "Test call, file is not an optimized message.";
sw.Stop();
@@ -317,7 +339,7 @@ private string PrepareParameters(TimeSpan timeout)
options.Add($"timeout={timeout.TotalSeconds}");
}
- return string.Join("/", new[] { Username, string.Join(",", options) }) + '/';
+ return string.Join("/", [Username, string.Join(",", options)]) + '/';
}
private void VerifyParameters()
diff --git a/ImageOptimApi/CropType.cs b/ImageOptimApi/CropType.cs
index e767ad5..1455d6d 100644
--- a/ImageOptimApi/CropType.cs
+++ b/ImageOptimApi/CropType.cs
@@ -9,4 +9,4 @@ public enum CropType
Right,
Bottom
}
-}
\ No newline at end of file
+}
diff --git a/ImageOptimApi/Format.cs b/ImageOptimApi/Format.cs
index 4db24ec..f2864cd 100644
--- a/ImageOptimApi/Format.cs
+++ b/ImageOptimApi/Format.cs
@@ -8,4 +8,4 @@ public enum Format
WebM,
H264
}
-}
\ No newline at end of file
+}
diff --git a/ImageOptimApi/HighDpi.cs b/ImageOptimApi/HighDpi.cs
index 9fcb4f6..46c7774 100644
--- a/ImageOptimApi/HighDpi.cs
+++ b/ImageOptimApi/HighDpi.cs
@@ -6,4 +6,4 @@ public enum HighDpi
Dpi2x,
Dpi3x
}
-}
\ No newline at end of file
+}
diff --git a/ImageOptimApi/ImageOptimApi.csproj b/ImageOptimApi/ImageOptimApi.csproj
index b4e00fc..5c66bad 100644
--- a/ImageOptimApi/ImageOptimApi.csproj
+++ b/ImageOptimApi/ImageOptimApi.csproj
@@ -16,7 +16,7 @@
https://github.com/MCLD/dotnet-imageoptim-api
netstandard2.1
ImageOptim API
- 1.1.0
+ 1.2.0
@@ -24,8 +24,8 @@
-
-
+
+
diff --git a/ImageOptimApi/OptimizedImageResult.cs b/ImageOptimApi/OptimizedImageResult.cs
index 281b58d..9541a7b 100644
--- a/ImageOptimApi/OptimizedImageResult.cs
+++ b/ImageOptimApi/OptimizedImageResult.cs
@@ -14,4 +14,4 @@ public class OptimizedImageResult
public string ViaHeader { get; set; }
public IEnumerable Warnings { get; set; }
}
-}
\ No newline at end of file
+}
diff --git a/ImageOptimApi/ParameterException.cs b/ImageOptimApi/ParameterException.cs
index 536f95a..243a67a 100644
--- a/ImageOptimApi/ParameterException.cs
+++ b/ImageOptimApi/ParameterException.cs
@@ -18,4 +18,4 @@ public ParameterException(string message, Exception innerException)
{
}
}
-}
\ No newline at end of file
+}
diff --git a/ImageOptimApi/Quality.cs b/ImageOptimApi/Quality.cs
index ef8f6f0..bc94c38 100644
--- a/ImageOptimApi/Quality.cs
+++ b/ImageOptimApi/Quality.cs
@@ -7,4 +7,4 @@ public enum Quality
High,
Lossless
}
-}
\ No newline at end of file
+}
diff --git a/ImageOptimApi/README.md b/ImageOptimApi/README.md
index d6ab74e..9f1ebac 100644
--- a/ImageOptimApi/README.md
+++ b/ImageOptimApi/README.md
@@ -100,6 +100,11 @@ When you need the `ImageOptimApi` client you can obtain it from the `ServiceProv
You can then configure and use the client to optimize your images.
+## Version History
+
+- v1.2.0 - .NET 8.0 - adds the ability to work on an image provided as a byte array
+- v1.1.0 - .NET 7.0
+
## License
The ImageOptimApi source code is Copyright 2022 by the Maricopa County Library District and is distributed under [The MIT License](http://opensource.org/licenses/MIT).
diff --git a/ImageOptimApi/Status.cs b/ImageOptimApi/Status.cs
index 26ac9d5..7ae7f2e 100644
--- a/ImageOptimApi/Status.cs
+++ b/ImageOptimApi/Status.cs
@@ -10,4 +10,4 @@ public enum Status
TestSuccess,
UsernameMissingIncorrect
}
-}
\ No newline at end of file
+}
diff --git a/build.bash b/build.bash
index 6e5ac1c..e88cc26 100755
--- a/build.bash
+++ b/build.bash
@@ -12,8 +12,6 @@
set -Eeuo pipefail
trap cleanup SIGINT SIGTERM ERR EXIT
-script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd -P)
-
usage() {
cat <&2 -e "${1-}"
+ echo >&2 -e "${1-}"
}
die() {
- local msg=$1
- local code=${2-1} # default exit status 1
- msg "$msg"
- exit "$code"
+ local msg=$1
+ local code=${2-1} # default exit status 1
+ msg "$msg"
+ exit "$code"
}
parse_params() {
- dockerfile=''
- publish=0
-
- while :; do
- case "${1-}" in
- -h | --help) usage ;;
- -v | --verbose) set -x ;;
- --no-color) NO_COLOR=1 ;;
- -df | --dockerfile)
- dockerfile="${2-}"
- shift
- ;;
- -p | --publish)
- publish=1
- ;;
- -?*) die "Unknown option: $1" ;;
- *) break ;;
- esac
- shift
- done
-
- readonly dockertag="${1-}"
-
- return 0
+ dockerfile=''
+ publish=0
+
+ while :; do
+ case "${1-}" in
+ -h | --help) usage ;;
+ -v | --verbose) set -x ;;
+ --no-color) NO_COLOR=1 ;;
+ -df | --dockerfile)
+ dockerfile="${2-}"
+ shift
+ ;;
+ -p | --publish)
+ publish=1
+ ;;
+ -?*) die "Unknown option: $1" ;;
+ *) break ;;
+ esac
+ shift
+ done
+
+ readonly dockertag="${1-}"
+
+ return 0
}
parse_params "$@"
@@ -103,6 +104,7 @@ readonly BLD_COMMIT
BLD_VERSION_DATE=$(date -u +'%Y%m%d_%H%M%SZ')
readonly BLD_VERSION_DATE
+BLD_LATEST=false
BLD_PUSH=false
BLD_RELEASE=false
BLD_VERSION=unknown
@@ -110,68 +112,105 @@ BLD_RELEASE_VERSION=''
readonly BLD_STARTAT=$SECONDS
+SYSARCH=$(arch)
+readonly SYSARCH
+
+if [[ ${SYSARCH} = "i386" ]]; then
+ readonly ARCH="x86_32"
+elif [[ ${SYSARCH} = "aarch64" ]]; then
+ readonly ARCH="armv7"
+else
+ readonly ARCH=${SYSARCH}
+fi
+
+OS=$(uname -s)
+readonly OS
+
+if [[ -z ${DOCKER_LOCK_VERSION-} && -f "docker-lock-version.txt" ]]; then
+ BLD_DOCKER_LOCK_VERSION=$(cat docker-lock-version.txt)
+ readonly BLD_DOCKER_LOCK_VERSION
+else
+ BLD_DOCKER_LOCK_VERSION=${DOCKER_LOCK_VERSION-}
+ readonly BLD_DOCKER_LOCK_VERSION
+fi
+
+if [[ -n ${BLD_DOCKER_LOCK_VERSION-} && -f "docker-lock.json" ]]; then
+ readonly DOCKER_LOCK_URL="https://github.com/safe-waters/docker-lock/releases/download/v${BLD_DOCKER_LOCK_VERSION}/docker-lock_${BLD_DOCKER_LOCK_VERSION}_${OS}_${ARCH}.tar.gz"
+ msg "${BLUE}===${NOFORMAT} Using docker-lock.json version ${BLD_DOCKER_LOCK_VERSION} to pin Dockerfile(s)"
+ mkdir -p ".docker/cli-plugins"
+ curl -fsSL "${DOCKER_LOCK_URL}" | tar -xz -C ".docker/cli-plugins" "docker-lock"
+ chmod +x ".docker/cli-plugins/docker-lock"
+ .docker/cli-plugins/docker-lock lock rewrite
+fi
+
# Try getting branch from Azure DevOps
readonly AZURE_BRANCH=${BUILD_SOURCEBRANCH-}
BLD_BRANCH=''
BLD_GITBRANCH=${AZURE_BRANCH#refs/heads/}
if [[ -n $BLD_GITBRANCH ]]; then
- BLD_BRANCH=$BLD_GITBRANCH
- msg "${BLUE}===${NOFORMAT} Branch from Azure DevOps: $BLD_BRANCH"
+ BLD_BRANCH=$BLD_GITBRANCH
+ msg "${BLUE}===${NOFORMAT} Branch from Azure DevOps: $BLD_BRANCH"
fi
if [[ -z ${BLD_BRANCH} ]]; then
- # Try getting branch from git
- if BLD_GITBRANCH=$(git symbolic-ref --short -q HEAD); then
- BLD_BRANCH=$BLD_GITBRANCH
- msg "${BLUE}===${NOFORMAT} Branch from git: $BLD_BRANCH"
- fi
+ # Try getting branch from git
+ if BLD_GITBRANCH=$(git symbolic-ref --short -q HEAD); then
+ BLD_BRANCH=$BLD_GITBRANCH
+ msg "${BLUE}===${NOFORMAT} Branch from git: $BLD_BRANCH"
+ fi
fi
if [[ $BLD_BRANCH = "develop"
- || $BLD_BRANCH = "main"
- || $BLD_BRANCH = "master"
- || $BLD_BRANCH = "test" ]]; then
- BLD_DOCKER_TAG=$BLD_BRANCH
- BLD_VERSION=${BLD_BRANCH}-${BLD_VERSION_DATE}
- BLD_PUSH=true
+ || $BLD_BRANCH = "main"
+ || $BLD_BRANCH = "master"
+ || $BLD_BRANCH = "test" ]]; then
+ BLD_DOCKER_TAG=$BLD_BRANCH
+ BLD_VERSION=${BLD_BRANCH}-${BLD_VERSION_DATE}
+ BLD_PUSH=true
elif [[ "$BLD_BRANCH" =~ release/([0-9]+\.[0-9]+\.[0-9]+.*) ]]; then
- BLD_RELEASE_VERSION=${BASH_REMATCH[1]}
- BLD_DOCKER_TAG=v${BLD_RELEASE_VERSION}
- BLD_VERSION=v${BLD_RELEASE_VERSION}
- BLD_RELEASE=true
- BLD_PUSH=true
+ BLD_RELEASE_VERSION=${BASH_REMATCH[1]}
+ BLD_DOCKER_TAG=v${BLD_RELEASE_VERSION}
+ BLD_VERSION=v${BLD_RELEASE_VERSION}
+ BLD_RELEASE=true
+ BLD_PUSH=true
else
- BLD_DOCKER_TAG=$BLD_COMMIT
- BLD_VERSION=${BLD_COMMIT}-${BLD_VERSION_DATE}
+ BLD_DOCKER_TAG=$BLD_COMMIT
+ BLD_VERSION=${BLD_COMMIT}-${BLD_VERSION_DATE}
+fi
+
+# check if this is latest
+if [[ $BLD_BRANCH = "main"
+ || $BLD_BRANCH = "master" ]]; then
+ BLD_LATEST=true
fi
# Check if we should use a different Dockerfile
if [[ -z $dockerfile ]]; then
- BLD_DOCKERFILE="Dockerfile"
+ BLD_DOCKERFILE="Dockerfile"
else
- BLD_DOCKERFILE="$dockerfile"
- msg "${BLUE}===${NOFORMAT} Using Dockerfile: $BLD_DOCKERFILE"
+ BLD_DOCKERFILE="$dockerfile"
+ msg "${BLUE}===${NOFORMAT} Using Dockerfile: $BLD_DOCKERFILE"
fi
# Ensure a configured Docker image name
if [[ -z ${BLD_DOCKER_IMAGE-} ]]; then
- BLD_DIRECTORY=${PWD##*/}
- BLD_DOCKER_IMAGE=${BLD_DIRECTORY,,}
- msg "${ORANGE}===${NOFORMAT} No BLD_DOCKER_IMAGE configured, using this directory name: $BLD_DOCKER_IMAGE"
+ BLD_DIRECTORY=${PWD##*/}
+ BLD_DOCKER_IMAGE=${BLD_DIRECTORY,,}
+ msg "${ORANGE}===${NOFORMAT} No BLD_DOCKER_IMAGE configured, using this directory name: $BLD_DOCKER_IMAGE"
fi
# Perform release prep if necessary and script is present
-if [[ $BLD_RELEASE = "true" && -f "release-prep.bash" ]]; then
- msg "${BLUE}===${NOFORMAT} Running release preparation for version $BLD_RELEASE_VERSION"
- #shellcheck disable=SC1091
- source release-prep.bash
- msg "${GREEN}===${NOFORMAT} Release preparation script complete"
+if [[ $BLD_RELEASE = "true" && -x "release-prep.bash" ]]; then
+ msg "${BLUE}===${NOFORMAT} Running release preparation for version $BLD_RELEASE_VERSION"
+ #shellcheck disable=SC1091
+ source release-prep.bash
+ msg "${GREEN}===${NOFORMAT} Release preparation script complete"
fi
# If there's a specified Docker tag, use it
if [[ -n $dockertag ]]; then
- BLD_DOCKER_TAG="$dockertag"
- msg "${BLUE}===${NOFORMAT} Using specified Docker tag $BLD_DOCKER_TAG"
+ BLD_DOCKER_TAG="$dockertag"
+ msg "${BLUE}===${NOFORMAT} Using specified Docker tag $BLD_DOCKER_TAG"
fi
# Construct complete Docker image and tag from provided values
@@ -181,119 +220,119 @@ BLD_FULL_DOCKER_IMAGE=${BLD_DOCKER_IMAGE}
BLD_FULL_DOCKER_LATEST=${BLD_DOCKER_LATEST}
if [[ -n ${CR_OWNER-} ]]; then
- msg "${BLUE}===${NOFORMAT} Adding container registry owner $CR_OWNER"
- BLD_FULL_DOCKER_IMAGE=${CR_OWNER}/${BLD_FULL_DOCKER_IMAGE}
- BLD_FULL_DOCKER_LATEST=${CR_OWNER}/${BLD_FULL_DOCKER_LATEST}
+ msg "${BLUE}===${NOFORMAT} Adding container registry owner $CR_OWNER"
+ BLD_FULL_DOCKER_IMAGE=${CR_OWNER}/${BLD_FULL_DOCKER_IMAGE}
+ BLD_FULL_DOCKER_LATEST=${CR_OWNER}/${BLD_FULL_DOCKER_LATEST}
fi
if [[ -n ${CR_HOST-} ]]; then
- msg "${BLUE}===${NOFORMAT} Adding container registry host $CR_HOST"
- BLD_FULL_DOCKER_IMAGE=${CR_HOST}/${BLD_FULL_DOCKER_IMAGE}
- BLD_FULL_DOCKER_LATEST=${CR_HOST}/${BLD_FULL_DOCKER_LATEST}
+ msg "${BLUE}===${NOFORMAT} Adding container registry host $CR_HOST"
+ BLD_FULL_DOCKER_IMAGE=${CR_HOST}/${BLD_FULL_DOCKER_IMAGE}
+ BLD_FULL_DOCKER_LATEST=${CR_HOST}/${BLD_FULL_DOCKER_LATEST}
fi
msg "${BLUE}===${NOFORMAT} Building branch $BLD_BRANCH commit $BLD_COMMIT as Docker image $BLD_FULL_DOCKER_IMAGE"
msg "${BLUE}===${NOFORMAT} Image version: $BLD_VERSION"
if [[ $BLD_PUSH = true ]]; then
- docker build -f "$BLD_DOCKERFILE" -t "$BLD_FULL_DOCKER_IMAGE" \
- --build-arg BRANCH="$BLD_BRANCH" \
- --build-arg IMAGE_CREATED="$BLD_VERSION_DATE" \
- --build-arg IMAGE_REVISION="$BLD_COMMIT" \
- --build-arg IMAGE_VERSION="$BLD_VERSION" .
-
- msg "${GREEN}===${NOFORMAT} Docker image built"
-
- dockeruser=${CR_USER-}
- dockerpass=${CR_PASSWORD-}
-
- if [[ -z $dockeruser || -z $dockerpass ]]; then
- msg "${ORANGE}===${NOFORMAT} Not pushing Docker image: username or password not specified"
- else
- msg "${BLUE}===${NOFORMAT} Authenticating..."
- if [[ -z ${CR_HOST-} ]]; then
- echo "$dockerpass" | \
- docker login -u "$dockeruser" --password-stdin || exit $?
- else
- echo "$dockerpass" | \
- docker login -u "$dockeruser" --password-stdin "${CR_HOST-}" || exit $?
- fi
-
- msg "${BLUE}===${NOFORMAT} Pushing image $BLD_FULL_DOCKER_IMAGE"
- docker push "$BLD_FULL_DOCKER_IMAGE"
-
- if [[ $BLD_RELEASE = "true" ]]; then
- msg "${BLUE}===${NOFORMAT} Tagging and pushing $BLD_FULL_DOCKER_LATEST"
- docker tag "$BLD_FULL_DOCKER_IMAGE" "$BLD_FULL_DOCKER_LATEST"
- docker push "$BLD_FULL_DOCKER_LATEST"
- fi
-
- msg "${GREEN}===${NOFORMAT} Docker image pushed"
-
- msg "${BLUE}===${NOFORMAT} Executing logout"
- if [[ -z ${CR_HOST-} ]]; then
- docker logout
+ docker build -f "$BLD_DOCKERFILE" -t "$BLD_FULL_DOCKER_IMAGE" \
+ --build-arg BRANCH="$BLD_BRANCH" \
+ --build-arg IMAGE_CREATED="$BLD_VERSION_DATE" \
+ --build-arg IMAGE_REVISION="$BLD_COMMIT" \
+ --build-arg IMAGE_VERSION="$BLD_VERSION" .
+
+ msg "${GREEN}===${NOFORMAT} Docker image built"
+
+ dockeruser=${CR_USER-}
+ dockerpass=${CR_PASSWORD-}
+
+ if [[ -z $dockeruser || -z $dockerpass ]]; then
+ msg "${ORANGE}===${NOFORMAT} Not pushing Docker image: username or password not specified"
else
- docker logout "${CR_HOST-}"
+ msg "${BLUE}===${NOFORMAT} Authenticating..."
+ if [[ -z ${CR_HOST-} ]]; then
+ echo "$dockerpass" | \
+ docker login -u "$dockeruser" --password-stdin || exit $?
+ else
+ echo "$dockerpass" | \
+ docker login -u "$dockeruser" --password-stdin "${CR_HOST-}" || exit $?
+ fi
+
+ msg "${BLUE}===${NOFORMAT} Pushing image $BLD_FULL_DOCKER_IMAGE"
+ docker push "$BLD_FULL_DOCKER_IMAGE"
+
+ if [[ $BLD_LATEST = "true" ]]; then
+ msg "${BLUE}===${NOFORMAT} Tagging and pushing $BLD_FULL_DOCKER_LATEST"
+ docker tag "$BLD_FULL_DOCKER_IMAGE" "$BLD_FULL_DOCKER_LATEST"
+ docker push "$BLD_FULL_DOCKER_LATEST"
+ fi
+
+ msg "${GREEN}===${NOFORMAT} Docker image pushed"
+
+ msg "${BLUE}===${NOFORMAT} Executing logout"
+ if [[ -z ${CR_HOST-} ]]; then
+ docker logout
+ else
+ docker logout "${CR_HOST-}"
+ fi
fi
- fi
-
- ghcruser=${GHCR_USER-}
-
- if [[ -n $ghcruser ]]; then
- ghcrowner=${GHCR_OWNER-}
- if [[ -z $ghcrowner ]]; then
- ghcrowner=$ghcruser
+
+ ghcruser=${GHCR_USER-}
+
+ if [[ -n $ghcruser ]]; then
+ ghcrowner=${GHCR_OWNER-}
+ if [[ -z $ghcrowner ]]; then
+ ghcrowner=$ghcruser
+ fi
+ msg "${BLUE}===${NOFORMAT} Pushing image to ghcr.io/${ghcrowner}/${BLD_DOCKER_IMAGE}"
+ docker tag "${BLD_FULL_DOCKER_IMAGE}" "ghcr.io/${ghcrowner}/${BLD_DOCKER_IMAGE}"
+ echo "$GHCR_PAT" | \
+ docker login ghcr.io -u "${ghcruser}" --password-stdin || exit $?
+ docker push "ghcr.io/${ghcrowner}/${BLD_DOCKER_IMAGE}"
+
+ if [[ $BLD_LATEST = "true" ]]; then
+ msg "${BLUE}===${NOFORMAT} Tagging and pushing ghcr.io/${ghcrowner}/${BLD_DOCKER_LATEST}"
+ docker tag "${BLD_FULL_DOCKER_IMAGE}" "ghcr.io/${ghcrowner}/${BLD_DOCKER_LATEST}"
+ docker push "ghcr.io/${ghcrowner}/${BLD_DOCKER_LATEST}"
+ fi
+
+ docker logout ghcr.io
+
+ msg "${GREEN}===${NOFORMAT} Docker image pushed to ghcr.io"
fi
- msg "${BLUE}===${NOFORMAT} Pushing image to ghcr.io/${ghcrowner}/${BLD_DOCKER_IMAGE}"
- docker tag "${BLD_FULL_DOCKER_IMAGE}" "ghcr.io/${ghcrowner}/${BLD_DOCKER_IMAGE}"
- echo "$GHCR_PAT" | \
- docker login ghcr.io -u "${ghcruser}" --password-stdin || exit $?
- docker push "ghcr.io/${ghcrowner}/${BLD_DOCKER_IMAGE}"
-
- if [[ $BLD_RELEASE = "true" ]]; then
- msg "${BLUE}===${NOFORMAT} Tagging and pushing ghcr.io/${ghcrowner}/${BLD_DOCKER_LATEST}"
- docker tag "${BLD_FULL_DOCKER_IMAGE}" "ghcr.io/${ghcrowner}/${BLD_DOCKER_LATEST}"
- docker push "ghcr.io/${ghcrowner}/${BLD_DOCKER_LATEST}"
- fi
-
- docker logout ghcr.io
-
- msg "${GREEN}===${NOFORMAT} Docker image pushed to ghcr.io"
- fi
-
- # Perform release publish in the Docker machine if configuration is present
-
- if [[ $BLD_RELEASE = "true" && -f "release-publish.bash" && publish -eq 1 ]]; then
- msg "${BLUE}===${NOFORMAT} Publishing release package for $BLD_RELEASE_VERSION"
- mkdir -p publish
- if [[ -f "release.env" ]]; then
- docker run -i \
- --rm \
- --entrypoint "/app/release-publish.bash" \
- --env-file release.env \
- -e BLD_RELEASE_VERSION="$BLD_RELEASE_VERSION" \
- -v "${PWD}/package:/package" \
- "$BLD_FULL_DOCKER_IMAGE"
- else
- docker run -i \
- --rm \
- --entrypoint "/app/release-publish.bash" \
- -e BLD_RELEASE_VERSION="$BLD_RELEASE_VERSION" \
- -v "${PWD}/package:/package" \
- "$BLD_FULL_DOCKER_IMAGE"
+
+ # Perform release publish in the Docker machine if configuration is present
+
+ if [[ $BLD_RELEASE = "true" && -x "release-publish.bash" && publish -eq 1 ]]; then
+ msg "${BLUE}===${NOFORMAT} Publishing release package for $BLD_RELEASE_VERSION"
+ mkdir -p publish
+ if [[ -f "release.env" ]]; then
+ docker run -i \
+ --rm \
+ --entrypoint "/app/release-publish.bash" \
+ --env-file release.env \
+ -e BLD_RELEASE_VERSION="$BLD_RELEASE_VERSION" \
+ -v "${PWD}/package:/package" \
+ "$BLD_FULL_DOCKER_IMAGE"
+ else
+ docker run -i \
+ --rm \
+ --entrypoint "/app/release-publish.bash" \
+ -e BLD_RELEASE_VERSION="$BLD_RELEASE_VERSION" \
+ -v "${PWD}/package:/package" \
+ "$BLD_FULL_DOCKER_IMAGE"
+ fi
+ msg "${GREEN}===${NOFORMAT} Publish script complete"
fi
- msg "${GREEN}===${NOFORMAT} Publish script complete"
- fi
else
- docker build -f "$BLD_DOCKERFILE" -t "$BLD_FULL_DOCKER_IMAGE" \
- --build-arg BRANCH="$BLD_BRANCH" \
- --build-arg IMAGE_CREATED="$BLD_VERSION_DATE" \
- --build-arg IMAGE_REVISION="$BLD_COMMIT" \
- --build-arg IMAGE_VERSION="$BLD_VERSION" \
- --target build .
- msg "${GREEN}===${NOFORMAT} Docker image built"
- msg "${ORANGE}===${NOFORMAT} Not pushing Docker image: branch is not develop, main, test, or versioned release"
+ docker build -f "$BLD_DOCKERFILE" -t "$BLD_FULL_DOCKER_IMAGE" \
+ --build-arg BRANCH="$BLD_BRANCH" \
+ --build-arg IMAGE_CREATED="$BLD_VERSION_DATE" \
+ --build-arg IMAGE_REVISION="$BLD_COMMIT" \
+ --build-arg IMAGE_VERSION="$BLD_VERSION" \
+ --target build .
+ msg "${GREEN}===${NOFORMAT} Docker image built"
+ msg "${ORANGE}===${NOFORMAT} Not pushing Docker image: branch is not develop, main, test, or versioned release"
fi
msg "${PURPLE}===${NOFORMAT} Build script complete in $((SECONDS - BLD_STARTAT)) seconds."