From 3a9520ffae308f4c9bed43f1b3ba0a9465311e70 Mon Sep 17 00:00:00 2001 From: quike Date: Fri, 28 Apr 2023 23:11:38 -0400 Subject: [PATCH] feat: add screwdriver.cd support. (#278) Co-authored-by: Enrique Mora Parraga --- README.md | 71 +++++++++++++++++++++-------- index.js | 2 + package.json | 1 + services/screwdriver.js | 26 +++++++++++ test/index.test.js | 7 +++ test/services/screwdriver.test.js | 74 +++++++++++++++++++++++++++++++ 6 files changed, 162 insertions(+), 19 deletions(-) create mode 100644 services/screwdriver.js create mode 100644 test/services/screwdriver.test.js diff --git a/README.md b/README.md index f56910e..2087c95 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,9 @@ if (isCI) { **Note**: Some variables can be detected only on certain CI services. See [Supported CI](#supported-ci). -**Note**: The `pr` and `prBranch` properties are only available for builds triggered when a Pull Request is opened/updated and not on builds triggered by a push on a branch even if that branch happens to be the branch from which the Pull Request originated. +**Note**: The `pr` and `prBranch` properties are only available for builds triggered when a Pull Request is +opened/updated and not on builds triggered by a push on a branch even if that branch happens to be the branch from which +the Pull Request originated. ## Supported CI @@ -101,6 +103,7 @@ if (isCI) { | [Netlify](https://docs.netlify.com/configure-builds/environment-variables/#netlify-configuration-variables) | `netlify` | :white_check_mark: | [:warning:](#netlify) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | [Puppet](https://puppet.com/docs/pipelines-for-apps/enterprise/environment-variable.html) | `puppet` | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | | [Sail CI](https://sail.ci/docs/environment-variables) | `sail` | :white_check_mark: | [:warning:](#sail) | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| [Screwdriver.cd](https://docs.screwdriver.cd/user-guide/environment-variables) | `screwdriver` | :white_check_mark: | [:warning:](#screwdriver) | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | [Scrutinizer](https://scrutinizer-ci.com/docs/build/environment-variables) | `scrutinizer` | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | | [Semaphore](https://docs.semaphoreci.com/article/12-environment-variables) | `semaphore` | :white_check_mark: | [:warning:](#semaphore) | :white_check_mark: | [:warning:](#semaphore) | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | [Shippable](http://docs.shippable.com/ci/env-vars/#stdEnv) | `shippable` | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | @@ -114,9 +117,11 @@ if (isCI) { :warning: See [Caveats](#caveats) -**Note**: Unsupported properties will always be `undefined`. For example if a Ci services doesn't support triggering builds when a Pull Request is opened/updated, `isPr` will be `undefined`. +**Note**: Unsupported properties will always be `undefined`. For example if a Ci services doesn't support triggering +builds when a Pull Request is opened/updated, `isPr` will be `undefined`. -**Note**: If none of the above CI services is detected, `commit` and `branch` are determined based on the local Git repository, and `isCi` is determined based on the `CI` environment variable. +**Note**: If none of the above CI services is detected, `commit` and `branch` are determined based on the local Git +repository, and `isCi` is determined based on the `CI` environment variable. ## API @@ -138,7 +143,8 @@ The object to read environment variables from. Type: `String`
Default: `process.cwd()` -The current working directory in which to execute `git` commands used to determine the `commit` and `branch` [Result](#result) properties in case no [supported CI](#supported-ci) is detected. +The current working directory in which to execute `git` commands used to determine the `commit` +and `branch` [Result](#result) properties in case no [supported CI](#supported-ci) is detected. ### Result @@ -150,48 +156,75 @@ Type: `Object` ### AWS CodeBuild -AWS CodeBuild doesn't provide an environment variable to determine the current Git branch being built. In addition, it clones the repository in a [detached head state](https://git-scm.com/docs/git-checkout#_detached_head) so the branch cannot be determined with `git rev-parse --abbrev-ref HEAD`. -To work around this limitation, `env-ci` look for the remote branches having the same `HEAD` as the local detached `HEAD` to determine the branch from which the detached `HEAD` was created. -In the rare case where there is multiple remote branches with the same `HEAD` as the local detached `HEAD`, `env-ci` will arbitrarily pick the first one. This can lead to an inaccurate `branch` value in such circumstances. +AWS CodeBuild doesn't provide an environment variable to determine the current Git branch being built. In addition, it +clones the repository in a [detached head state](https://git-scm.com/docs/git-checkout#_detached_head) so the branch +cannot be determined with `git rev-parse --abbrev-ref HEAD`. +To work around this limitation, `env-ci` look for the remote branches having the same `HEAD` as the local +detached `HEAD` to determine the branch from which the detached `HEAD` was created. +In the rare case where there is multiple remote branches with the same `HEAD` as the local detached `HEAD`, `env-ci` +will arbitrarily pick the first one. This can lead to an inaccurate `branch` value in such circumstances. ### Buddy -For builds triggered when [a Pull Request is opened/updated](https://buddy.works/knowledge/deployments/pull-requests), Buddy doesn't provide an environment variable indicating the branch from which the Pull Request originated nor the target branch. It also build from a branch named `pull/` so the target branch cannot be determined with a `git` command. -Therefore in the case of Pull Request builds, `env-ci` will not be able to determine the `branch` and `prBranch` properties. +For builds triggered when [a Pull Request is opened/updated](https://buddy.works/knowledge/deployments/pull-requests), +Buddy doesn't provide an environment variable indicating the branch from which the Pull Request originated nor the +target branch. It also build from a branch named `pull/` so the target branch cannot be determined with +a `git` command. +Therefore, in the case of Pull Request builds, `env-ci` will not be able to determine the `branch` and `prBranch` +properties. See [feature request](https://forum.buddy.works/t/determine-pull-request-branch-with-environment-variable/911). ### CircleCI -For builds triggered when a Pull Request is opened/updated, CircleCI doesn't provide an environment variable indicating the target branch. -Therefore in the case of Pull Request builds, `env-ci` will not be able to determine the `branch` property. However `prBranch` will be set. +For builds triggered when a Pull Request is opened/updated, CircleCI doesn't provide an environment variable indicating +the target branch. +Therefore, in the case of Pull Request builds, `env-ci` will not be able to determine the `branch` property. +However `prBranch` will be set. See [feature request](https://discuss.circleci.com/t/create-a-circle-target-branch-envar/10022). ### Cloudflare Pages -For builds triggered when a Pull Request is opened/updated, Cloudflare Pages will re-use the branch variable for the originating branch and not provide a target. Therefore `env-ci` will not be able to determine the `prBranch` property however `branch` will always be set. +For builds triggered when a Pull Request is opened/updated, Cloudflare Pages will re-use the branch variable for the +originating branch and not provide a target. Therefore `env-ci` will not be able to determine the `prBranch` property +however `branch` will always be set. ### Jenkins -Triggering build when a Pull Request is opened/updated is supported only via the [ghprb-plugin](https://github.com/jenkinsci/ghprb-plugin) and [gitlab-plugin](https://github.com/jenkinsci/gitlab-plugin). Therefore `env-ci` will set `isPr`, `pr` and `prBranch` and define `branch` with the Pull Request target branch only if one those plugin is used. +Triggering build when a Pull Request is opened/updated is supported only via +the [ghprb-plugin](https://github.com/jenkinsci/ghprb-plugin) +and [gitlab-plugin](https://github.com/jenkinsci/gitlab-plugin). Therefore `env-ci` will set `isPr`, `pr` and `prBranch` +and define `branch` with the Pull Request target branch only if one those plugin is used. ### Netlify -For builds triggered when a Pull Request is opened/updated, Netlify doesn't provide an environment variable indicating the target branch. -Therefore in the case of Pull Request builds, `env-ci` will not be able to determine the `branch` property. However `prBranch` will be set. +For builds triggered when a Pull Request is opened/updated, Netlify doesn't provide an environment variable indicating +the target branch. +Therefore, in the case of Pull Request builds, `env-ci` will not be able to determine the `branch` property. +However `prBranch` will be set. See [feature request](https://answers.netlify.com/t/access-pr-target-branch-when-deploying-preview-build/32402) ### Sail -For builds triggered when a Pull Request is opened/updated, Sail doesn't provide an environment variable indicating the target branch, and the one for the current branch is set to `pull/` independently of the the branch name from which the Pull Request originated. -Therefore in the case of Pull Request builds, `env-ci` will not be able to determine the `branch` and `prBranch` properties. +For builds triggered when a Pull Request is opened/updated, Sail doesn't provide an environment variable indicating the +target branch, and the one for the current branch is set to `pull/` independently of the the branch name from +which the Pull Request originated. +Therefore, in the case of Pull Request builds, `env-ci` will not be able to determine the `branch` and `prBranch` +properties. ### Semaphore -For builds triggered when a Pull Request is opened/updated, Semaphore 1.0 doesn't provide an environment variable indicating the target branch. -Therefore in the case of Pull Request builds, `env-ci` will not be able to determine the `branch` property. However `prBranch` will be set. +For builds triggered when a Pull Request is opened/updated, Semaphore 1.0 doesn't provide an environment variable +indicating the target branch. +Therefore, in the case of Pull Request builds, `env-ci` will not be able to determine the `branch` property. +However `prBranch` will be set. On Semaphore 2.0 the `branch` and `prBranch` properties will work as expected. The property `tag` is only available on Semaphore 2.0. + +### Screwdriver + +For builds triggered when a Pull Request is opened/updated, Screwdriver sets the `env.GIT_BRANCH` as `head:pr` branch +type (Example:`origin/refs/pull/1/head:pr`) while at commit level (non PR) it does set it with the actual branch (Example: `origin/main`). diff --git a/index.js b/index.js index c7f5593..c5914d5 100644 --- a/index.js +++ b/index.js @@ -19,6 +19,7 @@ import jenkins from "./services/jenkins.js"; import netlify from "./services/netlify.js"; import puppet from "./services/puppet.js"; import sail from "./services/sail.js"; +import screwdriver from "./services/screwdriver.js"; import scrutinizer from "./services/scrutinizer.js"; import semaphore from "./services/semaphore.js"; import shippable from "./services/shippable.js"; @@ -50,6 +51,7 @@ const services = { netlify, puppet, sail, + screwdriver, scrutinizer, semaphore, shippable, diff --git a/package.json b/package.json index bf11a93..edd5c01 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "netlify", "puppet", "sail", + "screwdriver", "scrutinizer", "semaphore", "shippable", diff --git a/services/screwdriver.js b/services/screwdriver.js new file mode 100644 index 0000000..8fecc2a --- /dev/null +++ b/services/screwdriver.js @@ -0,0 +1,26 @@ +// https://docs.screwdriver.cd/user-guide/environment-variables + +export default { + detect({ env }) { + return Boolean(env.SCREWDRIVER); + }, + configuration({ env }) { + const pr = env.SD_PULL_REQUEST; + const isPr = Boolean(pr); + + return { + name: "Screwdriver.cd", + service: "screwdriver", + branch: isPr ? env.PR_BASE_BRANCH_NAME : env.GIT_BRANCH, + prBranch: isPr ? env.PR_BRANCH_NAME : undefined, + commit: env.SD_BUILD_SHA, + build: env.SD_BUILD_ID, + buildUrl: env.SD_UI_BUILD_URL, + job: env.SD_JOB_ID, + pr, + isPr, + slug: env.SD_PIPELINE_NAME, + root: env.SD_ROOT_DIR, + }; + }, +}; diff --git a/test/index.test.js b/test/index.test.js index 4cd77ee..ef66c5b 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -146,6 +146,13 @@ test("Sail CI", (t) => { t.is(service, "sail"); }); +test("Screwdriver.cd", (t) => { + const { isCi, service } = envCi({ env: { SCREWDRIVER: "true" } }); + + t.is(isCi, true); + t.is(service, "screwdriver"); +}); + test("Scrutinizer", (t) => { const { isCi, service } = envCi({ env: { SCRUTINIZER: "true" } }); diff --git a/test/services/screwdriver.test.js b/test/services/screwdriver.test.js new file mode 100644 index 0000000..7a37c06 --- /dev/null +++ b/test/services/screwdriver.test.js @@ -0,0 +1,74 @@ +import test from "ava"; +import screwdriver from "../../services/screwdriver.js"; + +const env = { + SCREWDRIVER: "true", + SD_BUILD_SHA: "b5a94cdabf23b21303a0e6d5be5e96bd6300847a", + SD_PROJECT: "259", + SD_BUILD_ID: "173", + SD_EVENT_ID: "1", + SD_JOB_ID: "123", + SD_PIPELINE_NAME: "d2lam/myPipeline", + SCM_URL: "https://github.com/d2lam/myPipeline", + GIT_URL: "https://github.com/d2lam/myPipeline.git", + GIT_BRANCH: "my-branch", + SD_ROOT_DIR: "sd/workspace", + SD_SOURCE_DIR: "sd/workspace/src/github.com/d2lam/myPipeline", +}; + +test("Push", (t) => { + t.deepEqual( + screwdriver.configuration({ + env: { + ...env, + SD_EVENT_ID: "pipeline", + GIT_BRANCH: "origin/main", + SD_UI_BUILD_URL: `https://cd.screwdriver.cd/pipelines/${env.SD_PROJECT}/builds/${env.SD_BUILD_ID}`, + }, + }), + { + name: "Screwdriver.cd", + service: "screwdriver", + commit: "b5a94cdabf23b21303a0e6d5be5e96bd6300847a", + build: "173", + buildUrl: "https://cd.screwdriver.cd/pipelines/259/builds/173", + job: "123", + branch: "origin/main", + prBranch: undefined, + pr: undefined, + isPr: false, + slug: "d2lam/myPipeline", + root: "sd/workspace", + } + ); +}); + +test("PR", (t) => { + t.deepEqual( + screwdriver.configuration({ + env: { + ...env, + SD_PULL_REQUEST: "1", + SD_EVENT_ID: "pr", + PR_BASE_BRANCH_NAME: "main", + PR_BRANCH_NAME: "origin/feat/env-ci", + GIT_BRANCH: "origin/refs/pull/1/head:pr", + SD_UI_BUILD_URL: `https://cd.screwdriver.cd/pipelines/${env.SD_PROJECT}/builds/${env.SD_BUILD_ID}`, + }, + }), + { + name: "Screwdriver.cd", + service: "screwdriver", + commit: "b5a94cdabf23b21303a0e6d5be5e96bd6300847a", + build: "173", + buildUrl: "https://cd.screwdriver.cd/pipelines/259/builds/173", + job: "123", + branch: "main", + prBranch: "origin/feat/env-ci", + pr: "1", + isPr: true, + slug: "d2lam/myPipeline", + root: "sd/workspace", + } + ); +});