From f8310a76fc2f23eb39127e88bbcef7bb49ff528c Mon Sep 17 00:00:00 2001 From: Simon Hornby Date: Mon, 23 Sep 2024 15:27:53 +0200 Subject: [PATCH] chore: ARM ruby build (#145) --- .github/workflows/publish-ruby.yaml | 17 ++++----- .github/workflows/sarif-and-test.yaml | 2 +- .gitignore | 2 +- ruby-engine/build.sh | 46 ++++++++++++++++++++++- ruby-engine/lib/yggdrasil_engine.rb | 25 +++++++++--- ruby-engine/spec/yggdrasil_engine_spec.rb | 16 +++++++- ruby-engine/yggdrasil-engine.gemspec | 2 +- unleash-yggdrasil/src/lib.rs | 25 +++++++++--- unleash-yggdrasil/src/strategy_upgrade.rs | 28 +++++++------- 9 files changed, 122 insertions(+), 41 deletions(-) diff --git a/.github/workflows/publish-ruby.yaml b/.github/workflows/publish-ruby.yaml index 4a87f099..3cd6d94e 100644 --- a/.github/workflows/publish-ruby.yaml +++ b/.github/workflows/publish-ruby.yaml @@ -1,8 +1,5 @@ name: Build Ruby on: - push: - tags: - - "*" workflow_dispatch: jobs: @@ -14,11 +11,11 @@ jobs: - os: ubuntu-latest target: x86_64-unknown-linux-gnu output: libyggdrasilffi.so - name: libyggdrasilffi.so + name: libyggdrasilffi_x86_64.so - os: windows-latest target: x86_64-pc-windows-gnu output: yggdrasilffi.dll - name: yggdrasilffi.dll + name: libyggdrasilffi_x86_64.dll - os: macos-13 target: x86_64-apple-darwin output: libyggdrasilffi.dylib @@ -51,7 +48,7 @@ jobs: - name: Upload Artifact uses: actions/upload-artifact@v4 with: - name: ${{ matrix.output }} + name: ${{ matrix.name }} path: target/${{ matrix.target }}/release/${{ matrix.name }} build_single_binary_gems: @@ -60,9 +57,9 @@ jobs: matrix: include: - os: ubuntu-latest - binary: libyggdrasilffi.so + binary: libyggdrasilffi_x86_64.so - os: windows-latest - binary: yggdrasilffi.dll + binary: libyggdrasilffi_x86_64.dll - os: macos-13 binary: libyggdrasilffi_x86_64.dylib platform: x86_64-darwin @@ -105,6 +102,8 @@ jobs: ruby: jruby-9.3 - java: 17 ruby: jruby-9.4 + - java: 21 + ruby: jruby-9.4 needs: build-binaries steps: @@ -134,4 +133,4 @@ jobs: gem push *.gem working-directory: ${{ github.workspace }} env: - GEM_HOST_API_KEY: ${{ secrets.GEMS_PUBLISH_KEY }} \ No newline at end of file + GEM_HOST_API_KEY: ${{ secrets.GEMS_PUBLISH_KEY }} diff --git a/.github/workflows/sarif-and-test.yaml b/.github/workflows/sarif-and-test.yaml index 372f0ba4..01d9e346 100644 --- a/.github/workflows/sarif-and-test.yaml +++ b/.github/workflows/sarif-and-test.yaml @@ -49,7 +49,7 @@ jobs: uses: actions/checkout@v3 with: repository: Unleash/client-specification - ref: v5.1.0 + ref: v5.1.7 path: client-specification - name: Run tests run: | diff --git a/.gitignore b/.gitignore index 9187011d..b744e785 100644 --- a/.gitignore +++ b/.gitignore @@ -20,7 +20,7 @@ /go-engine/unleash_engine.h /php-engine/unleash_engine.h /php-engine/libyggdrasilffi.so -/ruby-engine/lib/libyggdrasilffi.* +/ruby-engine/lib/libyggdrasilffi*.* # Devenv .devenv* diff --git a/ruby-engine/build.sh b/ruby-engine/build.sh index 536871cd..1faff629 100755 --- a/ruby-engine/build.sh +++ b/ruby-engine/build.sh @@ -1,4 +1,46 @@ +#!/bin/bash +set -e + cargo build --release -rm -f lib/libyggdrasilffi.so -cp ../target/release/libyggdrasilffi.so lib/ + +## Start copy the correct binary to the correct name +OS=$(uname -s | tr '[:upper:]' '[:lower:]') +ARCH=$(uname -m) + +case "$OS" in + darwin) + EXT="dylib" + ;; + linux) + EXT="so" + ;; + msys*|mingw*|cygwin*) + EXT="dll" + ;; + *) + echo "Unsupported platform: $OS" + exit 1 + ;; +esac + +case "$ARCH" in + x86_64) + ARCH_SUFFIX="x86_64" + ;; + arm*|aarch64) + ARCH_SUFFIX="arm" + ;; + *) + echo "Unsupported architecture: $ARCH" + exit 1 + ;; +esac + +LIB_NAME="libyggdrasilffi_${ARCH_SUFFIX}.${EXT}" + +rm -f "lib/$LIB_NAME" +cp "../target/release/libyggdrasilffi.${EXT}" "lib/$LIB_NAME" +## End copy the correct binary to the correct name + +# Build the gem gem build yggdrasil-engine.gemspec \ No newline at end of file diff --git a/ruby-engine/lib/yggdrasil_engine.rb b/ruby-engine/lib/yggdrasil_engine.rb index 3c23456f..fcd7be54 100644 --- a/ruby-engine/lib/yggdrasil_engine.rb +++ b/ruby-engine/lib/yggdrasil_engine.rb @@ -7,16 +7,30 @@ OK_RESPONSE = 'Ok'.freeze def platform_specific_lib - case RbConfig::CONFIG['host_os'] + os = RbConfig::CONFIG['host_os'] + cpu = RbConfig::CONFIG['host_cpu'] + + extension = case os when /darwin|mac os/ - 'libyggdrasilffi.dylib' + 'dylib' when /linux/ - 'libyggdrasilffi.so' + 'so' when /mswin|msys|mingw|cygwin|bccwin|wince|emc/ - 'libyggdrasilffi.dll' + 'dll' else - raise "unsupported platform #{RbConfig::CONFIG['host_os']}" + raise "unsupported platform #{os}" end + + arch_suffix = case cpu + when /x86_64/ + 'x86_64' + when /arm|aarch64/ + 'arm64' + else + raise "unsupported architecture #{cpu}" + end + + "libyggdrasilffi_#{arch_suffix}.#{extension}" end def to_variant(raw_variant) @@ -24,6 +38,7 @@ def to_variant(raw_variant) { name: raw_variant[:name], enabled: raw_variant[:enabled], + feature_enabled: raw_variant[:featureEnabled], payload: payload, } end diff --git a/ruby-engine/spec/yggdrasil_engine_spec.rb b/ruby-engine/spec/yggdrasil_engine_spec.rb index 543ad2ec..31b77f09 100644 --- a/ruby-engine/spec/yggdrasil_engine_spec.rb +++ b/ruby-engine/spec/yggdrasil_engine_spec.rb @@ -5,6 +5,16 @@ index_file_path = '../client-specification/specifications/index.json' test_suites = JSON.parse(File.read(index_file_path)) +def test_suite_variant(base_variant) + payload = base_variant[:payload] && base_variant[:payload].transform_keys(&:to_s) + { + name: base_variant[:name], + enabled: base_variant[:enabled], + feature_enabled: base_variant[:feature_enabled], + payload: payload, + } +end + RSpec.describe YggdrasilEngine do let(:yggdrasil_engine) { YggdrasilEngine.new } @@ -119,18 +129,20 @@ describe "Variant Test '#{test[:description]}'" do let(:context) { test[:context] } let(:toggle_name) { test[:toggleName] } - let(:expected_result) { to_variant(test[:expectedResult]) } + let(:expected_result) { test_suite_variant(test[:expectedResult]) } it 'returns correct result for `get_variant` method' do result = yggdrasil_engine.get_variant(toggle_name, context) || { :name => 'disabled', :payload => nil, - :enabled => false + :enabled => false, + :feature_enabled => false } expect(result[:name]).to eq(expected_result[:name]) expect(result[:payload]).to eq(expected_result[:payload]) expect(result[:enabled]).to eq(expected_result[:enabled]) + expect(result[:feature_enabled]).to eq(expected_result[:feature_enabled]) end end end diff --git a/ruby-engine/yggdrasil-engine.gemspec b/ruby-engine/yggdrasil-engine.gemspec index d234a2d0..317f59ab 100644 --- a/ruby-engine/yggdrasil-engine.gemspec +++ b/ruby-engine/yggdrasil-engine.gemspec @@ -3,7 +3,7 @@ Gem::Specification.new do |s| target_platform = -> { ENV['YGG_BUILD_PLATFORM'] || Gem::Platform::CURRENT } s.name = 'yggdrasil-engine' - s.version = '0.0.5.beta.11' + s.version = '0.0.5.beta.19' s.date = '2023-06-28' s.summary = 'Unleash engine for evaluating feature toggles' s.description = '...' diff --git a/unleash-yggdrasil/src/lib.rs b/unleash-yggdrasil/src/lib.rs index 2c37d51b..419f2940 100644 --- a/unleash-yggdrasil/src/lib.rs +++ b/unleash-yggdrasil/src/lib.rs @@ -529,11 +529,12 @@ impl EngineState { context: &Context, external_values: &Option>, ) -> Option { - self.get_toggle(name).and_then(|toggle| { + self.get_toggle(name).map(|toggle| { if self.enabled(toggle, context, external_values) { self.check_variant_by_toggle(toggle, context) + .unwrap_or_default() } else { - None + VariantDef::default() } }) } @@ -650,6 +651,7 @@ impl VariantDef { } #[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone)] +#[serde(rename_all = "camelCase")] pub struct ExtendedVariantDef { pub name: String, #[serde(skip_serializing_if = "Option::is_none")] @@ -673,11 +675,11 @@ mod test { use serde::Deserialize; use std::{collections::HashMap, fs}; use test_case::test_case; - use unleash_types::client_features::{ClientFeatures, FeatureDependency, Override}; + use unleash_types::client_features::{ClientFeatures, FeatureDependency, Override, Payload}; use crate::{ check_for_variant_override, get_seed, CompiledToggle, CompiledVariant, Context, - EngineState, ExtendedVariantDef, VariantDef, + EngineState, VariantDef, }; const SPEC_FOLDER: &str = "../client-specification/specifications"; @@ -705,7 +707,15 @@ mod test { pub(crate) description: String, pub(crate) context: Context, pub(crate) toggle_name: String, - pub(crate) expected_result: ExtendedVariantDef, + pub(crate) expected_result: TestCaseVariantDef, + } + + #[derive(Deserialize, Debug)] + pub struct TestCaseVariantDef { + pub name: String, + pub payload: Option, + pub enabled: bool, + pub feature_enabled: bool, } fn load_spec(spec_name: &str) -> TestSuite { @@ -763,7 +773,10 @@ mod test { ); let expected = test_case.expected_result; let actual = engine.get_variant(&test_case.toggle_name, &test_case.context, &None); - assert_eq!(expected, actual); + assert_eq!(expected.enabled, actual.enabled); + assert_eq!(expected.feature_enabled, actual.feature_enabled); + assert_eq!(expected.name, actual.name); + assert_eq!(expected.payload, actual.payload); } } } diff --git a/unleash-yggdrasil/src/strategy_upgrade.rs b/unleash-yggdrasil/src/strategy_upgrade.rs index 2289a0a8..1af280ab 100644 --- a/unleash-yggdrasil/src/strategy_upgrade.rs +++ b/unleash-yggdrasil/src/strategy_upgrade.rs @@ -430,7 +430,7 @@ mod tests { variants: None, }; - let output = upgrade(&vec![strategy], &HashMap::new()); + let output = upgrade(&[strategy], &HashMap::new()); assert_eq!(output, "user_id in [\"123\",\"222\",\"88\"]".to_string()) } @@ -448,7 +448,7 @@ mod tests { variants: None, }; - let output = upgrade(&vec![strategy], &HashMap::new()); + let output = upgrade(&[strategy], &HashMap::new()); assert_eq!(output, "user_id in [\"123\",\"222\",\"88\"]".to_string()) } @@ -472,7 +472,7 @@ mod tests { variants: None, }; - let output = upgrade(&vec![strategy], &HashMap::new()); + let output = upgrade(&[strategy], &HashMap::new()); assert_eq!(output, "(true and (user_id in [\"7\"]))".to_string()) } @@ -496,7 +496,7 @@ mod tests { variants: None, }; - let output = upgrade(&vec![strategy], &HashMap::new()); + let output = upgrade(&[strategy], &HashMap::new()); assert_eq!( output, "(true and (user_id in [\"7\"] and user_id in [\"7\"]))".to_string() @@ -544,7 +544,7 @@ mod tests { #[test] fn no_strategy_is_always_true() { - let output = upgrade(&vec![], &HashMap::new()); + let output = upgrade(&[], &HashMap::new()); assert_eq!(output.as_str(), "true") } @@ -568,7 +568,7 @@ mod tests { variants: None, }; - let output = upgrade(&vec![strategy], &HashMap::new()); + let output = upgrade(&[strategy], &HashMap::new()); assert_eq!( output.as_str(), "(true and (context[\"country\"] in [\"norway\"]))" @@ -592,7 +592,7 @@ mod tests { variants: None, }; - let output = upgrade(&vec![strategy], &HashMap::new()); + let output = upgrade(&[strategy], &HashMap::new()); assert_eq!( output.as_str(), "55% sticky on user_id with group_id of \"Feature.flexibleRollout.userId.55\"" @@ -615,7 +615,7 @@ mod tests { variants: None, }; - let output = upgrade(&vec![strategy], &HashMap::new()); + let output = upgrade(&[strategy], &HashMap::new()); assert_eq!(output.as_str(), "55% sticky on user_id"); } @@ -635,7 +635,7 @@ mod tests { variants: None, }; - let output = upgrade(&vec![strategy], &HashMap::new()); + let output = upgrade(&[strategy], &HashMap::new()); assert_eq!( output.as_str(), "55% sticky on user_id | session_id | random[10000] with group_id of \"Feature.flexibleRollout.userId.55\"" @@ -657,7 +657,7 @@ mod tests { variants: None, }; - let output = upgrade(&vec![strategy], &HashMap::new()); + let output = upgrade(&[strategy], &HashMap::new()); assert_eq!( output.as_str(), "55% sticky on user_id | session_id | random[10000]" @@ -681,7 +681,7 @@ mod tests { variants: None, }; - let output = upgrade(&vec![strategy], &HashMap::new()); + let output = upgrade(&[strategy], &HashMap::new()); assert_eq!( output.as_str(), format!( @@ -707,7 +707,7 @@ mod tests { variants: None, }; - let output = upgrade(&vec![strategy], &HashMap::new()); + let output = upgrade(&[strategy], &HashMap::new()); assert_eq!( output.as_str(), format!("55% sticky on random[10000] with group_id of \"Feature.flexibleRollout.userId.55\"") @@ -806,7 +806,7 @@ mod tests { variants: None, }; - let output = upgrade(&vec![custom_strategy], &HashMap::new()); + let output = upgrade(&[custom_strategy], &HashMap::new()); assert_eq!(output.as_str(), "external_value[\"customStrategy1\"]") } @@ -874,7 +874,7 @@ mod tests { variants: None, }; - let output = upgrade(&vec![strategy], &HashMap::new()); + let output = upgrade(&[strategy], &HashMap::new()); assert!(compile_rule(&output).is_ok()); assert_eq!(output.as_str(), "hostname in [\"DOS\", \"pop-os\"]"); }