Skip to content
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
44 changes: 15 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
[![Scheduled CDN Upload](https://github.com/autonity/partner-registry/actions/workflows/scheduled-deployment.yaml/badge.svg)](https://github.com/autonity/partner-registry/actions/workflows/scheduled-deployment.yaml) [![Tests](https://github.com/autonity/partner-registry/actions/workflows/unit-tests.yaml/badge.svg?branch=develop)](https://github.com/autonity/partner-registry/actions/workflows/unit-tests.yaml)

# ECOSYSTEM Partner Registry

How to add your project to our [Partner-Registry](https://github.com/autonity/partner-registry) repo.

## Adding your project to the Partner Registry
# Adding your Project to the ECOSYSTEM Partner Registry

Firstly you need to fork the registry [repo](https://github.com/autonity/partner-registry), clone it locally and open in your favorite editor.

#### Step 1: Select the `partners/` folder.
### Step 1: Select the `partners/` folder.

#### Step 2: In the `partners/` folder create a folder named according to your project.
### Step 2: In the `partners/` folder create a folder named according to your project.

#### Step 3: In your project folder you need to add three files: `thumbnail.png`, `banner.png` & `info.yaml`.

The `info.yaml` file looks like this:
### Step 3: In your project folder you need to add light and dark images and a config file.
These are:
#### - info.yaml

```yaml
name: 'Test Partner' # 20 characters max
Expand All @@ -26,28 +22,18 @@ tags: # max 3 tags, the most relevant should be listed first
url: 'https://www.autonity.org' # must be a valid https url
```

The `thumbnail.png` must be no more than 196x160px. This is used when viewing your project in the grid list.
The `banner.png` must be no more than 274x105px. This is used when your product is featured and is in the carousel list.

#### Tags should be added in order of relevance! The most relevant tag should be the first.

#### Step 4: Create a pull-request containing your updated data.

#### Step 5: Submit Your Pull Request

**When you submit your PR, please use the following naming convention for the title:**

- **Title Format**: `Add <Project Name> to Partner Registry`
- **Example**: `Add MyProject to Partner Registry`
#### - thumbnail_light.png & thumbnail_dark.png:
These must be **no more** than 196x160px. This is used when viewing your project in the grid list.

If you are successfull, your PR will have a `new-partner` label applied to it:
#### - banner_light.png & banner_dark.png
These must be **no more** than 274x105px. This is used when your product is featured and is in the carousel list.

![Success Bot Label](resources/tutorial/success-label.png)
### Step 4: Create a pull-request containing your updated data.

And a success comment
### Step 5: Submit Your Pull Request

![Success Bot Comment](resources/tutorial/success-bot-comment.png)
---

If your PR failed validity checks, a bot will comment on the reasons why
If your PR fails validation checks, please check the github action, it will have the reason why. This will be in the **Check partners are valid** section of the github action.

![Failure bot comment](resources/tutorial/failure-bot-comment.png)
![Failure bot comment](resources/tutorial/gha.png)
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "autonity-partner-registry",
"version": "1.0.0",
"version": "1.0.5",
"description": "Sandbox for testing Github features relevant to Engineering",
"scripts": {
"build": "npx tsc",
Expand Down Expand Up @@ -45,4 +45,4 @@
"js-yaml": "^4.1.0",
"sharp": "^0.33.5"
}
}
}
File renamed without changes
Binary file added partners/Stakeflow/banner_light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed partners/Stakeflow/thumbnail.png
Binary file not shown.
Binary file added partners/Stakeflow/thumbnail_dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added partners/Stakeflow/thumbnail_light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
Binary file added partners/VIA Labs/banner_light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed partners/VIA Labs/thumbnail.png
Binary file not shown.
Binary file added partners/VIA Labs/thumbnail_dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added partners/VIA Labs/thumbnail_light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
Binary file added partners/Web3CDN/banner_light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed partners/Web3CDN/thumbnail.png
Binary file not shown.
Binary file added partners/Web3CDN/thumbnail_dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added partners/Web3CDN/thumbnail_light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
Binary file added partners/chorus-one/banner_light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added partners/chorus-one/thumbnail_light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 0 additions & 52 deletions partners/example/README.md

This file was deleted.

Binary file added partners/example/banner_dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added partners/example/banner_light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
File renamed without changes
Binary file removed resources/tutorial/failure-bot-comment.png
Diff not rendered.
Binary file added resources/tutorial/gha.png
Binary file removed resources/tutorial/success-bot-comment.png
Diff not rendered.
Binary file removed resources/tutorial/success-label.png
Diff not rendered.
9 changes: 6 additions & 3 deletions scripts/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
export const partnerFileName = 'info.yaml'
export const defaultThumbnailName = 'thumbnail.png'
export const defaultBannerName = 'banner.png'

export const defaultThumbnailNameLight = 'thumbnail_light.png'
export const defaultBannerNameLight = 'banner_light.png'
export const defaultThumbnailNameDark = 'thumbnail_dark.png'
export const defaultBannerNameDark = 'banner_dark.png'
export const partnerDir = '../partners'
export const partnerStorageName = 'partners.json'
export const examplePartnerName = 'example'
Expand All @@ -9,7 +12,7 @@ export const longDescriptionLimit = 175
export const nameLimit = 20
export const tagCharacterLimit = 12
export const maxNumberOfTags = 3
export const maxThumbnailWidth = 196
export const maxThumbnailWidth = 160
export const maxThumbnailHeight = 160
export const maxBannerWidth = 274
export const maxBannerHeight = 105
1 change: 0 additions & 1 deletion scripts/partners.json

This file was deleted.

59 changes: 41 additions & 18 deletions scripts/upload-layer.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { S3Client, PutObjectCommand, ListObjectsV2Command, DeleteObjectCommand } from '@aws-sdk/client-s3'
import dotenv from 'dotenv'
import { buildPartnersJson, getPartnerDirectories } from './generate-partners'
import { validatePartnerInfo } from './validate-partners'
import path from 'path'
import * as fs from 'fs'

import { DeleteObjectCommand, ListObjectsV2Command, PutObjectCommand, S3Client } from '@aws-sdk/client-s3'
import { buildPartnersJson, getPartnerDirectories } from './generate-partners'

import dotenv from 'dotenv'
import { getJsonfromYaml } from './translation-layer'
import { partnerFileName } from './constants'
import path from 'path'
import { validatePartnerInfo } from './validate-partners'

dotenv.config()

const REGION = process.env.REGION ?? ''
Expand All @@ -26,9 +29,9 @@ const cleanupUnusedImages = async (s3Client: S3Client, currentPartnerNames: Set<
Bucket: BUCKET_NAME,
Prefix: 'images/'
}

const listedObjects = await s3Client.send(new ListObjectsV2Command(listParams))

if (!listedObjects.Contents) return

for (const item of listedObjects.Contents) {
Expand Down Expand Up @@ -81,7 +84,7 @@ const run = async () => {
console.log('Proceeding with upload...')
const partners = buildPartnersJson(partnerDirectories)
const currentPartnerNames = new Set(partners.map(partner => partner.name))

const uploadParams = {
Bucket: BUCKET_NAME,
Key: OBJECT_KEY,
Expand All @@ -90,18 +93,38 @@ const run = async () => {
}
const data = await s3Client.send(new PutObjectCommand(uploadParams))
console.log(`Partners uploaded. ETag: ${data.ETag}`)

console.log('Proceeding with image uploads...')
for (const partnerDir of partnerDirectories) {
const {name } = getJsonfromYaml(`${partnerDir}/${partnerFileName}`)
const thumbnail = path.join(partnerDir, 'thumbnail.png')
const thumbnailKey = `images/${name}/thumbnail.png`

const banner = path.join(partnerDir, 'banner.png')
const bannerKey = `images/${name}/banner.png`

await uploadFile(s3Client, thumbnail, thumbnailKey)
await uploadFile(s3Client, banner, bannerKey)
const { name } = getJsonfromYaml(`${partnerDir}/${partnerFileName}`)

console.log('Uploading images for:', name)

// Light thumbnail
const thumbnailLight = path.join(partnerDir, 'thumbnail_light.png')
const thumbnailLightKey = `images/${name}/thumbnail_light.png`

// Dark thumbnail
const thumbnailDark = path.join(partnerDir, 'thumbnail_dark.png')
const thumbnailDarkKey = `images/${name}/thumbnail_dark.png`

// Light Banner
const bannerLight = path.join(partnerDir, 'banner_light.png')
const bannerLightKey = `images/${name}/banner_light.png`

// Dark Banner
const bannerDark = path.join(partnerDir, 'banner_dark.png')
const bannerDarkKey = `images/${name}/banner_dark.png`

//upload light thumbnail
await uploadFile(s3Client, thumbnailLight, thumbnailLightKey)
//upload dark thumbnail
await uploadFile(s3Client, thumbnailDark, thumbnailDarkKey)

//upload light banner
await uploadFile(s3Client, bannerLight, bannerLightKey)
//upload dark banner
await uploadFile(s3Client, bannerDark, bannerDarkKey)
}

console.log('Cleaning up unused images...')
Expand Down
77 changes: 61 additions & 16 deletions scripts/validate-partners.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as fs from 'fs';
import * as path from 'path';

import { defaultBannerName, defaultThumbnailName, longDescriptionLimit, maxBannerHeight, maxBannerWidth, maxNumberOfTags, maxThumbnailHeight, maxThumbnailWidth, nameLimit, partnerFileName, shortDescriptionLimit, tagCharacterLimit } from './constants';
import { defaultBannerNameDark, defaultBannerNameLight, defaultThumbnailNameDark, defaultThumbnailNameLight, longDescriptionLimit, maxBannerHeight, maxBannerWidth, maxNumberOfTags, maxThumbnailHeight, maxThumbnailWidth, nameLimit, partnerFileName, shortDescriptionLimit, tagCharacterLimit } from './constants';
import { getPartnerDirectories, getPartnerObject } from './generate-partners';

import { Partner } from './interface';
Expand All @@ -11,7 +11,7 @@ const requiredFields: (keyof Partner)[] = ['name', 'shortDescription', 'longDesc

/**
* Type guard to check if an object conforms to the Partner interface.
*
*
* @param {any} obj - The object to be checked.
* @returns {obj is Partner} - Returns true if the object matches the Partner interface.
*/
Expand All @@ -32,11 +32,12 @@ export function isPartner(obj: any): obj is Partner {
export async function validatePartnerInfo(partnerPath: string): Promise<string[]> {

const fullPartnerPath = path.join(partnerPath, partnerFileName);
const fullThumbnailPath = path.join(partnerPath, defaultThumbnailName);
const fullBannerPath = path.join(partnerPath, defaultBannerName);
const fullThumbnailPathLight = path.join(partnerPath, defaultThumbnailNameLight);
const fullBannerPathLight = path.join(partnerPath, defaultBannerNameLight);
const fullThumbnailPathDark = path.join(partnerPath, defaultThumbnailNameDark);
const fullBannerPathDark = path.join(partnerPath, defaultBannerNameDark);

let errorMessages: string[] = [];

if (!fs.existsSync(fullPartnerPath)) {
errorMessages.push(`${partnerFileName} is missing in ${partnerPath}`);
return errorMessages;
Expand All @@ -51,24 +52,43 @@ export async function validatePartnerInfo(partnerPath: string): Promise<string[]
});

// check images
if (!fs.existsSync(fullThumbnailPath)) {
errorMessages.push(`Thumbnail image is missing`);
if (!fs.existsSync(fullThumbnailPathLight)) {
errorMessages.push(`Light thumbnail image is missing`);
}

if (!fs.existsSync(fullThumbnailPathDark)) {
errorMessages.push(`Dark thumbnail image is missing`);
}

if (!fs.existsSync(fullBannerPath)) {
errorMessages.push(`Banner image is missing`)
if (!fs.existsSync(fullBannerPathLight)) {
errorMessages.push(`Light banner image is missing`)
}

if (!fullThumbnailPath.endsWith('.png')) {
errorMessages.push(`Thumbnail image is not a PNG`)
if (!fs.existsSync(fullBannerPathDark)) {
errorMessages.push(`Dark banner image is missing`)
}

if (!fullBannerPath.endsWith('.png')) {
errorMessages.push(`Banner image is not a PNG`)
if (!fullThumbnailPathLight.endsWith('.png')) {
errorMessages.push(`Light Thumbnail image is not a PNG`)
}

errorMessages = errorMessages.concat(await checkImageDimensions(fullThumbnailPath, maxThumbnailWidth, maxThumbnailHeight));
errorMessages = errorMessages.concat(await checkImageDimensions(fullBannerPath, maxBannerWidth, maxBannerHeight));
if (!fullThumbnailPathDark.endsWith('.png')) {
errorMessages.push(`Dark Thumbnail image is not a PNG`)
}

if (!fullBannerPathLight.endsWith('.png')) {
errorMessages.push(`Light Banner image is not a PNG`)
}

if (!fullBannerPathDark.endsWith('.png')) {
errorMessages.push(`Dark Banner image is not a PNG`)
}

errorMessages = errorMessages.concat(await checkImageDimensionsExact(fullThumbnailPathLight, maxThumbnailWidth, maxThumbnailHeight));
errorMessages = errorMessages.concat(await checkImageDimensions(fullBannerPathLight, maxBannerWidth, maxBannerHeight));

errorMessages = errorMessages.concat(await checkImageDimensionsExact(fullThumbnailPathDark, maxThumbnailWidth, maxThumbnailHeight));
errorMessages = errorMessages.concat(await checkImageDimensions(fullBannerPathDark, maxBannerWidth, maxBannerHeight));

// Check for character limits and valid types
validatePartnerFields(partnerInfo, errorMessages);
Expand All @@ -86,7 +106,7 @@ export async function validatePartnerInfo(partnerPath: string): Promise<string[]
* @param {string} filePath - The file path to the image.
* @returns {Promise<string[]>} - Returns a promise that resolves with an array of error messages if the image is invalid.
*/
async function checkImageDimensions(filePath: string, maxWidth = maxThumbnailWidth, maxHeight = maxThumbnailHeight): Promise<string[]> {
export async function checkImageDimensions(filePath: string, maxWidth = maxThumbnailWidth, maxHeight = maxThumbnailHeight): Promise<string[]> {
const errorMessages: string[] = [];
try {
const { width, height } = await sharp(filePath).metadata();
Expand All @@ -103,6 +123,31 @@ async function checkImageDimensions(filePath: string, maxWidth = maxThumbnailWid
}
}

/**
* Checks if the image at the given file path matches the exact width and height.
*
* @param {string} filePath - The file path to the image.
* @param {number} exactWidth - The required width of the image.
* @param {number} exactHeight - The required height of the image.
* @returns {Promise<string[]>} - Returns a promise that resolves with an array of error messages if the image does not match the exact dimensions.
*/
export async function checkImageDimensionsExact(filePath: string, exactWidth: number, exactHeight: number): Promise<string[]> {
const errorMessages: string[] = [];
try {
const { width, height } = await sharp(filePath).metadata();

if (!width || !height) {
errorMessages.push(`Image metadata could not be read for ${filePath}`);
} else if (width !== exactWidth || height !== exactHeight) {
errorMessages.push(`Image dimensions for ${filePath} are ${width}x${height}, but expected ${exactWidth}x${exactHeight}`);
}
} catch (error) {
errorMessages.push(`Error reading image metadata for ${filePath}: ${error}`);
}
return errorMessages;
}


/**
* Validates partner fields such as name, description, tags, and URL.
*
Expand Down
21 changes: 0 additions & 21 deletions tests/partners/autonity/README.md

This file was deleted.

Loading