Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8210939678 | |||
| 9ec88c41ee | |||
| d400084c45 | |||
| 20fd86373f | |||
| 5804f049e1 | |||
| 84daa2c0f0 | |||
| 6d98b259d9 | |||
| 3629f23f43 | |||
| 4bb2d37925 | |||
| 9f83520638 | |||
| 10f155294b | |||
| 49ce228ea7 | |||
| c08c5ace34 | |||
| c72844caa4 | |||
| ede6c15881 | |||
| 17cde8a7d8 | |||
| 1dccc4ccc6 | |||
| 35d8ea9fdb | |||
| 9a6a017c10 | |||
| 2540ed49e5 | |||
| 5611f921d9 | |||
| bc256c234b | |||
| 04f8ace9a0 | |||
| 4fd0ce7c29 | |||
| 27ab48741c | |||
| b287cb86e2 | |||
| 73a9531b26 | |||
| bc0f04c81b | |||
| 1fc9983a3b | |||
| 803e078eb5 | |||
| 9cf7227dfb | |||
| 7bbad93287 | |||
| e5568a0249 |
+1
-1
@@ -1 +1 @@
|
||||
* @gr2m @parkerbxyz @actions/github-app-token-maintainers
|
||||
* @gr2m @parkerbxyz @actions/create-github-app-token-maintainers
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
groups:
|
||||
production-dependencies:
|
||||
dependency-type: "production"
|
||||
development-dependencies:
|
||||
dependency-type: "development"
|
||||
commit-message:
|
||||
prefix: "fix"
|
||||
prefix-development: "build"
|
||||
include: "scope"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
@@ -14,24 +14,16 @@ jobs:
|
||||
name: release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: npm
|
||||
node-version: lts/*
|
||||
- run: npm ci
|
||||
- run: npm run build
|
||||
- uses: ./ # Uses the action in the root directory
|
||||
- uses: actions/create-github-app-token@v1
|
||||
id: app-token
|
||||
with:
|
||||
app_id: ${{ vars.RELEASER_APP_ID }}
|
||||
private_key: ${{ secrets.RELEASER_APP_PRIVATE_KEY }}
|
||||
|
||||
- id: commit
|
||||
uses: stefanzweifel/git-auto-commit-action@v4
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
commit_message: "build: update dist files"
|
||||
- run: npm i semantic-release-plugin-github-breaking-version-tag
|
||||
- run: npx semantic-release
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
- run: npm install --no-save @semantic-release/git semantic-release-plugin-github-breaking-version-tag
|
||||
- run: npm run build
|
||||
- run: npx semantic-release --debug
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
@@ -1,26 +1,49 @@
|
||||
name: test
|
||||
on: [push]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
integration:
|
||||
name: Integration
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "16.16"
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
- run: npm ci
|
||||
- run: npm test
|
||||
|
||||
end-to-end:
|
||||
name: End-to-End
|
||||
runs-on: ubuntu-latest
|
||||
# do not run from forks, as forks don’t have access to repository secrets
|
||||
if: github.event.pull_request.head.repo.owner.login == github.event.pull_request.base.repo.owner.login
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
- run: npm ci
|
||||
- run: npm run build
|
||||
- uses: ./ # Uses the action in the root directory
|
||||
id: demo
|
||||
id: test
|
||||
with:
|
||||
app_id: ${{ vars.TEST_APP_ID }}
|
||||
private_key: ${{ secrets.TEST_APP_PRIVATE_KEY }}
|
||||
- uses: octokit/request-action@v2.x
|
||||
id: get-repository
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.demo.outputs.token }}
|
||||
GITHUB_TOKEN: ${{ steps.test.outputs.token }}
|
||||
with:
|
||||
route: GET /installation/repositories
|
||||
- run: echo '${{ steps.get-repository.outputs.data }}'
|
||||
|
||||
@@ -10,7 +10,7 @@ In order to use this action, you need to:
|
||||
2. [Store the App's ID in your repository environment variables](https://docs.github.com/actions/learn-github-actions/variables#defining-configuration-variables-for-multiple-workflows) (example: `APP_ID`)
|
||||
3. [Store the App's private key in your repository secrets](https://docs.github.com/actions/security-guides/encrypted-secrets?tool=webui#creating-encrypted-secrets-for-a-repository) (example: `PRIVATE_KEY`)
|
||||
|
||||
### Minimal usage
|
||||
### Create a token for the current repository
|
||||
|
||||
```yaml
|
||||
on: [issues]
|
||||
@@ -57,6 +57,73 @@ jobs:
|
||||
github_token: ${{ steps.app-token.outputs.token }}
|
||||
```
|
||||
|
||||
### Create a token for all repositories in the current owner's installation
|
||||
|
||||
```yaml
|
||||
on: [workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
hello-world:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/create-github-app-token@v1
|
||||
id: app-token
|
||||
with:
|
||||
app_id: ${{ vars.APP_ID }}
|
||||
private_key: ${{ secrets.PRIVATE_KEY }}
|
||||
owner: ${{ github.repository_owner }}
|
||||
- uses: peter-evans/create-or-update-comment@v3
|
||||
with:
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
body: "Hello, World!"
|
||||
```
|
||||
|
||||
### Create a token for multiple repositories in the current owner's installation
|
||||
|
||||
```yaml
|
||||
on: [issues]
|
||||
|
||||
jobs:
|
||||
hello-world:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/create-github-app-token@v1
|
||||
id: app-token
|
||||
with:
|
||||
app_id: ${{ vars.APP_ID }}
|
||||
private_key: ${{ secrets.PRIVATE_KEY }}
|
||||
owner: ${{ github.repository_owner }}
|
||||
repositories: "repo1,repo2"
|
||||
- uses: peter-evans/create-or-update-comment@v3
|
||||
with:
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
body: "Hello, World!"
|
||||
```
|
||||
|
||||
### Create a token for all repositories in another owner's installation
|
||||
|
||||
```yaml
|
||||
on: [issues]
|
||||
|
||||
jobs:
|
||||
hello-world:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/create-github-app-token@v1
|
||||
id: app-token
|
||||
with:
|
||||
app_id: ${{ vars.APP_ID }}
|
||||
private_key: ${{ secrets.PRIVATE_KEY }}
|
||||
owner: another-owner
|
||||
- uses: peter-evans/create-or-update-comment@v3
|
||||
with:
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
body: "Hello, World!"
|
||||
```
|
||||
|
||||
## Inputs
|
||||
|
||||
### `app_id`
|
||||
@@ -67,6 +134,21 @@ jobs:
|
||||
|
||||
**Required:** GitHub App private key.
|
||||
|
||||
### `owner`
|
||||
|
||||
**Optional:** GitHub App installation owner. If empty, defaults to the current repository owner.
|
||||
|
||||
### `repositories`
|
||||
|
||||
**Optional:** Comma-separated list of repositories to grant access to.
|
||||
|
||||
> [!NOTE]
|
||||
> If `owner` is set and `repositories` is empty, access will be scoped to all repositories in the provided repository owner's installation. If `owner` and `repositories` are empty, access will be scoped to only the current repository.
|
||||
|
||||
### `skip_token_revoke`
|
||||
|
||||
**Optional:** If truthy, the token will not be revoked when the current job is complete.
|
||||
|
||||
## Outputs
|
||||
|
||||
### `token`
|
||||
@@ -77,11 +159,11 @@ GitHub App installation access token.
|
||||
|
||||
The action creates an installation access token using [the `POST /app/installations/{installation_id}/access_tokens` endpoint](https://docs.github.com/rest/apps/apps?apiVersion=2022-11-28#create-an-installation-access-token-for-an-app). By default,
|
||||
|
||||
1. The token is scoped to the current repository.
|
||||
1. The token is scoped to the current repository or `repositories` if set.
|
||||
2. The token inherits all the installation's permissions.
|
||||
3. The token is set as output `token` which can be used in subsequent steps.
|
||||
4. The token is revoked in the `post` step of the action, which means it cannot be passed to another job.
|
||||
5. The token is masked, it cannot be logged accidentally. That is not a feature by the action, but by the GitHub Actions runner itself, due to the specific format of GitHub tokens.
|
||||
4. Unless the `skip_token_revoke` input is set to a truthy value, the token is revoked in the `post` step of the action, which means it cannot be passed to another job.
|
||||
5. The token is masked, it cannot be logged accidentally.
|
||||
|
||||
> [!NOTE]
|
||||
> Installation permissions can differ from the app's permissions they belong to. Installation permissions are set when an app is installed on an account. When the app adds more permissions after the installation, an account administrator will have to approve the new permissions before they are set on the installation.
|
||||
|
||||
+10
-1
@@ -11,10 +11,19 @@ inputs:
|
||||
private_key:
|
||||
description: "GitHub App private key"
|
||||
required: true
|
||||
owner:
|
||||
description: "GitHub App owner (defaults to current repository owner)"
|
||||
required: false
|
||||
repositories:
|
||||
description: "Repositories to install the GitHub App on (defaults to current repository if owner is unset)"
|
||||
required: false
|
||||
skip_token_revoke:
|
||||
description: "If truthy, the token will not be revoked when the current job is complete"
|
||||
required: false
|
||||
outputs:
|
||||
token:
|
||||
description: "GitHub installation access token"
|
||||
runs:
|
||||
using: "node16"
|
||||
using: "node20"
|
||||
main: "dist/main.cjs"
|
||||
post: "dist/post.cjs"
|
||||
|
||||
Vendored
+1435
-9185
File diff suppressed because one or more lines are too long
Vendored
+289
-3217
File diff suppressed because one or more lines are too long
+100
-29
@@ -1,59 +1,130 @@
|
||||
// @ts-check
|
||||
|
||||
import core from "@actions/core";
|
||||
import { createAppAuth } from "@octokit/auth-app";
|
||||
import { request } from "@octokit/request";
|
||||
|
||||
/**
|
||||
* @param {string} appId
|
||||
* @param {string} privateKey
|
||||
* @param {string} repository
|
||||
* @param {core} core
|
||||
* @param {createAppAuth} createAppAuth
|
||||
* @param {request} request
|
||||
* @param {string} owner
|
||||
* @param {string} repositories
|
||||
* @param {import("@actions/core")} core
|
||||
* @param {import("@octokit/auth-app").createAppAuth} createAppAuth
|
||||
* @param {import("@octokit/request").request} request
|
||||
* @param {boolean} skipTokenRevoke
|
||||
*/
|
||||
export async function main(
|
||||
appId,
|
||||
privateKey,
|
||||
repository,
|
||||
owner,
|
||||
repositories,
|
||||
core,
|
||||
createAppAuth,
|
||||
request
|
||||
request,
|
||||
skipTokenRevoke
|
||||
) {
|
||||
// Get owner and repo name from GITHUB_REPOSITORY
|
||||
const [owner, repo] = repository.split("/");
|
||||
let parsedOwner = "";
|
||||
let parsedRepositoryNames = "";
|
||||
|
||||
// If neither owner nor repositories are set, default to current repository
|
||||
if (!owner && !repositories) {
|
||||
[parsedOwner, parsedRepositoryNames] = String(
|
||||
process.env.GITHUB_REPOSITORY
|
||||
).split("/");
|
||||
|
||||
core.info(
|
||||
`owner and repositories not set, creating token for the current repository ("${parsedRepositoryNames}")`
|
||||
);
|
||||
}
|
||||
|
||||
// If only an owner is set, default to all repositories from that owner
|
||||
if (owner && !repositories) {
|
||||
parsedOwner = owner;
|
||||
|
||||
core.info(
|
||||
`repositories not set, creating token for all repositories for given owner "${owner}"`
|
||||
);
|
||||
}
|
||||
|
||||
// If repositories are set, but no owner, default to `GITHUB_REPOSITORY_OWNER`
|
||||
if (!owner && repositories) {
|
||||
parsedOwner = String(process.env.GITHUB_REPOSITORY_OWNER);
|
||||
parsedRepositoryNames = repositories;
|
||||
|
||||
core.info(
|
||||
`owner not set, creating owner for given repositories "${repositories}" in current owner ("${parsedOwner}")`
|
||||
);
|
||||
}
|
||||
|
||||
// If both owner and repositories are set, use those values
|
||||
if (owner && repositories) {
|
||||
parsedOwner = owner;
|
||||
parsedRepositoryNames = repositories;
|
||||
|
||||
core.info(
|
||||
`owner and repositories set, creating token for repositories "${repositories}" owned by "${owner}"`
|
||||
);
|
||||
}
|
||||
|
||||
const auth = createAppAuth({
|
||||
appId,
|
||||
privateKey,
|
||||
request,
|
||||
});
|
||||
|
||||
const appAuthentication = await auth({
|
||||
type: "app",
|
||||
});
|
||||
|
||||
// Get the installation ID
|
||||
// https://docs.github.com/en/rest/apps/apps?apiVersion=2022-11-28#get-a-repository-installation-for-the-authenticated-app
|
||||
const { data: installation } = await request(
|
||||
"GET /repos/{owner}/{repo}/installation",
|
||||
{
|
||||
owner,
|
||||
repo,
|
||||
let authentication;
|
||||
// If at least one repository is set, get installation ID from that repository
|
||||
// https://docs.github.com/rest/apps/apps?apiVersion=2022-11-28#get-a-repository-installation-for-the-authenticated-app
|
||||
if (parsedRepositoryNames) {
|
||||
const response = await request("GET /repos/{owner}/{repo}/installation", {
|
||||
owner: parsedOwner,
|
||||
repo: parsedRepositoryNames.split(",")[0],
|
||||
headers: {
|
||||
authorization: `bearer ${appAuthentication.token}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Create a new installation token
|
||||
const authentication = await auth({
|
||||
type: "installation",
|
||||
installationId: installation.id,
|
||||
repositoryNames: [repo],
|
||||
});
|
||||
// Get token for given repositories
|
||||
authentication = await auth({
|
||||
type: "installation",
|
||||
installationId: response.data.id,
|
||||
repositoryNames: parsedRepositoryNames.split(","),
|
||||
});
|
||||
} else {
|
||||
// Otherwise get the installation for the owner, which can either be an organization or a user account
|
||||
// https://docs.github.com/rest/apps/apps?apiVersion=2022-11-28#get-a-repository-installation-for-the-authenticated-app
|
||||
const response = await request("GET /orgs/{org}/installation", {
|
||||
org: parsedOwner,
|
||||
headers: {
|
||||
authorization: `bearer ${appAuthentication.token}`,
|
||||
},
|
||||
}).catch((error) => {
|
||||
if (error.status !== 404) throw error;
|
||||
|
||||
// https://docs.github.com/rest/apps/apps?apiVersion=2022-11-28#get-a-user-installation-for-the-authenticated-app
|
||||
return request("GET /users/{username}/installation", {
|
||||
username: parsedOwner,
|
||||
headers: {
|
||||
authorization: `bearer ${appAuthentication.token}`,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Get token for for all repositories of the given installation
|
||||
authentication = await auth({
|
||||
type: "installation",
|
||||
installationId: response.data.id,
|
||||
});
|
||||
}
|
||||
|
||||
// Register the token with the runner as a secret to ensure it is masked in logs
|
||||
core.setSecret(authentication.token);
|
||||
|
||||
core.setOutput("token", authentication.token);
|
||||
|
||||
|
||||
// Make token accessible to post function (so we can invalidate it)
|
||||
core.saveState("token", authentication.token);
|
||||
if (!skipTokenRevoke) {
|
||||
core.saveState("token", authentication.token);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-5
@@ -1,15 +1,24 @@
|
||||
// @ts-check
|
||||
|
||||
import core from "@actions/core";
|
||||
import { request } from "@octokit/request";
|
||||
|
||||
/**
|
||||
* @param {core} core
|
||||
* @param {request} request
|
||||
* @param {import("@actions/core")} core
|
||||
* @param {import("@octokit/request").request} request
|
||||
*/
|
||||
export async function post(core, request) {
|
||||
const skipTokenRevoke = Boolean(core.getInput("skip_token_revoke"));
|
||||
|
||||
if (skipTokenRevoke) {
|
||||
core.info("Token revocation was skipped");
|
||||
return;
|
||||
}
|
||||
|
||||
const token = core.getState("token");
|
||||
|
||||
if (!token) {
|
||||
core.info("Token is not set");
|
||||
return;
|
||||
}
|
||||
|
||||
await request("DELETE /installation/token", {
|
||||
headers: {
|
||||
authorization: `token ${token}`,
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { request } from "@octokit/request";
|
||||
|
||||
export default request.defaults({
|
||||
baseUrl: process.env["GITHUB_API_URL"],
|
||||
headers: {
|
||||
"user-agent": "actions/create-github-app-token",
|
||||
},
|
||||
});
|
||||
@@ -2,22 +2,37 @@
|
||||
|
||||
import core from "@actions/core";
|
||||
import { createAppAuth } from "@octokit/auth-app";
|
||||
import { request } from "@octokit/request";
|
||||
|
||||
import { main } from "./lib/main.js";
|
||||
import request from "./lib/request.js";
|
||||
|
||||
if (!process.env.GITHUB_REPOSITORY) {
|
||||
throw new Error("GITHUB_REPOSITORY missing, must be set to '<owner>/<repo>'");
|
||||
}
|
||||
|
||||
if (!process.env.GITHUB_REPOSITORY_OWNER) {
|
||||
throw new Error("GITHUB_REPOSITORY_OWNER missing, must be set to '<owner>'");
|
||||
}
|
||||
|
||||
const appId = core.getInput("app_id");
|
||||
const privateKey = core.getInput("private_key");
|
||||
const owner = core.getInput("owner");
|
||||
const repositories = core.getInput("repositories");
|
||||
|
||||
const repository = process.env.GITHUB_REPOSITORY;
|
||||
const skipTokenRevoke = Boolean(core.getInput("skip_token_revoke"));
|
||||
|
||||
main(appId, privateKey, repository, core, createAppAuth, request).catch(
|
||||
(error) => {
|
||||
console.error(error);
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
);
|
||||
main(
|
||||
appId,
|
||||
privateKey,
|
||||
owner,
|
||||
repositories,
|
||||
core,
|
||||
createAppAuth,
|
||||
request.defaults({
|
||||
baseUrl: process.env["GITHUB_API_URL"],
|
||||
}),
|
||||
skipTokenRevoke
|
||||
).catch((error) => {
|
||||
console.error(error);
|
||||
core.setFailed(error.message);
|
||||
});
|
||||
|
||||
Generated
+2120
-224
File diff suppressed because it is too large
Load Diff
+23
-9
@@ -1,22 +1,25 @@
|
||||
{
|
||||
"name": "app-token-action",
|
||||
"name": "create-github-app-token",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "1.0.0",
|
||||
"version": "1.4.0",
|
||||
"description": "GitHub Action for creating a GitHub App Installation Access Token",
|
||||
"scripts": {
|
||||
"build": "esbuild main.js post.js --bundle --outdir=dist --out-extension:.js=.cjs --platform=node --target=node16.16",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "ava tests/index.js"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.0",
|
||||
"@octokit/auth-app": "^4.0.13",
|
||||
"@octokit/request": "^6.2.5"
|
||||
"@actions/core": "^1.10.1",
|
||||
"@octokit/auth-app": "^6.0.1",
|
||||
"@octokit/request": "^8.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"dotenv": "^16.0.3",
|
||||
"esbuild": "^0.17.19"
|
||||
"ava": "^5.3.1",
|
||||
"dotenv": "^16.3.1",
|
||||
"esbuild": "^0.19.4",
|
||||
"execa": "^8.0.1",
|
||||
"undici": "^5.25.2"
|
||||
},
|
||||
"release": {
|
||||
"branches": [
|
||||
@@ -27,7 +30,18 @@
|
||||
"@semantic-release/commit-analyzer",
|
||||
"@semantic-release/release-notes-generator",
|
||||
"@semantic-release/github",
|
||||
"semantic-release-plugin-github-breaking-version-tag"
|
||||
"@semantic-release/npm",
|
||||
"semantic-release-plugin-github-breaking-version-tag",
|
||||
[
|
||||
"@semantic-release/git",
|
||||
{
|
||||
"assets": [
|
||||
"package.json",
|
||||
"dist/*"
|
||||
],
|
||||
"message": "build(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
// @ts-check
|
||||
|
||||
import core from "@actions/core";
|
||||
import { request } from "@octokit/request";
|
||||
|
||||
import { post } from "./lib/post.js";
|
||||
import request from "./lib/request.js";
|
||||
|
||||
post(core, request).catch(
|
||||
(error) => {
|
||||
console.error(error);
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
);
|
||||
post(
|
||||
core,
|
||||
request.defaults({
|
||||
baseUrl: process.env["GITHUB_API_URL"],
|
||||
})
|
||||
).catch((error) => {
|
||||
console.error(error);
|
||||
core.setFailed(error.message);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Tests
|
||||
|
||||
Add one test file per scenario. You can run them in isolation with:
|
||||
|
||||
```bash
|
||||
node tests/post-token-set.test.js
|
||||
```
|
||||
|
||||
All tests are run together in [tests/index.js](index.js), which can be executed with ava
|
||||
|
||||
```
|
||||
npx ava tests/index.js
|
||||
```
|
||||
|
||||
or with npm
|
||||
|
||||
```
|
||||
npm test
|
||||
```
|
||||
@@ -0,0 +1,14 @@
|
||||
import { readdirSync } from "node:fs";
|
||||
|
||||
import { execa } from "execa";
|
||||
import test from "ava";
|
||||
|
||||
const tests = readdirSync("tests").filter((file) => file.endsWith(".test.js"));
|
||||
|
||||
for (const file of tests) {
|
||||
test(file, async (t) => {
|
||||
const { stderr, stdout } = await execa("node", [`tests/${file}`]);
|
||||
t.snapshot(stderr, "stderr");
|
||||
t.snapshot(stdout, "stdout");
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { MockAgent, setGlobalDispatcher } from "undici";
|
||||
|
||||
// state variables are set as environment variables with the prefix STATE_
|
||||
// https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#sending-values-to-the-pre-and-post-actions
|
||||
process.env.STATE_token = "secret123";
|
||||
|
||||
const mockAgent = new MockAgent();
|
||||
|
||||
setGlobalDispatcher(mockAgent);
|
||||
|
||||
// Provide the base url to the request
|
||||
const mockPool = mockAgent.get("https://api.github.com");
|
||||
|
||||
// intercept the request
|
||||
mockPool
|
||||
.intercept({
|
||||
path: "/installation/token",
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
authorization: "token secret123",
|
||||
},
|
||||
})
|
||||
.reply(204);
|
||||
|
||||
await import("../post.js");
|
||||
@@ -0,0 +1,29 @@
|
||||
import { MockAgent, setGlobalDispatcher } from "undici";
|
||||
|
||||
// state variables are set as environment variables with the prefix STATE_
|
||||
// https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#sending-values-to-the-pre-and-post-actions
|
||||
process.env.STATE_token = "secret123";
|
||||
|
||||
// inputs are set as environment variables with the prefix INPUT_
|
||||
// https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#example-specifying-inputs
|
||||
process.env.INPUT_SKIP_TOKEN_REVOKE = "true";
|
||||
|
||||
const mockAgent = new MockAgent();
|
||||
|
||||
setGlobalDispatcher(mockAgent);
|
||||
|
||||
// Provide the base url to the request
|
||||
const mockPool = mockAgent.get("https://api.github.com");
|
||||
|
||||
// intercept the request
|
||||
mockPool
|
||||
.intercept({
|
||||
path: "/installation/token",
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
authorization: "token secret123",
|
||||
},
|
||||
})
|
||||
.reply(204);
|
||||
|
||||
await import("../post.js");
|
||||
@@ -0,0 +1,5 @@
|
||||
// state variables are set as environment variables with the prefix STATE_
|
||||
// https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#sending-values-to-the-pre-and-post-actions
|
||||
delete process.env.STATE_token;
|
||||
|
||||
await import("../post.js");
|
||||
@@ -0,0 +1,35 @@
|
||||
# Snapshot report for `tests/index.js`
|
||||
|
||||
The actual snapshot is saved in `index.js.snap`.
|
||||
|
||||
Generated by [AVA](https://avajs.dev).
|
||||
|
||||
## post-token-set.test.js
|
||||
|
||||
> stderr
|
||||
|
||||
''
|
||||
|
||||
> stdout
|
||||
|
||||
'Token revoked'
|
||||
|
||||
## post-token-skipped.test.js
|
||||
|
||||
> stderr
|
||||
|
||||
''
|
||||
|
||||
> stdout
|
||||
|
||||
'Token revocation was skipped'
|
||||
|
||||
## post-token-unset.test.js
|
||||
|
||||
> stderr
|
||||
|
||||
''
|
||||
|
||||
> stdout
|
||||
|
||||
'Token is not set'
|
||||
Binary file not shown.
Reference in New Issue
Block a user