diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..957e5f3 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,76 @@ +# Tests aryeo/avro-php and publishes it to the Artifactory Composer repository. +# +# Branches run validation and the tests. A semver tag push (e.g. 1.1.1) runs the same +# checks, then packages the tagged source and publishes it. +# +# The job scripts come from the shared template. +include: + - project: vendor-platform/ci_cd/gitlab-ci-templates + ref: main + file: php-composer-package.yml + +stages: + - test + - package + - publish + +default: + tags: + - build + interruptible: true + +workflow: + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS + when: never + - if: $CI_COMMIT_BRANCH + - if: $CI_COMMIT_TAG + +validate: + stage: test + extends: .php-composer + script: + - composer validate --strict + +# GitHub runs these tests in an image that also builds the gmp and snappy extensions. The CI +# image has neither: LongEncodingTest skips its GMP tests (the library uses gmp only on 32-bit +# PHP), and the snappy codec cases in DataFileTest error until a PHP CI image includes snappy. +tests: + stage: test + extends: .php-tests + script: + # The tests write to these directories, as in the GitHub workflow. + - mkdir -p build/tmp build/share/test/schemas build/build/interop/data + - composer show -D + - vendor/bin/phpunit + +package: + stage: package + extends: .package + needs: [validate, tests] + rules: + - if: $CI_COMMIT_TAG =~ /^v?\d+\.\d+\.\d+$/ + +publish: + stage: publish + extends: .publish + needs: [package] + rules: + - if: $CI_COMMIT_TAG =~ /^v?\d+\.\d+\.\d+$/ + +# Publishes existing tags that predate the GitLab pipeline. Run a pipeline on master with +# BACKFILL_TAGS set, e.g. "1.0.0 1.1.0". Versions already in Artifactory are skipped. +backfill:package: + stage: package + extends: .backfill-package + needs: [] + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $BACKFILL_TAGS + +backfill:publish: + stage: publish + extends: .backfill-publish + needs: ["backfill:package"] + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $BACKFILL_TAGS diff --git a/composer.json b/composer.json index 4e8eedc..ef3b667 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { - "name": "flix-tech/avro-php", - "description": "Avro schema encoder/decoder. Fork of rg/avro-php", + "name": "aryeo/avro-php", + "description": "Fork of flix-tech/avro-php to patch schema object functionality for compatability with Streamz ", "license": "Apache-2.0", "require": { "php": "^8.1" @@ -8,6 +8,9 @@ "require-dev": { "phpunit/phpunit": "^10.5" }, + "replace": { + "flix-tech/avro-php": "5.1.1" + }, "suggest": { "ext-gmp": "Large integer support for 32-bit platforms.", "ext-zlib": "Zlib support for Deflate codec.", diff --git a/lib/avro/schema.php b/lib/avro/schema.php index 89b0de0..2b8fcae 100644 --- a/lib/avro/schema.php +++ b/lib/avro/schema.php @@ -183,6 +183,11 @@ class AvroSchema */ const TYPE_ATTR = 'type'; + /** + * @var string schema tags attribute name + */ + const TAGS_ATTR = 'tags'; + /** * @var string named schema name attribute name */ @@ -334,7 +339,7 @@ static function real_parse($avro, $default_namespace=null, &$schemata=null) $extra_attributes = array_diff_key($avro, array_flip(self::$reserved_attrs)); if (self::is_primitive_type($type)) - return new AvroPrimitiveSchema($type, $logical_type, $extra_attributes, true); + return new AvroPrimitiveSchema($type, $logical_type, $extra_attributes, false); elseif (self::is_named_type($type)) { @@ -393,7 +398,7 @@ static function real_parse($avro, $default_namespace=null, &$schemata=null) $type)); } elseif (self::is_primitive_type($avro)) - return new AvroPrimitiveSchema($avro, null, [], true); + return new AvroPrimitiveSchema($avro, null, [], false); else throw new AvroSchemaParseException( sprintf('%s is not a schema we know about.', @@ -893,6 +898,8 @@ public function to_avro() $avro[AvroSchema::NAMESPACE_ATTR] = $namespace; if (!is_null($this->doc)) $avro[AvroSchema::DOC_ATTR] = $this->doc; + if (array_key_exists(AvroSchema::TAGS_ATTR, $this->extra_attributes)) + $avro[AvroSchema::TAGS_ATTR] = $this->extra_attributes[AvroSchema::TAGS_ATTR]; if (null !== $this->logical_type) { return array_merge($avro, array( self::LOGICAL_TYPE_ATTR => $this->logical_type @@ -1332,6 +1339,14 @@ static function parse_fields($field_data, $default_namespace, &$schemata) $has_default = true; } + $tags = null; + $has_tags = false; + if (array_key_exists(AvroField::TAGS_ATTR, $field)) + { + $tags = $field[AvroField::TAGS_ATTR]; + $has_tags = true; + } + if (in_array($name, $field_names)) throw new AvroSchemaParseException( sprintf("Field name %s is already in use", $name)); @@ -1346,7 +1361,7 @@ static function parse_fields($field_data, $default_namespace, &$schemata) $field_schema = self::subparse($type, $default_namespace, $schemata); $new_field = new AvroField($name, $field_schema, $is_schema_from_schemata, - $has_default, $default, $order, $doc, + $has_default, $default, $has_tags, $tags, $order, $doc, $logical_type, $precision, $scale); $field_names []= $name; $fields []= $new_field; @@ -1467,6 +1482,11 @@ class AvroField extends AvroSchema */ const SCALE_ATTR = 'scale'; + /** + * @var string + */ + const TAGS_ATTR = 'tags'; + /** * @var string */ @@ -1526,6 +1546,16 @@ private static function check_order_value($order) */ private $default; + /** + * @var boolean whether or no there is a tags value + */ + private $has_tags; + + /** + * @var string field tags value + */ + private $tags; + /** * @var string sort order of this field */ @@ -1569,7 +1599,7 @@ private static function check_order_value($order) * @todo Check validity of $order value */ public function __construct($name, $schema, $is_type_from_schemata, - $has_default, $default, $order=null, $doc=null, + $has_default, $default, $has_tags, $tags, $order=null, $doc=null, $logical_type=null, $precision=null, $scale=null) { if (!AvroName::is_well_formed_name($name)) @@ -1581,6 +1611,9 @@ public function __construct($name, $schema, $is_type_from_schemata, $this->has_default = $has_default; if ($this->has_default) $this->default = $default; + $this->has_tags = $has_tags; + if ($this->has_tags) + $this->tags = $tags; $this->check_order_value($order); $this->order = $order; $this->doc = $doc; @@ -1602,6 +1635,9 @@ public function to_avro() if ($this->has_default) $avro[AvroField::DEFAULT_ATTR] = $this->default; + if ($this->has_tags) + $avro[AvroField::TAGS_ATTR] = $this->tags; + if ($this->order) $avro[AvroField::ORDER_ATTR] = $this->order;