Skip to content

Commit d04e7cf

Browse files
committed
feat(gh-action): create workflow for automatize stable-main creation
This PR is intended to add as functionality a workflow call that will: - Create a `stable-main-{release}` branch - Run the script that will ensure the branch will from a known good state and will take specific files from the stable branch - Create a PR against `main`
1 parent 90cfe53 commit d04e7cf

2 files changed

Lines changed: 225 additions & 0 deletions

File tree

.github/scripts/stable-sync.js

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#!/usr/bin/env node
2+
3+
// USAGE:
4+
// This will create/update a local stable-sync branch
5+
// and get it in the state needed for a stable-sync PR
6+
// Once the script successfully completes, you just
7+
// need to push the branch to the remote repo. This will
8+
// likely require a `git push --force`
9+
//
10+
// Usage: node stable-sync.js [branch-name]
11+
// If no branch name is provided, defaults to 'stable-sync'
12+
13+
const { promisify } = require('util');
14+
const exec = promisify(require('child_process').exec);
15+
16+
async function runGitCommands() {
17+
// Get branch name from command line arguments or use default
18+
const branchName = process.argv[2] || 'stable-main';
19+
20+
try {
21+
try {
22+
// Check if the branch already exists
23+
const { stdout: branchExists } = await exec(
24+
`git rev-parse --quiet --verify ${branchName}`,
25+
);
26+
if (branchExists.trim()) {
27+
// Branch exists, so simply check it out
28+
await exec(`git checkout ${branchName}`);
29+
console.log(`Checked out branch: ${branchName}`);
30+
} else {
31+
throw new Error(
32+
'git rev-parse --quiet --verify failed. Branch hash empty',
33+
);
34+
}
35+
} catch (error) {
36+
if (error.stdout === '') {
37+
console.warn(
38+
`Branch does not exist, creating new ${branchName} branch.`,
39+
);
40+
41+
// Branch does not exist, create and check it out
42+
await exec(`git checkout -b ${branchName}`);
43+
console.log(`Created and checked out branch: ${branchName}`);
44+
} else {
45+
console.error(`Error: ${error.message}`);
46+
process.exit(1);
47+
}
48+
}
49+
50+
await exec('git fetch');
51+
console.log('Executed: git fetch');
52+
53+
await exec('git reset --hard origin/stable');
54+
console.log('Executed: git reset --hard origin/stable');
55+
56+
try {
57+
await exec('git merge origin/main');
58+
console.log('Executed: git merge origin/main');
59+
} catch (error) {
60+
// Handle the error but continue script execution
61+
if (
62+
error.stdout.includes(
63+
'Automatic merge failed; fix conflicts and then commit the result.',
64+
)
65+
) {
66+
console.warn(
67+
'Merge conflict encountered. Continuing script execution.',
68+
);
69+
} else {
70+
console.error(`Error: ${error.message}`);
71+
process.exit(1);
72+
}
73+
}
74+
75+
await exec('git add .');
76+
await exec('git restore --source origin/main .');
77+
console.log('Executed: it restore --source origin/main .');
78+
79+
await exec('git checkout origin/main -- .');
80+
console.log('Executed: git checkout origin/main -- .');
81+
82+
await exec('git checkout origin/stable -- CHANGELOG.md');
83+
console.log('Executed: git checkout origin/stable -- CHANGELOG.md');
84+
85+
// Mobile Only
86+
await exec('git checkout origin/stable -- bitrise.yml');
87+
console.log('Executed: git checkout origin/stable -- bitrise.yml');
88+
89+
// Mobile Only
90+
await exec('git checkout origin/stable -- android/app/build.gradle');
91+
console.log('Executed: git checkout origin/stable -- android/app/build.gradle');
92+
93+
// Mobile Only
94+
await exec('git checkout origin/stable -- ios/MetaMask.xcodeproj/project.pbxproj');
95+
console.log('Executed: git checkout origin/stable -- ios/MetaMask.xcodeproj/project.pbxproj');
96+
97+
// Mobile Only
98+
await exec('git checkout origin/stable -- package.json');
99+
console.log('Executed: git checkout origin/stable -- package.json');
100+
101+
// Extension Only
102+
// const { stdout: packageJsonContent } = await exec(
103+
// 'git show origin/master:package.json',
104+
// );
105+
// const packageJson = JSON.parse(packageJsonContent);
106+
// const packageVersion = packageJson.version;
107+
108+
// await exec(`yarn version "${packageVersion}"`);
109+
// console.log('Executed: yarn version');
110+
111+
await exec('git add .');
112+
console.log('Executed: git add .');
113+
114+
await exec(`git commit -m "Merge origin/main into ${branchName}" --no-verify`);
115+
console.log('Executed: git commit');
116+
117+
console.log(`Your local ${branchName} branch is now ready to become a PR.`);
118+
console.log('You likely now need to do `git push --force`');
119+
} catch (error) {
120+
console.error(`Error: ${error.message}`);
121+
process.exit(1);
122+
}
123+
}
124+
125+
runGitCommands();

.github/workflows/stable-sync.yml

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
name: Stable Sync
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
version_type:
7+
description: 'Type of version bump (major, minor, patch)'
8+
required: true
9+
type: choice
10+
options:
11+
- major
12+
- minor
13+
- patch
14+
default: 'patch'
15+
16+
jobs:
17+
stable-sync:
18+
runs-on: ubuntu-latest
19+
steps:
20+
- uses: actions/checkout@v4
21+
with:
22+
fetch-depth: 0
23+
24+
- name: Setup Node.js
25+
uses: actions/setup-node@v4
26+
with:
27+
node-version: '18'
28+
29+
- name: Get next version from latest tag
30+
id: version
31+
run: |
32+
# Get the latest tag
33+
LATEST_TAG=$(git describe --tags --abbrev=0)
34+
35+
# Remove 'v' prefix if it exists
36+
LATEST_VERSION=${LATEST_TAG#v}
37+
38+
# Split version into components
39+
IFS='.' read -r major minor patch <<< "$LATEST_VERSION"
40+
41+
# Increment version based on input
42+
case "${{ github.event.inputs.version_type }}" in
43+
"major")
44+
major=$((major + 1))
45+
minor=0
46+
patch=0
47+
;;
48+
"minor")
49+
minor=$((minor + 1))
50+
patch=0
51+
;;
52+
"patch")
53+
patch=$((patch + 1))
54+
;;
55+
esac
56+
57+
# Construct new version
58+
NEW_VERSION="$major.$minor.$patch"
59+
echo "next_version=$NEW_VERSION" >> $GITHUB_OUTPUT
60+
echo "Current version: $LATEST_VERSION"
61+
echo "Next version: $NEW_VERSION"
62+
63+
- name: Check if PR exists
64+
id: check-pr
65+
uses: actions/github-script@v7
66+
with:
67+
script: |
68+
const { data: prs } = await github.rest.pulls.list({
69+
owner: context.repo.owner,
70+
repo: context.repo.repo,
71+
head: `${context.repo.owner}:stable-main-${process.env.NEXT_VERSION}`,
72+
base: 'main'
73+
});
74+
return prs.length > 0;
75+
env:
76+
NEXT_VERSION: ${{ steps.version.outputs.next_version }}
77+
78+
- name: Run stable sync
79+
# if: steps.check-pr.outputs.result != 'true'
80+
run: node .github/scripts/stable-sync.js "stable-main-${{ steps.version.outputs.next_version }}"
81+
82+
- name: Create Pull Request
83+
if: steps.check-pr.outputs.result != 'true'
84+
uses: peter-evans/create-pull-request@v5
85+
with:
86+
token: ${{ secrets.GITHUB_TOKEN }}
87+
commit-message: "chore: sync stable to main for version ${{ steps.version.outputs.next_version }}"
88+
title: "chore: sync stable to main for version ${{ steps.version.outputs.next_version }}"
89+
body: |
90+
This PR syncs the stable branch to main for version ${{ steps.version.outputs.next_version }}.
91+
92+
Changes:
93+
- Merged stable into main
94+
- Preserved stable-specific files
95+
- Updated version to ${{ steps.version.outputs.next_version }}
96+
branch: "stable-main-${{ steps.version.outputs.next_version }}"
97+
base: main
98+
labels: |
99+
sync
100+
stable

0 commit comments

Comments
 (0)