Skip to content

Commit

Permalink
Merge pull request #7 from TechForPalestine/unify-brands
Browse files Browse the repository at this point in the history
Recenter yaml files around brands instead of companies
  • Loading branch information
THM222 authored Jan 8, 2024
2 parents 9f5d06a + 9e0b197 commit bda1caf
Show file tree
Hide file tree
Showing 16 changed files with 231 additions and 78 deletions.
16 changes: 5 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,17 @@ jobs:

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v3

# Runs a single command using the runners shell
- name: Run a one-line script
run: echo Hello, world!

# Setup and run python script, generates a json file
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pip' # caching pip dependencies
- run: |
pip install -r requirements.txt
- run: pip install -r requirements.txt
- name: Validate YAML
run: |
python --version
python validate_model.py
python validate_yaml.py
if_merged:
if: github.event.pull_request.merged == true
Expand All @@ -55,7 +49,7 @@ jobs:
cache: 'pip' # caching pip dependencies
- run: |
pip install -r requirements.txt
python validate_model.py
python validate_yaml.py
python generate_model.py
- uses: mikeal/publish-to-github-action@master
env:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.DS_Store
.rtx.toml
49 changes: 6 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,50 +11,13 @@ Sources:

- https://pastebin.com/raw/ks9GRE4L

## Data
All data is inputted & stored as YAML files in the `data/` directory.
Output formats, such as CSV and JSON are in the `generated/` directory.

## Model

Standardised data model for each company:

Example:

```yaml

# name: required, brand name
- name: "Brand"

# website: optional, website of company, useful for alternatives to help users navigate to and shop from
website:
# image_url: optional, link to brand logo image
image_url: |-
https://1000logos.net/wp-content/uploads/2023/03/Whiskas-Logo-2003.png
# categories/tags: optional, for grouping data, makes it easier to find alternatives
categories: []

# parents: required, list of parents, since one brand can have different parent companies in a different country/region
parents:
# name: required, parent company name
- name: "Parent Company"

# location: required, list of locations where this is the parent company of the brand
location: [global]

# level: required, boycotting level, one of direct, alternative
level: direct

# details: optional - boycotting details, relevant for boycott brand, can be empty for alternative
# reason: reason for boycotting (if applicable)
# source_url: evidence for why this brand/parent should be boycotted
details:
reason: |-
**Wilson Partnership**
**Wilson** has partnered with **Delta Galil Industries**, Ltd. (DELT/Tel Aviv Stock Exchange), the global manufacturer and marketer of branded and private label apparel products for men, women, and children. **Delta Galil Industries** is an **Israeli** textile firm headquartered in **Tel Aviv**, with plants around the world.
source_url: |-
https://deltagalil.com/brands/licensed-brands/default.aspx
```
Schemas for the YAML data can be found in the `schemas` directory, along with descriptions for each field.
These schemas are in [JSON Schema](https://json-schema.org/) format, but represented in YAML for simplicity.
The `validate_yaml.py` script validates all brands and companies using the schemas.

## Useful Resources & Links

Expand Down
2 changes: 0 additions & 2 deletions data/alternative_brands/drinkmate.yaml

This file was deleted.

13 changes: 7 additions & 6 deletions data/companies/ahava.yaml → data/brands/ahava.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
name: "Ahava"
reason: |-
status: avoid
reasons: [operations_in_settlements, operations_in_israel]
countries: [global]
website: https://www.ahava.com/
logo_url: https://upload.wikimedia.org/wikipedia/commons/8/81/AhavaLogo.png
description: |-
Ahava is an Israeli cosmetics company which operates its main manufacturing plant and showroom in Mitzpe Shalem,
an illegal settlement in the West Bank.[^1]
The Palestinian BDS National Committee has called for a boycott of Ahava.[^2]
[^1]: https://en.wikipedia.org/wiki/Ahava
[^2]: https://bdsmovement.net/Act-Now-Against-These-Companies-Profiting-From-Genocide
brands:
- name: Ahava
slug: ahava
alternatives: []
[^2]: https://bdsmovement.net/Act-Now-Against-These-Companies-Profiting-From-Genocide
5 changes: 5 additions & 0 deletions data/brands/drinkmate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: "Drinkmate"
status: neutral
countries: [us, ca, gb, eu, au, co, pe, ae, sa, jp, sg, tw]
website: https://idrinkproducts.com/
description: Drinkmate offers sparkling water and soda makers (also known as soda machines).
11 changes: 5 additions & 6 deletions data/companies/puma-se.yaml → data/brands/puma.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
name: "Puma SE"
reason: |-
name: "Puma"
status: avoid
reasons: [operations_in_israel]
countries: [global]
description: |-
The Palestinian BDS National Committee has called for a boycott of Puma[^1] for several reasons, including their
sponsorship of the Israeli Football Association (IFA), which includes teams in illegal settlements on occupied
Palestinian land.
[^1]: https://bdsmovement.net/boycott-puma
brands:
- name: Puma
slug: puma
alternatives: []
16 changes: 16 additions & 0 deletions data/brands/sabra.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: "Sabra"
status: avoid
reasons: [operations_in_israel]
categories: [food]
website: https://sabra.com/
description: |-
Sabra was an Isareli hummus company, and is now a joint venture between Pepsi and Strauss. Strauss is an Israeli food company.
alternatives_text: |-
Most hummus is not Israeli. Any non-Israeli hummus at your local grocery store is preferred over Sabra.
stakeholders:
- id: pepsico
type: owner
percent: 50
- id: strauss-group
type: owner
percent: 50
18 changes: 18 additions & 0 deletions data/brands/sodastream.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: "SodaStream"
status: avoid
reasons: [operations_in_israel]
countries: [global]
website: https://sodastream.com/
logo_url: https://upload.wikimedia.org/wikipedia/commons/thumb/6/63/Soda_Stream_Logo.svg/2560px-Soda_Stream_Logo.svg.png
description: |- # optional
SodaStream has long been a BDS target due to their operation of factories on stolen land and their racial discrimination against Palestinian workers.[^1]
[^1]: https://bdsmovement.net/Act-Now-Against-These-Companies-Profiting-From-Genocide
alternatives: [drinkmate]
stakeholders:
- id: pepsi
type: owner
percent: 50
- id: strauss-group
type: owner
percent: 50
10 changes: 2 additions & 8 deletions data/companies/pepsico.yaml
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
name: "PepsiCo, Inc."
reason: |-
status: avoid
description: |-
PepsiCo purchased the Israeli company SodaStream in August 2018.[^1] SodaStream has long been a BDS target due to
their operation of factories on stolen land and their racial discrimination against Palestinian workers.[^2]
Pepsi also owns 50% of Sabra, with the other 50% being owned by Israeli food company Strauss.
[^1]: https://www.nasdaq.com/articles/sodastream-sells-out-price-too-low-2018-08-20
[^2]: https://bdsmovement.net/Act-Now-Against-These-Companies-Profiting-From-Genocide
brands:
- name: SodaStream
slug: sodastream
alternatives: [drinkmate]
- name: Sabra
slug: sabra
alternatives: []
4 changes: 4 additions & 0 deletions data/companies/strauss-group.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name: "Strauss Group Ltd."
status: avoid
description: |-
Strauss Group is an Israeli manufacturer and marketer of consumer foods.
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@

jsonschema == 4.20.0
pyyaml == 6.0.1
92 changes: 92 additions & 0 deletions schemas/brand_schema.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
type: object
description: A brand is something that a consumer may search to know whether or not to purchase a product.
properties:
name:
description: Name of the brand
type: string
description:
description: Explanation of why the brand is on this list. Or, if it's not a brand to avoid, just a description of the brand.
type: string
status:
description: Whether to support or avoid this brand
type: string
enum:
- support
- neutral
- avoid
reasons:
description: A list of reasons for why consumers should avoid this brand.
type: array
items:
type: string
enum:
- operations_in_israel
- operations_in_settlements
countries:
description: |-
A list of countries (ISO alpha-2 country codes) that the brand operates in.
Useful for filtering for brands that are relevant to a specific region.
"global" means it is available in all countries.
type: array
items:
anyOf:
- type: string
enum: [global]
- type: string
pattern: "^[a-z]{2}$"
categories:
type: array
items:
type: string
enum: [food]
website:
type: string
format: uri
pattern: "^https?://"
logo_url:
description: Logo should be at least 200x200 pixels
type: string
format: uri
pattern: "^https?://"
alternatives:
description: List of brands that would be an alternative option to purchasing from this brand.
type: array
items:
type: string
pattern: "^[a-z][a-z-]+[a-z]$"
alternatives_text:
description: |-
Plain text description of alternatives.
Especially useful when alternatives are difficult to enumerate.
type: string
stakeholders:
description: |-
If useful, a list of stakeholders, such as companies who own this brand.
type: array
items:
anyOf:
- type: object
properties:
id:
type: string
pattern: "^[a-z][a-z-]+[a-z]$"
type:
type: string
enum: [owner]
ownership_percent:
type: number
minimum: 10
maximum: 100
allOf:
if:
properties:
status:
const: avoid
required: [status]
then:
required: [reasons]
required:
- name
- status
- description
additionalProperties: false
21 changes: 21 additions & 0 deletions schemas/company_schema.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
type: object
description: A company is an entity that owns more than one brand, or owns other companies.
properties:
name:
type: string
description: Name of the company
description:
type: string
description: Description of the company, including why it is on the list
status:
type: string
description: Whether to support or avoid this company
enum:
- support
- neutral
- avoid
required:
- name
- status
- description
additionalProperties: false
1 change: 0 additions & 1 deletion validate_model.py

This file was deleted.

47 changes: 47 additions & 0 deletions validate_yaml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import os
import glob
import yaml
import logging
import jsonschema
from jsonschema import validate

def get_filename_only(file_path):
base_name = os.path.basename(file_path)
filename_only, _ = os.path.splitext(base_name)
return filename_only

def load_yaml(file_path):
with open(file_path, 'r') as file:
return yaml.safe_load(file)

def validate_with_schema(file_path, schema):
try:
validate(load_yaml(file_path), schema)
return True
except jsonschema.exceptions.ValidationError as ve:
logging.error('Validation error in ' + get_filename_only(file_path))
logging.error(ve)
return False

def main():
global root_path
root_path = os.path.dirname(os.path.realpath(__file__))

brand_schema = load_yaml(os.path.join(root_path, 'schemas/brand_schema.yaml'))
brand_files = glob.glob(os.path.join(root_path, 'data/brands/') + '*.yaml')
print('Validating', len(brand_files), 'brands')
for file in brand_files:
if not validate_with_schema(file, brand_schema):
exit(1)
print('All brands are valid.')

company_schema = load_yaml(os.path.join(root_path, 'schemas/company_schema.yaml'))
company_files = glob.glob(os.path.join(root_path, 'data/companies/') + '*.yaml')
print('Validating', len(company_files), 'companies')
for file in company_files:
if not validate_with_schema(file, company_schema):
exit(1)
print('All companies are valid.')

if __name__ == "__main__":
main()

0 comments on commit bda1caf

Please sign in to comment.