Skip to content

Commit

Permalink
feat: adapt for probot v11. Use @actions/core for logging (#19)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: package name has been renamed to "@probot/adapter-github-actions"

BREAKING CHANGE: the package now has the same export as `"probot"`.

Before

```js
const runProbot = require('probot-actions-adapter');
const app = require('./index');
runProbot(app);
```

After

```js
const { run } = require("@probot/adapter-github-actions");
const app = require("./app");
run(app);
```
  • Loading branch information
gr2m authored Feb 10, 2021
1 parent fce6350 commit 4aa298d
Show file tree
Hide file tree
Showing 17 changed files with 2,979 additions and 10,143 deletions.
25 changes: 0 additions & 25 deletions .eslintrc

This file was deleted.

32 changes: 22 additions & 10 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
on:
[push, pull_request]

name: Test
on:
push: {}
pull_request:
types: [opened, synchronize]

jobs:
build:
integration:
runs-on: ubuntu-latest
# don't run integration tests on push unless it's the main branch
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- run: npm ci
- run: npm test
createComment:
runs-on: ubuntu-latest
# only run on push events
if: github.event_name == 'push'
steps:
- name: Debug
run: echo '${{ toJson(github) }}'
- uses: actions/checkout@v2
- run: npm ci
- run: npm run lint
- run: npm test
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- run: npm ci
- run: node test/fixtures/app.js
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 0 additions & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,3 @@ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

96 changes: 42 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,80 +1,68 @@
# :electric_plug: `probot-actions-adapter`
# :electric_plug: `@probot/adapter-github-actions`

> An adapter that takes a [Probot](https://probot.github.io/) app and makes it compatible with [GitHub Actions](https://github.com/features/actions)
> Adapter to run a [Probot](https://probot.github.io/) application function in [GitHub Actions](https://github.com/features/actions)
<a href="https://github.com/probot/actions-adapter"><img alt="GitHub Actions status" src="https://github.com/probot/actions-adapter/workflows/Build/badge.svg"></a>

## Contents

- [Installation](#installation)
- [Usage](#usage)
- [Authentication](#authentication)
- [Caveats](#caveats)

## Installation

```shell
npm i -S probot-actions-adapter
```
[![Build Status](https://github.com/probot/adapter-github-actions/workflows/Test/badge.svg)](https://github.com/probot/adapter-github-actions/actions)

## Usage

1. Add an `action.js` to your Probot project, like [the one shown below](#example-actionjs)
1. Add an `action.yml` to your Probot project, like [the one shown below](#example-actionyml)
1. _Vendor in_ your `node_modules`, as [recommended by the official Actions documentation](https://docs.github.com/en/actions/creating-actions/creating-a-javascript-action#commit-tag-and-push-your-action-to-github)
1. Optional, but recommended, update your project's README with an example workflow showing how to consume your action
Create your Probot Application as always

### Example `action.js`
```js
// app.js
module.exports = (app) => {
app.on("issues.opened", async (context) => {
const params = context.issue({ body: "Hello World!" });
await context.octokit.issues.createComment(params);
});
};
```

```javascript
// Require the adapter
const runProbot = require('probot-actions-adapter');
Then in the entrypoint of your GitHub Action, require `@probot/github-action` instead of `probot`

// Require your Probot app's entrypoint, usually this is just index.js
const app = require('./index');
```js
// index.js
const { run } = require("@probot/github-action");
const app = require("./app");

// Adapt the Probot app for Actions
// This also acts as the main entrypoint for the Action
runProbot(app);
run(app).catch((error) => {
console.error(error);
process.exit(1);
});
```

### Example `action.yml`
Then use `index.js` as your entrypoint in the `action.yml` file

```yaml
name: 'Probot app name'
description: 'Probot app description.'
name: "Probot app name"
description: "Probot app description."
runs:
using: 'node12'
main: 'action.js'
using: "node12"
main: "action.js"
```
See [the documentation](https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions) for `action.yml` syntax details.
**Important**: Your external dependencies will not be installed, you have to either vendor them in by committing the contents of the `node_modules` folder, or compile the code to a single executable script (recommended). See [GitHub's documentation](https://docs.github.com/en/actions/creating-actions/creating-a-javascript-action#commit-tag-and-push-your-action-to-github)

## Authentication
For an example Probot App that is continuously published as GitHub Action, see https://github.com/probot/example-github-action#readme

Authentication is via [the `GITHUB_TOKEN` secret _automatically_ provided by GitHub](https://docs.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token), which should be exposed as an environment variable, `GITHUB_TOKEN`. This can be achieved by including the appropriate [`env`](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#env), [`jobs.<job_id>.env`](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idenv), or [`jobs.<job_id>.steps.env`](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsenv) value in your workflow file.
## How it works

### Example via `jobs.<job_id>.steps.env`
[Probot](https://probot.github.io/) is a framework for building [GitHub Apps](docs.github.com/apps), which is different to creating [GitHub Actions](https://docs.github.com/actions/) in many ways, but the functionality is the same:

Include the following in your workflow file, when calling your Probot action:
Both get notified about events on GitHub, which you can act on. While a GitHub App gets notified about a GitHub event via a webhook request sent by GitHub, a GitHub Action can receive the event payload by reading a JSON file from the file system. We can abstract away the differences, so the same hello world example app shown above works in both environments.

```yaml
...
steps:
- name: My probot action
...
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
...
```
Relevant differences for Probot applications:

## Caveats
1. You cannot authenticate as the app. The `probot` instance you receive is authenticated using a GitHub token. In most cases the token will be set to `secrets.GITHUB_TOKEN`, which is [an installation access token](https://docs.github.com/en/actions/reference/authentication-in-a-workflow#about-the-github_token-secret). The provided `GITHUB_TOKEN` expires when the job is done or after 6 hours, whichever comes first. You do not have access to an `APP_ID` or `PRIVATE_KEY`, you cannot create new tokens or renew the provided one.
2. `secrets.GITHUB_TOKEN` is scoped to the current repository. You cannot read data from other repositories unless they are public, you cannot update any other repositories, or access organization-level APIs.
3. You could provide a personal access token instead of `secrets.GITHUB_TOKEN` to workaround the limits of a repository-scoped token, but be sure you know what you are doing.
4. You don't need to configure `WEBHOOK_SECRET`, because no webhook request gets sent, the event information can directly be retrieved from environment variables and the local file system.

This adapter is designed to work well with Probot apps that are essentially stateless webhook handlers.
For a more thorough comparison, see [@jasonetco's](https://github.com/jasonetco) posts:

A few other limitations exist:
1. [Probot App or GitHub Action](https://jasonet.co/posts/probot-app-or-github-action/) (Jan 2019)
2. [Update from April 2020](https://jasonet.co/posts/probot-app-or-github-action-v2/)

1. The adapter will _only_ work for Probot apps that receive webhook events that Actions also receives: https://docs.github.com/en/actions/reference/events-that-trigger-workflows
1. The adapter will _only_ work for Probot apps with a permissions set that is less than, or equivalent to the permission set attached to the `GITHUB_TOKEN`: https://docs.github.com/en/actions/reference/authentication-in-a-workflow#permissions-for-the-github_token
## License

If that's you, then great! :rocket:
[ISC](LICENSE)
3 changes: 0 additions & 3 deletions fixtures/push.json

This file was deleted.

2 changes: 0 additions & 2 deletions index.d.ts

This file was deleted.

81 changes: 55 additions & 26 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,56 @@
process.env.DISABLE_WEBHOOK_EVENT_CHECK = 'true';

const path = require('path');
const uuid = require('uuid');

const core = require('@actions/core');

const { Probot } = require('probot');

module.exports = (...handlers) => {
// Setup Probot app
const githubToken = process.env.GITHUB_TOKEN;
const probot = new Probot({ githubToken });
probot.setup(handlers);

// Process the event
const event = process.env.GITHUB_EVENT_NAME;
const payloadPath = process.env.GITHUB_EVENT_PATH;
// eslint-disable-next-line global-require, import/no-dynamic-require
const payload = require(path.resolve(payloadPath));
core.debug(`Receiving event ${JSON.stringify(event)}`);
return probot.receive({ name: event, payload, id: uuid.v4() }).catch(err => {
// setFailed logs the message and sets a failing exit code
core.setFailed(`Action failed with error: ${err.message}`);
throw err;
const ProbotExports = require("probot");
const pino = require("pino");

const { transport } = require("./pino-transport-github-actions");

module.exports = { ...ProbotExports, run };

async function run(app) {
const log = pino({}, transport);

const githubToken =
process.env.GITHUB_TOKEN ||
process.env.INPUT_GITHUB_TOKEN ||
process.env.INPUT_TOKEN;

if (!githubToken) {
log.error(
"[probot/adapter-github-actions] a token must be passed as `env.GITHUB_TOKEN` or `with.GITHUB_TOKEN` or `with.token`, see https://github.com/probot/adapter-github-actions#usage"
);
return;
}

const envVariablesMissing = [
"GITHUB_RUN_ID",
"GITHUB_EVENT_NAME",
"GITHUB_EVENT_PATH",
].filter((name) => !process.env[name]);

if (envVariablesMissing.length) {
log.error(
`[probot/adapter-github-actions] GitHub Action default environment variables missing: ${envVariablesMissing.join(
", "
)}. See https://docs.github.com/en/free-pro-team@latest/actions/reference/environment-variables#default-environment-variables`
);
return;
}

const probot = ProbotExports.createProbot({
overrides: {
githubToken,
log,
},
});
};

await probot.load(app);

return probot
.receive({
id: process.env.GITHUB_RUN_ID,
name: process.env.GITHUB_EVENT_NAME,
payload: require(process.env.GITHUB_EVENT_PATH),
})
.catch((error) => {
probot.log.error(error);
});
}
56 changes: 0 additions & 56 deletions index.test.js

This file was deleted.

4 changes: 0 additions & 4 deletions jest.config.js

This file was deleted.

3 changes: 0 additions & 3 deletions jest.setup-env.js

This file was deleted.

Loading

0 comments on commit 4aa298d

Please sign in to comment.