Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recenter yaml files around brands instead of companies #7

Merged
merged 3 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of exitting on first failure, i think it'd be good to check and log messages for all failures, then exit

print('All companies are valid.')

if __name__ == "__main__":
main()