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

Rename app and move to product-os organization #9

Merged
merged 1 commit into from
Dec 3, 2024
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
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
**/npm-debug.log
**/coverage
**/.env
**/.env.prod
**/.env.test
**/.editorconfig
**/dist
**/*.pem
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/flowzone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,4 @@ jobs:
"environment": ["test"]
}
docker_images:
ghcr.io/balena-io-experimental/deployable
ghcr.io/product-os/deploynaut
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ npm-debug.log
*.pem
!mock-cert.pem
.env
.env.prod
.env.test
coverage
lib
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Deployable
# deploynaut

> A GitHub App built with [Probot](https://github.com/probot/probot) to Approve deployments via comments from maintainers
A GitHub App built with [Probot](https://github.com/probot/probot) to approve deployments via reviews from maintainers

## Setup

Expand All @@ -16,15 +16,15 @@ npm start

```sh
# 1. Build container
docker build -t deployable .
docker build -t deploynaut .

# 2. Start container
docker run -e APP_ID=<app-id> -e PRIVATE_KEY=<pem-value> deployable
docker run -e APP_ID=<app-id> -e PRIVATE_KEY=<pem-value> deploynaut
```

## Contributing

If you have suggestions for how Deployable could be improved, or want to report a bug, open an issue! We'd love all and any contributions.
If you have suggestions for how deploynaut could be improved, or want to report a bug, open an issue! We'd love all and any contributions.

For more, check out the [Contributing Guide](CONTRIBUTING.md).

Expand Down
6 changes: 3 additions & 3 deletions app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,13 @@ default_permissions:
# https://developer.github.com/v3/apps/permissions/
# organization_administration: read
# The name of the GitHub App. Defaults to the name specified in package.json
name: Deployable
name: deploynaut

# The homepage of your GitHub App.
url: https://github.com/balena-io-experimental/deployable
url: https://github.com/product-os/deploynaut

# A description of the GitHub App.
description: Approve deployments via comments from maintainers
description: Approve deployments via reviews from maintainers

# Set to true when your GitHub App is available to the public or false when it is only accessible to the owner of the app.
# Default: true
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"name": "deployable",
"name": "deploynaut",
"version": "0.0.3",
"private": true,
"description": "Approve deployments via comments from maintainers",
"description": "Approve deployments via reviews from maintainers",
"author": "Balena",
"license": "Apache-2.0",
"homepage": "https://github.com/balena-io-experimental/deployable",
"homepage": "https://github.com/product-os/deploynaut",
"keywords": [
"probot",
"github",
Expand Down
145 changes: 77 additions & 68 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,99 +8,130 @@ import * as GitHubClient from './client.js';
export default (app: Probot) => {
app.on('deployment_protection_rule.requested', async (context: Context) => {
const {
action,
event,
environment,
deployment,
deployment_callback_url: callbackUrl,
pull_requests: pullRequests,
} = context.payload as DeploymentProtectionRuleRequestedEvent;

if (
!deployment ||
!event ||
!environment ||
!callbackUrl ||
!pullRequests
) {
context.log.error('Deployment protection rule not found');
return;
}
const eventDetails = {
action,
environment,
event,
deployment: {
id: deployment?.id,
creator: {
id: deployment?.creator.id,
login: deployment?.creator.login,
},
ref: deployment?.ref,
sha: deployment?.sha,
},
};

app.log.info('Received event: deployment_protection_rule.requested');
// app.log.info(JSON.stringify(context.payload, null, 2));
context.log.info(
'Received deployment protection rule event: %s',
JSON.stringify(eventDetails, null, 2),
);

if (!['pull_request', 'pull_request_target'].includes(event)) {
context.log.info('Ignoring non-pull request event');
if (!deployment || !event || !environment || !callbackUrl) {
context.log.error('Payload is missing required properties');
return;
}

// app.log.info('Received Deployment Protection Rule with Deployment ID: %s', deployment.id);
// app.log.info(JSON.stringify(context.payload, null, 2));

// const client = await app.auth(); // Gets an authenticated Octokit client
// const { data: appDetails } = await client.apps.getAuthenticated(); // Retrieves details about the authenticated app
// // app.log.info(JSON.stringify(appDetails, null, 2)); // Logs details about the app

if (!['pull_request', 'pull_request_target', 'push'].includes(event)) {
context.log.info(
'Ignoring unsupported deployment protection rule event: %s',
event,
);
return;
}

const bypassActors = process.env.BYPASS_ACTORS?.split(',') ?? [];
if (bypassActors.includes(deployment.creator.id.toString())) {
// context.log.info('Approving deployment %s', deployment.id);
return context.octokit.request(`POST ${callbackUrl}`, {
environment_name: environment,
state: 'approved',
comment: `Approved via bypass actors list for ${deployment.creator.login}`,
});
}

for (const pull of pullRequests) {
// get all reviews for the pull request
const reviews = await GitHubClient.listPullRequestReviews(
context,
pull.number,
);
context.log.debug(
'Actor is not included in bypass actors: %s',
deployment.creator.login,
);

// find the first review that is not a changes requested review and has the same sha as the deployment
const deployReview = reviews.find(
(review) =>
review.state !== 'CHANGES_REQUESTED' &&
review.commit_id === deployment.sha &&
review.body.startsWith('/deploy'),
);
if (pullRequests) {
for (const pull of pullRequests) {
// get all reviews for the pull request
const reviews = await GitHubClient.listPullRequestReviews(
context,
pull.number,
);

if (deployReview) {
return context.octokit.request(`POST ${callbackUrl}`, {
environment_name: environment,
state: 'approved',
comment: `Approved by ${deployReview.user.login} via review [comment](${deployReview.html_url})`,
});
// find the first review that is not a changes requested review and has the same sha as the deployment
const deployReview = reviews.find(
(review) =>
review.state !== 'CHANGES_REQUESTED' &&
review.commit_id === deployment.sha &&
review.body.startsWith('/deploy'),
);

if (deployReview) {
return context.octokit.request(`POST ${callbackUrl}`, {
environment_name: environment,
state: 'approved',
comment: `Approved by ${deployReview.user.login} via [review](${deployReview.html_url})`,
});
}
}
}
});

app.on('pull_request_review.submitted', async (context: Context) => {
const {
review,
pull_request: {
head: { sha },
const { review } = context.payload as PullRequestReviewSubmittedEvent;

const eventDetails = {
review: {
id: review.id,
body: review.body,
commit_id: review.commit_id,
user: {
id: review.user.id,
login: review.user.login,
},
},
} = context.payload as PullRequestReviewSubmittedEvent;
};

app.log.info('Received event: pull_request_review.submitted');
// app.log.info(JSON.stringify(context.payload, null, 2));
context.log.info(
'Received pull request review event: %s',
JSON.stringify(eventDetails, null, 2),
);

if (review.user.type === 'Bot') {
context.log.info('Ignoring bot review');
return;
}

if (!review.body?.startsWith('/deploy')) {
context.log.info('Ignoring non-deploy comment');
context.log.info('Ignoring unsupported comment');
return;
}

// const client = await app.auth(); // Gets an authenticated Octokit client
// const { data: appDetails } = await client.apps.getAuthenticated(); // Retrieves details about the authenticated app
// // app.log.info(JSON.stringify(appDetails, null, 2)); // Logs details about the app

// let approved = false;

const runs = await GitHubClient.listWorkflowRuns(context, sha);
const runs = await GitHubClient.listWorkflowRuns(context, review.commit_id);

for (const run of runs) {
const deployments = await GitHubClient.listPendingDeployments(
Expand All @@ -122,37 +153,15 @@ export default (app: Probot) => {
.map((deployment) => deployment.environment.name);

for (const environment of environments) {
context.log.info(
'Reviewing deployment with run %s and environment %s',
run.id,
environment,
);
await GitHubClient.reviewWorkflowRun(
context,
run.id,
environment,
'approved',
`Approved by ${review.user.login} via review [comment](${review.html_url})`,
`Approved by ${review.user.login} via [review](${review.html_url})`,
);
// approved = true;
}
}

// if (approved) {
// // post a reaction to the comment with :rocket:
// await GitHubClient.addPullRequestReviewCommentReaction(
// context,
// review.id,
// 'rocket',
// );
// } else {
// // post a reaction to the comment with :confused:
// await GitHubClient.addPullRequestReviewCommentReaction(
// context,
// review.id,
// 'confused',
// );
// }
});
// For more information on building apps:
// https://probot.github.io/docs/
Expand Down
10 changes: 3 additions & 7 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,10 @@ const testFixtures = {
},
pull_request_review: {
action: 'submitted',
pull_request: {
head: {
sha: 'test-sha',
},
},
review: {
id: 456,
body: '/deploy please',
commit_id: 'test-sha',
user: {
login: 'test-user',
id: 789,
Expand Down Expand Up @@ -116,10 +112,10 @@ describe('GitHub Deployment App', () => {
expect(nock.pendingMocks()).toStrictEqual([]);
});

test('ignores non-pull-request events', async () => {
test('ignores unsupported events', async () => {
const payload = {
...testFixtures.deployment_protection_rule,
event: 'push',
event: 'workflow_run',
};

const result = await probot.receive({
Expand Down
Loading