Skip to content

feat: pull requests are automatically merged based on their activity #1

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

Merged
merged 107 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
107 commits
Select commit Hold shift + click to select a range
579042d
chore: init repo
gentlementlegen Jul 2, 2024
ab8dad9
chore: renamed action steps
gentlementlegen Jul 2, 2024
bb001cf
fix: fixed imports within main
gentlementlegen Jul 2, 2024
2dbe73b
feat: set db to be sqlite
gentlementlegen Jul 3, 2024
22c79f0
chore: added save to db step
gentlementlegen Jul 3, 2024
c18685a
chore: moved reflect metadata
gentlementlegen Jul 3, 2024
710686a
chore: moved reflect metadata
gentlementlegen Jul 3, 2024
3c709dc
chore: added type to column
gentlementlegen Jul 3, 2024
0142048
chore: added run input log
gentlementlegen Jul 3, 2024
df95f5f
chore: added default to env
gentlementlegen Jul 3, 2024
5bad80a
feat: database update step
gentlementlegen Jul 3, 2024
f55a47d
chore: [skip ci] updated database
github-actions[bot] Jul 3, 2024
c29a220
chore: added git pull before push
gentlementlegen Jul 3, 2024
f040003
chore: ours on conflict
gentlementlegen Jul 3, 2024
89c01d0
chore: update pull request set on activity
gentlementlegen Jul 3, 2024
bfc9791
chore: [skip ci] updated database
github-actions[bot] Jul 3, 2024
bdd59f2
chore: added PR close and delete
gentlementlegen Jul 3, 2024
46af921
chore: added minimum checks for settings
gentlementlegen Jul 4, 2024
584ce87
chore: delete PR from db if already closed
gentlementlegen Jul 4, 2024
98e21d0
chore: cleanup up db creation for tests
gentlementlegen Jul 4, 2024
c6ba786
chore: added test for non-closing PR
gentlementlegen Jul 6, 2024
336f0a0
chore: added test to close PR
gentlementlegen Jul 6, 2024
c9c88d3
chore: added collaborator status check for assignees
gentlementlegen Jul 7, 2024
ccf831a
chore: added required validation check
gentlementlegen Jul 7, 2024
f419e76
chore: added green CI check
gentlementlegen Jul 7, 2024
07e9186
chore: fixed tests
gentlementlegen Jul 7, 2024
2f9998e
chore: fixed knip
gentlementlegen Jul 7, 2024
c44fc3c
chore: fixed author association
gentlementlegen Jul 7, 2024
101a75d
chore: [skip ci] updated database
github-actions[bot] Jul 7, 2024
ba47c31
chore: updated README.md
gentlementlegen Jul 7, 2024
3518dce
chore: [skip ci] updated database
github-actions[bot] Jul 7, 2024
5ab8128
chore: fix cspell
gentlementlegen Jul 7, 2024
b5f8e7e
chore: fix tests
gentlementlegen Jul 7, 2024
7612e2b
chore: [skip ci] updated database
github-actions[bot] Jul 7, 2024
0e39a1a
chore: added git merge strategy
gentlementlegen Jul 7, 2024
adb8f1c
Merge branch 'refs/heads/meniole-main' into feat/auomated-merging
gentlementlegen Jul 7, 2024
7624bb5
chore: logs for activity
gentlementlegen Jul 7, 2024
efbd556
chore: [skip ci] updated database
github-actions[bot] Jul 7, 2024
4b0706e
chore: [skip ci] updated database
github-actions[bot] Jul 7, 2024
4a97732
Merge branch 'main' of https://github.com/Meniole/automated-merging
github-actions[bot] Jul 7, 2024
a615267
chore: added member as collaborator
gentlementlegen Jul 7, 2024
3987054
chore: added closed status removal for PRs
gentlementlegen Jul 7, 2024
42bd973
chore: [skip ci] updated database
github-actions[bot] Jul 7, 2024
d2aa853
chore: removed concurrency
gentlementlegen Jul 7, 2024
f1b4e93
chore: [skip ci] updated database
github-actions[bot] Jul 7, 2024
2b07b7e
chore: [skip ci] updated database
github-actions[bot] Jul 7, 2024
bad0d0c
chore: added sha log
gentlementlegen Jul 7, 2024
2512a9c
chore: added runs logs
gentlementlegen Jul 7, 2024
b758d95
chore: added skipped to success run
gentlementlegen Jul 7, 2024
a8cadf0
chore: retry function wip
gentlementlegen Jul 7, 2024
9304b36
chore: retry function now returns properly
gentlementlegen Jul 7, 2024
a47f49f
chore: fixed CI
gentlementlegen Jul 7, 2024
40578b7
chore: added logs for suite checks
gentlementlegen Jul 7, 2024
cfebc4b
chore: changed condition for failure
gentlementlegen Jul 7, 2024
b31b4ac
chore: ignore self runs
gentlementlegen Jul 7, 2024
0e361fb
chore: changed until condition
gentlementlegen Jul 7, 2024
1699101
chore: fixed CI
gentlementlegen Jul 7, 2024
cffd021
chore: fixed CI
gentlementlegen Jul 7, 2024
ff9e6eb
chore: filter results
gentlementlegen Jul 7, 2024
6f760d1
chore: [skip ci] updated database
github-actions[bot] Jul 7, 2024
318503d
Merge pull request #4 from Meniole/main
ubiquity-os-main[bot] Jul 7, 2024
74b7ff4
chore: added upload retry
gentlementlegen Jul 7, 2024
7457464
Update README.md
gentlementlegen Jul 7, 2024
51d03fe
chore: [skip ci] updated database
github-actions[bot] Jul 7, 2024
73cfc40
Merge pull request #5 from Meniole/development
ubiquity-os-main[bot] Jul 7, 2024
cee464a
chore: [skip ci] updated database
github-actions[bot] Jul 7, 2024
b4a91ec
Merge branch 'main' of https://github.com/Meniole/automated-merging
github-actions[bot] Jul 7, 2024
dfecd7c
chore: [skip ci] updated database
github-actions[bot] Jul 8, 2024
c59e010
chore: [skip ci] updated database
github-actions[bot] Jul 9, 2024
e23e411
chore: [skip ci] updated database
github-actions[bot] Jul 9, 2024
457f02a
Merge branch 'main' of https://github.com/Meniole/automated-merging
github-actions[bot] Jul 9, 2024
f7a9bc0
chore: [skip ci] updated database
github-actions[bot] Jul 9, 2024
bedb5ca
chore: manifest.json
gentlementlegen Jul 12, 2024
e1f50e9
fix: changed approval requirement check to use the configuration
gentlementlegen Jul 15, 2024
656bcbc
chore: removed last activity column in db
gentlementlegen Jul 15, 2024
0592aee
chore: changed plugin settings schema
gentlementlegen Jul 15, 2024
7677885
chore: added default values to the documentation
gentlementlegen Jul 16, 2024
f7a0d7f
chore: manifest.json
gentlementlegen Jul 16, 2024
6e3f575
chore: [skip ci] updated database
github-actions[bot] Jul 16, 2024
ead7f4a
chore: removed unused env variable
gentlementlegen Jul 16, 2024
8dc079b
chore: restored env variable
gentlementlegen Jul 16, 2024
ed30444
chore: deleted worker related files
gentlementlegen Jul 16, 2024
109beef
Update src/helpers/update-pull-requests.ts
gentlementlegen Jul 17, 2024
4a6f46f
chore: changed token to use workflow's token
gentlementlegen Jul 17, 2024
d7a4b56
chore: changed token to use workflow's token
gentlementlegen Jul 17, 2024
6f9518c
Update manifest.json
gentlementlegen Jul 17, 2024
1005d41
Update manifest.json
gentlementlegen Jul 17, 2024
89288b2
chore: [skip ci] updated database
github-actions[bot] Jul 17, 2024
82ab227
chore: [skip ci] updated database
github-actions[bot] Jul 17, 2024
07fab7c
chore: debug tests
gentlementlegen Jul 17, 2024
a58622c
chore: debug tests
gentlementlegen Jul 17, 2024
8dc95fe
chore: debug tests
gentlementlegen Jul 17, 2024
1137e12
chore: debug tests
gentlementlegen Jul 17, 2024
a5f244b
chore: debug tests
gentlementlegen Jul 17, 2024
b1393f8
chore: debug tests
gentlementlegen Jul 17, 2024
82c9c21
chore: debug tests
gentlementlegen Jul 17, 2024
bab134b
chore: debug tests
gentlementlegen Jul 17, 2024
091367e
chore: debug tests
gentlementlegen Jul 17, 2024
493fca8
chore: debug tests
gentlementlegen Jul 17, 2024
2adf74f
chore: debug tests
gentlementlegen Jul 17, 2024
a87d48b
chore: debug tests
gentlementlegen Jul 17, 2024
9bf2cc1
chore: debug tests
gentlementlegen Jul 17, 2024
1af81e5
chore: debug tests
gentlementlegen Jul 17, 2024
fd7da20
chore: manifest.json
gentlementlegen Jul 17, 2024
5b9a086
chore: [skip ci] updated database
github-actions[bot] Jul 17, 2024
366a6da
chore: [skip ci] updated database
github-actions[bot] Jul 17, 2024
0862845
Update package.json
gentlementlegen Jul 28, 2024
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
2 changes: 1 addition & 1 deletion .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"ignorePaths": ["**/*.json", "**/*.css", "node_modules", "**/*.log", "./src/adapters/supabase/**/**.ts"],
"useGitignore": true,
"language": "en",
"words": ["Nektos", "dataurl", "devpool", "outdir", "servedir", "Supabase", "SUPABASE", "typebox", "ubiquibot", "Smee"],
"words": ["Nektos", "dataurl", "devpool", "outdir", "servedir", "Supabase", "SUPABASE", "typebox", "ubiquibot", "Smee", "typeorm", "timespan", "mswjs"],
"dictionaries": ["typescript", "node", "software-terms"],
"import": ["@cspell/dict-typescript/cspell-ext.json", "@cspell/dict-node/cspell-ext.json", "@cspell/dict-software-terms"],
"ignoreRegExpList": ["[0-9a-fA-F]{6}"]
Expand Down
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1 +1 @@

./** @gentlementlegen
2 changes: 1 addition & 1 deletion .github/knip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const config: KnipConfig = {
ignore: ["src/types/config.ts", "**/__mocks__/**", "**/__fixtures__/**"],
ignoreExportsUsedInFile: true,
// eslint can also be safely ignored as per the docs: https://knip.dev/guides/handling-issues#eslint--jest
ignoreDependencies: ["eslint-config-prettier", "eslint-plugin-prettier", "@mswjs/data"],
ignoreDependencies: ["eslint-config-prettier", "eslint-plugin-prettier"],
eslint: true,
};

Expand Down
76 changes: 64 additions & 12 deletions .github/workflows/compute.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: "the name of the plugin"
name: "Automated Merging"

on:
workflow_dispatch:
Expand All @@ -16,29 +16,81 @@ on:
ref:
description: "Ref"

# Limits to one job at a time
#concurrency:
# group: ${{ github.workflow }}

jobs:
compute:
name: "plugin name"
name: "Automated Merging"
runs-on: ubuntu-latest
permissions: write-all
env:
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }}

steps:
- uses: actions/checkout@v4

- name: setup node
- name: Setup node
uses: actions/setup-node@v4
with:
node-version: "20.10.0"

- name: install dependencies
run: yarn
- name: Install dependencies
run: yarn install --immutable --immutable-cache --check-cache

- run: ${{ toJSON(inputs) }}
shell: cat {0}

- name: execute directive
- name: Execute directive
run: npx tsx ./src/main.ts
id: plugin-name
id: automated-merging
env:
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
SUPABASE_KEY: ${{ secrets.SUPABASE_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# Will try to upload the changes made within the DB during the run.
# If all tries fail, an artifact containing the db is uploaded.
- name: Commit and Push DB updates with Retry
id: commit_and_push
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
git config --global pull.rebase false
git add database/sql.db

attempts=0
max_attempts=10
success=false

while [ $attempts -lt $max_attempts ]; do
if [ -n "$(git diff-index --cached --name-only HEAD)" ]; then
if git commit -m "chore: [skip ci] updated database"; then
git pull -X ours
if git push origin main; then
success=true
break
fi
else
echo "Commit failed, retrying..."
fi
else
echo "No changes to commit"
success=true
break
fi
attempts=$((attempts + 1))
echo "Attempt $attempts/$max_attempts failed, retrying in 10 seconds..."
sleep 10
done

if [ "$success" = false ]; then
echo "Failed to commit and push changes after $max_attempts attempts" | tee failure.log
exit 1
fi
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Upload Failure Log
if: steps.commit_and_push.outcome == 'failure'
uses: actions/upload-artifact@v4
with:
name: sql.db
path: database/sql.db
2 changes: 2 additions & 0 deletions .github/workflows/jest-testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ jobs:

- name: Jest With Coverage
run: yarn install --immutable --immutable-cache --check-cache && yarn test
env:
GITHUB_TOKEN: "gh_token"

- name: Add Jest Report to Summary
if: always()
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ jobs:
- uses: googleapis/release-please-action@v4
with:
release-type: simple
target-branch: main
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ coverage
junit.xml
cypress/screenshots
script.ts
.wrangler
.wrangler
test-dashboard.md
database/tests/*
103 changes: 18 additions & 85 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,93 +1,26 @@
# `@ubiquibot/plugin-template`
# `@ubiquibot/automated-merging`

## Prerequisites
Automatically merge pull-requests based on the reviewer count, the time elapsed since the last activity, depending
on the association of the pull-request author.

- A good understanding of how the [kernel](https://github.com/ubiquity/ubiquibot-kernel) works and how to interact with it.
- A basic understanding of the Ubiquibot configuration and how to define your plugin's settings.

## Getting Started

1. Create a new repository using this template.
2. Clone the repository to your local machine.
3. Install the dependencies preferably using `yarn` or `bun`.

## Creating a new plugin

- If your plugin is to be used as a slash command which should have faster response times as opposed to longer running GitHub action tasks, you should use the `worker` type.

1. Ensure you understand and have setup the [kernel](https://github.com/ubiquity/ubiquibot-kernel).
2. Update [compute.yml](./.github/workflows/compute.yml) with your plugin's name and update the `id`.
3. Update [context.ts](./src/types/context.ts) with the events that your plugin will fire on.
4. Update [plugin-inputs.ts](./src/types/plugin-inputs.ts) to match the `with:` settings in your org or repo level configuration.

- Your plugin config should look similar to this:
## Configuration example

```yml
- plugin: <plugin-org/owner>/<plugin-repo-name>:compute.yml@development
name: plugin-name
id: plugin-name-command
description: "Plugin description" # small description of what the plugin does
command: "<regex for command>" # if you are creating a plugin with a slash command
example: "<example usage>" # how to invoke the slash command
with: # these are the example settings, the kernel passes these to the plugin.
disabledCommands: []
timers:
reviewDelayTolerance: 86000
taskStaleTimeoutDuration: 2580000
miscellaneous:
maxConcurrentTasks: 3
labels:
time: []
priority: []
- plugin: ubiquibot/automated-merging
name: automated-merging
id: automated-merging
description: "Automatically merge pull-requests."
with:
approvalsRequired:
collaborator: 1 # defaults to 1
contributor: 2 # defaults to 2
mergeTimeout:
collaborator: "3.5 days" # defaults to 3.5 days
contributor: "7 days" # defaults to 7 days
```

###### At this stage, your plugin will fire on your defined events with the required settings passed in from the kernel. You can now start writing your plugin's logic.

5. Start building your plugin by adding your logic to the [plugin.ts](./src/plugin.ts) file.

## Testing a plugin

### Worker Plugins
## Testing

- `yarn/bun worker` - to run the worker locally.
- To trigger the worker, `POST` requests to http://localhost:4000/ with an event payload similar to:

```ts
await fetch("http://localhost:4000/", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
stateId: "",
eventName: "",
eventPayload: "",
settings: "",
ref: "",
authToken: "",
}),
});
```shell
yarn test
```

A full example can be found [here](https://github.com/ubiquibot/assistive-pricing/blob/623ea3f950f04842f2d003bda3fc7b7684e41378/tests/http/request.http).

### Action Plugins

- Ensure the kernel is running and listening for events.
- Fire an event in/to the repo where the kernel is installed. This can be done in a number of ways, the easiest being via the GitHub UI or using the GitHub API, such as posting a comment, opening an issue, etc in the org/repo where the kernel is installed.
- The kernel will process the event and dispatch it using the settings defined in your `.ubiquibot-config.yml`.
- The `compute.yml` workflow will run and execute your plugin's logic.
- You can view the logs in the Actions tab of your repo.

[Nektos Act](https://github.com/nektos/act) - a tool for running GitHub Actions locally.

## More information

- [Full Ubiquibot Configuration](https://github.com/ubiquity/ubiquibot/blob/0fde7551585499b1e0618ec8ea5e826f11271c9c/src/types/configuration-types.ts#L62) - helpful for defining your plugin's settings as they are strongly typed and will be validated by the kernel.
- [Ubiquibot V1](https://github.com/ubiquity/ubiquibot) - helpful for porting V1 functionality to V2, helper/utility functions, types, etc. Everything is based on the V1 codebase but with a more modular approach. When using V1 code, keep in mind that most all code will need refactored to work with the new V2 architecture.

## Examples

- [Start/Stop Slash Command](https://github.com/ubq-testing/start-stop-module) - simple
- [Assistive Pricing Plugin](https://github.com/ubiquibot/assistive-pricing) - complex
- [Conversation Rewards](https://github.com/ubiquibot/conversation-rewards) - really complex
Binary file added database/sql.db
Binary file not shown.
5 changes: 5 additions & 0 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Automated merging",
"description": "Automatically merge pull-requests.",
"ubiquity:listeners": [ "push", "pull_request.opened", "pull_request.reopened" ]
}
23 changes: 14 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"name": "plugin-template",
"name": "@ubiquibot/automated-merging",
"version": "1.0.0",
"description": "Ubiquibot plugin template repository with TypeScript support.",
"description": "Conditionally merge pull requests after a timeout.",
"author": "Ubiquity DAO",
"license": "MIT",
"main": "src/worker.ts",
"main": "src/main.ts",
"engines": {
"node": ">=20.10.0"
},
Expand All @@ -16,8 +16,7 @@
"knip": "knip --config .github/knip.ts",
"knip-ci": "knip --no-exit-code --reporter json --config .github/knip.ts",
"prepare": "husky install",
"test": "jest --setupFiles dotenv/config --coverage",
"worker": "wrangler dev --env dev --port 4000"
"test": "jest --setupFiles dotenv/config --coverage"
},
"keywords": [
"typescript",
Expand All @@ -32,9 +31,14 @@
"@octokit/rest": "20.1.1",
"@octokit/webhooks": "13.2.7",
"@sinclair/typebox": "0.32.33",
"@supabase/supabase-js": "2.43.5",
"@ubiquity-dao/ubiquibot-logger": "1.2.0",
"dotenv": "16.4.5",
"typebox-validators": "0.3.5"
"ms": "2.1.3",
"reflect-metadata": "0.2.2",
"sqlite3": "5.1.7",
"ts-retry": "4.2.5",
"typebox-validators": "0.3.5",
"typeorm": "0.3.20"
},
"devDependencies": {
"@commitlint/cli": "19.3.0",
Expand All @@ -45,6 +49,7 @@
"@eslint/js": "9.5.0",
"@jest/globals": "29.7.0",
"@mswjs/data": "0.16.1",
"@types/ms": "0.7.34",
"@types/node": "20.14.5",
"cspell": "8.9.0",
"eslint": "9.5.0",
Expand All @@ -58,13 +63,13 @@
"jest-md-dashboard": "0.8.0",
"knip": "5.21.2",
"lint-staged": "15.2.7",
"msw": "2.3.1",
"npm-run-all": "4.1.5",
"prettier": "3.3.2",
"ts-jest": "29.1.5",
"tsx": "4.15.6",
"typescript": "5.4.5",
"typescript-eslint": "7.13.1",
"wrangler": "3.60.3"
"typescript-eslint": "7.13.1"
},
"lint-staged": {
"*.ts": [
Expand Down
60 changes: 60 additions & 0 deletions src/action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import * as github from "@actions/github";
import { Octokit } from "@octokit/rest";
import { Value } from "@sinclair/typebox/value";
import { plugin } from "./plugin";
import { envSchema, envValidator, PluginInputs, pluginSettingsSchema, pluginSettingsValidator } from "./types";

/**
* How a GitHub action executes the plugin.
*/
export async function run() {
const payload = github.context.payload.inputs;

payload.env = { ...(payload.env || {}), workflowName: github.context.workflow };
if (!envValidator.test(payload.env)) {
const errors: string[] = [];
for (const error of envValidator.errors(payload.env)) {
console.error(error);
errors.push(`${error.path}: ${error.message}`);
}
throw new Error(`Invalid environment provided:\n${errors.join(";\n")}`);
}
const env = Value.Decode(envSchema, payload.env || {});

payload.settings = Value.Default(pluginSettingsSchema, JSON.parse(payload.settings));
if (!pluginSettingsValidator.test(payload.settings)) {
const errors: string[] = [];
for (const error of pluginSettingsValidator.errors(payload.settings)) {
console.error(error);
errors.push(`${error.path}: ${error.message}`);
}
throw new Error(`Invalid settings provided:\n${errors.join(";\n")}`);
}

const settings = Value.Decode(pluginSettingsSchema, payload.settings);
const inputs: PluginInputs = {
stateId: payload.stateId,
eventName: payload.eventName,
eventPayload: JSON.parse(payload.eventPayload),
settings,
authToken: payload.authToken,
ref: payload.ref,
};

await plugin(inputs, env);

return returnDataToKernel(process.env.GITHUB_TOKEN, inputs.stateId, {});
}

async function returnDataToKernel(repoToken: string, stateId: string, output: object) {
const octokit = new Octokit({ auth: repoToken });
return octokit.repos.createDispatchEvent({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
event_type: "return_data_to_ubiquibot_kernel",
client_payload: {
state_id: stateId,
output: JSON.stringify(output),
},
});
}
Loading