Skip to content

Commit

Permalink
Add dry run mode
Browse files Browse the repository at this point in the history
Having a dry run mode is very useful, e.g. in a CI/CD pipeline the dry
run mode can be run on feature branches and pull requests to verify that
the Gauge specs are in a valid state for publishing.  If they are not
valid then the CI/CD pipeline build can fail, alerting the submitter
of the pull request to amend them on the feature branch.  This ensures
that the Gauge specs are always in good shape to be automatically
published by the CI/CD pipeline upon any push to the trunk branch (e.g.
upon a successful pull request merge).

The dry run mode is set by setting a `DRY_RUN` environment variable
or property (we can't use a command-line flag for this as [Gauge does
not propagate command line flags to documentation plugins][1]).

[1]: getgauge/spectacle#42 (comment)
  • Loading branch information
johnboyes authored Aug 16, 2021
1 parent 2414803 commit 233d0c3
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 7 deletions.
36 changes: 36 additions & 0 deletions functional-tests/specs/dry_run.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Dry run mode

Having a dry run mode is very useful, e.g. in a CI/CD pipeline the dry run mode can be run on feature branches and pull
requests to verify that the Gauge specs are in a valid state for publishing. If they are not valid then the CI/CD
pipeline build can fail, alerting the submitter of the pull request to amend them on the feature branch. This ensures
that the Gauge specs are always in good shape to be automatically published by the CI/CD pipeline upon any push to the
trunk branch (e.g. upon a successful pull request merge).

The dry run mode is set by setting a `DRY_RUN` environment variable or property (we can't use a command-line flag for
this as [Gauge does not propagate command line flags to documentation plugins][1]).


|spec 1 heading|spec 2 heading|did publishing occur?|message |
|--------------|--------------|---------------------|-----------------------------------|
|same |same |did not |Please fix the error then try again|
|same |different |did not |Dry run finished successfully |


## Dry run mode indicates if specs are in a publishable state or not

* Activate dry run mode

* Publish specs to Confluence:

|heading |
|----------------|
|<spec 1 heading>|
|<spec 2 heading>|

* Output contains <message>

* publishing <did publishing occur?> occur

__________________________________________________________________________________________

[1]: https://github.com/getgauge/spectacle/issues/42#issuecomment-813483933
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,9 @@ public ExecutionSummary publishConfluenceDocumentation(String[] args, Map<String
throws Exception {
if (!envVars.containsKey("CONFLUENCE_SPACE_KEY"))
envVars.put("CONFLUENCE_SPACE_KEY", (String) Confluence.getScenarioSpaceKey());
if (Confluence.isDryRun()) {
envVars.put("DRY_RUN", "true");
}
boolean success = executeGaugeCommand(args, envVars);
return new ExecutionSummary(String.join(" ", args), success, lastProcessStdout, lastProcessStderr);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class Confluence {
private static final String SCENARIO_SPACE_KEY_NAME = "confluence-space-key";
private static final String SCENARIO_SPACE_NAME = "Space";
private static final String SCENARIO_SPACE_HOMEPAGE_ID_KEY_NAME = "confluence-space-homepage-id-key";
private static final String DRY_RUN_MODE = "dry-run-mode";

public static String getScenarioSpaceKey() {
return (String) ScenarioDataStore.get(SCENARIO_SPACE_KEY_NAME);
Expand All @@ -29,18 +30,28 @@ public static String getScenarioSpaceHomepageID() {
return (String) ScenarioDataStore.get(SCENARIO_SPACE_HOMEPAGE_ID_KEY_NAME);
}

public static boolean isDryRun() {
return (boolean) ScenarioDataStore.get(DRY_RUN_MODE);
}

@BeforeScenario
public void BeforeScenario() {
ScenarioDataStore.put(SCENARIO_SPACE_KEY_NAME, generateUniqueSpaceKeyName());
String spaceHomepageID = ConfluenceClient.createSpace(getScenarioSpaceKey(), SCENARIO_SPACE_NAME);
ScenarioDataStore.put(SCENARIO_SPACE_HOMEPAGE_ID_KEY_NAME, spaceHomepageID);
ScenarioDataStore.put(DRY_RUN_MODE, false);
}

@AfterScenario
public void AfterScenario() {
ConfluenceClient.deleteSpace(getScenarioSpaceKey());
}

@Step("Activate dry run mode")
public void activateDryRunMode() {
ScenarioDataStore.put(DRY_RUN_MODE, true);
}

@Step("Published pages are: <table>")
public void assertPublishedPages(Table expectedPages) throws Exception {
int expectedTotal = expectedPages.getTableRows().size();
Expand All @@ -61,7 +72,7 @@ public void didPublishingOccur(String didPublishingOccur) throws IOException {
new Console().outputContains("Success: published");
assertThat(space.totalPages()).isGreaterThan(1);
} else {
new Console().outputContains("Failed");
new Console().outputDoesNotContain("Success: published");
assertThat(space.totalPages()).isEqualTo(1);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ public void outputContains(String message) throws IOException {
assertThat(output).contains(message);
}

@Step("Output doesNotContain <message>")
public void outputDoesNotContain(String message) throws IOException {
String output = getCurrentProject().getStdOut();
assertThat(output).doesNotContain(message);
}

@Step({ "Output contains <message> <message2> <message3>" })
public void outputContainsMessages(String message, String message2, String message3) throws IOException {
String output = getCurrentProject().getStdOut();
Expand Down
16 changes: 10 additions & 6 deletions internal/confluence/publisher.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,26 +47,30 @@ func makeSpecsMap(m *gauge_messages.SpecDetails) map[string]Spec {
func (p *Publisher) Publish(specPaths []string) {
var err error

logger.Infof(true, "Preparing to publish Gauge specs to Confluence ...")
logger.Infof(true, "Checking specs are in a valid state for publishing to Confluence ...")

err = p.space.setup()
if err != nil {
p.printFailureMessage(err)
return
}

logger.Infof(true, "Checking specs can be published ...")

for _, specPath := range specPaths {
err = p.dryRunChecks(specPath)
if err != nil {
p.printFailureMessage(err)
logger.Infof(true, "Please fix the error then try again")

return
}
}

logger.Infof(true, "Checking finished successfully ...")
if env.GetBoolean("DRY_RUN") {
logger.Infof(true, "Dry run finished successfully")
return
}

logger.Infof(true, "Checking finished successfully")
logger.Infof(true, "Publishing Gauge specs to Confluence ...")

err = p.space.deleteAllPagesExceptHomepage()
Expand Down Expand Up @@ -97,11 +101,11 @@ func (p *Publisher) Publish(specPaths []string) {
return
}

fmt.Printf("Success: published %d specs and directory pages to Confluence", len(p.space.publishedPages))
logger.Infof(true, "Success: published %d specs and directory pages to Confluence", len(p.space.publishedPages))
}

func (p *Publisher) printFailureMessage(s interface{}) {
fmt.Printf("Failed: %v", s)
logger.Infof(true, "Failed: %v", s)
}

func (p *Publisher) dryRunChecks(baseSpecPath string) (err error) {
Expand Down
7 changes: 7 additions & 0 deletions internal/env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package env
import (
"fmt"
"os"
"strings"
)

// GetRequired returns an environment variable value or panics if not present.
Expand All @@ -16,3 +17,9 @@ func GetRequired(key string) string {

return value
}

// GetBoolean returns true if the environment variable exists and has a value of "true"
func GetBoolean(key string) bool {
value := os.Getenv(key)
return strings.ToLower(value) == "true"
}

0 comments on commit 233d0c3

Please sign in to comment.