Skip to content

Commit d3dfc49

Browse files
authored
Add support for discovering and copying package.json files to publish_repo (#8)
* Add support for discovering and copying package.json files to publish_repo - Refactor github specific constants and methods. - Add debug info useful for dry runs - Bump version * Add different publish repo for test output
1 parent fd9238a commit d3dfc49

File tree

12 files changed

+209
-81
lines changed

12 files changed

+209
-81
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ jobs:
1919
- id: generate
2020
uses: ./
2121
with:
22+
publish_repo: 'stackaid/funding'
2223
skip_publish: true
2324
- run: echo $STACKAID_JSON
2425
env:

README.md

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ jobs:
2121
runs-on: ubuntu-latest
2222
steps:
2323
- uses: actions/checkout@v2
24-
- uses: actions/setup-go@v3
25-
- uses: stackaid/generate-stackaid-json@v1.7
24+
- uses: actions/setup-go@v3 # Only required for Go based repos
25+
- uses: stackaid/generate-stackaid-json@v1.8
2626
```
2727
2828
This will commit a `stackaid.json` file in your repository which will then automatically show up for funding in the StackAid dashboard.
@@ -35,9 +35,32 @@ The action also supports a few useful `inputs` and `outputs` so you can publish
3535
- `publish_repo`: The full name of the repository, (eg: `username/repo-name`) to publish the generated stackaid.json file. Defaults to the current repository.
3636
- `publish_path`: The path to publish to. By default the stackaid.json file is published to the root of the repository.
3737
- `skip_publish`: Set to `true` if you do not want to publish the generated file.
38+
- `include_package_json`: Only relavant when `publish_repo` is specified. Set to `true` if you want to copy `package.json` files to a non-sensitive repo. See the section below. Defaults to `true`.
3839

3940
**Note**: If you publish to a separate repo you will need to provide a [personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) with the appropriate repo permissions.
4041

4142
### Outputs
4243

4344
- `stackaid_json`: The generated stackaid.json file as a string.
45+
46+
## Funding dependencies in sensitive repositories.
47+
48+
While this action is primarily designed to support languages StackAid does not natively support, it can also be used to allow you to fund dependencies in repositories without giving StackAid access to your source code.
49+
50+
Here's a simple guide:
51+
52+
1. Create a new empty repository and grant acess to our [GitHub app](https://github.com/apps/stackaid). This repository will just store the dependecy files you want to fund.
53+
54+
2. Create a [personal access token](https://github.com/settings/tokens/new) with full `repo` access and set the expriation to "No Expiration"
55+
<img src="./docs/images/add_access_token.png" />
56+
57+
3. Add the token as a secret to your github action workflow: https://docs.github.com/en/actions/security-guides/encrypted-secrets
58+
<img src="./docs/images/add_secret.png"/>
59+
60+
4. Configure this GitHub action to publish to your new repository.
61+
62+
```yaml
63+
token: ${{ secrets.STACKAID_ACCESS_TOKEN }}
64+
publish_repo: 'owner/name' # of new repository
65+
publish_path: ${{ github.repository }} # Publishes dependecy files under the current repo name. Avoids name conflicts when using this action on multiple repositories.
66+
```

action.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ inputs:
2121
description: 'Source code root directory'
2222
default: ${{ github.workspace }}
2323
required: false
24+
include_package_json:
25+
description: "If true and publish_repo is different from the working repository, then package.json files will be copied to publish_repo. Use this option when you don't want StackAid to have access to your source."
26+
default: true
27+
required: false
2428
outputs:
2529
stackaid_json:
2630
description: 'The generated stackaid.json file'

dist/index.js

Lines changed: 93 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ exports.GITHUB_DOMAIN = 'github.com';
1212
exports.FileTypes = {
1313
go: ['go.mod'],
1414
java: ['pom.xml'],
15+
javascript: ['package.json'],
1516
php: ['composer.json'],
1617
python: ['pipfile', 'pyproject.toml', 'setup.py'],
1718
ruby: ['gemfile'],
@@ -29,7 +30,7 @@ exports.DEPENDENCY_FILE_TYPES = [
2930

3031
/***/ }),
3132

32-
/***/ 9783:
33+
/***/ 5865:
3334
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
3435

3536
"use strict";
@@ -57,18 +58,70 @@ var __importStar = (this && this.__importStar) || function (mod) {
5758
__setModuleDefault(result, mod);
5859
return result;
5960
};
61+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
62+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
63+
return new (P || (P = Promise))(function (resolve, reject) {
64+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
65+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
66+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
67+
step((generator = generator.apply(thisArg, _arguments || [])).next());
68+
});
69+
};
70+
Object.defineProperty(exports, "__esModule", ({ value: true }));
71+
exports.addFileChange = exports.publishFiles = exports.isSamePublishRepo = exports.sourceDir = void 0;
72+
const core = __importStar(__nccwpck_require__(2186));
73+
const github_1 = __nccwpck_require__(5438);
74+
const queries_1 = __nccwpck_require__(6719);
75+
exports.sourceDir = core.getInput('src_dir') || process.cwd();
76+
exports.isSamePublishRepo = core.getInput('publish_repo').toLowerCase() ===
77+
`${github_1.context.repo.owner.toLowerCase()}/${github_1.context.repo.repo.toLowerCase()}`;
78+
const publishFiles = (message, files) => __awaiter(void 0, void 0, void 0, function* () {
79+
const [publishOwner, publishRepo] = core
80+
.getInput('publish_repo')
81+
.split('/', 2);
82+
yield (0, queries_1.createCommit)(publishOwner, publishRepo, {
83+
message: {
84+
headline: message,
85+
body: '',
86+
},
87+
fileChanges: {
88+
additions: files,
89+
deletions: [],
90+
},
91+
});
92+
});
93+
exports.publishFiles = publishFiles;
94+
const addFileChange = (path, contents) => {
95+
const publishPath = core.getInput('publish_path');
96+
if (publishPath) {
97+
path = `${publishPath}/${path}`;
98+
}
99+
return {
100+
path,
101+
contents: Buffer.from(contents).toString('base64'),
102+
};
103+
};
104+
exports.addFileChange = addFileChange;
105+
106+
107+
/***/ }),
108+
109+
/***/ 9783:
110+
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
111+
112+
"use strict";
113+
60114
var __importDefault = (this && this.__importDefault) || function (mod) {
61115
return (mod && mod.__esModule) ? mod : { "default": mod };
62116
};
63117
Object.defineProperty(exports, "__esModule", ({ value: true }));
64118
exports.getDependencies = exports.getModuleGraph = exports.listDirectDeps = void 0;
65-
const core = __importStar(__nccwpck_require__(2186));
66119
const path_1 = __importDefault(__nccwpck_require__(1017));
67120
const constants_1 = __nccwpck_require__(9677);
68121
const child_process_1 = __nccwpck_require__(2081);
122+
const github_1 = __nccwpck_require__(5865);
69123
const lodash_1 = __nccwpck_require__(250);
70-
const sourceDir = core.getInput('src_dir') || process.cwd();
71-
const resolveDir = (dir) => path_1.default.resolve(sourceDir, dir);
124+
const resolveDir = (dir) => path_1.default.resolve(github_1.sourceDir, dir);
72125
const filterDependency = (line) => line.startsWith(constants_1.GITHUB_DOMAIN);
73126
const parseDependency = (line) => {
74127
switch (true) {
@@ -187,14 +240,17 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
187240
const core = __importStar(__nccwpck_require__(2186));
188241
const path_1 = __importDefault(__nccwpck_require__(1017));
189242
const constants_1 = __nccwpck_require__(9677);
190-
const queries_1 = __nccwpck_require__(6719);
243+
const github_1 = __nccwpck_require__(5865);
191244
const go_1 = __nccwpck_require__(9783);
245+
const queries_1 = __nccwpck_require__(6719);
192246
const utils_1 = __nccwpck_require__(7696);
247+
const fs_1 = __nccwpck_require__(7147);
193248
const lodash_1 = __nccwpck_require__(250);
194249
const run = () => __awaiter(void 0, void 0, void 0, function* () {
195250
var _a;
196251
const owner = process.env.GITHUB_REPOSITORY_OWNER;
197252
const repo = (_a = process.env.GITHUB_REPOSITORY) === null || _a === void 0 ? void 0 : _a.split('/', 2)[1];
253+
const packageJson = [];
198254
const stackAidJson = { version: 1, dependencies: [] };
199255
let direct = [];
200256
const glob = '**/';
@@ -208,6 +264,10 @@ const run = () => __awaiter(void 0, void 0, void 0, function* () {
208264
stackAidJson.dependencies.push(...deps);
209265
break;
210266
}
267+
case (0, utils_1.matches)(node.filename, constants_1.FileTypes.javascript, glob): {
268+
core.info(`Found ${node.filename}, copying dependencies`);
269+
packageJson.push(node.filename);
270+
}
211271
default:
212272
direct.push(...(yield (0, queries_1.getRepositoryDependencies)(owner, repo, 1, after)));
213273
break;
@@ -234,36 +294,28 @@ const run = () => __awaiter(void 0, void 0, void 0, function* () {
234294
}
235295
// Make file available to subsequent actions
236296
core.setOutput('stackaid_json', stackAidJson);
297+
// Create list of files for commit
298+
const files = [];
299+
if (stackAidJson.dependencies.length > 0) {
300+
(0, github_1.addFileChange)('stackaid.json', JSON.stringify(stackAidJson, null, 2));
301+
}
302+
const includePackageJson = core.getBooleanInput('include_package_json');
303+
if (includePackageJson && !github_1.isSamePublishRepo) {
304+
// Read each file and only pull out relevant fields
305+
files.push(...packageJson.map((filename) => {
306+
const { name, dependencies, devDependencies } = JSON.parse((0, fs_1.readFileSync)(path_1.default.resolve(github_1.sourceDir, filename), 'utf8'));
307+
return (0, github_1.addFileChange)(filename, JSON.stringify({ name, dependencies, devDependencies }, null, 2));
308+
}));
309+
}
310+
core.debug(`Files to be published`);
311+
core.debug(JSON.stringify(files, null, 2));
237312
const skipPublish = core.getBooleanInput('skip_publish');
238313
if (skipPublish) {
239-
core.info('Skipping publish of generated stackaid.json');
240-
return;
314+
core.info('Skipping publish of generated stackaid dependencies');
241315
}
242-
// Commit file to provided repo
243-
const [publishOwner, publishRepo] = core
244-
.getInput('publish_repo')
245-
.split('/', 2);
246-
let filePath = `stackaid.json`;
247-
const publishPath = core.getInput('publish_path');
248-
if (publishPath) {
249-
filePath = `${publishPath}/${filePath}`;
316+
else {
317+
yield (0, github_1.publishFiles)(`Update stackaid dependencies for ${owner}/${repo}`, files);
250318
}
251-
const fileContents = JSON.stringify(stackAidJson, null, 2);
252-
yield (0, queries_1.createCommit)(publishOwner, publishRepo, {
253-
message: {
254-
headline: `Update stackaid.json dependencies for ${owner}/${repo}`,
255-
body: '',
256-
},
257-
fileChanges: {
258-
additions: [
259-
{
260-
path: filePath,
261-
contents: Buffer.from(fileContents).toString('base64'),
262-
},
263-
],
264-
deletions: [],
265-
},
266-
});
267319
});
268320
run();
269321

@@ -5490,7 +5542,7 @@ exports.GraphQLError = void 0;
54905542
exports.formatError = formatError;
54915543
exports.printError = printError;
54925544

5493-
var _isObjectLike = __nccwpck_require__(5865);
5545+
var _isObjectLike = __nccwpck_require__(681);
54945546

54955547
var _location = __nccwpck_require__(1922);
54965548

@@ -6138,7 +6190,7 @@ var _invariant = __nccwpck_require__(8847);
61386190

61396191
var _isIterableObject = __nccwpck_require__(1258);
61406192

6141-
var _isObjectLike = __nccwpck_require__(5865);
6193+
var _isObjectLike = __nccwpck_require__(681);
61426194

61436195
var _isPromise = __nccwpck_require__(3910);
61446196

@@ -9697,7 +9749,7 @@ function isIterableObject(maybeIterable) {
96979749

96989750
/***/ }),
96999751

9700-
/***/ 5865:
9752+
/***/ 681:
97019753
/***/ ((__unused_webpack_module, exports) => {
97029754

97039755
"use strict";
@@ -15185,7 +15237,7 @@ var _inspect = __nccwpck_require__(102);
1518515237

1518615238
var _instanceOf = __nccwpck_require__(3481);
1518715239

15188-
var _isObjectLike = __nccwpck_require__(5865);
15240+
var _isObjectLike = __nccwpck_require__(681);
1518915241

1519015242
var _keyMap = __nccwpck_require__(711);
1519115243

@@ -16488,7 +16540,7 @@ var _inspect = __nccwpck_require__(102);
1648816540

1648916541
var _instanceOf = __nccwpck_require__(3481);
1649016542

16491-
var _isObjectLike = __nccwpck_require__(5865);
16543+
var _isObjectLike = __nccwpck_require__(681);
1649216544

1649316545
var _toObjMap = __nccwpck_require__(4728);
1649416546

@@ -17895,7 +17947,7 @@ exports.specifiedScalarTypes = void 0;
1789517947

1789617948
var _inspect = __nccwpck_require__(102);
1789717949

17898-
var _isObjectLike = __nccwpck_require__(5865);
17950+
var _isObjectLike = __nccwpck_require__(681);
1789917951

1790017952
var _GraphQLError = __nccwpck_require__(4797);
1790117953

@@ -18269,7 +18321,7 @@ var _inspect = __nccwpck_require__(102);
1826918321

1827018322
var _instanceOf = __nccwpck_require__(3481);
1827118323

18272-
var _isObjectLike = __nccwpck_require__(5865);
18324+
var _isObjectLike = __nccwpck_require__(681);
1827318325

1827418326
var _toObjMap = __nccwpck_require__(4728);
1827518327

@@ -19846,7 +19898,7 @@ var _invariant = __nccwpck_require__(8847);
1984619898

1984719899
var _isIterableObject = __nccwpck_require__(1258);
1984819900

19849-
var _isObjectLike = __nccwpck_require__(5865);
19901+
var _isObjectLike = __nccwpck_require__(681);
1985019902

1985119903
var _kinds = __nccwpck_require__(1927);
1985219904

@@ -20165,7 +20217,7 @@ var _devAssert = __nccwpck_require__(6514);
2016520217

2016620218
var _inspect = __nccwpck_require__(102);
2016720219

20168-
var _isObjectLike = __nccwpck_require__(5865);
20220+
var _isObjectLike = __nccwpck_require__(681);
2016920221

2017020222
var _keyValMap = __nccwpck_require__(9268);
2017120223

@@ -20563,7 +20615,7 @@ var _invariant = __nccwpck_require__(8847);
2056320615

2056420616
var _isIterableObject = __nccwpck_require__(1258);
2056520617

20566-
var _isObjectLike = __nccwpck_require__(5865);
20618+
var _isObjectLike = __nccwpck_require__(681);
2056720619

2056820620
var _Path = __nccwpck_require__(1262);
2056920621

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/images/add_access_token.png

223 KB
Loading

docs/images/add_secret.png

105 KB
Loading

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "stackaid-json-generator",
3-
"version": "1.7.0",
3+
"version": "1.8.0",
44
"private": false,
55
"description": "A GitHub action to generate a stackaid.json file based on your repository's dependency graph",
66
"main": "lib/src/main.js",

src/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export const GITHUB_DOMAIN = 'github.com'
33
export const FileTypes = {
44
go: ['go.mod'],
55
java: ['pom.xml'],
6+
javascript: ['package.json'],
67
php: ['composer.json'],
78
python: ['pipfile', 'pyproject.toml', 'setup.py'],
89
ruby: ['gemfile'],

src/github.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import * as core from '@actions/core'
2+
import { context } from '@actions/github'
3+
import { FileAddition } from '../types/graphql'
4+
import { createCommit } from './queries'
5+
6+
export const sourceDir = core.getInput('src_dir') || process.cwd()
7+
8+
export const isSamePublishRepo =
9+
core.getInput('publish_repo').toLowerCase() ===
10+
`${context.repo.owner.toLowerCase()}/${context.repo.repo.toLowerCase()}`
11+
12+
export const publishFiles = async (message: string, files: FileAddition[]) => {
13+
const [publishOwner, publishRepo] = core
14+
.getInput('publish_repo')
15+
.split('/', 2)
16+
17+
await createCommit(publishOwner, publishRepo, {
18+
message: {
19+
headline: message,
20+
body: '',
21+
},
22+
fileChanges: {
23+
additions: files,
24+
deletions: [],
25+
},
26+
})
27+
}
28+
29+
export const addFileChange = (path: string, contents: string) => {
30+
const publishPath = core.getInput('publish_path')
31+
if (publishPath) {
32+
path = `${publishPath}/${path}`
33+
}
34+
35+
return {
36+
path,
37+
contents: Buffer.from(contents).toString('base64'),
38+
}
39+
}

0 commit comments

Comments
 (0)