Skip to content

Commit

Permalink
feat(check-for-non-releasable-actions): find reusable workflows too
Browse files Browse the repository at this point in the history
We need to release reusable workflows just like we do for Actions. The
current linter didn't check for that, so it's added here. This required
an extra library to parse the YAML, and GitHub scripts can't install new
dependencies, so it's broken out to a small `internal/` composite action
which can.

Now we have two Typescript actions, it made sense to centralise some of
the setup. We have a shared `eslint` config now, and `bun` workspaces
for each of the modules so they can cross-reference.
  • Loading branch information
iainlane committed Dec 2, 2024
1 parent 14d9a80 commit c7f4ffd
Show file tree
Hide file tree
Showing 20 changed files with 599 additions and 89 deletions.
28 changes: 3 additions & 25 deletions .github/workflows/check-for-non-releasable-actions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,32 +24,10 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
sparse-checkout: |
./.github/workflows
./actions
./internal
./release-please-config.json
- name: Check for non-releasable actions
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
with:
script: |
const fs = require('fs/promises');
const releasePleaseConfig = JSON.parse(await fs.readFile('release-please-config.json', 'utf-8'));
const configuredPackageNames = new Set(Object.keys(releasePleaseConfig.packages));
const packageNames = new Set();
const folders = await fs.readdir('actions', { withFileTypes: true });
for (const folder of folders) {
if (folder.isDirectory()) {
packageNames.add('actions/' + folder.name);
}
}
const missingConfigurations = [...packageNames].filter(pkg => !configuredPackageNames.has(pkg));
if (missingConfigurations.length > 0) {
console.log('The following actions are missing from the release-please-config.json file and thus won\'t be automatically released:');
console.log(missingConfigurations.join('\n'));
console.log('Please add them in release-please-config.json!');
} else {
console.log('All actions are releasable!');
}
uses: ./internal/check-for-non-releasable-actions
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ on:
branches:
- main
paths:
- .github/workflows/test-lint-pr-title.yml
- .github/workflows/test-typescript-action.yml
- actions/lint-pr-title/**
- internal/check-for-non-releasable-actions/**

pull_request:
paths:
- .github/workflows/test-lint-pr-title.yml
- .github/workflows/test-typescript-action.yml
- actions/lint-pr-title/**
- internal/check-for-non-releasable-actions/**
types:
- edited
- opened
Expand All @@ -20,22 +22,31 @@ on:
merge_group:

jobs:
build-lint-pr-title:
build-lint-test:
runs-on: ubuntu-latest

strategy:
matrix:
directory:
- actions/lint-pr-title
- internal/check-for-non-releasable-actions

name: Build, lint, and test `${{ matrix.directory }}`

defaults:
run:
working-directory: actions/lint-pr-title
working-directory: ${{ matrix.directory }}

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Install bun package manager
uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1
with:
bun-version-file: "actions/lint-pr-title/package.json"
bun-version-file: "${{ matrix.directory }}/package.json"

- name: Install lint-pr-title dependencies
working-directory: ${{ github.workspace }}
run: bun install --frozen-lockfile

- name: Lint
Expand Down
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
.idea/

# JS / Bun bits
**/node_modules/
**/.*.bun-build

# Test files
**/coverage/

# Generated build output
**/dist/

# Don't commit any log files
**/*.log
17 changes: 0 additions & 17 deletions actions/lint-pr-title/.gitignore

This file was deleted.

Binary file removed actions/lint-pr-title/bun.lockb
Binary file not shown.
41 changes: 2 additions & 39 deletions actions/lint-pr-title/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,40 +1,3 @@
import eslint from "@eslint/js";
import eslintPluginJest from "eslint-plugin-jest";
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
import js from "@eslint/js";
import tseslint from "typescript-eslint";
import config from "@grafana/eslint-config-shared-workflows";

export default tseslint.config(
js.configs.recommended,
eslint.configs.recommended,
...tseslint.configs.strictTypeChecked,
eslintPluginPrettierRecommended,
{
// Allow unused vars if they start with an underscore
rules: {
"@typescript-eslint/no-unused-vars": [
"error",
{
varsIgnorePattern: "^_",
argsIgnorePattern: "^_",
},
],
},
languageOptions: {
parserOptions: {
projectService: true,
},
},
},
{
files: ["**/*.js", "**/*.mjs"],
...tseslint.configs.disableTypeChecked,
},
{
files: ["test/**/*.ts"],
...eslintPluginJest.configs["flat/recommended"],
},
{
ignores: ["coverage/", "dist/", "node_modules/"],
},
);
export default config;
3 changes: 2 additions & 1 deletion actions/lint-pr-title/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
"eslint-plugin-prettier": "5.2.1",
"prettier": "3.4.1",
"typescript": "5.7.2",
"typescript-eslint": "8.16.0"
"typescript-eslint": "8.16.0",
"@grafana/eslint-config-shared-workflows": "workspace:*"
},
"packageManager": "[email protected]"
}
Binary file added bun.lockb
Binary file not shown.
15 changes: 15 additions & 0 deletions internal/check-for-non-releasable-actions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# check-for-non-releasable-actions

To install dependencies:

```bash
bun install
```

To run:

```bash
bun run main.ts
```

This project was created using `bun init` in bun v1.1.36. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
24 changes: 24 additions & 0 deletions internal/check-for-non-releasable-actions/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Check for actions and reusable workflows without a release
description: Check for actions and reusable workflows that don't have a release-please configuration.

runs:
using: "composite"
steps:
- name: Install bun package manager
uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.1
with:
bun-version-file: actions/lint-pr-title/package.json

- name: Install dependencies
shell: sh
working-directory: ${{ github.action_path }}
run: |
bun install --frozen-lockfile --production
- name: Lint PR title
shell: sh
working-directory: ${{ github.action_path }}
env:
NODE_ENV: "production"
run: |
bun run --cwd ../.. internal/check-for-non-releasable-actions/index.ts
3 changes: 3 additions & 0 deletions internal/check-for-non-releasable-actions/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import config from "@grafana/eslint-config-shared-workflows";

export default config;
35 changes: 35 additions & 0 deletions internal/check-for-non-releasable-actions/filesystem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { readFile, readdir } from "fs/promises";

/**
* A representation of a directory entry, which can be either a file or a
* directory. This is a subset of the `fs.Dirent` interface containing just the
* parts we need.
*/
export interface DirectoryEntry {
name: string;
isDirectory: () => boolean;
isFile: () => boolean;
}

/**
* Abstraction of the filesystem for reading directories and files. This is to
* allow for easier testing by providing an in-memory filesystem implementation.
*/
export interface FileSystem {
readDirectory: (path: string) => Promise<DirectoryEntry[]>;
readFile: (path: string) => Promise<string>;
}

/**
* Implementation of the filesystem using Node.js's built-in `fs` module, used
* in production.
*/
export class NodeFileSystem implements FileSystem {
async readDirectory(path: string): Promise<DirectoryEntry[]> {
return readdir(path, { withFileTypes: true });
}

async readFile(path: string): Promise<string> {
return readFile(path, "utf-8");
}
}
6 changes: 6 additions & 0 deletions internal/check-for-non-releasable-actions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { NodeFileSystem } from "./filesystem";
import { main } from "./main";
import config from "../../release-please-config.json" assert { type: "json" };

const fs = new NodeFileSystem();
process.exit(await main(fs, config));
Loading

0 comments on commit c7f4ffd

Please sign in to comment.