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

feat: add token file validation CI #45

Merged
merged 5 commits into from
Apr 17, 2024
Merged

feat: add token file validation CI #45

merged 5 commits into from
Apr 17, 2024

Conversation

mmeloni
Copy link
Collaborator

@mmeloni mmeloni commented Apr 8, 2024

This PR add token meta json file validation step with this script:

https://github.com/InjectiveLabs/token-meta-validator

First it run a semantic content validtion check then it fetch provided markets to check existance.

image

If content is not matching provided struct schema it will error:
image

Summary by CodeRabbit

  • New Features
    • Introduced a validation process for token metadata files on pull requests, ensuring format correctness and market availability through Injective Protocol's exchange APIs.

Copy link

coderabbitai bot commented Apr 8, 2024

Walkthrough

The recent updates introduce a GitHub Actions workflow to validate JSON files during pull requests, ensuring they meet a specified structure. Additionally, a new Go program has been developed to validate these JSON files and interact with the Injective Protocol's APIs to retrieve market data based on the tokens specified in the files.

Changes

File Path Change Summary
.github/.../test.yaml Introduces a GitHub Actions workflow to validate token meta JSON files on pull requests to master.
internal/validator/main.go Adds a program to validate JSON format of token files and fetch market data from Injective Protocol.

🐇✨
In the world of code, where changes brew,
A rabbit hopped, and a new workflow flew.
Validating JSON, with a hop and a skip,
Fetching data where the market chips dip.
🌟📜🔍


Recent Review Details

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between b6ebe91 and caf55e0.
Files selected for processing (2)
  • .github/workflows/test.yaml (1 hunks)
  • internal/validator/main.go (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/test.yaml

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@mmeloni mmeloni force-pushed the feat/ci-valid branch 12 times, most recently from 998141b to 499a620 Compare April 9, 2024 07:49
@mmeloni mmeloni marked this pull request as ready for review April 9, 2024 08:50
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Comment on lines 30 to 33
- name: Install and build
run: |
cd validator
go install .
Copy link

Choose a reason for hiding this comment

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

Tip

Codebase Verification

The verification script confirmed that the token-meta-validator binary is not accessible in the PATH, indicating that the installation step in the workflow might not ensure the binary's availability for subsequent steps. This aligns with the initial concern raised in the review comment about ensuring the installed binary is accessible in the PATH.

Analysis chain

Ensure that the installed token-meta-validator binary is accessible in the PATH.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Verify if token-meta-validator binary is accessible
if ! command -v token-meta-validator &> /dev/null
then
    echo "token-meta-validator could not be found"
    exit 1
fi

Length of output: 131

@hmoragrega
Copy link
Contributor

why have a different repo for the validation command?
Looks more optimal to have it together, so we update the validation if we change the json schema

It can be put in the /internal folder so it's not imported where requiring this module

@mmeloni
Copy link
Collaborator Author

mmeloni commented Apr 11, 2024

why have a different repo for the validation command? Looks more optimal to have it together, so we update the validation if we change the json schema

It can be put in the /internal folder so it's not imported where requiring this module

done @hmoragrega

for key, client := range f.exchangeClient {
spotMarketInfo := injective_spot_exchange_rpcpb.MarketResponse{}
derivativeMarketInfo := injective_derivative_exchange_rpcpb.MarketResponse{}
spotMarketInfo, err := client.GetSpotMarket(ctx, market)
Copy link
Contributor

Choose a reason for hiding this comment

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

I’m not sure se should go as deep as check markets here, for example, do this requests return non active markets? I would simply validate the market Id is sintactically correct,

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Its present a market white list that allow to skip not existent markets check

Comment on lines +84 to +85
log.Errorf("cannot create testnet exchange client: %s", err)
os.Exit(1)

Choose a reason for hiding this comment

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

nit: we can use log.Fatalf("cannot read token file: %w", err) as a one-liner. It already calls os.Exit(1)

Comment on lines +135 to +137
if err != nil {
continue
}

Choose a reason for hiding this comment

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

We should never ignore an error or we might have a bad time troubleshooting issues.
I understand that this is just a validation tool and it shouldn't really bother us with bugs but we should always handle the error or log it.

For this case, a simple log would work

Copy link
Collaborator Author

@mmeloni mmeloni Apr 12, 2024

Choose a reason for hiding this comment

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

Its expected too much false positive errors here, but at the end Ill return last error if market is not found or in other cases

@proofofze
Copy link

proofofze commented Apr 11, 2024

why have a different repo for the validation command? Looks more optimal to have it together, so we update the validation if we change the json schema

It can be put in the /internal folder so it's not imported where requiring this module

@hmoragrega, I am not sure if I agree to have this inside internal. Tools are supposed to be on cmd, no? Maybe I am missing something

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Comment on lines +22 to +24
tokenFile := flag.String("token-file", "token.json", "path to token file")
marketSkipList := flag.String("market-skip-list", "", "comma separated list of markets to skip")
flag.Parse()
Copy link

Choose a reason for hiding this comment

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

Consider using a more descriptive flag usage message to improve user experience.

- tokenFile := flag.String("token-file", "token.json", "path to token file")
+ tokenFile := flag.String("token-file", "token.json", "Specify the path to the token JSON file to be validated.")
- marketSkipList := flag.String("market-skip-list", "", "comma separated list of markets to skip")
+ marketSkipList := flag.String("market-skip-list", "", "Specify a comma-separated list of market identifiers to skip during validation.")

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
tokenFile := flag.String("token-file", "token.json", "path to token file")
marketSkipList := flag.String("market-skip-list", "", "comma separated list of markets to skip")
flag.Parse()
tokenFile := flag.String("token-file", "token.json", "Specify the path to the token JSON file to be validated.")
marketSkipList := flag.String("market-skip-list", "", "Specify a comma-separated list of market identifiers to skip during validation.")
flag.Parse()

Comment on lines +33 to +38
log.Fatalf("cannot read token file: %s", err)
}
isValid := json.Valid(tokens)
if !isValid {
log.Fatalf("invalid json: %s", tokens)
}
Copy link

Choose a reason for hiding this comment

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

Ensure graceful handling of errors rather than using log.Fatalf which causes the program to exit immediately.

- log.Fatalf("cannot read token file: %s", err)
+ log.Errorf("cannot read token file: %s", err)
+ return
- log.Fatalf("invalid json: %s", tokens)
+ log.Errorf("invalid json: %s", tokens)
+ return

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
log.Fatalf("cannot read token file: %s", err)
}
isValid := json.Valid(tokens)
if !isValid {
log.Fatalf("invalid json: %s", tokens)
}
log.Errorf("cannot read token file: %s", err)
return
isValid := json.Valid(tokens)
if !isValid {
log.Errorf("invalid json: %s", tokens)
return
}

Comment on lines +45 to +46
if err != nil {
log.Fatalf("cannot decode token file: %s", err)
Copy link

Choose a reason for hiding this comment

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

Duplicate JSON decoding: decoder.Decode and json.Unmarshal are both used to decode the same token file.

Consider removing one of the decoding steps to optimize performance and avoid redundancy.

Comment on lines +61 to +65
exchangeClient, err := exchange.NewExchangeClient(network)
if err != nil {
log.Errorf("cannot create mainnet exchange client: %s", err)
os.Exit(1)
}
Copy link

Choose a reason for hiding this comment

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

Error handling could be improved by returning after logging the error, to prevent further execution.

- log.Errorf("cannot create mainnet exchange client: %s", err)
- os.Exit(1)
+ log.Errorf("cannot create mainnet exchange client: %s", err)
+ return

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
exchangeClient, err := exchange.NewExchangeClient(network)
if err != nil {
log.Errorf("cannot create mainnet exchange client: %s", err)
os.Exit(1)
}
exchangeClient, err := exchange.NewExchangeClient(network)
if err != nil {
log.Errorf("cannot create mainnet exchange client: %s", err)
return
}

Comment on lines +71 to +73
log.Errorf("cannot create testnet exchange client: %s", err)
os.Exit(1)
}
Copy link

Choose a reason for hiding this comment

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

Similar to previous comment, improve error handling by returning after logging.

- log.Errorf("cannot create testnet exchange client: %s", err)
- os.Exit(1)
+ log.Errorf("cannot create testnet exchange client: %s", err)
+ return

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
log.Errorf("cannot create testnet exchange client: %s", err)
os.Exit(1)
}
log.Errorf("cannot create testnet exchange client: %s", err)
return
}

Comment on lines +90 to +94
_, err = finder.findMarketOnAllNetwork(context.TODO(), market)
if err != nil {
log.Fatalf("%s: market %s not found: %s. If this is expected is possible to whitelist this market using `--market-skip-list` flag.", key, market, err)
}
log.Infof("%s: market %s found", key, market)
Copy link

Choose a reason for hiding this comment

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

Consider handling errors more gracefully instead of using log.Fatalf, which stops program execution.

- log.Fatalf("%s: market %s not found: %s. If this is expected is possible to whitelist this market using `--market-skip-list` flag.", key, market, err)
+ log.Errorf("%s: market %s not found: %s. Consider whitelisting this market using the `--market-skip-list` flag if this is expected.", key, market, err)
+ continue

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
_, err = finder.findMarketOnAllNetwork(context.TODO(), market)
if err != nil {
log.Fatalf("%s: market %s not found: %s. If this is expected is possible to whitelist this market using `--market-skip-list` flag.", key, market, err)
}
log.Infof("%s: market %s found", key, market)
_, err = finder.findMarketOnAllNetwork(context.TODO(), market)
if err != nil {
log.Errorf("%s: market %s not found: %s. Consider whitelisting this market using the `--market-skip-list` flag if this is expected.", key, market, err)
continue
}
log.Infof("%s: market %s found", key, market)

Comment on lines +105 to +131
func (f MarketFinder) findMarketOnAllNetwork(ctx context.Context, market string) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), 1000*time.Second)
defer cancel()
var err error
for key, client := range f.exchangeClient {
spotMarketInfo := injective_spot_exchange_rpcpb.MarketResponse{}
derivativeMarketInfo := injective_derivative_exchange_rpcpb.MarketResponse{}
spotMarketInfo, err = client.GetSpotMarket(ctx, market)
if err != nil {
derivativeMarketInfo, err = client.GetDerivativeMarket(ctx, market)
if err != nil &&
!strings.Contains(err.Error(), "not found") &&
!strings.Contains(err.Error(), "502") {
return "", fmt.Errorf("cannot get market %s on %s: %s", market, key, err)
}
if err != nil {
continue
}
return derivativeMarketInfo.Market.Ticker, nil
}
return spotMarketInfo.Market.Ticker, nil
}
if err != nil {
return "", fmt.Errorf("market %s not found: %s", market, err)
}
return "", fmt.Errorf("market %s not found", market)
}
Copy link

Choose a reason for hiding this comment

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

The method findMarketOnAllNetwork should accept a context from the caller instead of creating a new one to maintain control over the timeout across different calls.

- func (f MarketFinder) findMarketOnAllNetwork(ctx context.Context, market string) (string, error) {
-	ctx, cancel := context.WithTimeout(context.Background(), 1000*time.Second)
+ func (f MarketFinder) findMarketOnAllNetwork(ctx context.Context, market string) (string, error) {
+	ctx, cancel := context.WithTimeout(ctx, 1000*time.Second)
  defer cancel()

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
func (f MarketFinder) findMarketOnAllNetwork(ctx context.Context, market string) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), 1000*time.Second)
defer cancel()
var err error
for key, client := range f.exchangeClient {
spotMarketInfo := injective_spot_exchange_rpcpb.MarketResponse{}
derivativeMarketInfo := injective_derivative_exchange_rpcpb.MarketResponse{}
spotMarketInfo, err = client.GetSpotMarket(ctx, market)
if err != nil {
derivativeMarketInfo, err = client.GetDerivativeMarket(ctx, market)
if err != nil &&
!strings.Contains(err.Error(), "not found") &&
!strings.Contains(err.Error(), "502") {
return "", fmt.Errorf("cannot get market %s on %s: %s", market, key, err)
}
if err != nil {
continue
}
return derivativeMarketInfo.Market.Ticker, nil
}
return spotMarketInfo.Market.Ticker, nil
}
if err != nil {
return "", fmt.Errorf("market %s not found: %s", market, err)
}
return "", fmt.Errorf("market %s not found", market)
}
func (f MarketFinder) findMarketOnAllNetwork(ctx context.Context, market string) (string, error) {
ctx, cancel := context.WithTimeout(ctx, 1000*time.Second)
defer cancel()
var err error
for key, client := range f.exchangeClient {
spotMarketInfo := injective_spot_exchange_rpcpb.MarketResponse{}
derivativeMarketInfo := injective_derivative_exchange_rpcpb.MarketResponse{}
spotMarketInfo, err = client.GetSpotMarket(ctx, market)
if err != nil {
derivativeMarketInfo, err = client.GetDerivativeMarket(ctx, market)
if err != nil &&
!strings.Contains(err.Error(), "not found") &&
!strings.Contains(err.Error(), "502") {
return "", fmt.Errorf("cannot get market %s on %s: %s", market, key, err)
}
if err != nil {
continue
}
return derivativeMarketInfo.Market.Ticker, nil
}
return spotMarketInfo.Market.Ticker, nil
}
if err != nil {
return "", fmt.Errorf("market %s not found: %s", market, err)
}
return "", fmt.Errorf("market %s not found", market)
}

@hmoragrega hmoragrega merged commit a8a9211 into master Apr 17, 2024
3 checks passed
@hmoragrega hmoragrega deleted the feat/ci-valid branch April 17, 2024 13:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants