diff --git a/.betterer.results b/.betterer.results index 3e165bedf0d..59d950253ae 100644 --- a/.betterer.results +++ b/.betterer.results @@ -876,21 +876,11 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "1"], [0, 0, 0, "Unexpected any. Specify a different type.", "2"] ], - "packages/grafana-toolkit/src/cli/tasks/plugin.utils.ts:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"], - [0, 0, 0, "Unexpected any. Specify a different type.", "1"], - [0, 0, 0, "Unexpected any. Specify a different type.", "2"] - ], "packages/grafana-toolkit/src/cli/tasks/task.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"], [0, 0, 0, "Unexpected any. Specify a different type.", "2"] ], - "packages/grafana-toolkit/src/cli/utils/githubRelease.ts:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"], - [0, 0, 0, "Unexpected any. Specify a different type.", "1"], - [0, 0, 0, "Unexpected any. Specify a different type.", "2"] - ], "packages/grafana-toolkit/src/cli/utils/useSpinner.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] diff --git a/packages/grafana-toolkit/config/circleci/config.yml b/packages/grafana-toolkit/config/circleci/config.yml deleted file mode 100644 index d1438c2be92..00000000000 --- a/packages/grafana-toolkit/config/circleci/config.yml +++ /dev/null @@ -1,295 +0,0 @@ -version: 2.1 - -parameters: - ssh-fingerprint: - type: string - default: ${GITHUB_SSH_FINGERPRINT} - -aliases: - # Workflow filters - - &filter-only-master - branches: - only: master - - &filter-only-release - branches: - only: /^v[1-9]*[0-9]+\.[1-9]*[0-9]+\.x$/ - -workflows: - plugin_workflow: - jobs: - - yarn_install - - build_docs: - requires: - - yarn_install - - build_frontend: - requires: - - yarn_install - - build_backend: - requires: - - yarn_install - - package: - requires: - - build_frontend - - build_backend - - build_docs - - provisioning: - requires: - - build_frontend - - build_backend - - build_docs - - e2e_canary: - requires: - - provisioning - - package - - report: - requires: - - package - - e2e_canary - - approve_release: - type: approval - requires: - - report - filters: *filter-only-release - - publish_github_release: - requires: - - approve_release - filters: *filter-only-release - -executors: - default_exec: # declares a reusable executor - docker: - - image: srclosson/grafana-plugin-ci-alpine:latest - e2e_exec: - docker: - - image: srclosson/grafana-plugin-ci-e2e:latest - -jobs: - yarn_install: - executor: default_exec - steps: - - checkout - - restore_cache: - name: restore yarn cache - keys: - - build-cache-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }} - - run: - name: Install dependencies - command: | - mkdir ci - yarn bin grafana-toolkit ] || yarn install --immutable - - save_cache: - name: save yarn cache - paths: - - ~/project/.yarn - key: build-cache-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }} - - save_cache: - name: save cypress cache - paths: - - ~/.cache/Cypress - key: cypress-cache-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }} - - build_docs: - executor: default_exec - steps: - - checkout - - restore_cache: - name: restore yarn cache - keys: - - build-cache-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }} - - run: - name: Build docs - command: | - yarn run grafana-toolkit plugin:ci-docs - [ -d "dist" ] || circleci-agent step halt - - persist_to_workspace: - root: . - paths: - - dist - - build_frontend: - executor: default_exec - steps: - - checkout - - restore_cache: - name: restore yarn cache - keys: - - build-cache-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }} - - run: - name: Build and test frontend - command: yarn run grafana-toolkit plugin:ci-build - - persist_to_workspace: - root: . - paths: - - dist - - build_backend: - executor: default_exec - steps: - - checkout - - restore_cache: - name: restore yarn cache - keys: - - build-cache-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }} - - run: - name: Exit if no backend - command: | - [ -f "Magefile.go" ] || circleci-agent step halt - - run: - name: Build backend - command: mage -v buildAll - - run: - name: Test backend - command: | - mage -v lint - mage -v coverage - - persist_to_workspace: - root: . - paths: - - dist - - package: - executor: default_exec - steps: - - checkout - - restore_cache: - name: restore yarn cache - keys: - - build-cache-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }} - - attach_workspace: - at: . - - run: - name: Move results to ci folder - command: yarn run grafana-toolkit plugin:ci-build --finish - - run: - name: Package distribution - command: | - yarn run grafana-toolkit plugin:ci-package - - persist_to_workspace: - root: . - paths: - - ci/jobs/package - - ci/packages - - ci/dist - - ci/grafana-test-env - - store_artifacts: - path: ci - - provisioning: - executor: default_exec - steps: - - run: - name: Continue if this plugin has a provisioning path - command: | - [ -z "${PROVISIONING_REPO_PATH}" ] && circleci-agent step halt - - checkout - - add_ssh_keys: - fingerprints: - - << pipeline.parameters.ssh-fingerprint >> - - run: - name: Checkout provisioning files - command: git clone --depth 1 git@github.com:grafana/plugin-provisioning.git - - run: - name: Prepare task output dir - command: | - mkdir ci # Avoid error if not exists - mkdir ci/jobs # Avoid error if not exists - mkdir ci/jobs/provisioning - mv plugin-provisioning/${PROVISIONING_REPO_PATH}/* ci/jobs/provisioning - - persist_to_workspace: - root: . - paths: - - ci/jobs/provisioning - - e2e_canary: - executor: e2e_exec - steps: - - run: - name: Continue if this plugin has a provisioning path - command: | - [ -z "${PROVISIONING_REPO_PATH}" ] && circleci-agent step halt - - checkout - - attach_workspace: - at: . - - restore_cache: - name: Restore yarn cache - keys: - - build-cache-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }} - - restore_cache: - name: Restore cypress cache - keys: - - cypress-cache-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }} - - run: - name: Exit if no e2e tests configured - command: | - [ -d cypress ] || circleci-agent step halt - - run: - name: Setup Grafana (local install) - command: | - ginstall canary - /opt/grafana/bin/grafana-server -config ci/grafana-test-env/custom.ini -homepath /opt/grafana & - ## To make sure grafana has started up - while ! $(netstat -tulpn | grep 3000 >/dev/null 2>&1); do sleep 1; done - /opt/grafana/bin/grafana-cli --version - - run: - name: Copy provisioning files - command: cp -r ci/jobs/provisioning provisioning/ - - run: - name: Run e2e tests - command: | - # If the tests fail, but GRAFANACI_STRICT_E2E=0, don't worry about it - yarn run grafana-e2e run \ - || ( - [ "$GRAFANACI_STRICT_E2E" -eq 0 ] && echo "Bypassing fail. ci-nostrict enabled" - ) - - run: - when: always - name: Prepare task output dir - command: | - # TODO: probably move all of this to `@grafana/toolkit plugin:ci-test` - mkdir ci/jobs/e2e_canary - # only copy if they exist - cp cypress/screenshots/*.* ci/jobs/e2e_canary 2>/dev/null || : - cp cypress/videos/*.* ci/jobs/e2e_canary 2>/dev/null || : - - persist_to_workspace: - root: . - paths: - - ci/jobs/e2e_canary - - store_test_results: - path: ci/jobs/e2e_canary - - store_artifacts: - path: ci/jobs/e2e_canary - - report: - executor: default_exec - steps: - - checkout - - attach_workspace: - at: . - - restore_cache: - name: restore yarn cache - keys: - - build-cache-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }} - - run: - name: Toolkit report - command: | - yarn run grafana-toolkit plugin:ci-report - - store_artifacts: - path: ci - - publish_github_release: - executor: default_exec - steps: - - checkout - - add_ssh_keys: - fingerprints: - - "dc:60:ab:c7:2d:8c:82:50:2a:2a:97:1a:c0:66:83:14" - - attach_workspace: - at: . - - restore_cache: - name: restore yarn cache - keys: - - build-cache-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }} - - run: - name: "Publish Release on GitHub" - command: | - yarn run grafana-toolkit plugin:github-publish diff --git a/packages/grafana-toolkit/package.json b/packages/grafana-toolkit/package.json index 6d36ce4b905..5741702f91e 100644 --- a/packages/grafana-toolkit/package.json +++ b/packages/grafana-toolkit/package.json @@ -57,7 +57,6 @@ "@grafana/ui": "10.0.0-pre", "@jest/core": "27.5.1", "@types/eslint": "8.4.1", - "@types/fs-extra": "^9.0.13", "@types/jest": "27.4.1", "@types/lodash": "4.14.181", "@types/node": "16.11.26", @@ -68,7 +67,6 @@ "@types/tmp": "0.2.3", "@typescript-eslint/eslint-plugin": "5.36.2", "@typescript-eslint/parser": "5.36.2", - "axios": "^0.26.1", "babel-jest": "27.5.1", "babel-loader": "^8.2.5", "babel-plugin-angularjs-annotate": "0.10.0", @@ -84,7 +82,6 @@ "eslint-plugin-react-hooks": "4.6.0", "execa": "^5.1.1", "fork-ts-checker-webpack-plugin": "^7.2.1", - "fs-extra": "^10.0.0", "globby": "^11.0.4", "html-loader": "^3.1.0", "html-webpack-plugin": "^5.5.0", diff --git a/packages/grafana-toolkit/src/cli/index.ts b/packages/grafana-toolkit/src/cli/index.ts index 0507f026aba..d2ceffd8867 100644 --- a/packages/grafana-toolkit/src/cli/index.ts +++ b/packages/grafana-toolkit/src/cli/index.ts @@ -4,7 +4,7 @@ import { program } from 'commander'; import { nodeVersionCheckerTask } from './tasks/nodeVersionChecker'; import { buildPackageTask } from './tasks/package.build'; import { pluginBuildTask } from './tasks/plugin.build'; -import { getToolkitVersion, githubPublishTask } from './tasks/plugin.utils'; +import { getToolkitVersion } from './tasks/plugin.utils'; import { templateTask } from './tasks/template'; import { toolkitBuildTask } from './tasks/toolkit.build'; import { execTask } from './utils/execTask'; @@ -127,26 +127,6 @@ export const run = (includeInternalScripts = false) => { process.exit(1); }); - program - .command('plugin:github-publish') - .option('--dryrun', 'Do a dry run only', false) - .option('--verbose', 'Print verbose', false) - .option('--commitHash ', 'Specify the commit hash') - .description('[Deprecated] Publish to github') - .action(async (cmd) => { - console.log( - chalk.yellow.bold(`⚠️ This command is deprecated and will be removed . No further support will be provided. ⚠️`) - ); - console.log( - 'We recommend using github actions directly for plugin releasing. You can find an example here: https://github.com/grafana/plugin-tools/tree/main/packages/create-plugin/templates/github/ci/.github/workflows' - ); - await execTask(githubPublishTask)({ - dryrun: cmd.dryrun, - verbose: cmd.verbose, - commitHash: cmd.commitHash, - }); - }); - program.on('command:*', () => { console.error('Invalid command: %s\nSee --help for a list of available commands.', program.args.join(' ')); process.exit(1); diff --git a/packages/grafana-toolkit/src/cli/tasks/plugin.utils.ts b/packages/grafana-toolkit/src/cli/tasks/plugin.utils.ts index 7852bd1d8b6..78254f43065 100644 --- a/packages/grafana-toolkit/src/cli/tasks/plugin.utils.ts +++ b/packages/grafana-toolkit/src/cli/tasks/plugin.utils.ts @@ -1,147 +1,4 @@ -import execa = require('execa'); import { readFileSync } from 'fs'; -import path = require('path'); - -import { getPluginId } from '../../config/utils/getPluginId'; -import { getPluginJson } from '../../config/utils/pluginValidation'; -import { getCiFolder } from '../../plugins/env'; -import { GitHubRelease } from '../utils/githubRelease'; -import { useSpinner } from '../utils/useSpinner'; - -import { Task, TaskRunner } from './task'; - -interface Command extends Array {} -const DEFAULT_EMAIL_ADDRESS = 'eng@grafana.com'; -const DEFAULT_USERNAME = 'CircleCI Automation'; - -const releaseNotes = async (): Promise => { - const { stdout } = await execa(`awk 'BEGIN {FS="##"; RS="##"} FNR==3 {print "##" $1; exit}' CHANGELOG.md`, { - shell: true, - }); - return stdout; -}; - -const checkoutBranch = async (branchName: string): Promise => { - const currentBranch = await execa(`git rev-parse --abbrev-ref HEAD`, { shell: true }); - const branchesAvailable = await execa( - `(git branch -a | grep "${branchName}$" | grep -v remote) || echo 'No release found'`, - { shell: true } - ); - - if (currentBranch.stdout !== branchName) { - console.log('available', branchesAvailable.stdout.trim()); - if (branchesAvailable.stdout.trim() === branchName) { - return ['git', ['checkout', branchName]]; - } else { - return ['git', ['checkout', '-b', branchName]]; - } - } - return []; -}; - -const gitUrlParse = (url: string): { owner: string; name: string } => { - let matchResult: RegExpMatchArray | null = []; - - if (url.match(/^git@github.com/)) { - // We have an ssh style url. - matchResult = url.match(/^git@github.com:(.*?)\/(.*?)\.git/); - } - - if (url.match(/^https:\/\/github.com\//)) { - // We have an https style url - matchResult = url.match(/^https:\/\/github.com\/(.*?)\/(.*?)\/.git/); - } - - if (matchResult && matchResult.length > 2) { - return { - owner: matchResult[1], - name: matchResult[2], - }; - } - - throw `Could not find a suitable git repository. Received [${url}]`; -}; - -const prepareRelease = ({ dryrun, verbose }: any) => - useSpinner('Preparing release', async () => { - const ciDir = getCiFolder(); - const distDir = path.resolve(ciDir, 'dist'); - const distContentDir = path.resolve(distDir, getPluginId()); - const pluginJsonFile = path.resolve(distContentDir, 'plugin.json'); - const pluginJson = getPluginJson(pluginJsonFile); - - const githubPublishScript: Command = [ - ['git', ['config', 'user.email', DEFAULT_EMAIL_ADDRESS]], - ['git', ['config', 'user.name', DEFAULT_USERNAME]], - await checkoutBranch(`release-${pluginJson.info.version}`), - ['/bin/rm', ['-rf', 'dist'], { dryrun }], - ['mv', ['-v', distContentDir, 'dist']], - ['git', ['add', '--force', 'dist'], { dryrun }], - ['/bin/rm', ['-rf', 'src'], { enterprise: true }], - ['git', ['rm', '-rf', 'src'], { enterprise: true }], - [ - 'git', - ['commit', '-m', `automated release ${pluginJson.info.version} [skip ci]`], - { - dryrun, - okOnError: [/nothing to commit/g, /nothing added to commit/g, /no changes added to commit/g], - }, - ], - ['git', ['push', '-f', 'origin', `release-${pluginJson.info.version}`], { dryrun }], - ['git', ['tag', '-f', `v${pluginJson.info.version}`]], - ['git', ['push', '-f', 'origin', `v${pluginJson.info.version}`]], - ]; - - for (let line of githubPublishScript) { - const opts = line.length === 3 ? line[2] : {}; - const command = line[0]; - const args = line[1]; - - try { - if (verbose) { - console.log('executing >>', line); - } - - if (line.length > 0 && line[0].length > 0) { - if (opts['dryrun']) { - line[1].push('--dry-run'); - } - - // Exit if the plugin is NOT an enterprise plugin - if (pluginJson.enterprise && !opts['enterprise']) { - continue; - } - - const { stdout } = await execa(command, args); - if (verbose) { - console.log(stdout); - } - } else { - if (verbose) { - console.log('skipping empty line'); - } - } - } catch (ex: any) { - const err: string = ex.message; - if (opts['okOnError'] && Array.isArray(opts['okOnError'])) { - let trueError = true; - for (let regex of opts['okOnError']) { - if (err.match(regex)) { - trueError = false; - break; - } - } - - if (!trueError) { - // This is not an error - continue; - } - } - console.error(err); - process.exit(-1); - } - } - }); export const getToolkitVersion = () => { const pkg = readFileSync(`${__dirname}/../../../package.json`, 'utf8'); @@ -151,73 +8,3 @@ export const getToolkitVersion = () => { } return version; }; -interface GithubPublishReleaseOptions { - commitHash?: string; - githubToken: string; - githubUser: string; - gitRepoName: string; -} - -const createRelease = ({ commitHash, githubUser, githubToken, gitRepoName }: GithubPublishReleaseOptions) => - useSpinner('Creating release', async () => { - const gitRelease = new GitHubRelease(githubToken, githubUser, gitRepoName, await releaseNotes(), commitHash); - return gitRelease.release(); - }); - -export interface GithubPublishOptions { - dryrun?: boolean; - verbose?: boolean; - commitHash?: string; - dev?: boolean; -} - -const githubPublishRunner: TaskRunner = async ({ dryrun, verbose, commitHash }) => { - let repoUrl: string | undefined = process.env.DRONE_REPO_LINK || process.env.CIRCLE_REPOSITORY_URL; - if (!repoUrl) { - // Try and figure it out - const repo = await execa('git', ['config', '--local', 'remote.origin.url']); - if (repo && repo.stdout) { - repoUrl = repo.stdout; - } else { - throw new Error( - 'The release plugin requires you specify the repository url as environment variable DRONE_REPO_LINK or ' + - 'CIRCLE_REPOSITORY_URL' - ); - } - } - - if (!process.env['GITHUB_ACCESS_TOKEN']) { - // Try to use GITHUB_TOKEN, which may be set. - if (process.env['GITHUB_TOKEN']) { - process.env['GITHUB_ACCESS_TOKEN'] = process.env['GITHUB_TOKEN']; - } else { - throw new Error( - `GitHub publish requires that you set the environment variable GITHUB_ACCESS_TOKEN to a valid github api token. - See: https://github.com/settings/tokens for more details.` - ); - } - } - - if (!process.env['GITHUB_USERNAME']) { - // We can default this one - process.env['GITHUB_USERNAME'] = DEFAULT_EMAIL_ADDRESS; - } - - const parsedUrl = gitUrlParse(repoUrl); - const githubToken = process.env['GITHUB_ACCESS_TOKEN']; - const githubUser = parsedUrl.owner; - - await prepareRelease({ - dryrun, - verbose, - }); - - await createRelease({ - commitHash, - githubUser, - githubToken, - gitRepoName: parsedUrl.name, - }); -}; - -export const githubPublishTask = new Task('GitHub Publish', githubPublishRunner); diff --git a/packages/grafana-toolkit/src/cli/utils/githubClient.test.ts b/packages/grafana-toolkit/src/cli/utils/githubClient.test.ts deleted file mode 100644 index ff6cfb0b132..00000000000 --- a/packages/grafana-toolkit/src/cli/utils/githubClient.test.ts +++ /dev/null @@ -1,107 +0,0 @@ -import GithubClient from './githubClient'; - -const fakeClient = jest.fn(); - -beforeEach(() => { - delete process.env.GITHUB_USERNAME; - delete process.env.GITHUB_ACCESS_TOKEN; -}); - -afterEach(() => { - delete process.env.GITHUB_USERNAME; - delete process.env.GITHUB_ACCESS_TOKEN; -}); - -describe('GithubClient', () => { - it('should initialise a GithubClient', () => { - const github = new GithubClient(); - const githubEnterprise = new GithubClient({ enterprise: true }); - expect(github).toBeInstanceOf(GithubClient); - expect(githubEnterprise).toBeInstanceOf(GithubClient); - }); - - describe('#client', () => { - it('it should contain a grafana client', () => { - // @ts-ignore - const spy = jest.spyOn(GithubClient.prototype, 'createClient').mockImplementation(() => fakeClient); - - const github = new GithubClient(); - const client = github.client; - - expect(spy).toHaveBeenCalledWith({ - baseURL: 'https://api.github.com/repos/grafana/grafana', - timeout: 10000, - }); - expect(client).toEqual(fakeClient); - }); - - it('it should contain a grafana enterprise client', () => { - // @ts-ignore - const spy = jest.spyOn(GithubClient.prototype, 'createClient').mockImplementation(() => fakeClient); - - const github = new GithubClient({ enterprise: true }); - const client = github.client; - - expect(spy).toHaveBeenCalledWith({ - baseURL: 'https://api.github.com/repos/grafana/grafana-enterprise', - timeout: 10000, - }); - expect(client).toEqual(fakeClient); - }); - - describe('when the credentials are required', () => { - it('should create the client when the credentials are defined', () => { - const username = 'grafana'; - const token = 'averysecureaccesstoken'; - - process.env.GITHUB_USERNAME = username; - process.env.GITHUB_ACCESS_TOKEN = token; - - // @ts-ignore - const spy = jest.spyOn(GithubClient.prototype, 'createClient').mockImplementation(() => fakeClient); - - const github = new GithubClient({ required: true }); - const client = github.client; - - expect(spy).toHaveBeenCalledWith({ - baseURL: 'https://api.github.com/repos/grafana/grafana', - timeout: 10000, - auth: { username, password: token }, - }); - - expect(client).toEqual(fakeClient); - }); - - it('should create the enterprise client when the credentials are defined', () => { - const username = 'grafana'; - const token = 'averysecureaccesstoken'; - - process.env.GITHUB_USERNAME = username; - process.env.GITHUB_ACCESS_TOKEN = token; - - // @ts-ignore - const spy = jest.spyOn(GithubClient.prototype, 'createClient').mockImplementation(() => fakeClient); - - const github = new GithubClient({ required: true, enterprise: true }); - const client = github.client; - - expect(spy).toHaveBeenCalledWith({ - baseURL: 'https://api.github.com/repos/grafana/grafana-enterprise', - timeout: 10000, - auth: { username, password: token }, - }); - - expect(client).toEqual(fakeClient); - }); - - describe('when the credentials are not defined', () => { - it('should throw an error', () => { - expect(() => { - // eslint-disable-next-line - new GithubClient({ required: true }); - }).toThrow(/operation needs a GITHUB_USERNAME and GITHUB_ACCESS_TOKEN environment variables/); - }); - }); - }); - }); -}); diff --git a/packages/grafana-toolkit/src/cli/utils/githubClient.ts b/packages/grafana-toolkit/src/cli/utils/githubClient.ts deleted file mode 100644 index 9643c166874..00000000000 --- a/packages/grafana-toolkit/src/cli/utils/githubClient.ts +++ /dev/null @@ -1,49 +0,0 @@ -import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'; - -const grafanaURL = (owner: string, repo: string) => `https://api.github.com/repos/${owner}/${repo}`; -const enterpriseURL = 'https://api.github.com/repos/grafana/grafana-enterprise'; - -// Encapsulates the creation of a client for the GitHub API -// -// Two key things: -// 1. You can specify whenever you want the credentials to be required or not when imported. -// 2. If the credentials are available as part of the environment, even if -// they're not required - the library will use them. This allows us to overcome -// any API rate limiting imposed without authentication. - -interface GithubClientProps { - required?: boolean; - enterprise?: boolean; - owner?: string; - repo?: string; -} - -class GithubClient { - client: AxiosInstance; - - constructor({ required = false, enterprise = false, owner = 'grafana', repo = 'grafana' }: GithubClientProps = {}) { - const username = process.env.GITHUB_USERNAME; - const token = process.env.GITHUB_ACCESS_TOKEN; - - const clientConfig: AxiosRequestConfig = { - baseURL: enterprise ? enterpriseURL : grafanaURL(owner, repo), - timeout: 10000, - }; - - if (required && !username && !token) { - throw new Error('operation needs a GITHUB_USERNAME and GITHUB_ACCESS_TOKEN environment variables'); - } - - if (username && token) { - clientConfig.auth = { username: username, password: token }; - } - - this.client = this.createClient(clientConfig); - } - - private createClient(clientConfig: AxiosRequestConfig) { - return axios.create(clientConfig); - } -} - -export default GithubClient; diff --git a/packages/grafana-toolkit/src/cli/utils/githubRelease.test.ts b/packages/grafana-toolkit/src/cli/utils/githubRelease.test.ts deleted file mode 100644 index 74fedc2a759..00000000000 --- a/packages/grafana-toolkit/src/cli/utils/githubRelease.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { GitHubRelease } from './githubRelease'; - -describe('GithubRelease', () => { - it('should initialise a GithubRelease', () => { - process.env.GITHUB_ACCESS_TOKEN = '12345'; - process.env.GITHUB_USERNAME = 'test@grafana.com'; - const github = new GitHubRelease('A token', 'A username', 'A repo', 'Some release notes'); - expect(github).toBeInstanceOf(GitHubRelease); - }); -}); diff --git a/packages/grafana-toolkit/src/cli/utils/githubRelease.ts b/packages/grafana-toolkit/src/cli/utils/githubRelease.ts deleted file mode 100644 index 1d59e2d4516..00000000000 --- a/packages/grafana-toolkit/src/cli/utils/githubRelease.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { AxiosResponse } from 'axios'; -import fs = require('fs'); -import path = require('path'); - -import { getPluginId } from '../../config/utils/getPluginId'; -import { getPluginJson } from '../../config/utils/pluginValidation'; -import { getCiFolder } from '../../plugins/env'; - -import GithubClient from './githubClient'; - -const resolveContentType = (extension: string): string => { - if (extension.startsWith('.')) { - extension = extension.slice(1); - } - switch (extension) { - case 'zip': - return 'application/zip'; - case 'json': - return 'application/json'; - case 'sha1': - return 'text/plain'; - default: - return 'application/octet-stream'; - } -}; - -class GitHubRelease { - token: string; - username: string; - repository: string; - releaseNotes: string; - commitHash?: string; - git: GithubClient; - - constructor(token: string, username: string, repository: string, releaseNotes: string, commitHash?: string) { - this.token = token; - this.username = username; - this.repository = repository; - this.releaseNotes = releaseNotes; - this.commitHash = commitHash; - - this.git = new GithubClient({ - required: true, - owner: username, - repo: repository, - }); - } - - publishAssets(srcLocation: string, destUrl: string) { - // Add the assets. Loop through files in the ci/dist folder and upload each asset. - const files = fs.readdirSync(srcLocation); - - return files.map(async (file: string) => { - const fileStat = fs.statSync(`${srcLocation}/${file}`); - const fileData = fs.readFileSync(`${srcLocation}/${file}`); - return this.git.client.post(`${destUrl}?name=${file}`, fileData, { - headers: { - 'Content-Type': resolveContentType(path.extname(file)), - 'Content-Length': fileStat.size, - }, - maxContentLength: fileStat.size * 2 * 1024 * 1024, - }); - }); - } - - async release() { - const ciDir = getCiFolder(); - const distDir = path.resolve(ciDir, 'dist'); - const distContentDir = path.resolve(distDir, getPluginId()); - const pluginJsonFile = path.resolve(distContentDir, 'plugin.json'); - const pluginInfo = getPluginJson(pluginJsonFile).info; - const PUBLISH_DIR = path.resolve(getCiFolder(), 'packages'); - const commitHash = this.commitHash || pluginInfo.build?.hash; - - try { - const latestRelease: AxiosResponse = await this.git.client.get(`releases/tags/v${pluginInfo.version}`); - - // Re-release if the version is the same as an existing release - if (latestRelease.data.tag_name === `v${pluginInfo.version}`) { - await this.git.client.delete(`releases/${latestRelease.data.id}`); - } - } catch (reason: any) { - if (reason.response.status !== 404) { - // 404 just means no release found. Not an error. Anything else though, re throw the error - throw reason; - } - } - - try { - // Now make the release - const newReleaseResponse = await this.git.client.post('releases', { - tag_name: `v${pluginInfo.version}`, - target_commitish: commitHash, - name: `v${pluginInfo.version}`, - body: this.releaseNotes, - draft: false, - prerelease: false, - }); - - const publishPromises = this.publishAssets( - PUBLISH_DIR, - `https://uploads.github.com/repos/${this.username}/${this.repository}/releases/${newReleaseResponse.data.id}/assets` - ); - await Promise.all(publishPromises); - } catch (reason: any) { - console.error(reason.data?.message ?? reason.response.data ?? reason); - // Rethrow the error so that we can trigger a non-zero exit code to circle-ci - throw reason; - } - } -} - -export { GitHubRelease }; diff --git a/packages/grafana-toolkit/src/plugins/env.ts b/packages/grafana-toolkit/src/plugins/env.ts deleted file mode 100644 index 56b9e126351..00000000000 --- a/packages/grafana-toolkit/src/plugins/env.ts +++ /dev/null @@ -1,10 +0,0 @@ -import fs from 'fs'; -import path from 'path'; - -export const getCiFolder = () => { - const dir = path.resolve(process.cwd(), 'ci'); - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir, { recursive: true }); - } - return dir; -}; diff --git a/packages/grafana-toolkit/src/plugins/index.ts b/packages/grafana-toolkit/src/plugins/index.ts deleted file mode 100644 index c1532d6d2e4..00000000000 --- a/packages/grafana-toolkit/src/plugins/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './env'; diff --git a/yarn.lock b/yarn.lock index 0cd65e92e8d..5c6a2b2c782 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3399,7 +3399,6 @@ __metadata: "@grafana/ui": 10.0.0-pre "@jest/core": 27.5.1 "@types/eslint": 8.4.1 - "@types/fs-extra": ^9.0.13 "@types/jest": 27.4.1 "@types/lodash": 4.14.181 "@types/node": 16.11.26 @@ -3410,7 +3409,6 @@ __metadata: "@types/tmp": 0.2.3 "@typescript-eslint/eslint-plugin": 5.36.2 "@typescript-eslint/parser": 5.36.2 - axios: ^0.26.1 babel-jest: 27.5.1 babel-loader: ^8.2.5 babel-plugin-angularjs-annotate: 0.10.0 @@ -3426,7 +3424,6 @@ __metadata: eslint-plugin-react-hooks: 4.6.0 execa: ^5.1.1 fork-ts-checker-webpack-plugin: ^7.2.1 - fs-extra: ^10.0.0 globby: ^11.0.4 html-loader: ^3.1.0 html-webpack-plugin: ^5.5.0 @@ -9495,15 +9492,6 @@ __metadata: languageName: node linkType: hard -"@types/fs-extra@npm:^9.0.13": - version: 9.0.13 - resolution: "@types/fs-extra@npm:9.0.13" - dependencies: - "@types/node": "*" - checksum: add79e212acd5ac76b97b9045834e03a7996aef60a814185e0459088fd290519a3c1620865d588fa36c4498bf614210d2a703af5cf80aa1dbc125db78f6edac3 - languageName: node - linkType: hard - "@types/geojson@npm:*": version: 7946.0.8 resolution: "@types/geojson@npm:7946.0.8" @@ -12471,15 +12459,6 @@ __metadata: languageName: node linkType: hard -"axios@npm:^0.26.1": - version: 0.26.1 - resolution: "axios@npm:0.26.1" - dependencies: - follow-redirects: ^1.14.8 - checksum: d9eb58ff4bc0b36a04783fc9ff760e9245c829a5a1052ee7ca6013410d427036b1d10d04e7380c02f3508c5eaf3485b1ae67bd2adbfec3683704745c8d7a6e1a - languageName: node - linkType: hard - "axios@npm:^0.27.2": version: 0.27.2 resolution: "axios@npm:0.27.2" @@ -19119,7 +19098,7 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.14.8": +"follow-redirects@npm:^1.0.0": version: 1.14.8 resolution: "follow-redirects@npm:1.14.8" peerDependenciesMeta: