Skip to content

Commit ef9edc5

Browse files
authored
ci: Automate GitHub Release Status Update Based on ZetaChain Governance Proposals (#2192)
* adding pipeline to automatically update the release status when a release has gone live i.e. the upgrade height is met and the network is processing blocks again. The script will then update the github release from pre-release to release as long as the release name matches the release title from the governance proposal * updated links to new all that node links
1 parent 0afe725 commit ef9edc5

File tree

3 files changed

+169
-0
lines changed

3 files changed

+169
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import requests
2+
import time
3+
import logging
4+
import os
5+
from github import Github
6+
from datetime import datetime, timezone, timedelta
7+
import sys
8+
9+
# Setup logger
10+
logger = logging.getLogger(__name__)
11+
logger.setLevel(logging.DEBUG)
12+
ch = logging.StreamHandler()
13+
ch.setLevel(logging.DEBUG)
14+
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
15+
ch.setFormatter(formatter)
16+
logger.addHandler(ch)
17+
18+
STATUS_ENDPOINT = os.environ["STATUS_ENDPOINT"]
19+
PROPOSALS_ENDPOINT = os.environ["PROPOSAL_ENDPOINT"]
20+
21+
22+
def get_current_block_height():
23+
response = requests.get(STATUS_ENDPOINT)
24+
response.raise_for_status()
25+
data = response.json()
26+
return int(data['result']['sync_info']['latest_block_height'])
27+
28+
29+
def get_proposals():
30+
response = requests.get(PROPOSALS_ENDPOINT)
31+
response.raise_for_status()
32+
data = response.json()
33+
return [proposal['id'] for proposal in data['proposals']]
34+
35+
36+
def get_proposal_details(proposal_id):
37+
url = f"{PROPOSALS_ENDPOINT}/{proposal_id}"
38+
response = requests.get(url)
39+
response.raise_for_status()
40+
data = response.json()
41+
return data
42+
43+
44+
def is_older_than_one_week(submit_time_str):
45+
submit_time_str = submit_time_str.split('.')[0] + 'Z'
46+
submit_time = datetime.strptime(submit_time_str, '%Y-%m-%dT%H:%M:%S%z')
47+
current_time = datetime.now(timezone.utc)
48+
return current_time - submit_time > timedelta(weeks=1)
49+
50+
51+
def monitor_block_height(proposal_height):
52+
max_checks = int(os.environ["MAX_WAIT_FOR_PROCESSING_BLOCKS_CHECK"])
53+
checks = 0
54+
while checks < max_checks:
55+
current_height = get_current_block_height()
56+
if current_height >= proposal_height:
57+
for _ in range(50):
58+
prev_height = current_height
59+
time.sleep(3)
60+
current_height = get_current_block_height()
61+
if current_height > prev_height:
62+
logger.info("Block height is moving. Network is processing blocks.")
63+
return True
64+
logger.warning("Network is not processing blocks.")
65+
return False
66+
checks += 1
67+
time.sleep(3)
68+
logger.warning("Max wait time reached. Proposal height not reached.")
69+
return False
70+
71+
72+
def update_github_release(proposal_title):
73+
github_token = os.environ["GITHUB_TOKEN"]
74+
g = Github(github_token)
75+
repo = g.get_repo("zeta-chain/node")
76+
releases = repo.get_releases()
77+
for release in releases:
78+
if release.title == proposal_title and release.prerelease:
79+
release.update_release(release.title, release.body, draft=False, prerelease=False)
80+
logger.info(f"Updated GitHub release '{proposal_title}' from pre-release to release.")
81+
return
82+
logger.warning(f"No matching GitHub pre-release found for title '{proposal_title}'.")
83+
84+
85+
def main():
86+
current_block_height = get_current_block_height()
87+
logger.info(f"Current Block Height: {current_block_height}")
88+
proposals_retrieved = get_proposals()
89+
proposals = {}
90+
91+
for proposal_id in proposals_retrieved:
92+
proposal_details = get_proposal_details(proposal_id)
93+
94+
submit_time_str = proposal_details["proposal"]["submit_time"]
95+
if is_older_than_one_week(submit_time_str):
96+
logger.info(f"Proposal {proposal_id} is older than one week. Skipping.")
97+
continue
98+
99+
for message in proposal_details["proposal"]["messages"]:
100+
if "content" not in message:
101+
continue
102+
proposal_type = message["content"]["@type"]
103+
logger.info(f"id: {proposal_id}, proposal type: {proposal_type}")
104+
if "plan" not in message["content"]:
105+
continue
106+
if proposal_details["proposal"]["status"] != "PROPOSAL_STATUS_PASSED":
107+
logger.info(f'Proposal did not pass: {proposal_details["proposal"]["status"]}')
108+
continue
109+
if 'SoftwareUpgradeProposal' in str(proposal_type) or 'MsgSoftwareUpgrade' in str(proposal_type):
110+
proposals[proposal_id] = {
111+
"proposal_height": int(message["content"]["plan"]["height"]),
112+
"proposal_title": message["content"]["title"]
113+
}
114+
break
115+
if len(proposals) <= 0:
116+
logger.info("No proposals found within the timeframe.")
117+
sys.exit(0)
118+
for proposal_id, proposal_data in proposals.items():
119+
if current_block_height >= proposal_data["proposal_height"]:
120+
logger.info(f"Proposal {proposal_id} height {proposal_data['proposal_height']} has been reached.")
121+
update_github_release(proposal_data["proposal_title"])
122+
else:
123+
logger.info(
124+
f"Waiting for proposal {proposal_id} height {proposal_data['proposal_height']} to be reached. Current height: {current_block_height}")
125+
if monitor_block_height(proposal_data['proposal_height']):
126+
logger.info(
127+
f"Proposal {proposal_id} height {proposal_data['proposal_height']} has been reached and network is processing blocks.")
128+
update_github_release(proposal_data["proposal_title"])
129+
else:
130+
logger.warning(
131+
f"Failed to reach proposal {proposal_id} height {proposal_data['proposal_height']} or network is not processing blocks.")
132+
133+
134+
if __name__ == "__main__":
135+
main()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: "RELEASE:STATUS:UPDATER"
2+
3+
on:
4+
schedule:
5+
- cron: "*/10 * * * *"
6+
workflow_dispatch:
7+
8+
jobs:
9+
run-script:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- name: Checkout Repository
14+
uses: actions/checkout@v2
15+
16+
- name: Set up Python
17+
uses: actions/setup-python@v2
18+
with:
19+
python-version: '3.x'
20+
21+
- name: Install Dependencies
22+
run: |
23+
python -m pip install --upgrade pip
24+
pip install requests PyGithub
25+
26+
- name: Execute Status Check
27+
env:
28+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29+
STATUS_ENDPOINT: "https://zetachain-mainnet.g.allthatnode.com/archive/tendermint/status"
30+
PROPOSAL_ENDPOINT: "https://zetachain-mainnet.g.allthatnode.com/archive/rest/cosmos/gov/v1/proposals"
31+
MAX_WAIT_FOR_PROCESSING_BLOCKS_CHECK: "500"
32+
run: |
33+
python .github/actions/release-status-checker/check_and_update.py

changelog.md

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
* [2119](https://github.com/zeta-chain/node/pull/2119) - Updated the release pipeline to only run on hotfix/ and release/ branches. Added option to only run pre-checks and not cut release as well. Switched approval steps to use environments.
4242
* [2189](https://github.com/zeta-chain/node/pull/2189) - Updated the docker tag when a release trigger runs to be the github event for the release name which should be the version. Removed mac specific build as the arm build should handle that.
4343
* [2191](https://github.com/zeta-chain/node/pull/2191) - Fixed conditional logic for the docker build step for non release builds to not overwrite the github tag.
44+
* [2192](https://github.com/zeta-chain/node/pull/2192) - Added release status checker and updater pipeline that will update release statuses when they go live on network.
4445
## v16.0.0
4546

4647
### Breaking Changes

0 commit comments

Comments
 (0)